cadence census item 3: footstep smoother intake clocked at 28Hz (gotcha 32) -- the authored olympic windows breathe at their authored width again. The N=30/15 fill-0 windows (AUDWTHR.h:457) are sized for one sample per POD frame; the port's watcher poll fed one per poll, and the bench measured the poll path at ~141-147/s (MORE than render -- the wall window was 0.2s, not even 0.5s). Fix: only the Add is clocked (per-instance 28Hz wall clock, catch-up repeats the current sample capped at the largest authored window 30); the downstream forward still runs every poll with the held average, so watcher semantics are untouched; N untouched. BT_AUD_SMOOTH_HZ override (=0 restores per-poll). Measured: avgUpdates 70.6 -> 19-20/s, envelope wobble -26-45%, ramp90 0.55s -> 1.23s (the authored 30-sample/28Hz ~ 1.07s window restored in wall time), steady levels unchanged (0.852 vs 0.863 -- smoothing only, no level shift).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bw71WVsccjwW7uKRg4aWD
This commit is contained in:
Joe DiPrima
2026-08-13 19:54:34 -05:00
co-authored by Claude Fable 5
parent 567ffacaae
commit b355844847
+49 -1
View File
@@ -1,4 +1,5 @@
#include <cstdlib>
#include <map> // (BT411) the 28Hz smoother-intake clock (cadence census item 3)
#include "munga.h"
#pragma hdrstop
@@ -958,7 +959,54 @@ void
if (control_ID == controlID)
{
audioControlAverage.Add(control_value);
// (BT411 cadence census item 3, gotcha 32) SAMPLE INTAKE AT 28 Hz:
// the authored olympic windows (N=30/15, fill 0) are SIZED for one
// sample per POD frame (28 Hz -- AUDWTHR.h:457); the port's watcher
// poll feeds one per RENDER frame (~59), which halves the smoothing
// window in wall time and feeds a noisier operand. Clock ONLY the
// Add (the smoother's own intake) on a per-instance 28 Hz wall
// clock; the forward below still runs EVERY poll with the held
// average, so downstream watcher semantics are untouched. During a
// hitch the pod would have taken ~28 samples/s of the stalled
// value -- catch-up repeats the current sample, capped at the
// largest authored window (30), heat.cpp #119 pattern.
// BT_AUD_SMOOTH_HZ=<hz> overrides (=0 restores per-poll intake).
{
static Scalar s_hz = -2.0f;
if (s_hz < -1.0f)
{
const char *hz = getenv("BT_AUD_SMOOTH_HZ");
s_hz = (hz != 0 && *hz != '\0') ? (Scalar)atof(hz) : 28.0f;
}
if (s_hz > 0.0f)
{
static std::map<const void *, DWORD> s_nextMs;
const DWORD now = GetTickCount();
const DWORD tick = (DWORD)(1000.0f / s_hz); // 35 ms at 28
DWORD &next = s_nextMs[this];
if (next == 0)
{
audioControlAverage.Add(control_value);
next = now + tick;
}
else if ((long)(now - next) >= 0)
{
int added = 0;
while ((long)(now - next) >= 0 && ++added <= 30)
{
audioControlAverage.Add(control_value);
next += tick;
}
if ((long)(now - next) >= 0)
next = now + tick; // hitch: resync
}
// else: off-tick poll -- hold; the average is forwarded below
}
else
{
audioControlAverage.Add(control_value); // legacy per-poll
}
}
if (getenv("BT_AUDIO_SPATIAL")) { static int s_sa=0;
if ((controlID == 100 || controlID == 101) && s_sa++ < 3000)