Skip to content
NewTesting a swim metronome with a Mac microphone
Logbook
Oct 31, 2026·5 MIN READ
Testing a swim metronome with a Mac microphone

Testing a swim metronome with a Mac microphone

A tester heard Vimo Swim beep 33% slower than set. We fixed the firmware in an afternoon, then built one command that records the beeps with the Mac mic and checks the tempo to 1%.

One of our testers set Vimo Swim to 0.75 s in the Tempo program and noticed it beeped in step with a FINIS Tempo Trainer set to 1.00 s. He did not stop at a feeling. He recorded it at home and showed me a spectrogram from BirdNET, an app made to recognise bird song. The device's own counter agreed with him: 694 beeps in 12:16, about 1.06 s per beep.

His device ran firmware 2.2.0-b82, and his spectrogram showed the same story: a steady rhythm, just at the wrong speed.

A metronome that is 33% slow is not a metronome. So today I fixed it, and then I made sure we can prove the fix with one command.

The bug was the beep itself

The cause was simple once we looked. The trainer waited the full interval after each signal had finished. So every beat came late by the length of the beep. With a 250 ms beep, 0.75 s became 1.00 s. With a 100 ms beep it became 0.85 s, which matched what the tester measured at the pool before he changed the beep length.

The fix moves every program to a fixed schedule: the next beat is due one interval after the previous beat was due, not after it ended. A signal longer than the interval delays the next beat, but never causes a burst of catch-up beats. The tick programs (Interval, Pace, Pomodoro and the rest) had the same problem with their seconds, so they got the same treatment.

That was the easy half. The hard half was: how do I know it is right, to 1%, without a lab?

One command, a microphone and a grid

I wanted something I can run on my desk with the device next to the MacBook. The result is a few just recipes in the firmware repo:

firmware repo
just beat-test 0.75          # record 120 s with the Mac mic, PASS/FAIL within 1%
just beat-test 1.00 300      # 5 minutes for a longer run
just beat-live 0.75          # live window with level and interval charts
just beat-spec 1.00 rec.wav  # spectrogram with the ideal beat grid

beat-test records with rec from sox (mono, 48 kHz, 16-bit), finds the start of each beep and compares the intervals with the set tempo. It prints a small ASCII chart in the terminal, writes an SVG next to the WAV and appends every result, with the firmware build number, to one log file.

Record in 16-bit. sox saves 24-bit audio in a WAV format that Python's standard wave module cannot read, and 16-bit is more than enough for timing.

The first runs were garbage

My first real recordings said the device was 15% fast, then 41% slow. The firmware was fine. The microphone was not. The device sat too far away, so most beeps never crossed the detection threshold, and room noise did.

You can see it in the top panel: the beeps are there, but most peaks stay just under the dashed threshold. A simple "mean gap between beeps" falls apart when you miss half of them.

So we changed the maths. Instead of averaging gaps, the script fits every beep time to a regular grid, t = t0 + k × interval. A missed beep just skips a k. A noise hit that lands off the grid gets dropped. The slope over the whole run still catches slow drift. After that change the same weak recordings gave a sensible answer, and a synthetic copy of the old bug still showed +33% FAIL.

Test your checker against the bug before you test the fix. If a fake recording of the broken behaviour does not FAIL, a PASS means nothing.

What the spectrogram showed

When a run at 1.00 s showed a few strange intervals, I drew a spectrogram, the same kind of chart the tester had sent me. The beep is a 1500 Hz tone with clear harmonics at 3, 4.5, 6 and 7.5 kHz. The dashed lines are a perfect 1.00 s grid.

Two things stood out. The odd intervals between 32 and 49 s were low-frequency noise, most likely talking or handling the device, not the firmware. And the zoom shows something real: at 54.46 s one beat came 85 ms early, and every beat after it stayed 85 ms ahead of the grid. A one-off phase jump, not drift. The 0.75 s recording had the same jump once, at 81.5 s.

The 5-minute run

Then I set a 250 ms beep, the worst case for the old bug, and recorded five minutes at 1.00 s.

results.txt
beeps     286 over 299.9 s  (missed 15, noise dropped 24)
target    1.000 s
interval  1.0000 s  (-0.00%)  fitted over the whole run
median    1.0000 s
PASS (limit 1%)

The old firmware would have shown 1.25 s. The phase stayed steady for the whole 300 s. The only movement was about 0.03 ms per beat, which is the Mac clock against the device clock. The 85 ms jump did not come back on a schedule, so my guess is a button press or the display waking up. That one, plus the 0.50 and 2.00 s runs with a 100 ms beep, went into tickets.

What it took

One afternoon: the fix, about 500 lines of Python, sox and a MacBook. The first few runs were wasted on a bad recording that looked like a firmware bug. Next time I would start with beat-spec on the very first recording. A spectrogram shows in one glance whether you are measuring the device or the room, and the tester knew that before I did.