Merge BT411 audio-fidelity + combat work (4e72f0c..abed41e) into BT412
Brings the post-fork BT411 line forward via a local-path merge (never touches the BT411 gitea remote): the full audio-fidelity system (engine AUD*/L4AUD* + audiopresets.cpp + ~600 content wavs + AUDIO_FIDELITY.md), missiles/rear-fire/HUD/gyro/gait tasks (#66-68), FOGDAY.EGG, and refreshed context docs -- 91 commits, ~688 files clean. Only 5 files overlapped the steamification; resolved keeping BOTH: - L4NET.CPP: took BT411's task-#50 fix (don't close the game listener on console loss) over the seam's adaptation of the old buggy close; sends stay on NetTransport_Get(). - L4NETTRANSPORT.cpp: folded BT411's TCP_NODELAY latency fix into WinsockNetTransport::Connect (the seam already had retry + nonblocking). - mechmppr.cpp: combined the device_owns_input gating with BT411's task-#68 look-behind, gating the lookBehind write too. - .gitignore / CMakeLists.txt / mech4.cpp: trivial / auto-merged (deviceOwnsInput gating preserved). Verified: clean build (default + implicitly the Steam TU untouched); solo front-end mode; loopback MP through the seam (mesh completes, both tick, replication works, no NODELAY warnings). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
#include <cstdlib>
|
||||
#include "munga.h"
|
||||
#pragma hdrstop
|
||||
|
||||
@@ -290,6 +291,11 @@ AudioControlSend::AudioControlSend(
|
||||
MemoryStream_Read(stream, &control_ID);
|
||||
MemoryStream_Read(stream, &control_value);
|
||||
|
||||
if (getenv("BT_ATTRBIND_LOG")) { static int s_sd=0; if (s_sd++<80)
|
||||
DEBUG_STREAM << "[sendcfg] tgt=" << (void*)audio_component
|
||||
<< " ctl=" << (int)control_ID << "/" << control_value
|
||||
<< " entity=" << (void*)entity << "\n" << std::flush; }
|
||||
|
||||
Check(entity);
|
||||
entity->AddAudioComponent(this);
|
||||
|
||||
@@ -472,6 +478,9 @@ void
|
||||
while ((audio_component = iterator.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(audio_component);
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_sp2=0; if (s_sp2++<200)
|
||||
DEBUG_STREAM << "[split] " << (void*)this << " -> tgt=" << (void*)audio_component
|
||||
<< " ctl=" << (int)control_ID << "/" << control_value << "\n" << std::flush; }
|
||||
audio_component->ReceiveControl(control_ID, control_value);
|
||||
}
|
||||
}
|
||||
@@ -631,6 +640,10 @@ void
|
||||
}
|
||||
|
||||
Check(audioComponentSocket.GetCurrent());
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_mix=0; if (s_mix++<80)
|
||||
DEBUG_STREAM << "[mix] mixer=" << (void*)this << " -> tgt=" << (void*)audioComponentSocket.GetCurrent()
|
||||
<< " outCtl=" << (int)outputControlID << " in[" << index << "]=" << control_value
|
||||
<< " sum=" << mixed_value << "\n" << std::flush; }
|
||||
audioComponentSocket.GetCurrent()->ReceiveControl(
|
||||
outputControlID,
|
||||
mixed_value
|
||||
@@ -793,6 +806,9 @@ void
|
||||
}
|
||||
|
||||
Check(audioComponentSocket.GetCurrent());
|
||||
if (getenv("BT_AUDIO_SPATIAL") && mult_value <= 0.0f) { static int s_mx=0; if (s_mx++<300)
|
||||
DEBUG_STREAM << "[mult0] mult=" << (void*)this << " -> tgt=" << (void*)audioComponentSocket.GetCurrent()
|
||||
<< " in[" << index << "]=" << control_value << " product=" << mult_value << "\n" << std::flush; }
|
||||
audioComponentSocket.GetCurrent()->ReceiveControl(
|
||||
outputControlID,
|
||||
mult_value
|
||||
@@ -840,6 +856,11 @@ AudioControlSmoother::AudioControlSmoother(
|
||||
MemoryStream_Read(stream, &initial_fill_value);
|
||||
audioControlAverage.SetSize(number_of_samples, initial_fill_value);
|
||||
|
||||
if (getenv("BT_ATTRBIND_LOG")) { static int s_sm=0; if (s_sm++<40)
|
||||
DEBUG_STREAM << "[smoothcfg] this=" << (void*)this << " ctlID=" << (int)control_ID
|
||||
<< " samples=" << (int)number_of_samples << " fill=" << initial_fill_value
|
||||
<< "\n" << std::flush; }
|
||||
|
||||
AudioControlSmootherX(
|
||||
audio_component,
|
||||
entity,
|
||||
@@ -939,6 +960,14 @@ void
|
||||
{
|
||||
audioControlAverage.Add(control_value);
|
||||
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_sa=0;
|
||||
if ((controlID == 100 || controlID == 101) && s_sa++ < 3000)
|
||||
DEBUG_STREAM << "[smooth] t=" << (GetTickCount() % 1000000)
|
||||
<< " this=" << (void*)this << " ctl=" << (int)controlID
|
||||
<< " in=" << control_value
|
||||
<< " avg=" << audioControlAverage.CalculateOlympicAverage()
|
||||
<< "\n" << std::flush; }
|
||||
|
||||
Check(audioComponentSocket.GetCurrent());
|
||||
audioComponentSocket.GetCurrent()->ReceiveControl(
|
||||
controlID,
|
||||
@@ -1315,6 +1344,10 @@ void
|
||||
nextSampleTime += sampleDuration;
|
||||
|
||||
Check(audioComponentSocket.GetCurrent());
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_sh=0; if (s_sh++<60)
|
||||
DEBUG_STREAM << "[snh] this=" << (void*)this << " -> tgt=" << (void*)audioComponentSocket.GetCurrent()
|
||||
<< " ctlID=" << (int)audioControlID << " val=" << currentValue
|
||||
<< " range=[" << minValue << "," << maxValue << "]\n" << std::flush; }
|
||||
audioComponentSocket.GetCurrent()->ReceiveControl(
|
||||
audioControlID,
|
||||
currentValue
|
||||
|
||||
@@ -232,6 +232,12 @@ class AudioControlMixer:
|
||||
public AudioComponent
|
||||
{
|
||||
public:
|
||||
// DIAG/game-facing: expose the authored output control so game-side control
|
||||
// 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(); }
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
// Construction, Destruction, Testing
|
||||
@@ -307,6 +313,12 @@ class AudioControlMultiplier:
|
||||
public AudioComponent
|
||||
{
|
||||
public:
|
||||
// DIAG/game-facing: expose the authored output control so game-side control
|
||||
// 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(); }
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
// Construction, Destruction, Testing
|
||||
|
||||
+91
-3
@@ -1,3 +1,4 @@
|
||||
#include <cstdlib>
|
||||
#include "munga.h"
|
||||
#pragma hdrstop
|
||||
|
||||
@@ -94,8 +95,15 @@ void
|
||||
}
|
||||
headEntitySocket.Add(entity);
|
||||
|
||||
alDistanceModel(AL_LINEAR_DISTANCE);
|
||||
alDopplerFactor(0.3f);
|
||||
// FIDELITY (AUDIO_FIDELITY.md F3/F10): the engine computes the AUTHORED
|
||||
// distance-attenuation curve (AUDIO.INI amplitude_rolloff knee/exponent ->
|
||||
// AudioLocation::distanceVolumeScale) and the authored doppler-cents model.
|
||||
// Disable OpenAL's own models so they can't double-apply / fight them:
|
||||
// AL_LINEAR_DISTANCE made far battle audio fade to zero on a straight line
|
||||
// (-6 dB vs authored at 300u), and AL doppler ran with the wrong constants
|
||||
// AND a sign-inverted velocity feed (approaching sources pitched DOWN).
|
||||
alDistanceModel(AL_NONE);
|
||||
alDopplerFactor(0.0f);
|
||||
|
||||
#if 0
|
||||
//
|
||||
@@ -131,8 +139,39 @@ 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; }
|
||||
|
||||
// (task #50, AUDIO_FIDELITY F13) service the authored release fades
|
||||
// registered by PatchLevelOfDetail::StopNote (dB-linear note-off ramps).
|
||||
{
|
||||
extern void PRESET_serviceReleaseFades(float elapsed_seconds);
|
||||
static long s_lastFadeTicks = 0;
|
||||
long now_ticks = Now().ticks;
|
||||
if (s_lastFadeTicks != 0 && now_ticks > s_lastFadeTicks)
|
||||
{
|
||||
double tps = (double)SystemClock::GetTicksPerSecond();
|
||||
if (tps <= 0.0) tps = 1000.0;
|
||||
PRESET_serviceReleaseFades((float)((now_ticks - s_lastFadeTicks) / tps));
|
||||
}
|
||||
s_lastFadeTicks = now_ticks;
|
||||
}
|
||||
|
||||
//set current listener orientation
|
||||
Vector3D headVelocity;
|
||||
@@ -140,6 +179,32 @@ void
|
||||
headVelocity.MultiplyByInverse(this->GetHeadEntity()->GetWorldLinearVelocity(), this->GetHeadEntity()->localToWorld);
|
||||
alListener3f(AL_VELOCITY, -headVelocity.x, -headVelocity.y, -headVelocity.z);
|
||||
|
||||
// LIVE-PLAYING DUMP (BT_AUDIO_DUMP): once a second list every playing AL
|
||||
// source with its sample name / gain / pitch / loop -- catches "mystery
|
||||
// sounds" (wrong sample, wrong pitch, chopped) red-handed.
|
||||
if (getenv("BT_AUDIO_DUMP")) {
|
||||
static long s_dumpTick = 0;
|
||||
if ((++s_dumpTick % 45) == 0) {
|
||||
extern ALuint *g_buffers; extern int g_numBuffers; extern const char *g_bufferNames[512];
|
||||
for (ALuint sid = 1; sid <= 40; ++sid) {
|
||||
if (!alIsSource(sid)) continue;
|
||||
ALint st = 0; alGetSourcei(sid, AL_SOURCE_STATE, &st);
|
||||
if (st != AL_PLAYING) continue;
|
||||
ALint buf = 0, looping = 0; ALfloat gain = 0, pitch = 0;
|
||||
alGetSourcei(sid, AL_BUFFER, &buf);
|
||||
alGetSourcei(sid, AL_LOOPING, &looping);
|
||||
alGetSourcef(sid, AL_GAIN, &gain);
|
||||
alGetSourcef(sid, AL_PITCH, &pitch);
|
||||
const char *nm = "?";
|
||||
for (int b = 0; b < g_numBuffers && b < 512; ++b)
|
||||
if ((ALint)g_buffers[b] == buf) { nm = g_bufferNames[b] ? g_bufferNames[b] : "?"; break; }
|
||||
DEBUG_STREAM << "[playing] src=" << sid << " " << nm
|
||||
<< " gain=" << gain << " pitch=" << pitch
|
||||
<< " loop=" << looping << "\n" << std::flush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
//
|
||||
// Get the entity
|
||||
@@ -398,6 +463,29 @@ void
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
AudioComponent::PrimeWatchers(int passes)
|
||||
{
|
||||
Check(this);
|
||||
for (int pass = 0; pass < passes; ++pass)
|
||||
{
|
||||
ChainIteratorOf<Component*> iterator(&audioWatcherSocket);
|
||||
Component *component;
|
||||
while ((component = iterator.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(component);
|
||||
// recurse gate-free: an AudioComponent child (mixer/smoother/
|
||||
// splitter) pumps ITS chain; an attribute watcher re-reads +
|
||||
// re-sends. One pass per level keeps total work = passes x chain.
|
||||
component->PrimeWatchers(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
|
||||
@@ -454,6 +454,14 @@ public:
|
||||
void
|
||||
ExecuteWatchers();
|
||||
|
||||
// (task #50, AUDIO_FIDELITY F19) gate-free watcher pump for the transient
|
||||
// cold-start prime: ExecuteWatchers above is frame-gated
|
||||
// (DefaultAudioFrameDelay), so N calls in one tick collapse to one.
|
||||
// Recurses through the watcher CHAIN (source <- mixer <- smoother <-
|
||||
// scale), each hop gate-free.
|
||||
virtual void
|
||||
PrimeWatchers(int passes);
|
||||
|
||||
void
|
||||
Execute();
|
||||
|
||||
|
||||
@@ -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:
|
||||
//
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@@ -174,6 +174,10 @@ void
|
||||
|
||||
if (audio_source->IsAudioSourceClipped(GetAudioHead()))
|
||||
{
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_cl=0; if (s_cl++<40)
|
||||
DEBUG_STREAM << "[spatial] CLIPPED src=" << (void*)audio_source
|
||||
<< " headPos=(" << GetAudioHead()->GetHeadEntity()->localOrigin.linearPosition.x
|
||||
<< "," << GetAudioHead()->GetHeadEntity()->localOrigin.linearPosition.z << ")\n" << std::flush; }
|
||||
//
|
||||
// If it is a transient source then ignore request
|
||||
//
|
||||
@@ -181,7 +185,7 @@ void
|
||||
{
|
||||
#ifdef LAB_ONLY
|
||||
sourceClippedCount++;
|
||||
#endif
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
audio_source_priority = audio_source->GetAudioSourcePriority();
|
||||
@@ -190,7 +194,25 @@ void
|
||||
else
|
||||
{
|
||||
audio_source_priority = audio_source->GetAudioSourcePriority();
|
||||
// (task #50, AUDIO_FIDELITY F19) COLD-START PRIME: an idle source's own
|
||||
// watcher socket only executes at Start attempts, so its authored
|
||||
// AudioControlSmoothers (footstep volume: N=30/15, fill 0) warmed ONE
|
||||
// sample per attempt -- and the transient drop gate below (vol < 0.3)
|
||||
// rejected the first ~25 footfalls (~10-20 s of silent steps) before
|
||||
// the average could cross the gate. On a Start request, pump the
|
||||
// source's watchers a full smoother window so the volume chain is
|
||||
// evaluated at its true steady state; the smoother keeps its authored
|
||||
// smoothing role for live variation once the source is playing.
|
||||
if (message->controlID == StartAudioControlID)
|
||||
{
|
||||
audio_source->PrimeWatchers(30);
|
||||
}
|
||||
audio_source_volume_scale = audio_source->CalculateSourceVolumeScale();
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_vs=0; if ((s_vs++ % 120)==0)
|
||||
DEBUG_STREAM << "[spatial] request src=" << (void*)audio_source
|
||||
<< " vol=" << audio_source_volume_scale
|
||||
<< " headPos=(" << GetAudioHead()->GetHeadEntity()->localOrigin.linearPosition.x
|
||||
<< "," << GetAudioHead()->GetHeadEntity()->localOrigin.linearPosition.z << ")\n" << std::flush; }
|
||||
}
|
||||
|
||||
//
|
||||
@@ -199,17 +221,38 @@ void
|
||||
// Then return
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// DIAG (BT_AUDIO_NODROP): deliver low-volume transient starts anyway (at a
|
||||
// floor volume) to isolate volume-feed problems from the rest of the chain.
|
||||
if (getenv("BT_AUDIO_NODROP") &&
|
||||
message->controlID == StartAudioControlID &&
|
||||
audio_source->GetAudioRenderType() == TransientAudioRenderType &&
|
||||
audio_source_volume_scale < LowAudioVolumeThreshold)
|
||||
{
|
||||
DEBUG_STREAM << "[spatial] NODROP forcing start src=" << (void*)audio_source
|
||||
<< " vol=" << audio_source_volume_scale << "\n" << std::flush;
|
||||
audio_source->ReceiveControl(VolumeAudioControlID, 0.7f);
|
||||
audio_source_volume_scale = 0.7f;
|
||||
}
|
||||
if (
|
||||
message->controlID == StartAudioControlID &&
|
||||
audio_source->GetAudioRenderType() == TransientAudioRenderType &&
|
||||
audio_source_volume_scale < LowAudioVolumeThreshold
|
||||
)
|
||||
{
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_dr=0; if (s_dr++<40)
|
||||
DEBUG_STREAM << "[spatial] DROP transient start t=" << (GetTickCount() % 1000000)
|
||||
<< " src=" << (void*)audio_source
|
||||
<< " vol=" << audio_source_volume_scale
|
||||
<< " (below threshold " << LowAudioVolumeThreshold << ")\n" << std::flush; }
|
||||
#ifdef LAB_ONLY
|
||||
sourceClippedCount++;
|
||||
#endif
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if (getenv("BT_AUDIO_SPATIAL") && message->controlID == StartAudioControlID) {
|
||||
static int s_st=0; if (s_st++<40)
|
||||
DEBUG_STREAM << "[spatial] START request src=" << (void*)audio_source
|
||||
<< " vol=" << audio_source_volume_scale << "\n" << std::flush; }
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <cstdlib>
|
||||
#include "munga.h"
|
||||
#pragma hdrstop
|
||||
|
||||
@@ -67,6 +68,9 @@ void
|
||||
{
|
||||
Check(this);
|
||||
Check(audio_component);
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_ev=0; if (s_ev++<200)
|
||||
DEBUG_STREAM << "[seqev] tgt=" << (void*)audio_component
|
||||
<< " ctl=" << (int)audioControlID << "/" << audioControlValue << "\n" << std::flush; }
|
||||
audio_component->ReceiveControl(audioControlID, audioControlValue);
|
||||
}
|
||||
|
||||
@@ -189,6 +193,16 @@ AudioControlSequence::AudioControlSequence(
|
||||
audioControlEventSocket.Add(audio_control_event);
|
||||
}
|
||||
|
||||
if (getenv("BT_ATTRBIND_LOG")) { static int s_sq=0; if (s_sq++<60) {
|
||||
DEBUG_STREAM << "[seqcfg] seq=" << (void*)this << " tgt=" << (void*)audio_component
|
||||
<< " looped=" << (int)is_looped << " div=" << (int)divisions_per_beat
|
||||
<< " tempo=" << (int)tempo << " events=" << (int)number_of_control_events << " ";
|
||||
{ SChainIteratorOf<AudioControlEvent*> it(&audioControlEventSocket);
|
||||
AudioControlEvent *e; int n=0;
|
||||
while ((e = it.ReadAndNext()) != NULL && n++ < 24)
|
||||
DEBUG_STREAM << *e; }
|
||||
DEBUG_STREAM << "\n" << std::flush; } }
|
||||
|
||||
AudioControlSequenceX(
|
||||
audio_component,
|
||||
entity,
|
||||
@@ -378,6 +392,9 @@ Logical
|
||||
void
|
||||
AudioControlSequence::StartSequence()
|
||||
{
|
||||
if (getenv("BT_ATTRBIND_LOG")) { static int s_ss=0; if (s_ss++<40)
|
||||
DEBUG_STREAM << "[seqstart] seq=" << (void*)this << "\n" << std::flush; }
|
||||
|
||||
Check(this);
|
||||
|
||||
//
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <cstdlib>
|
||||
#include "munga.h"
|
||||
#pragma hdrstop
|
||||
|
||||
@@ -416,6 +417,12 @@ AudioControlValue
|
||||
volume_scale;
|
||||
|
||||
volume_scale = volumeScale * volumeMixScale * volumeCompressionScale;
|
||||
if (getenv("BT_AUDIO_SPATIAL") && volume_scale <= 0.0f) {
|
||||
static int s_z=0; if (s_z++<40)
|
||||
DEBUG_STREAM << "[spatial] vol=0 breakdown src=" << (void*)this
|
||||
<< " volumeScale=" << volumeScale
|
||||
<< " mixScale=" << volumeMixScale
|
||||
<< " compression=" << volumeCompressionScale << "\n" << std::flush; }
|
||||
Clamp(volume_scale, MinAudioVolume, MaxAudioVolume);
|
||||
return volume_scale;
|
||||
}
|
||||
@@ -656,6 +663,8 @@ void
|
||||
Check(this);
|
||||
Clamp(control_value, MinAudioVolume, MaxAudioVolume);
|
||||
volumeScale = control_value / (MaxAudioVolume - MinAudioVolume);
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_vh=0; if (s_vh++<300)
|
||||
DEBUG_STREAM << "[volset] src=" << (void*)this << " vol=" << volumeScale << "\n" << std::flush; }
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <cstdlib>
|
||||
#include "munga.h"
|
||||
#pragma hdrstop
|
||||
|
||||
@@ -134,6 +135,12 @@ AudioMotionTrigger::AudioMotionTrigger(
|
||||
MemoryStream_Read(stream, &motionType);
|
||||
MemoryStream_Read(stream, &motionValue);
|
||||
|
||||
if (getenv("BT_ATTRBIND_LOG")) { static int s_mt=0; if (s_mt++<40)
|
||||
DEBUG_STREAM << "[motiontrigcfg] attrPtr=" << (void*)attributePointer
|
||||
<< " motionType=" << (int)motionType << " (0=linear,1=angular)"
|
||||
<< " motionValue=" << (int)motionValue << " (0=X,1=Y,2=Z,3=len)"
|
||||
<< "\n" << std::flush; }
|
||||
|
||||
PrimeWatcher();
|
||||
}
|
||||
|
||||
@@ -283,6 +290,12 @@ AudioMotionScale::AudioMotionScale(
|
||||
MemoryStream_Read(stream, &motionType);
|
||||
MemoryStream_Read(stream, &motionValue);
|
||||
|
||||
if (getenv("BT_ATTRBIND_LOG")) { static int s_ms=0; if (s_ms++<40)
|
||||
DEBUG_STREAM << "[motionscalecfg] attrPtr=" << (void*)attributePointer
|
||||
<< " motionType=" << (int)motionType << " (0=linear,1=angular)"
|
||||
<< " motionValue=" << (int)motionValue << " (0=X,1=Y,2=Z,3=len)"
|
||||
<< "\n" << std::flush; }
|
||||
|
||||
PrimeWatcher();
|
||||
}
|
||||
|
||||
@@ -873,6 +886,31 @@ AudioStateWatcher::AudioStateWatcher(
|
||||
AudioWatcherOf<StateIndicator>(stream, entity)
|
||||
{
|
||||
Check_Pointer(attributePointer);
|
||||
// BRING-UP GUARD [T3, temporary]: an AudioStateWatcher binds to a StateIndicator
|
||||
// attribute BY NAME. The Mech's own state indicators (SimulationState, Animation/
|
||||
// ReplicantAnimationState, CollisionState) are real; but audio also binds state
|
||||
// attrs on subsystems that are not fully reconstructed yet (GeneratorState,
|
||||
// CondenserState, Torso MotionState, ...). Those resolve to an unconstructed
|
||||
// object -- a null/garbage vtable at +0 or a debug-fill (0xCDCDCDCD) watcher chain
|
||||
// at +0x18 -- and AddAudioWatcher would AV in SChainOf::Add. Skip the register
|
||||
// (that subsystem's state audio stays silent) until the subsystem is built; this
|
||||
// is SELF-CLEARING (a real StateIndicator passes). See docs: audio subsystem wave.
|
||||
// Validate the AUDIO SOCKET at +0x18 (what AddAudioWatcher touches), NOT the
|
||||
// object's +0 vtable: a real StateIndicator has a vtable at +0, but the binary's
|
||||
// 0x54 subsystem alarm (GaugeAlarm54) is non-polymorphic there (a raw header) yet
|
||||
// has a real, constructed SChainOf socket at +0x18. A skip means the socket is
|
||||
// unconstructed (null / debug-fill 0xCDCDCDCD) -- the inert pad or a subsystem not
|
||||
// yet reconstructed. Registering there would AV in SChainOf::Add.
|
||||
{
|
||||
unsigned chain = *(unsigned*)((char*)attributePointer + 0x18);
|
||||
if (chain == 0 || chain == 0xCDCDCDCD)
|
||||
{
|
||||
if (getenv("BT_AUDIO_LOG"))
|
||||
DEBUG_STREAM << "[audiostate] skip watcher on unbuilt StateIndicator "
|
||||
<< attributePointer << " (chain=" << (void*)chain << ")\n" << std::flush;
|
||||
return;
|
||||
}
|
||||
}
|
||||
Cast_Object(StateIndicator*, attributePointer)->AddAudioWatcher(this);
|
||||
}
|
||||
|
||||
@@ -936,6 +974,14 @@ AudioStateTrigger::AudioStateTrigger(
|
||||
MemoryStream_Read(stream, &excludeTransition);
|
||||
MemoryStream_Read(stream, &excludeState);
|
||||
|
||||
if (getenv("BT_ATTRBIND_LOG")) { static int s_stc=0; if (s_stc++<120)
|
||||
DEBUG_STREAM << "[statecfg] attrPtr=" << (void*)attributePointer
|
||||
<< " comp=" << (void*)audioComponentSocket.GetCurrent()
|
||||
<< " trigState=" << triggerState << " inv=" << (int)inverseTrigger
|
||||
<< " ctl=" << (int)controlID << "/" << controlValue
|
||||
<< " excl=" << (int)excludeTransition << "/" << excludeState
|
||||
<< "\n" << std::flush; }
|
||||
|
||||
PrimeWatcher();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include <cstdlib>
|
||||
|
||||
#include "watcher.h"
|
||||
#include "audio.h"
|
||||
@@ -304,6 +305,14 @@ template <class T>
|
||||
MemoryStream_Read(stream, &controlValueOff);
|
||||
|
||||
triggerOn = False;
|
||||
|
||||
if (getenv("BT_ATTRBIND_LOG")) { static int s_tc=0; if (s_tc++<80)
|
||||
DEBUG_STREAM << "[trigcfg] attrPtr=" << (void*)attributePointer << " comp=" << (void*)audioComponentSocket.GetCurrent()
|
||||
<< " thresh=" << attributeValueThreshold
|
||||
<< " inverse=" << (int)inverseTrigger
|
||||
<< " onID=" << (int)controlIDOn << "/" << controlValueOn
|
||||
<< " offID=" << (int)controlIDOff << "/" << controlValueOff
|
||||
<< "\n" << std::flush; }
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -357,6 +366,10 @@ template <class T> void
|
||||
Check_Pointer(attribute_ptr);
|
||||
Scalar current_value = ExtractInterestingValue(attribute_ptr);
|
||||
|
||||
if (getenv("BT_AUDIO_SPATIAL") && current_value > 0.0f) { static int s_tg=0; if (s_tg++<120)
|
||||
DEBUG_STREAM << "[trigger] attrPtr=" << (void*)attributePointer
|
||||
<< " val=" << current_value << " thresh=" << attributeValueThreshold
|
||||
<< " armed=" << (int)!triggerOn << "\n" << std::flush; }
|
||||
if (triggerOn)
|
||||
{
|
||||
if (
|
||||
@@ -432,6 +445,30 @@ public:
|
||||
);
|
||||
~AudioScaleOf();
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
// Execute -- scales send EVERY poll (task #50, AUDIO_FIDELITY F19).
|
||||
//
|
||||
// The base watcher gate is a BITWISE compare (Motion::operator== is
|
||||
// memcmp) that existed to skip truly static values. In the original,
|
||||
// scale-watched attributes (velocities, accelerations, temperatures)
|
||||
// were noisy physics floats that practically changed every poll, so
|
||||
// scales streamed per-poll values into their authored consumers -- the
|
||||
// footstep AudioControlSmoothers (N=30/15, fill 0) are SIZED for that
|
||||
// cadence. Our reconstruction's math can be deterministic (the gait
|
||||
// integrator lands on bit-identical derived values during smooth
|
||||
// acceleration), which froze the gate and starved the smoothers (the
|
||||
// 10-20 s footstep warm-up). Sending unconditionally restores the
|
||||
// original's practical behavior; triggers/matchers keep the change
|
||||
// gate (their semantics are edge-based).
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
void
|
||||
Execute()
|
||||
{
|
||||
GrabCurrentValue();
|
||||
}
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
// BuildFromPage
|
||||
@@ -508,6 +545,13 @@ template <class T>
|
||||
MemoryStream_Read(stream, &controlValueBoundary1);
|
||||
MemoryStream_Read(stream, &controlValueBoundary2);
|
||||
MemoryStream_Read(stream, &exponent);
|
||||
|
||||
if (getenv("BT_ATTRBIND_LOG")) { static int s_scf=0; if (s_scf++<160)
|
||||
DEBUG_STREAM << "[scalecfg] attrPtr=" << (void*)attributePointer
|
||||
<< " comp=" << (void*)audioComponentSocket.GetCurrent()
|
||||
<< " ctlID=" << (int)controlID
|
||||
<< " aB=[" << attributeValueBoundary1 << "," << attributeValueBoundary2 << "]"
|
||||
<< " cB=[" << controlValueBoundary1 << "," << controlValueBoundary2 << "]\n" << std::flush; }
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -625,6 +669,16 @@ template <class T> void
|
||||
|
||||
Check(&audioComponentSocket);
|
||||
Check(audioComponentSocket.GetCurrent());
|
||||
if (getenv("BT_AUDIO_SPATIAL") && control_value <= 0.0f) {
|
||||
static int s_sc=0; if (s_sc++<400)
|
||||
DEBUG_STREAM << "[spatial] scale->0 attrPtr=" << (void*)attributePointer << " comp=" << (void*)audioComponentSocket.GetCurrent() << " raw=" << current_value << " ctlID=" << (int)controlID << " ctl=" << control_value << " aB=[" << attributeValueBoundary1 << "," << attributeValueBoundary2 << "]" << " cB=[" << controlValueBoundary1 << "," << controlValueBoundary2 << "]\n" << std::flush; }
|
||||
if (getenv("BT_AUDIO_SPATIAL") && (controlID == 100 || controlID == 101)) {
|
||||
static int s_fs2=0; if (s_fs2++<2000)
|
||||
DEBUG_STREAM << "[fsscale] t=" << (GetTickCount() % 1000000)
|
||||
<< " attrPtr=" << (void*)attributePointer
|
||||
<< " comp=" << (void*)audioComponentSocket.GetCurrent()
|
||||
<< " ctl" << (int)controlID << " raw=" << current_value
|
||||
<< " out=" << control_value << "\n" << std::flush; }
|
||||
audioComponentSocket.GetCurrent()->ReceiveControl(
|
||||
controlID,
|
||||
control_value
|
||||
@@ -721,6 +775,12 @@ template <class T>
|
||||
MemoryStream_Read(stream, &attributeMatchValue);
|
||||
MemoryStream_Read(stream, &controlID);
|
||||
MemoryStream_Read(stream, &controlValue);
|
||||
|
||||
if (getenv("BT_ATTRBIND_LOG")) { static int s_mc=0; if (s_mc++<80)
|
||||
DEBUG_STREAM << "[matchcfg] attrPtr=" << (void*)attributePointer
|
||||
<< " match=" << attributeMatchValue
|
||||
<< " ctlID=" << (int)controlID << " ctlVal=" << controlValue
|
||||
<< "\n" << std::flush; }
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -767,6 +827,10 @@ template <class T> void
|
||||
|
||||
if (current_value == attributeMatchValue)
|
||||
{
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_mf=0; if (s_mf++<40)
|
||||
DEBUG_STREAM << "[matchfire] attrPtr=" << (void*)attributePointer << " comp=" << (void*)audioComponentSocket.GetCurrent() << " compClass=" << (int)audioComponentSocket.GetCurrent()->GetClassID()
|
||||
<< " val=" << current_value << " -> ctl " << (int)controlID
|
||||
<< "/" << controlValue << "\n" << std::flush; }
|
||||
Check(&audioComponentSocket);
|
||||
Check(audioComponentSocket.GetCurrent());
|
||||
#if 1
|
||||
|
||||
@@ -11,6 +11,17 @@ public:
|
||||
|
||||
virtual void Execute();
|
||||
|
||||
// (task #50, AUDIO_FIDELITY F19) gate-free watcher pump for the audio
|
||||
// transient cold-start prime. Default: run Execute() N times (attribute
|
||||
// watchers re-read + re-send each pass). AudioComponent overrides it to
|
||||
// RECURSE through its watcher chain, bypassing the per-component
|
||||
// audio-frame gate that otherwise collapses the passes to one.
|
||||
virtual void PrimeWatchers(int passes)
|
||||
{
|
||||
for (int pass = 0; pass < passes; ++pass)
|
||||
Execute();
|
||||
}
|
||||
|
||||
static Derivation *GetClassDerivations();
|
||||
static SharedData DefaultData;
|
||||
|
||||
|
||||
+60
-8
@@ -11,6 +11,34 @@
|
||||
#include "line.h"
|
||||
#include "app.h"
|
||||
#include "notation.h"
|
||||
#include <math.h>
|
||||
|
||||
//
|
||||
// EXACT axis-angle rotation composition -- matches the 1995 BT binary's angular
|
||||
// integrator (FUN_00409f58): build a unit rotation quaternion from the rotation
|
||||
// VECTOR `rotVec` (angle = |rotVec|, axis = rotVec/angle) as { axis*sin(angle/2),
|
||||
// cos(angle/2) } and Hamilton-multiply it onto `base`. The dead-reckoner previously
|
||||
// did `out.Add(base, rotVec)` -- adding a scaled angular-velocity vector to the heading
|
||||
// quaternion. That is only a small-angle approximation: fine per-frame (tiny angle),
|
||||
// but over a long replicant dead-reckon gap it DIVERGES (the heading drifts to ~180deg
|
||||
// then snaps -- the spinning-peer hesitation). This composition is exact for any angle
|
||||
// and stays on the unit sphere.
|
||||
//
|
||||
static void ExactAngularProject(Quaternion &out, const Quaternion &base, const Vector3D &rotVec)
|
||||
{
|
||||
const Scalar ang = rotVec.Length();
|
||||
if (ang > 1.0e-6f)
|
||||
{
|
||||
const Scalar h = 0.5f * (Scalar)fmodf((float)ang, 6.2831853f); // half of angle mod 2pi
|
||||
const Scalar s = (Scalar)(sinf((float)h) / ang); // sin(angle/2)/angle
|
||||
const Quaternion dq(rotVec.x * s, rotVec.y * s, rotVec.z * s, (Scalar)cosf((float)h));
|
||||
out.Multiply(base, dq); // base (X) dq
|
||||
}
|
||||
else
|
||||
{
|
||||
out = base;
|
||||
}
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
//############################### Mover #################################
|
||||
@@ -395,10 +423,8 @@ Logical
|
||||
//-------------------------------
|
||||
//
|
||||
position_delta.Multiply(updateVelocity.angularMotion, time_slice);
|
||||
projectedOrigin.angularPosition.Add(
|
||||
updateOrigin.angularPosition,
|
||||
position_delta
|
||||
);
|
||||
ExactAngularProject(projectedOrigin.angularPosition, // was .Add (diverging vector-add)
|
||||
updateOrigin.angularPosition, position_delta);
|
||||
projectedVelocity = updateVelocity;
|
||||
|
||||
Check_Fpu();
|
||||
@@ -460,10 +486,8 @@ Logical
|
||||
updateVelocity.angularMotion,
|
||||
time_slice
|
||||
);
|
||||
projectedOrigin.angularPosition.Add(
|
||||
updateOrigin.angularPosition,
|
||||
position_delta
|
||||
);
|
||||
ExactAngularProject(projectedOrigin.angularPosition, // was .Add (diverging vector-add)
|
||||
updateOrigin.angularPosition, position_delta);
|
||||
|
||||
//
|
||||
//-----------------------------------
|
||||
@@ -1113,6 +1137,34 @@ BoxedSolid*
|
||||
return solid;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// The "static world" tail of FindBoxedSolidHitBy on its own: ray-test ONLY the
|
||||
// zone's static solid tree (world structures -- garages, walls, props), NOT the
|
||||
// tangible movers/doors. Same tree the mech's walk collides against, so a shot
|
||||
// designated through this lands on exactly the geometry that blocks the mech.
|
||||
// FindBoundingBoxHitBy clips line->length to the hit distance (HitByBounded ->
|
||||
// line->length = enter), so the caller reads the entry point via line->FindEnd.
|
||||
//
|
||||
BoxedSolid*
|
||||
Mover::FindStaticSolidHitBy(
|
||||
Line *line
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check(line);
|
||||
|
||||
InterestManager *interest_mgr = application->GetInterestManager();
|
||||
Check(interest_mgr);
|
||||
InterestZone *zone = interest_mgr->GetInterestZone(interestZoneID);
|
||||
Check(zone);
|
||||
BoxedSolidTree* tree = zone->GetCollisionRoot();
|
||||
Check(tree);
|
||||
BoxedSolid *result = (BoxedSolid*)tree->FindBoundingBoxHitBy(line);
|
||||
Check_Fpu();
|
||||
return result;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
BoxedSolidCollisionList*
|
||||
|
||||
@@ -300,6 +300,16 @@ public:
|
||||
Line *line,
|
||||
Entity *except_by
|
||||
);
|
||||
// STATIC-WORLD-ONLY ray query: the "test against the static world" tail of
|
||||
// FindBoxedSolidHitBy factored out -- ray-tests ONLY the zone's static solid
|
||||
// tree (the world structures: garages, walls, props), skipping the tangible
|
||||
// movers/doors. Used by the weapon boresight pick so a shot lands on the SAME
|
||||
// static geometry that already blocks the mech's walk (mechs are picked
|
||||
// separately, with their damage zones/lock). Clips line->length to the entry.
|
||||
BoxedSolid*
|
||||
FindStaticSolidHitBy(
|
||||
Line *line
|
||||
);
|
||||
BoxedSolidCollisionList*
|
||||
CollideCenterOfMotion(
|
||||
Line *line,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <cstdlib>
|
||||
#include "munga.h"
|
||||
#pragma hdrstop
|
||||
|
||||
@@ -486,6 +487,14 @@ void
|
||||
//#############################################################################
|
||||
// Watcher Support
|
||||
//
|
||||
int
|
||||
Simulation::DebugAudioWatcherCount()
|
||||
{
|
||||
SChainIteratorOf<Component*> iterator(audioWatcherSocket);
|
||||
return (int)iterator.GetSize();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Simulation::ExecuteWatchers()
|
||||
{
|
||||
@@ -496,6 +505,8 @@ void
|
||||
// Audio
|
||||
{
|
||||
SChainIteratorOf<Component*> iterator(audioWatcherSocket);
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_ec=0; if ((s_ec++ % 600)==0)
|
||||
DEBUG_STREAM << "[watchpoll] sim=" << (void*)this << " audioSocket size=" << iterator.GetSize() << "\n" << std::flush; }
|
||||
while ((watcher = iterator.ReadAndNext()) != NULL)
|
||||
{
|
||||
watcher->Execute();
|
||||
|
||||
@@ -247,6 +247,9 @@ public:
|
||||
void
|
||||
ExecuteWatchers();
|
||||
|
||||
int // DEBUG (BT_AUDIO_LOG): how many audio watchers are registered on this sim
|
||||
DebugAudioWatcherCount();
|
||||
|
||||
private:
|
||||
SChainOf<Component*>
|
||||
audioWatcherSocket;
|
||||
|
||||
+40
-15
@@ -1,3 +1,4 @@
|
||||
#include <cstdlib>
|
||||
#include "munga.h"
|
||||
#pragma hdrstop
|
||||
|
||||
@@ -95,21 +96,45 @@ AttributeWatcher::AttributeWatcher(
|
||||
|
||||
attributePointer = simulation->GetAttributePointer(attribute_name);
|
||||
|
||||
#if DEBUG_LEVEL>0
|
||||
if (attributePointer == NULL)
|
||||
{
|
||||
Dump(attribute_name);
|
||||
}
|
||||
#else
|
||||
if (attributePointer == NULL)
|
||||
{
|
||||
DEBUG_STREAM <<
|
||||
"AttributeWatcher::AttributeWatcher - attribute " <<
|
||||
attribute_name <<
|
||||
"\n";
|
||||
Fail("AttributeWatcher::AttributeWatcher - attribute not found\n");
|
||||
}
|
||||
#endif
|
||||
if (getenv("BT_ATTRBIND_LOG"))
|
||||
{
|
||||
extern int g_curAudioWatcherClass;
|
||||
DEBUG_STREAM << "[attrbind] class=" << g_curAudioWatcherClass
|
||||
<< " subsys=[" << subsystem_name
|
||||
<< "] attr=[" << attribute_name << "] -> ptr=" << attributePointer
|
||||
<< " vtbl=" << (attributePointer ? *(void**)attributePointer : (void*)0)
|
||||
<< "\n" << std::flush;
|
||||
}
|
||||
|
||||
// BRING-UP GUARD [T3, temporary]: audio references attributes on subsystems that
|
||||
// are not fully reconstructed yet (GeneratorState/On, CondenserState, ReportLeak,
|
||||
// Torso SpeedOfTorsoHorizontal/MotionState, Reservoir/Avionics/ControlsMapper ...).
|
||||
// GetAttributePointer returns NULL for those, and the original engine Fail()s
|
||||
// (fatal) -- which would abort every audio-enabled run. Redirect NULL to a shared
|
||||
// inert zero pad so scalar/vector watchers read 0 (that sound stays silent) instead
|
||||
// of crashing; state watchers on it are skipped by the AudioStateWatcher guard.
|
||||
// Self-clearing: a registered attribute resolves to its real member. Remove once
|
||||
// the subsystem attribute tables are reconstructed (the audio subsystem wave).
|
||||
if (attributePointer == NULL)
|
||||
{
|
||||
static char s_missingAttrPad[64] = {0};
|
||||
// TYPED pad: ConfigureActivePress is the held-configure-button INDEX whose
|
||||
// authored idle is -1 (none) -- NINE audio triggers gate the configure-mode
|
||||
// ticker on it with threshold -1 across the configurable subsystems. The
|
||||
// zero pad read as "button 0 held" and started the ticker at load (the
|
||||
// eternal 2.7/s chirp). Redirect this attribute to a -1 pad; others keep 0.
|
||||
static int s_configureIdlePad = -1;
|
||||
CString configure_name("ConfigureActivePress");
|
||||
if (attribute_name == configure_name)
|
||||
attributePointer = &s_configureIdlePad;
|
||||
else
|
||||
attributePointer = s_missingAttrPad;
|
||||
if (getenv("BT_AUDIO_LOG"))
|
||||
DEBUG_STREAM << "[attrnull] " << subsystem_name << "." << attribute_name
|
||||
<< " not reconstructed -> "
|
||||
<< (attributePointer == (void*)&s_configureIdlePad ? "-1 pad" : "inert pad")
|
||||
<< "\n" << std::flush;
|
||||
}
|
||||
|
||||
Check_Pointer(attributePointer);
|
||||
#endif
|
||||
|
||||
+30
-1
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include <cstdlib>
|
||||
|
||||
#include "cmpnnt.h"
|
||||
#include "slot.h"
|
||||
@@ -155,14 +156,18 @@ private:
|
||||
void
|
||||
InitializeCurrentValue();
|
||||
|
||||
protected:
|
||||
//
|
||||
//-----------------------------------------------------------------------
|
||||
// GrabCurrentValue
|
||||
// GrabCurrentValue -- protected (task #50): AudioScaleOf's per-poll
|
||||
// Execute override calls it directly (see AUDWTHR.h).
|
||||
//-----------------------------------------------------------------------
|
||||
//
|
||||
void
|
||||
GrabCurrentValue();
|
||||
|
||||
private:
|
||||
|
||||
//
|
||||
//-----------------------------------------------------------------------
|
||||
// DumpValue
|
||||
@@ -262,8 +267,32 @@ template <class T> void
|
||||
Check(this);
|
||||
|
||||
Check_Pointer(attributePointer);
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { // poll-rate probe: total watcher polls + change events
|
||||
static long s_polls=0; if ((++s_polls % 2000)==0)
|
||||
DEBUG_STREAM << "[watchpoll] total polls=" << s_polls << "\n" << std::flush;
|
||||
extern void *g_btFootStepAddr; // DIAG: uncapped tracer on THE footstep watcher
|
||||
if ((void*)attributePointer == g_btFootStepAddr) {
|
||||
static long s_fsp=0;
|
||||
if ((++s_fsp % 120)==0 || !(currentValue == *(T*)attributePointer))
|
||||
DEBUG_STREAM << "[fswatch] poll#" << s_fsp << " cur=" << (int)*(int*)¤tValue
|
||||
<< " mem=" << *(int*)attributePointer << "\n" << std::flush;
|
||||
}
|
||||
extern void *g_btAccelAddr; // DIAG: poll-vs-change split on the accel attr
|
||||
if ((void*)attributePointer == g_btAccelAddr) {
|
||||
static long s_ap=0, s_ac=0;
|
||||
int changed = !(currentValue == *(T*)attributePointer);
|
||||
if (changed) ++s_ac;
|
||||
if ((++s_ap % 120)==0 || (changed && (s_ac % 30)==0))
|
||||
DEBUG_STREAM << "[accwatch] t=" << (GetTickCount() % 1000000)
|
||||
<< " poll#" << s_ap << " changes=" << s_ac
|
||||
<< " memY=" << ((float*)attributePointer)[1]
|
||||
<< " curY=" << ((float*)¤tValue)[1] << "\n" << std::flush;
|
||||
}
|
||||
}
|
||||
if (!(currentValue == *(T*)attributePointer))
|
||||
{
|
||||
if (getenv("BT_AUDIO_SPATIAL")) { static int s_chg=0; if (s_chg++<60)
|
||||
DEBUG_STREAM << "[watchpoll] CHANGE attrPtr=" << (void*)attributePointer << "\n" << std::flush; }
|
||||
#if DEBUG_LEVEL>0
|
||||
if (dumpValue)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user