the REVERSE DISABLED voice (#78): SimulationState 3/4 IS the trigger -- mirror the gimp level into the engine cell
User + old-timers were right; the earlier "no voice exists" verdict was wrong. The authored mech audio has state watchers on Entity.SimulationState==3/4 (the binary's one-cell mech+0x40) that start sequence notes 29,16,40 -- two klaxon hits then Warnings01 zone 8 (key 40-41) = the "reverse disabled" voice line the testers remember. The port's cell split (graphicAlarm vs engine simulationState, gotcha #23) meant the trigger value never arrived. - mechdmg: mirror gimp 3/4 into SetSimulationState at the leg-half crossing (guarded: never stomps disabled/fall/dead states). Voice verified playing end-to-end on the bench: SetupPatch bank2 patch113 note=40 -> Warnings01_z7.wav. - mech.cpp: BT_GIMP_SAFE_BASE_READ on all seven Simulation::ReadUpdateRecord sites -- gimp is monotonic per life; a record captured pre-gimp must not stomp the cell (the loopback otherwise perpetuates the stale value and restarts the warning on every damage event). - diagnostics (all env-gated): [statefire]/[startreq]/[animind]/[gimp-sim]/ [simstomp]/[indstomp] + StateIndicator::DebugAudioWatcherCount + raised spatial-log caps. These traced the whole chain and PROVED no SetState path stomps the cell. OPEN (follow-up): a RAW writer (bypasses SetState entirely; invisible to the indicator-level trap) resets the cell between damage events -- under the bench's 1 Hz metronome harness it restarted the sequence before the 1.8 s voice note; sporadic real-play damage is unaffected (one edge -> full sequence). Needs a cdb write-watchpoint session; candidates: a recon raw +0x2c-equivalent write or a struct copy spanning it. Also decoded en route: the AnimationState triggers on the limp states play EngineShiftRev01 (the downshift foley) -- working, and NOT the voice. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
7838df2924
commit
1671b7d4b2
@@ -250,7 +250,7 @@ void
|
||||
return;
|
||||
}
|
||||
if (getenv("BT_AUDIO_SPATIAL") && message->controlID == StartAudioControlID) {
|
||||
static int s_st=0; if (s_st++<40)
|
||||
static int s_st=0; if (s_st++<5000)
|
||||
DEBUG_STREAM << "[spatial] START request src=" << (void*)audio_source
|
||||
<< " vol=" << audio_source_volume_scale << "\n" << std::flush; }
|
||||
|
||||
|
||||
@@ -1083,6 +1083,7 @@ void
|
||||
DEBUG_STREAM << "[statefire] trigState=" << triggerState
|
||||
<< " old=" << old_state << " new=" << new_state
|
||||
<< " comp=" << (void*)audioComponentSocket.GetCurrent()
|
||||
<< " compClass=" << (int)audioComponentSocket.GetCurrent()->GetClassID()
|
||||
<< " ctl=" << (int)controlID << "/" << controlValue
|
||||
<< "\n" << std::flush; }
|
||||
#if 1
|
||||
|
||||
@@ -157,6 +157,17 @@ void
|
||||
{
|
||||
Check(this);
|
||||
Verify(new_state < stateCount);
|
||||
// #78 DIAG: trap ANY 3/4 -> <=1 transition on ANY indicator, with the
|
||||
// caller's return address (symbolize via tools/symcrash.py). Catches
|
||||
// writers that bypass Simulation::SetSimulationState.
|
||||
if (getenv("BT_AUDIO_SPATIAL")
|
||||
&& (currentState == 3 || currentState == 4) && new_state <= 1)
|
||||
{
|
||||
static int s_it=0; if (s_it++<40)
|
||||
DEBUG_STREAM << "[indstomp] " << currentState << "->" << new_state
|
||||
<< " ind=" << (void*)this
|
||||
<< " ra=" << _ReturnAddress() << "\n" << std::flush;
|
||||
}
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
+14
-1
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "state.h"
|
||||
#include "receiver.h"
|
||||
#include <intrin.h> // _ReturnAddress (the #78 simstomp diag)
|
||||
#include "time.h"
|
||||
#include "resource.h"
|
||||
|
||||
@@ -221,7 +222,19 @@ public:
|
||||
{Check(this); return simulationState.GetOldState();}
|
||||
void
|
||||
SetSimulationState(unsigned new_state)
|
||||
{Check(this); simulationState.SetState(new_state);}
|
||||
{Check(this);
|
||||
// #78 DIAG: trap the gimp-cell downgrade (3/4 -> <=1) with the
|
||||
// caller's return address (symbolize via tools/symcrash.py).
|
||||
if (getenv("BT_AUDIO_SPATIAL")) {
|
||||
unsigned _cur = simulationState.GetState();
|
||||
if ((_cur == 3 || _cur == 4) && new_state != _cur) {
|
||||
static int s_ds=0; if (s_ds++<40)
|
||||
DEBUG_STREAM << "[simstomp] " << _cur << "->" << new_state
|
||||
<< " this=" << (void*)this
|
||||
<< " ra=" << _ReturnAddress()
|
||||
<< "\n" << std::flush; }
|
||||
}
|
||||
simulationState.SetState(new_state);}
|
||||
|
||||
StateIndicator
|
||||
simulationState;
|
||||
|
||||
@@ -47,6 +47,13 @@ public:
|
||||
Check(&gaugeWatcherSocket);
|
||||
gaugeWatcherSocket.Add(watcher);
|
||||
}
|
||||
int DebugAudioWatcherCount() // DEBUG (#78 audio flake): registered audio watchers
|
||||
{
|
||||
int n = 0;
|
||||
SChainIteratorOf<Component*> it(audioWatcherSocket);
|
||||
while (it.ReadAndNext() != NULL) ++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
private:
|
||||
SChainOf<Component*> audioWatcherSocket;
|
||||
|
||||
@@ -593,13 +593,19 @@ void
|
||||
{
|
||||
Check(this);
|
||||
Check(audio_source);
|
||||
|
||||
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_sr=0; if (s_sr++<5000)
|
||||
DEBUG_STREAM << "[startreq] src=" << (void*)audio_source
|
||||
<< " state=" << (int)audio_source->GetAudioSourceState()
|
||||
<< " class=" << (int)audio_source->GetClassID()
|
||||
<< "\n" << std::flush; }
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Verify that the source is stopped
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
Verify(audio_source->GetAudioSourceState() == StoppedAudioSourceState);
|
||||
Verify(audio_source->GetAudioSourceState() == StoppedAudioSourceState);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -619,6 +625,9 @@ void
|
||||
);
|
||||
if (!resources_available)
|
||||
{
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_rf=0; if (s_rf++<40)
|
||||
DEBUG_STREAM << "[startreq] RESOURCE FAIL src=" << (void*)audio_source
|
||||
<< "\n" << std::flush; }
|
||||
// Audio-dropout fix: a failed acquisition can leave a PARTIAL set
|
||||
// (alGenSources succeeded for some slots before the pool ran dry).
|
||||
// A dropped transient never plays and nothing else ever released it,
|
||||
|
||||
Reference in New Issue
Block a user