a11a6978241af51cf8f18c23d6ed44744a9cf9a5
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a11a697824 |
Audio: footsteps arrive on the FIRST stride -- the 10-20 s warm-up bug
User report: footfalls silent for the first 10-20 s of every mission (all
mechs), then solid. Root cause was three interlocking layers, each measured
with timestamped traces:
1. The authored footstep volume chain (LocalAcceleration [0,10]->ctl100 +
LocalVelocity [0,0.6]->ctl101 through authored N=30/N=15
AudioControlSmoothers, fill 0) hangs off the SOURCE's watcher chain
(scale watches smoother watches mixer watches source), and an idle
source's chain executes only at Start attempts -- one smoother sample
per stride.
2. Each hop is frame-gated (AudioComponent::ExecuteWatchers,
DefaultAudioFrameDelay), so any burst collapses to one execution.
3. The transient drop gate (vol < 0.3, AUDREND) rejected every Start while
the smoother average crawled up 1/30th per attempt -> ~25 dropped strides
before the first audible step, then per-frame execution while playing
kept it warm forever ("solid after that").
Fixes (engine-level, each documented in place):
- AudioScaleOf<T>::Execute now sends EVERY poll (scales are continuous
value-feeders; the base bitwise change-gate -- Motion::operator== is
memcmp -- froze on our deterministic gait math, where the original's
noisy physics floats never bit-repeated. Triggers/matchers keep the
change gate: their semantics are edge-based).
- Component/AudioComponent::PrimeWatchers(passes): recursive, GATE-FREE
watcher pump; AUDREND runs 30 passes on every transient Start request so
the authored smoothers evaluate at their true steady state before the
drop gate reads the volume.
- localAcceleration derives via the binary's exact structure: 15-sample
ring buffers of the raw position derivative + dt (ctor part_012.c:9836,
derive :15169-15195), in the PerformAndWatch tail so it runs every frame.
- AttributeWatcherOf::GrabCurrentValue private -> protected (the scale
override calls it).
Verified (30 s walk from cold start): drops 25 -> 3 (the survivors are
authentic quiet-stride gating: first gentle strides at vol ~0.28 vs the 0.3
gate), footfalls deliver from the first stride, 43 delivered with live
per-stride gain variation. Diag traces added: [accwatch]/[fsscale]/
[smooth]/[smoothcfg]/[motionscalecfg] + timestamps on DROP/volset.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
be626c71ce |
Audio: KILL THE CHIRP -- ConfigureActivePress backed real (idle -1) on Sensor+Myomers (task #50)
The obnoxious always-on clicking was the cockpit CONFIGURE-MODE ticker: an
authored looped sequence gated by an AudioIntegerTrigger with threshold -1 on
<subsystem>.ConfigureActivePress (the held-configure-button index; -1 = none).
The attribute was one of the inert-pad redirects -- the pad reads 0 = "button 0
held forever" -> the ticker Start-fired at load and pulsed 2.7/s eternally.
Found via [sendcfg]/[seqstart] traces: the first seq start immediately follows
the trigcfg(thresh=-1, onID=Start) construction on the pad address.
Fix: real int configureActivePress = -1 APPENDED to Sensor ("Avionics") and
Myomers, registered in their attribute tables. Both classes are byte-exact
factory allocs, so the sizeof locks AND the placement-new alloc constants are
bumped TOGETHER (Sensor 0x328->0x32C, Myomers 0x358->0x35C) -- the tripwire
caught a mid-layout insert (seekVoltage@0x330 shift) and a fixed-alloc overrun
before they shipped; member moved to the true tail. Wiring the live value
(EnterConfiguration/ExitConfiguration sets/clears the index) restores the
authored hold-to-configure tick later; idle -1 is the correct silent state.
VERIFIED: ProgramButton01 plays ZERO times (was the 2.7/s chirp);
ConfigureActivePress binds real (vtbl=FFFFFFFF = the -1); FootFallInt at 0.98
gain; stable.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
99757a947d |
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> |
||
|
|
c4be8d3a07 |
Audio: footstep volume chain FULLY mapped -- blocked on gait-state id mismatch (task #50)
Chain (every hop verified live): FootStep pulse (SetBodyAnimation, decay in PerformAndWatch) -> AudioMatchOf match=1 -> Start(2.0) on the FootFall DirectPatchSource... which the renderer DROPS because its volume is 0: an AudioControlMixer (outCtl=3/Volume + a second outCtl=5 mixer) feeds the source, and BOTH mixer inputs are 0 -- nothing ever sends them. Eliminated as senders (all traced): AudioScaleOf scales (29 total, none target the mixer), AudioControlMultiplier (one instance, other target), Random/ AudioSampleAndHold (RNG verified WORKING -- varied samples; RANDOM.cpp is in the build, the self-init ctor runs). HYPOTHESIS [T4, next session]: the mixer inputs are fed by AudioStateTriggers on AnimationState keyed to the AUTHORED gait-clip ids (walk 2/3, run 8/9 = per-gait footstep volume). Our runtime body SM walks in states 12<->13 -- which the recovered MechAnimationState enum names RightStandToReverse/ LeftStandToReverse. If the authored audio expects 2/3 for forward walk, the runtime clip NUMBERING in the reconstructed gait SM is offset from the authentic ids -- a locomotion-layer mismatch with implications beyond audio (the audio config is an independent witness to the true clip numbering). Verify via the AudioStateTrigger configs on the AnimationState watcher (trigcfg dump exists) and cross-check the SetBodyAnimation clip table. New diagnostics: [snh] SampleAndHold sends, [mix] mixer forwards with input index + sum, [scalecfg] authored scale bindings/boundaries, [volset]. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
1d019e8109 |
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> |
||
|
|
7b7d465e5e |
Initial commit: bt411 -- standalone Windows BattleTech (Tesla 4.10 port)
Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.
Layout:
engine/ MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
models) + image codec; the minimal rp/ headers the audio HAL needs
game/ reconstructed BT logic + surviving-original BT source + fwd shims
+ WinMain launcher
content/ full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
docs/ format specs + reconstruction ledgers
reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
tools/ MP console emulator + map/resource scanners
One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|