Audio Phase 1 (AUDIO_FIDELITY F3/F4/F10/F15/F18/F20 + KB): the quick wins

F3 distance: alDistanceModel(AL_NONE); restored the commented authored
  distance multiply in Dynamic3D::CalculateSourceVolumeScale, added the same
  override to Static3D, dropped the (now inert) AL_MAX_DISTANCE writes.  Far
  battle audio follows the authored knee/rolloff curve again, and the volume
  cull / voice steal / ducking chains are distance-aware.
F4 volume law: AL_GAIN = volume_scale^2 at all 3 per-frame sites (Direct/
  Dyn3D/Static3D) -- the GM CC7 squared curve; linear was ~+6 dB at mids.
F10 doppler: alDopplerFactor(0) (AL's model ran wrong constants + sign-
  inverted velocity: approaching sources pitched DOWN); the AUTHORED
  dopplerCents (AUDIO.INI range/speed-of-sound model, decomp-proven consumer
  part_008.c:7466) now adds into the Dynamic3D pitch chain.
F15 ConfigureActivePress: published at the MechSubsystem BASE (binary id 2,
  descriptor @0x50de5c -> +0x110); renamed the misnamed vitalSubsystemIndex
  member (the weapon ConfigureMappables handler already drives it 0/-1).
  Removed the invented Sensor/Myomers duplicates and RESTORED their byte-
  exact layouts (0x328/0x358 allocs + asserts).  MechWeapon's pinned-id pad
  absorbed the +1 chain shift -- which matches the binary's own numbering.
F18 cook-off warning: AmmoBin FireCountdownStarted -> the existing
  cookOffArmed @0x18C (binary table @0x512600); the countdown klaxon can fire.
F20 zoom blip: L4MechControlsMapper publishes TargetRangeExponent -> the live
  @0x1a4 zoom member (own table chained to MechControlsMapper).
KB: replaced the bogus divisionParameters+0x10 rate read with
  SystemClock::GetTicksPerSecond() (FUN_0044e19c is GetFrameRate -- original
  audio frames were CLOCK TICKS).

Regression (35s drive+fire): stable; ConfigureActivePress binds real on all 9
subsystems (idle -1, zero pad redirects); FireCountdownStarted +
TargetRangeExponent bind live members; attrnull 53 -> 41; chirp still dead;
footfalls still fire (gain now correctly squared).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-16 10:43:38 -05:00
co-authored by Claude Opus 4.8
parent 05cb3f5549
commit fc7f311771
16 changed files with 162 additions and 81 deletions
+13 -19
View File
@@ -280,27 +280,21 @@ BTL4Application::SharedData
}
//
// FUN_0044e19c read the sample rate as a float out of the division
// parameter block (@+0x10). In WinTesla that block is the public
// L4Application::divisionParameters char*; fall back to 1000.0f (the
// RP default) when it is absent. Second arg is the mission-review
// flag (the 1995 binary hard-coded it off; DAT_004fd550 == 0).
// AUDIO CLOCK RATE (AUDIO_FIDELITY.md KB correction): FUN_0044e19c is
// ApplicationManager::GetFrameRate() -- the ORIGINAL audio "frames" were
// system CLOCK TICKS (the DOS 18.2/28 Hz timer), not a sample rate. The
// old port read a float from divisionParameters+0x10 (a raw 1995-layout
// offset = garbage, -1.6e14 measured). The Windows equivalent of the
// original semantic is the system tick rate: AudioHead::Execute stamps
// audioFrameCount from SystemClock ticks, so calibrating the renderer to
// the same tick rate keeps every AudioTime conversion unit-consistent.
//
RendererRate sample_rate =
divisionParameters
? (RendererRate)*reinterpret_cast<float*>(divisionParameters + 0x10)
: (RendererRate)1000.0f;
// DATABINDING GUARD (task #50): divisionParameters is a raw engine block
// pointer and +0x10 is a 1995-layout offset; on the port it read GARBAGE
// (-1.6e14 measured), poisoning calibrationRate -> every AudioTime
// conversion (sequence event scheduling, compression durations) broke,
// which is why AudioControlSequence timeline events (footstep volumes!)
// never landed. Sanity-clamp to the authored 1000 frames/sec default.
if (!(sample_rate > 0.0f && sample_rate <= 100000.0f))
sample_rate = (RendererRate)1000.0f;
long ticks_per_second = SystemClock::GetTicksPerSecond();
if (ticks_per_second <= 0) ticks_per_second = 1000; // GetTickCount ms (static not yet measured)
RendererRate sample_rate = (RendererRate)ticks_per_second;
if (getenv("BT_AUDIO_LOG"))
DEBUG_STREAM << "[audio] renderer sample_rate=" << sample_rate
<< " (divisionParameters=" << (void*)divisionParameters << ")" << "\n" << std::flush;
DEBUG_STREAM << "[audio] renderer calibration rate=" << sample_rate
<< " (SystemClock ticks/sec)" << "\n" << std::flush;
return
new BTL4AudioRenderer(