Audio: fix stuck weapon charge/sustain/loading loops -- maintain GaugeAlarm54 oldState (task #50)
WeaponState -> weaponAlarm (mechweap.cpp:149), and the weapon's looping audio (LaserACharge/LaserASustain/MissileLoading, all SF2 sampleModes=1) is STARTED by an AudioStateWatcher on the firing/charging state and STOPPED by an inverse AudioStateTrigger that keys on old_state (== the state being LEFT). The subsystem-state commit fired GaugeAlarm54 watchers on SetLevel but deliberately left levelB (the oldState slot @0x10) untouched to avoid disturbing the weapon's LevelCountB read. Consequence: the audio watcher's StateChanged(oldState,newState) saw a stale oldState, so the inverse/STOP triggers never matched -> the charge/ sustain/loading loops played forever. Fix: SetLevel now sets levelB := level (oldState := currentState) before the change, exactly like StateIndicator::SetState. The stop triggers now match on leaving the state and StopNote the loop. This is also authentic: in the binary the 0x54 alarm +0x10 IS oldState, and the weapon's LevelCountB()/weaponIdle read of +0x10 is that same oldState (the old static-count reading was the reconstruction's accident). weaponIdle is only consumed in the MP replicant record-apply path, so single-player firing is unaffected; the value is now the authentic oldState-based one. Subsystem state audio unaffected (0 skips). Diagnostics: BT_AUDIO_LOG now traces SetupPatch src/file/loop + StopNote. 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
41c8ac120d
commit
c27af4800b
@@ -141,7 +141,7 @@ void
|
||||
if (sourceState == AL_INITIAL)
|
||||
{
|
||||
alSourcei(sourceSet.sources[i],AL_BUFFER,AL_getBuffer(info.bufferIndex));
|
||||
{ static int s_a=0; if (getenv("BT_AUDIO_LOG") && s_a++<8) DEBUG_STREAM << "[audio] SetupPatch attach bank=" << (int)bankID << " patch=" << (int)patchID << " buf=" << info.bufferIndex << "\n" << std::flush; }
|
||||
{ static int s_a=0; if (getenv("BT_AUDIO_LOG") && s_a++<24) DEBUG_STREAM << "[audio] SetupPatch src=" << sourceSet.sources[i] << " file=" << (info.file?info.file:"?") << " loop=" << (info.loop==ForceStatic?0:1) << "\n" << std::flush; }
|
||||
alSourcei(sourceSet.sources[i],AL_SOURCE_RELATIVE,AL_TRUE);
|
||||
|
||||
AudioRenderer *render = application->GetAudioRenderer();
|
||||
@@ -190,7 +190,7 @@ void PatchLevelOfDetail::PlayNote(SourceSet sourceSet)
|
||||
if (state != AL_PLAYING)
|
||||
{
|
||||
alSourcePlay(sourceSet.sources[i]);
|
||||
{ static int s_p=0; if (getenv("BT_AUDIO_LOG") && s_p++<8) DEBUG_STREAM << "[audio] PlayNote alSourcePlay src=" << sourceSet.sources[i] << "\n" << std::flush; }
|
||||
{ static int s_p=0; if (getenv("BT_AUDIO_LOG") && s_p++<30) DEBUG_STREAM << "[audio] PlayNote alSourcePlay src=" << sourceSet.sources[i] << "\n" << std::flush; }
|
||||
}
|
||||
|
||||
ALenum error = alGetError();
|
||||
@@ -205,6 +205,7 @@ void PatchLevelOfDetail::PlayNote(SourceSet sourceSet)
|
||||
|
||||
void PatchLevelOfDetail::StopNote(SourceSet sourceSet)
|
||||
{
|
||||
{ static int s_s=0; if (getenv("BT_AUDIO_LOG") && s_s++<30) DEBUG_STREAM << "[audio] StopNote count=" << sourceSet.count << " src0=" << (sourceSet.count>0?sourceSet.sources[0]:0) << "\n" << std::flush; }
|
||||
if (sourceSet.count >0 && sourceSet.sources != NULL)
|
||||
{
|
||||
alSourceStopv(sourceSet.count, sourceSet.sources);
|
||||
|
||||
@@ -97,7 +97,13 @@ public:
|
||||
: audioWatcherSocket(0), videoWatcherSocket(0), gaugeWatcherSocket(0)
|
||||
{ levelA = levelB = levels; level = 0; }
|
||||
void Initialize(int levels) { levelA = levelB = levels; level = 0; }
|
||||
void SetLevel(int n) { if (n != level) { level = n; NotifyWatchers(); } }
|
||||
// StateIndicator::SetState semantics: oldState (levelB@0x10) := currentState
|
||||
// BEFORE the change, so the audio watcher's StateChanged(oldState,newState) is
|
||||
// correct -- this is what the inverse/STOP AudioStateTriggers key on (old_state ==
|
||||
// firing/charging state) to StopNote a looping charge/sustain/loading sample when
|
||||
// the weapon leaves that state. (In the binary levelB@0x10 IS oldState; the
|
||||
// weapon's LevelCountB() reading @0x10 is that same authentic oldState.)
|
||||
void SetLevel(int n) { levelB = level; if (n != level) { level = n; NotifyWatchers(); } }
|
||||
int GetLevel() const { return level; }
|
||||
int Level() const { return level; }
|
||||
int LevelCountB() const { return levelB; } // +0x10 (the weapon update-record "reset" source)
|
||||
|
||||
Reference in New Issue
Block a user