Audio: footstep chain traced to the END -- gait VINDICATED; audio clock 18x unit mismatch found (task #50)

MAJOR RESULT -- THE GAIT IS CORRECT, the enum was mislabeled:
LoadLocomotionClips (binary-verified slot map) proves namedClip==&animationClips[5]:
clips 6/7 = wwr/wwl (WALK cycle), 12/13 = rrr/rrl (RUN cycle -- what autodrive
uses at full throttle), 10/11 = wrr/wrl, 14/15 = rwr/rwl, 16-21 = reverse set.
The mech2.cpp "MechAnimationState" enum (0x3c-stride name table) does NOT match
the runtime clip ids -- it is the mislabel (12/13 are NOT StandToReverse).
The authored AudioStateTriggers on AnimationState (statecfg dump: states
1,2,5,8,9,10,11,14,15,16,17,20,21,22,23,26,27 -> Start) align EXACTLY with the
TRANSITION clips under the true map; the CYCLING strides (6/7, 12/13) have no
state triggers because the FootStep pulse attribute serves them -- our FootStep
reconstruction is the authentic design.  DO NOT renumber the gait.

Footstep chain, fully mapped (all empirtical):
pulse -> AudioMatchOf(match=1) -> Start on the FootFall DirectPatchSource ->
DROPPED at volume 0.  Volume path: an AudioControlMixer (2 inputs, never fed)
<- an AudioControlSplitter <- AudioControlSequence timeline events.  The
sequences DO fire -- but only value-0 events (the tick-0 initializers); the
later (real-volume) events never land.

NEW ROOT-CAUSE CANDIDATE [T3]: audio clock unit mismatch.  The renderer is
constructed with DefaultRendererRate=30 (calibrationRate: Seconds_To_Frames =
s*30) but AudioHead::Execute sets audioFrameCount = Now().ticks which advances
~550/s (measured via the [audioclock] probe) -- sequence event scheduling runs
~18x off the authored timing.  Fix candidate: calibrate the audio renderer to
the actual Now().ticks rate (or drive audioFrameCount at the calibrated 30/s).

Also corrected en route: FUN_004b9550/95b8 are MechWeapon ConfigureMappables/
ChooseButton (mapper EnterConfiguration +0x38), NOT Myomers::ConnectToMover;
+0x31c there is fireImpulse.  Myomers::speedEffect has NO binary writer found
beyond the ctor 1.0f (its 'mover coupling' stand-in is spurious).

Diagnostics added: [statecfg] AudioStateTrigger ctor dump, [split] splitter
forwards, [seqev] sequence timeline events, [audioclock] frame-rate probe.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-16 00:25:18 -05:00
co-authored by Claude Opus 4.8
parent c4be8d3a07
commit 99757a947d
4 changed files with 18 additions and 0 deletions
+3
View File
@@ -473,6 +473,9 @@ void
while ((audio_component = iterator.ReadAndNext()) != NULL)
{
Check(audio_component);
if (getenv("BT_AUDIO_SPATIAL")) { static int s_sp2=0; if (s_sp2++<200)
DEBUG_STREAM << "[split] " << (void*)this << " -> tgt=" << (void*)audio_component
<< " ctl=" << (int)control_ID << "/" << control_value << "\n" << std::flush; }
audio_component->ReceiveControl(control_ID, control_value);
}
}
+3
View File
@@ -1,3 +1,4 @@
#include <cstdlib>
#include "munga.h"
#pragma hdrstop
@@ -133,6 +134,8 @@ void
//
audioFrameCount = Now().ticks;
Verify(audioFrameCount < LONG_MAX);
if (getenv("BT_AUDIO_SPATIAL")) { static long s_hx=0; if ((++s_hx % 300)==0)
DEBUG_STREAM << "[audioclock] frame=" << audioFrameCount << " execs=" << s_hx << "\n" << std::flush; }
//set current listener orientation
Vector3D headVelocity;
+4
View File
@@ -1,3 +1,4 @@
#include <cstdlib>
#include "munga.h"
#pragma hdrstop
@@ -67,6 +68,9 @@ void
{
Check(this);
Check(audio_component);
if (getenv("BT_AUDIO_SPATIAL")) { static int s_ev=0; if (s_ev++<200)
DEBUG_STREAM << "[seqev] tgt=" << (void*)audio_component
<< " ctl=" << (int)audioControlID << "/" << audioControlValue << "\n" << std::flush; }
audio_component->ReceiveControl(audioControlID, audioControlValue);
}
+8
View File
@@ -962,6 +962,14 @@ AudioStateTrigger::AudioStateTrigger(
MemoryStream_Read(stream, &excludeTransition);
MemoryStream_Read(stream, &excludeState);
if (getenv("BT_ATTRBIND_LOG")) { static int s_stc=0; if (s_stc++<120)
DEBUG_STREAM << "[statecfg] attrPtr=" << (void*)attributePointer
<< " comp=" << (void*)audioComponentSocket.GetCurrent()
<< " trigState=" << triggerState << " inv=" << (int)inverseTrigger
<< " ctl=" << (int)controlID << "/" << controlValue
<< " excl=" << (int)excludeTransition << "/" << excludeState
<< "\n" << std::flush; }
PrimeWatcher();
}