Files
lintunes/lintunes/tap_tempo.py
T
travandClaude Fable 5 407c5669c5 BPM tap button averages the whole session, not the last 8 taps
TapTempo kept a rolling window of 8 taps, so a long tapping session
chased the most recent taps instead of converging on the overall tempo
(trav noticed the estimate never settled). Every tap since the session
started now counts; a >2.5s gap still begins a fresh session.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 11:30:37 -04:00

35 lines
1.1 KiB
Python

"""Tap-tempo math, kept Qt-free so it's unit-testable."""
class TapTempo:
RESET_GAP_SECONDS = 2.5
def __init__(self):
self._taps: list[float] = []
def tap(self, now: float) -> int | None:
"""Record a tap at monotonic time `now`; returns the current bpm
estimate (None until there are two taps in the series). Every tap
since the series started counts — the estimate converges on the
overall tempo instead of chasing the most recent few taps."""
if self._taps and now - self._taps[-1] > self.RESET_GAP_SECONDS:
self._taps = []
self._taps.append(now)
return self.bpm()
def bpm(self) -> int | None:
if len(self._taps) < 2:
return None
intervals = [b - a for a, b in zip(self._taps, self._taps[1:])]
average = sum(intervals) / len(intervals)
if average <= 0:
return None
return round(60.0 / average)
@property
def tap_count(self) -> int:
return len(self._taps)
def reset(self):
self._taps = []