Skip to content

SPLIT v0.1.0 — first pre-release

Pre-release
Pre-release

Choose a tag to compare

@GPTmadeit GPTmadeit released this 09 Aug 04:38
· 22 commits to main since this release

A shot timer for Pixel Watch 4. The watch beeps, listens and times; the phone is a durable replica.

▶ Try it in your browser — no install, works on a phone.


Why a watch microphone can do this at all

A 9mm at the shooter's ear runs 160–165 dB SPL. The MEMS capsule in the watch clips around 120–130 dB, so every shot overdrives it by 30–45 dB and the amplitude coming off the ADC is meaningless — it is simply railed.

That does not matter, because a shot timer needs an arrival time, not a level. And the saturation turns out to be the best discriminator available: your own muzzle rails the converter for milliseconds, while the shooter two bays over arrives ~30 dB down and never rails at all.

What's in it

  • Sample-accurate timing. AudioRecord.getTimestamp() gives a HAL (framePosition, nanoTime) anchor, so onset resolution is one sample (20.8 µs @ 48 kHz) rather than one buffer (~10 ms). The start instant is AudioTrack.getTimestamp() rewound to frame 0, making first-shot time a difference of two HAL timestamps rather than two thread wakeups.
  • AGC defeated. AudioSource.UNPROCESSED where supported, else VOICE_RECOGNITION. Leave AGC live and gain ducks after round one, so every subsequent split is measured through a moving target.
  • Neighbour rejection via clip-run length, plus an optional accelerometer recoil gate (off by default — read the caveats first).
  • Two transports. MessageClient mirrors a running string (best effort, droppable). DataClient carries completed strings (replicated, survives the phone sitting in a range bag out of Bluetooth range all session). The watch writes locally before it ever reaches for the phone.
  • Nine drills — Bill, Failure to Stop, F.A.S.T., 1‑Reload‑1, Blake, El Presidente, Casino, Dot Torture, Freestyle — with enforced shot counts and pars, split σ, and USPSA hit factor.
  • Wear Compose M3 on the watch, Material 3 Expressive on the phone, physics-based motion throughout.

Install

Both APKs are debug-signed — fine for sideloading, not for Play. Publishing needs your own signing key.

adb -s <watch-serial> install -r split-wear-v0.1.0-debug.apk
adb -s <phone-serial> install -r split-mobile-v0.1.0-debug.apk

The two share an applicationId on purpose: that is what makes Play deliver the watch APK to a paired watch when the phone app installs.

⚠️ Read before trusting a number this produces

Nothing here has run on hardware, and no live fire has been recorded through it. ./gradlew build passes clean — both modules, debug and release, Android Lint reporting no issues — and the manifests are verified against the packaged APKs. That is the entire extent of the validation.

The detector constants are reasoned starting points, not measured ones:

Constant Value Basis
Clip-run threshold 3 samples estimate
Echo blanking 60 ms estimate
Recoil window ±40 ms estimate
Recoil threshold 18 m/s² estimate

Expect to characterise all four against your own gun and your own range. The recoil gate in particular depends on grip and which wrist you wear the watch on — support-hand on a two-handed grip reads cleanly, one-handed off-hand may read nothing.

Known limitations

  • compileSdk is pinned at 36 and several dependencies are held back accordingly; platform 37 is not published yet. material3 is on 1.5.0-alpha18 because the Expressive API is compiled internal in 1.4.0 stable. Details in the README.
  • The browser prototype cannot truly pin UNPROCESSED — browsers apply AGC and noise suppression by default and the page can only request they be turned off.
  • No licence file, so default copyright applies.