From c68307ad538a204075a767fa8967c362716984ab Mon Sep 17 00:00:00 2001 From: arcattack Date: Thu, 16 Jul 2026 09:07:36 -0500 Subject: [PATCH] Audio: kill the per-footfall static -- smooth the PUBLISHED velocity (task #50) User pinpointed it: the per-stride 'static' was NOT the footstep sample -- it was the ambient engine hum being interrupted in time with the footfalls. Diagnosis (live tape): EnginePower01 was caught in a rapid Play->Stop cycle (80x/session). The idle-hum is gated by authored LocalVelocity triggers (hum ON in speed [1,20], OFF above 20) -- and the port's localVelocity is a RAW per-frame position derivative that pulses with every stride (gait acceleration + ground-snap bob). At walking speed |v| straddles the 20 band edge, so the trigger Start/Stop-flapped the hum on every foot plant; at run |v| >> 20 keeps it off (matching 'goes away at higher speeds'). Fix: ~0.25s exponential filter on the PUBLISHED localVelocity.linearMotion (fwd + vertical) -- kills the stride ripple, tracks real speed changes within a couple strides. The physics worldLinearVelocity (StaticBounce, collision damage pricing) is untouched; update records + the impact gate get the smoother value (both benefit). VERIFIED: EnginePower 1 play / 0 stops for the whole run (was 80 stop-cycles); FootFall cycles normally per stride; gear shifts/windup lifecycle intact. Co-Authored-By: Claude Opus 4.8 (1M context) --- game/reconstructed/mech.cpp | 2 ++ game/reconstructed/mech.hpp | 4 ++++ game/reconstructed/mech4.cpp | 15 ++++++++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/game/reconstructed/mech.cpp b/game/reconstructed/mech.cpp index 2def1f2..8f227cf 100644 --- a/game/reconstructed/mech.cpp +++ b/game/reconstructed/mech.cpp @@ -925,6 +925,8 @@ Mech::Mech( collisionTemporaryState = 0; footStep = 0; // FootStep pulse (audio trigger) footStepDecay = 0; + fwdSpeedFiltered = 0.0f; // smoothed published velocity (see mech4 derive) + vertSpeedFiltered = 0.0f; { extern void *g_btFootStepAddr; g_btFootStepAddr = &footStep; } // DIAG: watcher-poll tracer target radarRange = 1000.0f; // radar display scale (SetTargetRange is stubbed; // 1km default zoom so contacts within ~500m show on diff --git a/game/reconstructed/mech.hpp b/game/reconstructed/mech.hpp index 94f46c6..ac78da9 100644 --- a/game/reconstructed/mech.hpp +++ b/game/reconstructed/mech.hpp @@ -848,6 +848,10 @@ protected: // per-frame motion tick decays it back to 0 a few frames later, giving one // clean rising edge per step. [T2] int footStep; // the Logical the matcher polls (1 = contact) + Scalar fwdSpeedFiltered; // smoothed |v| published via localVelocity (the raw + Scalar vertSpeedFiltered; // per-frame position derivative pulses per stride and + // flapped the audio's speed triggers -- engine-hum + // restarts on every footfall) int footStepDecay; // MILLISECONDS until the pulse clears (time-based: // the watcher polls ~10Hz and strides re-pulse ~2Hz, // so the pulse must be one poll-period wide but end diff --git a/game/reconstructed/mech4.cpp b/game/reconstructed/mech4.cpp index 685975c..227158a 100644 --- a/game/reconstructed/mech4.cpp +++ b/game/reconstructed/mech4.cpp @@ -3639,7 +3639,20 @@ void Scalar fwdSpeed = (Scalar)sqrtf( worldLinearVelocity.x * worldLinearVelocity.x + worldLinearVelocity.z * worldLinearVelocity.z); - localVelocity.linearMotion = Vector3D(0.0f, worldLinearVelocity.y, -fwdSpeed); + // SMOOTH the PUBLISHED velocity (localVelocity feeds the audio speed + // triggers, the update records, and the impact gate -- NOT the physics + // worldLinearVelocity above). The raw per-frame derivative pulses per + // stride (gait acceleration + ground-snap bob): at walking speed the + // oscillation straddled the authored idle-hum band edge (speed 20) and + // Start/Stop-flapped the engine ambience on every footfall (heard as a + // static tick per step). ~0.25s exponential filter kills the stride + // ripple while tracking real speed changes within a couple of strides. + { + Scalar alpha = dt / (dt + 0.25f); + fwdSpeedFiltered += alpha * (fwdSpeed - fwdSpeedFiltered); + vertSpeedFiltered += alpha * (worldLinearVelocity.y - vertSpeedFiltered); + } + localVelocity.linearMotion = Vector3D(0.0f, vertSpeedFiltered, -fwdSpeedFiltered); localVelocity.angularMotion = Vector3D(0.0f, turn * authTurnRate, 0.0f); // MASTER twin of [replmov]: the velocity this mech PUBLISHES vs its own