Audio: footstep pulse VERIFIED end-to-end to the matcher; volume chain traced (task #50)
Footstep chain progress (each step empirically verified): - The FootStep watcher is an AudioMatchOf<Logical> (AudioLogicalTrigger extends AudioMatchOf, NOT AudioTriggerOf): authored config match=1 -> Start(2.0) on a DirectPatchSource. [trigcfg]/[matchcfg] ctor dumps added. - The pulse was pinned at 1: the decay lived in IntegrateMotion, which the current gait path NEVER CALLS. Moved to Mech::PerformAndWatch (provably per-frame) with a time-based 150ms window sized to the ~10Hz watcher poll. The matcher now fires per stride (14/run, was 1). - Every footstep Start is DROPPED at the renderer: the source's volumeScale is 0 (five VolumeAudioHandler sends of exactly 0 = inert/one-shot primes). The volume arrives through the authored control chain (AudioControlMultiplier inputs ctl 100+; one 0 input pins the product). Chain scales identified on this entity: LocalVelocity (live), LocalAcceleration (live), Myomers. SpeedEffect (=1.0 healthy; one authored scale maps [0,1]->[1,0] INVERTED), UnstablePercentage (INERT PAD -- always 0!), HeatSink.CurrentTemperature. PRIME SUSPECT: an UnstablePercentage-fed multiplier input primes 0 once and never updates (the pad never changes), pinning footstep volume at 0. - SF2 numbering fact recorded: 38 presets in AUDIO1 / 5 in AUDIO2 have wPreset != file index (gap at preset 77); my table keys by wPreset. The 184x ProgramButton01 (bank1 patch83) storm at ~7/s needs an identity check against index-numbering (it may be the wrong sample for that patch id). Diagnostics added (BT_AUDIO_SPATIAL/BT_ATTRBIND_LOG): [trigcfg]/[matchcfg] ctor dumps, [matchfire] with component ptr+class, [volset] VolumeAudioHandler, [mult0] multiplier zero-products, scale sends with authored boundaries, [fswatch] dedicated footstep watcher tracer (g_btFootStepAddr), SetupPatch ENTRY with bank/patch/state, Simulation::DebugAudioWatcherCount. NEXT: back UnstablePercentage with a real (live) member -- it is the mech's stability 0..1 (the stabilityAlarm/gyro family) -- or confirm via a one-run chain dump which multiplier input pins the FS source; then the footstep transient should clear the 0.3 drop gate at walking speed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
ba3040ea09
commit
1d019e8109
@@ -1,3 +1,4 @@
|
||||
#include <cstdlib>
|
||||
#include "munga.h"
|
||||
#pragma hdrstop
|
||||
|
||||
@@ -793,6 +794,9 @@ void
|
||||
}
|
||||
|
||||
Check(audioComponentSocket.GetCurrent());
|
||||
if (getenv("BT_AUDIO_SPATIAL") && mult_value <= 0.0f) { static int s_mx=0; if (s_mx++<300)
|
||||
DEBUG_STREAM << "[mult0] mult=" << (void*)this << " -> tgt=" << (void*)audioComponentSocket.GetCurrent()
|
||||
<< " in[" << index << "]=" << control_value << " product=" << mult_value << "\n" << std::flush; }
|
||||
audioComponentSocket.GetCurrent()->ReceiveControl(
|
||||
outputControlID,
|
||||
mult_value
|
||||
|
||||
@@ -663,6 +663,8 @@ void
|
||||
Check(this);
|
||||
Clamp(control_value, MinAudioVolume, MaxAudioVolume);
|
||||
volumeScale = control_value / (MaxAudioVolume - MinAudioVolume);
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_vh=0; if (s_vh++<300)
|
||||
DEBUG_STREAM << "[volset] src=" << (void*)this << " vol=" << volumeScale << "\n" << std::flush; }
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
+20
-4
@@ -305,6 +305,14 @@ template <class T>
|
||||
MemoryStream_Read(stream, &controlValueOff);
|
||||
|
||||
triggerOn = False;
|
||||
|
||||
if (getenv("BT_ATTRBIND_LOG")) { static int s_tc=0; if (s_tc++<80)
|
||||
DEBUG_STREAM << "[trigcfg] attrPtr=" << (void*)attributePointer
|
||||
<< " thresh=" << attributeValueThreshold
|
||||
<< " inverse=" << (int)inverseTrigger
|
||||
<< " onID=" << (int)controlIDOn << "/" << controlValueOn
|
||||
<< " offID=" << (int)controlIDOff << "/" << controlValueOff
|
||||
<< "\n" << std::flush; }
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -631,10 +639,8 @@ template <class T> void
|
||||
Check(&audioComponentSocket);
|
||||
Check(audioComponentSocket.GetCurrent());
|
||||
if (getenv("BT_AUDIO_SPATIAL") && control_value <= 0.0f) {
|
||||
static int s_sc=0; if (s_sc++<40)
|
||||
DEBUG_STREAM << "[spatial] scale->0 attrPtr=" << (void*)attributePointer
|
||||
<< " raw=" << current_value << " ctlID=" << (int)controlID
|
||||
<< " ctl=" << control_value << "\n" << std::flush; }
|
||||
static int s_sc=0; if (s_sc++<400)
|
||||
DEBUG_STREAM << "[spatial] scale->0 attrPtr=" << (void*)attributePointer << " comp=" << (void*)audioComponentSocket.GetCurrent() << " raw=" << current_value << " ctlID=" << (int)controlID << " ctl=" << control_value << " aB=[" << attributeValueBoundary1 << "," << attributeValueBoundary2 << "]" << " cB=[" << controlValueBoundary1 << "," << controlValueBoundary2 << "]\n" << std::flush; }
|
||||
audioComponentSocket.GetCurrent()->ReceiveControl(
|
||||
controlID,
|
||||
control_value
|
||||
@@ -731,6 +737,12 @@ template <class T>
|
||||
MemoryStream_Read(stream, &attributeMatchValue);
|
||||
MemoryStream_Read(stream, &controlID);
|
||||
MemoryStream_Read(stream, &controlValue);
|
||||
|
||||
if (getenv("BT_ATTRBIND_LOG")) { static int s_mc=0; if (s_mc++<80)
|
||||
DEBUG_STREAM << "[matchcfg] attrPtr=" << (void*)attributePointer
|
||||
<< " match=" << attributeMatchValue
|
||||
<< " ctlID=" << (int)controlID << " ctlVal=" << controlValue
|
||||
<< "\n" << std::flush; }
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -777,6 +789,10 @@ template <class T> void
|
||||
|
||||
if (current_value == attributeMatchValue)
|
||||
{
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_mf=0; if (s_mf++<40)
|
||||
DEBUG_STREAM << "[matchfire] attrPtr=" << (void*)attributePointer << " comp=" << (void*)audioComponentSocket.GetCurrent() << " compClass=" << (int)audioComponentSocket.GetCurrent()->GetClassID()
|
||||
<< " val=" << current_value << " -> ctl " << (int)controlID
|
||||
<< "/" << controlValue << "\n" << std::flush; }
|
||||
Check(&audioComponentSocket);
|
||||
Check(audioComponentSocket.GetCurrent());
|
||||
#if 1
|
||||
|
||||
@@ -266,6 +266,13 @@ template <class T> void
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { // poll-rate probe: total watcher polls + change events
|
||||
static long s_polls=0; if ((++s_polls % 2000)==0)
|
||||
DEBUG_STREAM << "[watchpoll] total polls=" << s_polls << "\n" << std::flush;
|
||||
extern void *g_btFootStepAddr; // DIAG: uncapped tracer on THE footstep watcher
|
||||
if ((void*)attributePointer == g_btFootStepAddr) {
|
||||
static long s_fsp=0;
|
||||
if ((++s_fsp % 120)==0 || !(currentValue == *(T*)attributePointer))
|
||||
DEBUG_STREAM << "[fswatch] poll#" << s_fsp << " cur=" << (int)*(int*)¤tValue
|
||||
<< " mem=" << *(int*)attributePointer << "\n" << std::flush;
|
||||
}
|
||||
}
|
||||
if (!(currentValue == *(T*)attributePointer))
|
||||
{
|
||||
|
||||
@@ -138,6 +138,11 @@ void
|
||||
ALenum sourceState;
|
||||
alGetSourcei(sourceSet.sources[i], AL_SOURCE_STATE, &sourceState);
|
||||
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_se=0; if (s_se++<200)
|
||||
DEBUG_STREAM << "[audio] SetupPatch ENTRY bank=" << (int)bankID << " patch=" << (int)patchID << " src=" << sourceSet.sources[i]
|
||||
<< " file=" << (info.file?info.file:"?")
|
||||
<< " state=" << sourceState << " (INITIAL=" << AL_INITIAL << ")" << "\n" << std::flush; }
|
||||
|
||||
if (sourceState == AL_INITIAL)
|
||||
{
|
||||
alSourcei(sourceSet.sources[i],AL_BUFFER,AL_getBuffer(info.bufferIndex));
|
||||
|
||||
@@ -398,3 +398,7 @@ void VideoComponent::ReceiveControl(VideoControlID /*control_ID*/, Scalar /*cont
|
||||
void VideoComponent::Execute()
|
||||
{
|
||||
}
|
||||
|
||||
// DIAG (audio footstep chain): the live &mech->footStep, exported so the
|
||||
// engine watcher poll can trace THE footstep watcher without per-run pointers.
|
||||
void *g_btFootStepAddr = 0;
|
||||
|
||||
@@ -925,6 +925,7 @@ Mech::Mech(
|
||||
collisionTemporaryState = 0;
|
||||
footStep = 0; // FootStep pulse (audio trigger)
|
||||
footStepDecay = 0;
|
||||
{ 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
|
||||
// the radar, vs the config maximum_range=4000 edge)
|
||||
|
||||
@@ -847,8 +847,12 @@ protected:
|
||||
// stride clip (each walk/run/reverse alternation == one foot plant) and the
|
||||
// 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 trigger polls (1 = contact)
|
||||
int footStepDecay; // frames until the pulse clears
|
||||
int footStep; // the Logical the matcher polls (1 = contact)
|
||||
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
|
||||
// well before the next stride -- match=1 fires on the
|
||||
// CHANGE to 1, so footStep must return to 0 in between)
|
||||
// Radar/map gauge attributes (binary @0x404/0x408/0x40c/0x3f8). The map
|
||||
// widget reads position/angle as POINTERS into the mech's live origin, so
|
||||
// radarLinearPosition/radarAngularPosition point at localOrigin.{linear,
|
||||
|
||||
@@ -261,9 +261,9 @@ void
|
||||
if (state >= 1 && state <= 0x17)
|
||||
{
|
||||
footStep = 1;
|
||||
footStepDecay = 20; // ~1/3s: outlives the watcher poll cadence (still < stride period)
|
||||
footStepDecay = 150; // ms: ~1.5 poll periods ON, OFF well before the next stride
|
||||
if (getenv("BT_AUDIO_LOG")) { static int s_fs=0; if (s_fs++<40)
|
||||
DEBUG_STREAM << "[audio] footstep pulse (clip " << state << ") addr=" << (void*)&footStep << "\n" << std::flush; }
|
||||
DEBUG_STREAM << "[audio] footstep pulse (clip " << state << ") leftover=" << footStepDecay << "\n" << std::flush; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -292,10 +292,8 @@ Logical
|
||||
// Choose this frame's forward-cycle slew rate.
|
||||
forwardCycleRate = airborneSelect ? airborneCycleRate : groundCycleRate; // 0x344<-0x5bc/0x5b8
|
||||
|
||||
// FootStep pulse decay (see SetBodyAnimation): clear the contact flag a few
|
||||
// frames after the plant so the AudioLogicalTrigger re-arms for the next step.
|
||||
if (footStepDecay > 0 && --footStepDecay == 0)
|
||||
footStep = 0;
|
||||
// (FootStep pulse decay moved to PerformAndWatch -- this integrator does not
|
||||
// run on the current gait path, so a decay here never fired.)
|
||||
|
||||
if (IsDisabled()) // FUN_0049fb54
|
||||
{
|
||||
@@ -5205,6 +5203,21 @@ void
|
||||
// (AudioLogicalTrigger FootStep, AudioMotionScale/Trigger LocalVelocity, ...)
|
||||
// never executed -- only the PUSHED StateIndicator watchers fired. That's
|
||||
// why footsteps/motion-scaled sounds were silent while state sounds worked. [T0]
|
||||
// FootStep pulse decay (see SetBodyAnimation): clear the contact flag ~150ms
|
||||
// after the plant so the FootStep matcher (fires on the CHANGE to 1) sees a 0
|
||||
// before the next stride re-pulses. Lives HERE (not IntegrateMotion, which the
|
||||
// current gait path never calls) so it provably ticks every mech frame, right
|
||||
// before the watcher poll below reads it. Time-based -- tick-rate immune.
|
||||
if (footStepDecay > 0)
|
||||
{
|
||||
footStepDecay -= (int)(dt * 1000.0f);
|
||||
if (footStepDecay <= 0)
|
||||
{
|
||||
footStepDecay = 0;
|
||||
footStep = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (getenv("BT_AUDIO_LOG")) { static int s_wd=0; if ((s_wd++ % 300)==0)
|
||||
DEBUG_STREAM << "[audio] mech watcher poll: delayed=" << (int)AreWatchersDelayed() << " audioWatchers=" << DebugAudioWatcherCount()
|
||||
<< " simFlags=0x" << std::hex << (unsigned)simulationFlags << std::dec
|
||||
|
||||
Reference in New Issue
Block a user