cadence census item 4: doppler velocity operand sample-and-held at 28Hz (gotcha 32) [T2 mechanism / T3 perceptual]. worldLinearVelocity is a raw per-render-frame position derivative; at ~59fps its gait-aliasing noise reached the doppler divisor directly. Fix is consumer-side only per the census: the relative WORLD velocity held per AudioLocation on a 28Hz wall clock; head-frame transform + geometry stay live per call; the mech4 producer untouched. BT_AUD_DOPPLER_HZ override (=0 per-call) + [doppler] receipt under BT_AUD_DOPPLER_LOG (cents/v/d/h/hm2). Measured: clock proven live (55% of calls held vs 0% in control), operand total-variation 67.8 -> 54.2 u/s-per-s (-20%) with std preserved (real stride oscillation kept). T3 flag: cents jitter only -11% on the solo rig because the loud sources ride the player's own entity at d~1 where live near-field geometry dominates -- the nearby-walking-mech warble needs an ear A/B or a 2-node rig. Bonus finding (pre-existing, receipt-exposed, NOT touched): sources linked to child entities of a moving mech read relative v = full ground speed (child worldLinearVelocity=0) -> cents ~ -200 on self-sounds; new census row.

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:50 -05:00
co-authored by Claude Fable 5
parent b355844847
commit f9546d254f
+54
View File
@@ -1,3 +1,5 @@
#include <cstdlib> // (BT411) getenv -- the 28Hz doppler-operand clock (cadence census item 4)
#include <map> // (BT411) per-instance sample-and-hold registry
#include "munga.h"
#pragma hdrstop
@@ -442,6 +444,45 @@ void
);
Check(&relative_velocity_temp);
//
// (BT411 cadence census item 4, gotcha 32) 28 Hz SAMPLE-AND-HOLD on the
// doppler velocity operand: worldLinearVelocity is a raw per-render-frame
// position derivative (the mech4 producer feeds other consumers and is
// NOT touched); at ~59 fps its gait-aliasing noise reaches this divisor
// directly and warbles dopplerCents per stride. The pod computed this
// once per 28 Hz frame. Hold the RELATIVE WORLD velocity per instance
// on a 28 Hz wall clock; the head-frame transform below stays live per
// call (geometry is smooth -- only the noisy operand is clocked).
// BT_AUD_DOPPLER_HZ=<hz> overrides (=0 restores per-call sampling).
//
int dopplerFresh = -1; // receipt: -1 legacy / 1 sampled / 0 held
{
static Scalar s_dopHz = -2.0f;
if (s_dopHz < -1.0f)
{
const char *hz = getenv("BT_AUD_DOPPLER_HZ");
s_dopHz = (hz != 0 && *hz != '\0') ? (Scalar)atof(hz) : 28.0f;
}
if (s_dopHz > 0.0f)
{
struct DopplerHold { DWORD nextMs; Vector3D held; };
static std::map<const void *, DopplerHold> s_dopHold;
DopplerHold &h = s_dopHold[this];
const DWORD now = GetTickCount();
if (h.nextMs == 0 || (long)(now - h.nextMs) >= 0)
{
h.held = relative_velocity_temp;
h.nextMs = now + (DWORD)(1000.0f / s_dopHz);
dopplerFresh = 1;
}
else
{
relative_velocity_temp = h.held;
dopplerFresh = 0;
}
}
}
relative_velocity.MultiplyByInverse(
relative_velocity_temp,
head_entity->localToWorld
@@ -473,6 +514,19 @@ void
{
dopplerCents = cents;
}
// (BT411) doppler receipt -- jitter A/B for the 28Hz operand clock.
// hm2 = |held relative WORLD velocity|^2 (the clocked operand itself,
// geometry-free); h = 1 fresh sample / 0 held / -1 legacy per-call.
if (getenv("BT_AUD_DOPPLER_LOG")) { static int s_dl = 0; if (s_dl++ < 6000)
DEBUG_STREAM << "[doppler] t=" << (GetTickCount() % 1000000)
<< " this=" << (void *)this
<< " cents=" << dopplerCents
<< " v=" << speed_of_source
<< " d=" << distanceToSource
<< " h=" << dopplerFresh
<< " hm2=" << relative_velocity_temp.LengthSquared()
<< "\n" << std::flush; }
}
else
{