Releases: fobiat/openBPM
Release list
openBPM v1.2.0 - tested, and a real bug fixed
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
openBPM v1.1.0 - works with no wiring
openBPM now runs with nothing wired to the board.
A pin scan of the ideaspark ESP32-WROOM-32 showed that GPIO0 (BOOT) is the only onboard button software can read — the board's other buttons are EN/RST, which reset the chip in hardware and never reach a GPIO. GPIO34–GPIO39 idle low and cross-talk because they're input-only with no internal pull-up, so their apparent presses were floating noise rather than buttons.
So the BOOT button now drives all three actions by press length:
| Gesture | Action |
|---|---|
| Short press (< 0.6 s) | TAP |
| Long press (0.6 – 1.6 s) | SWAP |
| Hold (≥ 1.6 s) | MODE |
Flash it and it works immediately — no soldering required.
Also in this release
- Wired buttons keep single-press behaviour and work alongside the onboard one; each action accepts several pins. Set
GESTURE_PIN = 255insrc/main.cppto turn gestures off once you have three real buttons. pinscanno longer reports per-edge noise on input-only pins. It prints a twice-a-second level snapshot instead, so a held button is distinguishable from a floating pin.
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.0.0...v1.1.0
openBPM v1.0.0
First tagged release of openBPM — a tap-tempo BPM counter and beatmatch assistant for vinyl DJing on an ideaspark ESP32-WROOM-32.
Features
- Tap tempo with a rolling 8-interval average, outlier rejection and 3s idle auto-reset
- Two decks (A/B) with a pitch % readout — exactly how far to move the pitch fader
- Octave-aware matching — half/double-time records still line up, tagged
x2/1/2 - Drift timer — how long until the decks slip a full beat apart (
60 / ΔBPM) - Pitch bar with a centre detent, colour-coded green/amber/red on the TFT
- Pitch-range warning when a match needs more than ±8 %
- Beat pulse indicator as a visual metronome
- Tap-jitter readout so you know whether to trust the reading
- 8 named BPM slots persisted to flash, survive power-off
- WiFi library — the ESP32 hosts its own AP so you can name records and export CSV from a phone
- Screen sleep after 2 minutes idle
Supported boards
| Firmware | Board |
|---|---|
openBPM-tft.bin |
ideaspark ESP32-WROOM-32 + 1.14" ST7789 240×135 colour |
openBPM-oled.bin |
ideaspark ESP32-WROOM-32 + 0.96" SSD1306 128×64 mono |
openBPM-pinscan.bin |
Diagnostic — reports which GPIO each onboard button uses |
Buttons
Every action accepts several pins, so the board's onboard buttons and external wired buttons both work. Defaults: TAP = GPIO0 (onboard BOOT) + GPIO27, SWAP = GPIO26, MODE = GPIO25. Use the pin scanner to identify your board's onboard buttons and edit the lists in src/main.cpp.
Flashing
Build from source with PlatformIO:
pio run -e tft -t uploadOr flash a prebuilt binary at offset 0x10000:
esptool.py --chip esp32 write_flash 0x10000 openBPM-tft.binMIT licensed.