From 847b9b85cdd605d3279e738d9645316f701c2c34 Mon Sep 17 00:00:00 2001 From: arcattack Date: Thu, 16 Jul 2026 08:36:28 -0500 Subject: [PATCH] Audio: target the step-intensity send at FOOTSTEP sources only (task #50) The output-filtered broadcast still fed EVERY volume/brightness mixer -- the always-on ambience pulse's own volume mixer got cranked to step intensity on every stride ('a stuck button', 3/s, loud). The send now identifies footstep sources by authored patch (FootFallInt/Ext: bank2 37-39, bank1 106/107) through mixer->GetTargetComponent() -> AudioSource -> PatchResource LOD bank/patch (new accessors: GetTargetComponent, GetBankID/GetPatchID, AudioResource::PeekAudioLevelOfDetail). Also: step intensity curve raised (speed/25, floor 0.55 -- a mech stomp is never subtle; it was firing at ~0.4 gain and masked under 0.9-gain layers, heard as an unrecognizable 'orchestral hit'). Verified: FootFallInt at 0.78 gain in the live tape; the ambience pulse back to its brief authored form (absent from 1/s snapshots). Co-Authored-By: Claude Opus 4.8 (1M context) --- engine/MUNGA/AUDCMP.h | 2 ++ engine/MUNGA/AUDLVL.h | 5 +++++ engine/MUNGA_L4/L4AUDLVL.h | 5 +++++ game/reconstructed/mech2.cpp | 41 ++++++++++++++++++++++++++++++------ 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/engine/MUNGA/AUDCMP.h b/engine/MUNGA/AUDCMP.h index 0d27235..3f6d98d 100644 --- a/engine/MUNGA/AUDCMP.h +++ b/engine/MUNGA/AUDCMP.h @@ -236,6 +236,7 @@ public: // broadcasts (the foot-plant intensity send) can target only volume/brightness // mix stages and never Start-outputting stages. AudioControlID GetOutputControlID() const { return outputControlID; } + AudioComponent *GetTargetComponent() { return audioComponentSocket.GetCurrent(); } // //-------------------------------------------------------------------- @@ -316,6 +317,7 @@ public: // broadcasts (the foot-plant intensity send) can target only volume/brightness // mix stages and never Start-outputting stages. AudioControlID GetOutputControlID() const { return outputControlID; } + AudioComponent *GetTargetComponent() { return audioComponentSocket.GetCurrent(); } // //-------------------------------------------------------------------- diff --git a/engine/MUNGA/AUDLVL.h b/engine/MUNGA/AUDLVL.h index 8312df0..8ca6f9d 100644 --- a/engine/MUNGA/AUDLVL.h +++ b/engine/MUNGA/AUDLVL.h @@ -162,6 +162,11 @@ protected: AudioLevelOfDetail* GetAudioLevelOfDetail(); +public: + // (task #50) public read of the active LOD -- the game-side footstep + // intensity send identifies footstep sources by their patch bank/id. + AudioLevelOfDetail* PeekAudioLevelOfDetail() { return GetAudioLevelOfDetail(); } + private: // //----------------------------------------------------------------------- diff --git a/engine/MUNGA_L4/L4AUDLVL.h b/engine/MUNGA_L4/L4AUDLVL.h index 16d333b..4d87e4a 100644 --- a/engine/MUNGA_L4/L4AUDLVL.h +++ b/engine/MUNGA_L4/L4AUDLVL.h @@ -69,6 +69,11 @@ public: GetVoiceCount() {return PRESET_getNumSamples(bankID,patchID);} + // (task #50) expose the authored bank/patch so the game-side footstep + // intensity send can identify footstep sources precisely. + int GetBankID() const { return (int)bankID; } + int GetPatchID() const { return (int)patchID; } + // //----------------------------------------------------------------------- // BuildFromPage diff --git a/game/reconstructed/mech2.cpp b/game/reconstructed/mech2.cpp index 49f0162..0e60623 100644 --- a/game/reconstructed/mech2.cpp +++ b/game/reconstructed/mech2.cpp @@ -91,6 +91,9 @@ #include #include // AudioComponent -- the foot-plant step-intensity broadcast +#include // AudioSource -- footstep-source identification +#include // AudioResource::GetAudioLevelOfDetail +#include // PatchLevelOfDetail -- bank/patch of the target source #pragma hdrstop #if !defined(MECH_HPP) @@ -281,29 +284,53 @@ void // by their own scales, so the broadcast cannot durably disturb them. { Scalar speed = localVelocity.linearMotion.Length(); - Scalar intensity = speed * (1.0f / 40.0f); + Scalar intensity = speed * (1.0f / 25.0f); // full stomp by run speed (~25 u/s) if (intensity > 1.0f) intensity = 1.0f; - if (intensity < 0.35f) intensity = 0.35f; // audible floor (> the 0.3 transient drop gate) + if (intensity < 0.55f) intensity = 0.55f; // a mech step is never subtle; floor well over the 0.3 drop gate int runFamily = (state >= 0x0a && state <= 0x0f); // wrr/wrl/rrr/rrl/rwr/rwl Entity::AudioSocketIterator it(this); Component *c; while ((c = it.ReadAndNext()) != NULL) { - // Feed ONLY the volume/brightness MIX stages (the footstep loudness - // inputs). A blind broadcast misfires: mixers whose OUTPUT control - // is Start would forward the send as a Start and fire their sound - // per stride (the "chirp per step" bug -- ProgramButton clicked on - // every plant), and an AudioSource Fail()s on the 100+ input ids. + // Feed ONLY the volume/brightness mix stages WHOSE TARGET IS A + // FOOTSTEP SOURCE. Two earlier bugs shaped this filter: a blind + // broadcast Start-fired sounds through Start-outputting mixers, and + // an output-only filter still cranked OTHER sounds' volume mixers + // (the always-on ambience pulsed to full step intensity -- the + // 'stuck button'). Identify footstep sources by their authored + // patch: FootFallInt/Ext live at bank2 patches 37/38/39 and bank1 + // 106/107 (audiopresets.cpp, from the AUDIO1/2.RES soundfonts). int cid = (int)c->GetClassID(); + AudioComponent *tgt; AudioControlID out; if (cid == (int)RegisteredClass::AudioControlMixerClassID) + { out = ((AudioControlMixer *)c)->GetOutputControlID(); + tgt = ((AudioControlMixer *)c)->GetTargetComponent(); + } else if (cid == (int)RegisteredClass::AudioControlMultiplierClassID) + { out = ((AudioControlMultiplier *)c)->GetOutputControlID(); + tgt = ((AudioControlMultiplier *)c)->GetTargetComponent(); + } else continue; if (out != VolumeAudioControlID && out != BrightnessAudioControlID) continue; + if (tgt == 0) + continue; + int tcid = (int)tgt->GetClassID(); + if (tcid != 1001 && tcid != 1002 && tcid != 1005) // Direct/Dyn3D/Static3D patch sources + continue; + PatchLevelOfDetail *lod = Cast_Object(PatchLevelOfDetail*, + ((AudioSource *)tgt)->GetAudioResource()->PeekAudioLevelOfDetail()); + if (lod == 0) + continue; + int b = lod->GetBankID(), pp = lod->GetPatchID(); + Logical isFootfall = + (b == 2 && pp >= 37 && pp <= 39) || (b == 1 && (pp == 106 || pp == 107)); + if (!isFootfall) + continue; AudioComponent *ac = (AudioComponent *)c; ac->ReceiveControl((AudioControlID)(runFamily ? 101 : 100), intensity); ac->ReceiveControl((AudioControlID)(runFamily ? 100 : 101), 0.0f);