--downbeat-log: the estimator's terms, one row per beat
The one instrument on this page that runs the live app rather than a headless
capture, and that is the point of it (Plan 0086 Phase 1). The question it exists
for cannot be asked of synthesized audio: the downbeat estimator publishes on
6.0 % of audible time and on backbeat rock/pop 0.14 %, and the cause is
still inferred — diagnostics.log samples at 1 Hz and records the estimator’s
outcome, not its per-beat terms, so three different failures fit the same reading.
# Windows: a row per detected beat, alongside the 1 Hz diagnostics.logritmolux.exe --downbeat-logritmolux.exe --downbeat-log C:\path\to\downbeat.log # or --downbeat-log=<path>A bare flag writes downbeat.log beside diagnostics.log under the per-user app
dir — the same three argument shapes --soak takes. Off by default:
without the flag no logger exists and the frame loop is unchanged.
One tab-separated row per beat, header on a fresh file:
| column | what it is |
|---|---|
beat | the beat clock’s beat_index — gaps mean beats the render loop coalesced. Not the counter the fold buckets by; that is fold_beat, below |
s0..s3 | mean accent per candidate beat-1 alignment: the 4/4 fold’s own output |
best | the alignment the fold favours right now |
held | the alignment actually held, which lags best by the hysteresis |
effect_raw | between-alignment share of accent variance, before correction |
null_share | what four groups would explain by chance at this history length |
effect_corrected | what the gate compares — and the published downbeat_confidence, bit for bit |
beats_seen | accents recorded, against the 8-beat floor, saturating at 32 |
locked | 0/1, so the publish rate over a run is the mean of the column |
bass mid treb onset | the normalized levels for context |
bpm | the tempo tracker’s estimate — read the row rate against it (see below) |
time_since_beat | how stale this row’s band levels are: they come from the latest analysis hop, not necessarily the hop the beat fired on |
unix_ms | the time axis. Deltas between rows are the inter-detection interval, and it lines a capture up against a diagnostics.log from the same session |
fold_beat | the counter s0..s3, best and held are indexed in — the grid’s tempo-driven beat count once the grid runs, beat_index before that. Bucket the accent by fold_beat % 4, never by beat % 4 |
grid_bar_phase | where fold_beat sits across the bar, [0, 1), ungated — no alignment subtracted, so it says where the grid is rather than where the estimator thinks beat 1 is. Only a grid reading where bpm > 0; on a warmup row it is the tempo tracker’s onset-reset phase, so do not average the column down the whole file |
The last five are appended, never interleaved — the frozen-prefix rule
diagnostics.logfollows — so a capture taken before they existed stays parseable by column name.
beat and fold_beat are two different counters, and only the second one
indexes the alignment block. They were one number until Plan 0095 moved the fold
onto the bar grid (ADR-0109);
beat still means beat_index, unchanged, so that every capture taken before
that keeps parsing and stays comparable. Reading s0..s3 against beat % 4
produces a plausible, wrong answer — on the synthesized 4/4 in
standalone/src/downbeatlog.rs it puts the accent on phase 0 while the fold
reports 3 — which is what these two columns exist to stop.
Read the row rate against bpm before reading anything else. The beat flag
that paces these rows comes from the onset detector — an adaptive threshold on
spectral flux with a 96 ms refractory — and it is not tempo-gated
(core/src/dsp/onset.rs); beat_index is a straight count of those events
(core/src/dsp/tempo.rs). So rows / seconds against bpm / 60 is the number of
detections per musical beat, and it is not guaranteed to be 1. On a synthesized
clip with one transient per beat it measures exactly 1.00; on real material with
hats it does not — which is why the fold stopped bucketing by beat_index in
Plan 0095, and why the ratio is still worth reading: it is the size of the gap
between the beat column and fold_beat.
Reading it is what tells the three stories apart — the reason the plan spends a phase capturing before choosing a repair:
s0..s3flat andeffect_rawlow → the accent carries no bar-scale structure → the accent feature is the defect.- two scores tied and high, the other two low → a kick on 1 and 3 is 2-periodic, so the fold is choosing between two equally good answers → the repair is a cue independent of the drum pattern, and a second percussive band is the same ambiguity phase-shifted.
effect_rawhealthy buteffect_correctednear zero → the noise correction is eating a real effect at this history length → the window or the measure.
Three things to know before running one:
- It costs the estimator nothing.
Analyzer::downbeat_termsis&self, allocation-free and clock-free, so being observed cannot change what is observed. The write is on the render thread — never the audio callback — and event-paced: ~2 rows/s at 120 BPM, and a frame with no beat costs a bool test. - A hidden window logs nothing. Rows come off the frame path, which returns early while occluded or zero-sized. Keep the window up for a capture.
- Run matched material. The measurement this file exists for is a genre
split — unambiguous 4/4 backbeat rock/pop against a four-on-the-floor control,
matched in duration — so the result is comparable with Plan 0068’s 6.79 % /
0.14 % baseline. And do not re-measure by ear:
lockedis the outcome instrument and the score columns are the decomposition.
Built from a8ce055 at version 0.115.0. This site tracks main and is not versioned per release.