Pitch Contour Recorder
Lossless, append-only record of a detected pitch contour.
The detector feeds every frame here, in detection order, via the internal write surface. Consumers read it two ways:
snapshot — the whole contour. For post-session scoring / analysis (read once at the end).
recent — the last N seconds. For a scrolling visualization, pulled each render frame.
Unbounded: it holds the whole session. A session is bounded in practice (a few minutes — tens of thousands of points, a few MB), so this is fine; for an open-ended use, call clear. There is deliberately no reactive emission — nothing is copied on write. snapshot / recent copy on read, so a render-rate consumer pays render-rate cost and a score-once consumer pays once. (Contrast the old per-frame whole-contour StateFlow, which copied on every detection frame.)
Thread-safe: the detector writes on the audio thread; visualization and end-of-session scoring read on other threads.
Functions
The recorded frame nearest timeSeconds, or null when nothing has been recorded. Frames are time-ordered, so this is a binary search — cheap enough to call per audio buffer (e.g. on-pitch clap judging).
The tail of the contour — frames within seconds of the most recent frame. For a scrolling visualization, pulled per render frame. Returns an empty contour when nothing has been recorded.
The whole recorded contour. For post-session scoring / analysis.