← Back to SnoreLog

SnoreLog records audio through the night and needs to automatically identify which segments are snoring. The challenge is that bedrooms aren't quiet — air conditioning, fans, traffic, and other ambient noise all register as sound. A simple “loud = snoring” approach would flag everything.

For v1, I deliberately avoided ML and frequency analysis. The goal was a baseline that runs in real time on any phone with zero dependencies — just raw amplitude. The detector is a 4-state finite state machine that watches dB levels sampled every 200ms and groups sustained loud segments into discrete snore events.

  • Sampling — Audio amplitude is read every 200ms and converted to a dB scale (20–90 range) using the formula (dbFS + 60) × 1.5, clamped.
  • IDLE → DETECTING — When dB exceeds the 40 dB threshold, the detector starts watching.
  • DETECTING → SNORE EVENT — If the sound stays above threshold for 500ms+, it's confirmed as a snore event. Brief spikes that drop below threshold are discarded.
  • SNORE EVENT → COOLDOWN — When sound drops below threshold, a 10-second cooldown begins. If sound resumes within the cooldown, it's merged into the same event. Otherwise, the event is finalized.

Score is based on events per hour: <5 → 95 (Great), 5–15 → 80, 15–30 → 60, 30–60 → 40, 60+ → 20 (Poor). Simple, but gives users a quick sense of severity.

In real-world testing, v1 completely failed to distinguish snoring from environmental noise. Sleeping rooms are far noisier than I expected — a ticking clock on the nightstand, an air purifier humming, a phone vibrating, even bedsheets rustling all exceeded 40 dB. In one test, the clock next to my phone was recorded louder than my actual snoring, generating dozens of false positives while the real snore events were buried in the noise floor. The algorithm detected “loud sounds,” not snoring — and in a bedroom at night, most loud sounds aren't snoring.

  • Amplitude alone is not enough — Snoring has a distinctive low-frequency pattern (typically 80–300 Hz with harmonics), but v1 only looks at overall loudness. A ticking clock at 60 dB and a snore at 60 dB are treated identically.
  • No ambient baseline — The fixed 40 dB threshold assumes a quiet room. In practice, background noise often sits at 35–45 dB, making the threshold useless.
  • Temporal pattern ignored — Snoring has a rhythmic, breath-linked cadence (inhale silence → exhale snore, repeating every 3–5 seconds). Clocks tick at a constant rate. The algorithm doesn't analyze periodicity at all.
  • Frequency analysis (FFT) — Decompose audio into frequency bands and look for energy concentrated in the 80–300 Hz snoring range, filtering out high-frequency noise like clock ticks or phone buzzes.
  • Adaptive threshold — Sample the first few minutes of recording to establish a room-specific noise baseline, then set thresholds relative to that baseline instead of using a fixed value.
  • Periodicity detection — Identify the rhythmic inhale-exhale cycle characteristic of snoring. Regular, breath-interval repetitions are a strong signal that amplitude alone can't capture.
  • Spectral shape classification — Snoring produces a broadband, harmonic-rich spectrum distinct from narrow-band mechanical sounds. Even a simple spectral template match could dramatically reduce false positives.