From f4b2a7f87fdfd49f56e541fe05540d7e4b72ae42 Mon Sep 17 00:00:00 2001 From: arcattack Date: Thu, 16 Jul 2026 00:31:55 -0500 Subject: [PATCH] Audio: fix POISONED calibration rate (raw-offset garbage) + calibrated audio clock (task #50) Two real bugs found + fixed chasing the footstep volume: 1. BTL4Application::MakeAudioRenderer read sample_rate from a raw 1995-layout offset (divisionParameters+0x10) -- the databinding trap: it yielded -1.6e14 (measured), poisoning Renderer::calibrationRate for the ENTIRE audio system. Every AudioTime conversion (sequence event scheduling, compression curve durations, Seconds_To_Frames) was garbage. Sanity-clamp to the authored 1000 frames/sec default (BT_AUDIO_LOG logs the value). 2. AudioHead::Execute fed audioFrameCount raw OS ticks; now converts ticks -> calibrated frames via SystemClock::GetTicksPerSecond (1000ms fallback when the static isn't measured yet), so AudioTime consumers see the rate they were calibrated for. With rate=1000 + ms ticks the units now align end-to-end. Footstep status: chain verified through pulse -> matcher -> Start -> renderer; the volume mixer's two inputs receive only value-0 AudioControlSequence events even with correct timing -- the authored event VALUES need decoding next (sequence tempo/divisions ctor dump; possibly Verify()-stripped tempo garbage or the events are resets and the true volume rides another control id). Co-Authored-By: Claude Opus 4.8 (1M context) --- engine/MUNGA/AUDIO.cpp | 16 +++++++++++++++- game/reconstructed/btl4app.cpp | 11 +++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/engine/MUNGA/AUDIO.cpp b/engine/MUNGA/AUDIO.cpp index f2d96e0..60232e3 100644 --- a/engine/MUNGA/AUDIO.cpp +++ b/engine/MUNGA/AUDIO.cpp @@ -132,7 +132,21 @@ void // // Increment frame counter // - audioFrameCount = Now().ticks; + // AUDIO CLOCK CALIBRATION FIX: AudioTime consumers (sequence event timing, + // compression curves) assume audioFrameCount advances at the renderer's + // calibrationRate (DefaultRendererRate = 30 frames/sec: + // Seconds_To_Frames = s * rate). The WinTesla port set raw Now().ticks here + // (~hundreds/sec), running sequences ~18x off the authored timing -- the + // AudioControlSequence events carrying the real footstep volumes never + // landed where authored. Convert ticks -> calibrated frames properly. + { + double tps = (double)SystemClock::GetTicksPerSecond(); + if (tps <= 0.0) tps = 1000.0; // GetTickCount ms fallback (static not yet measured) + audioFrameCount = (AudioFrameCount)( + (double)Now().ticks + * (double)application->GetAudioRenderer()->GetCalibrationRate() + / tps); + } Verify(audioFrameCount < LONG_MAX); if (getenv("BT_AUDIO_SPATIAL")) { static long s_hx=0; if ((++s_hx % 300)==0) DEBUG_STREAM << "[audioclock] frame=" << audioFrameCount << " execs=" << s_hx << "\n" << std::flush; } diff --git a/game/reconstructed/btl4app.cpp b/game/reconstructed/btl4app.cpp index 1b6a2c9..08c5e04 100644 --- a/game/reconstructed/btl4app.cpp +++ b/game/reconstructed/btl4app.cpp @@ -290,6 +290,17 @@ BTL4Application::SharedData divisionParameters ? (RendererRate)*reinterpret_cast(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; + if (getenv("BT_AUDIO_LOG")) + DEBUG_STREAM << "[audio] renderer sample_rate=" << sample_rate + << " (divisionParameters=" << (void*)divisionParameters << ")" << "\n" << std::flush; return new BTL4AudioRenderer(