This release adds a desktop unit-test suite, and the suite immediately earned its keep by finding a genuine bug in the tap-tempo engine.
The bug it found
An off-beat tap cleared the averaging window and was then stored as its only sample. So one fumbled tap while tapping a steady 120 BPM slammed the readout to ~43 BPM — precisely the behaviour the docs claimed was handled.
The outlier is now discarded as well as resetting the window, and the previous reading stands while the window refills. Two clean taps re-establish the tempo, which is also what you want when you've genuinely moved to a record at a different speed.
Configurable pitch range
±8 % was hardcoded — correct for a Technics 1210, wrong for the many decks that do ±16 or wider, which were being told perfectly reachable matches were OUT OF RANGE.
Set it from the WiFi page; it's persisted to flash, and the pitch bar scales with it so full deflection always means the end of your fader.
Other fixes
- Clearing a slot on the device zeroed the BPM but left the record's name behind
- The OLED's jitter readout built its
±from a raw0xB1byte, which a font withoutU+00B1would silently drop — now ASCII+/- - A failed TFT sprite allocation left a silently black screen, indistinguishable from a wiring fault; it now says so
- The CSV download was still named
openbpmcount.csvafter the rename
Testing
pio test -e native # 34 tests, no board requiredapp.cpp has no Arduino dependency — Deck takes the current time as a parameter rather than calling millis() — so a whole tapping session can be simulated deterministically. Coverage spans tempo averaging, outlier rejection, idle reset, jitter, beat prediction, octave matching, pitch range and the drift timer. CI now runs these before building any firmware, so binaries can't ship from a tree whose maths is broken.
Flashing
pio run -e tft -t uploadOr flash a prebuilt binary at offset 0x10000:
esptool.py --chip esp32 write_flash 0x10000 openBPM-tft.binFull changelog: v1.1.0...v1.2.0