Files
TeslaRel410/restoration/source410/MUNGA/AUDREND.CPP
T
CydandClaude Fable 5 5b35eb973c 4.10 reconstruction: BTL4OPT.EXE links clean and BOOTS to the first staged brick
The reconstructed tree now produces a runnable binary with the authentic
1995 toolchain (BC4.52 / tlink32 / DPMI32):

- BTL4.CPP main TU reconstructed from the 4.11 Ghidra decomp (FUN_0040109c)
  + the 4.10 binary's own string pool + surviving RPL4TOOL.CPP house style;
  probe_main.cpp scaffold retired (BTL4.NOTES.md documents every decoded call)
- L4NET.CPP staged: L4NetworkManager ctor/dtor + 10 vtable-pulled virtuals
  (standalone-benign ones no-op, network ones Fail loudly) + NetNub client
  globals (Net_Common_Ptr=NULL routes L4File to its plain-DOS path)
- build410.sh: libs now built in the AUTHENTIC makefile member order
  (MUNGA.MAK / mungal4.mak / BT.MAK / BTL4.MAK). Order is load-bearing:
  tlink emits static-init records in module pull order, and alphabetical
  order booted into a null-vptr crash (IcomManager::ClassDerivations
  constructing before parent NetworkClient::ClassDerivations). Also fixed
  stage_link to the proven 32-bit lib set (SOSDBXC+SOSMBXC, no WATTCPLG)
- BOXTREE.HPP MemoryBlock unify, BTL4GRND notify stubs, remaining engine
  backfills (audio/gauge/resource/stream TUs) that closed the deep ledger

Smoke test (DOSBox-X + 32RTM, copy of the pod BT tree, our exe swapped in):
  BattleTech v4.10
  BTL4Application::BTL4Application
  l4net.cpp(22): L4NetworkManager -- l4net.cpp not yet reconstructed
Static init, main, -egg parse, BTL4.RES load (version 1.0.6 check passes),
ApplicationManager and the BTL4Application ctor chain all execute real
reconstructed code; boot halts at the first staged Fail() as designed.
Next brick: the real l4net.cpp body.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 19:05:53 -05:00

541 lines
15 KiB
C++

# if !defined(MUNGA_HPP)
# include <munga.hpp>
# endif
#pragma hdrstop
# if !defined(AUDREND_HPP)
# include <audrend.hpp>
# endif
# if !defined(AUDENT_HPP)
# include <audent.hpp>
# endif
# if !defined(JMOVER_HPP)
# include <jmover.hpp>
# endif
# if !defined(APP_HPP)
# include <app.hpp>
# endif
//#############################################################################
//########################### AudioRenderer #############################
//#############################################################################
//
//#############################################################################
// AudioRenderer
//#############################################################################
//
AudioRenderer::AudioRenderer(RendererRate render_rate):
Renderer(
render_rate,
MaxRendererComplexity,
DefaultRendererPriority,
AudioInterestType,
DefaultInterestDepth,
AudioRendererClassID
),
audioEventSocket(NULL, False)
{
audioHead = NULL;
#ifdef LAB_ONLY
sourceClippedCount = 0;
sourceStartCount = 0;
sourceSuspendCount = 0;
sourceResumeCount = 0;
doubleTriggerCount = 0;
resourceStealCount = 0;
resourceStealPriorityCount = 0;
resourceStealVolumeCount = 0;
stealShortDurationCount = 0;
#endif
}
//
//#############################################################################
// ~AudioRenderer
//#############################################################################
//
AudioRenderer::~AudioRenderer()
{
Unregister_Object(audioHead);
delete audioHead;
#ifdef LAB_ONLY
cout << "AudioRenderer::~AudioRenderer - sourceClippedCount="
<< sourceClippedCount << "\n";
cout << "AudioRenderer::~AudioRenderer - sourceStartCount="
<< sourceStartCount << "\n";
cout << "AudioRenderer::~AudioRenderer - sourceSuspendCount="
<< sourceSuspendCount << "\n";
cout << "AudioRenderer::~AudioRenderer - sourceResumeCount="
<< sourceResumeCount << "\n";
cout << "AudioRenderer::~AudioRenderer - doubleTriggerCount="
<< doubleTriggerCount << "\n";
cout << "AudioRenderer::~AudioRenderer - resourceStealCount="
<< resourceStealCount << "\n";
cout << "AudioRenderer::~AudioRenderer - resourceStealPriorityCount="
<< resourceStealPriorityCount << "\n";
cout << "AudioRenderer::~AudioRenderer - resourceStealVolumeCount="
<< resourceStealVolumeCount << "\n";
cout << "AudioRenderer::~AudioRenderer - stealShortDurationCount="
<< stealShortDurationCount << "\n";
#endif
}
//
//#############################################################################
// Initialize
//#############################################################################
//
void
AudioRenderer::Initialize()
{
audioHead = MakeAudioHead();
Register_Object(audioHead);
}
//
//#############################################################################
// TestInstance
//#############################################################################
//
Logical
AudioRenderer::TestInstance() const
{
Renderer::TestInstance();
if (audioHead != NULL)
{
Check(audioHead);
}
Check(&audioEventSocket);
return True;
}
//
//#############################################################################
// LinkToEntity
//#############################################################################
//
void
AudioRenderer::LinkToEntity(Entity *entity)
{
Check(this);
Check(entity);
//
//--------------------------------------------------------------------------
// Link the head to the entity
//--------------------------------------------------------------------------
//
Check(audioHead);
audioHead->LinkToEntity(entity);
//
//--------------------------------------------------------------------------
// Call inherited method
//--------------------------------------------------------------------------
//
Renderer::LinkToEntity(entity);
}
//
//#############################################################################
// ExecuteImplementation
//#############################################################################
//
void
AudioRenderer::ExecuteImplementation(
RendererComplexity,
RendererOrigin::InterestingEntityIterator*
)
{
Check(this);
Check(audioHead);
audioHead->Execute();
}
//
//#############################################################################
// PostAudioRequestMessage
//#############################################################################
//
void
AudioRenderer::PostAudioRequestMessage(
AudioSource *audio_source,
AudioSource::RequestMessage *message
)
{
Check(this);
Check(audio_source);
Check(message);
//
//--------------------------------------------------------------------------
// If audio source is clipped and the source is transient
// Then ignore
// Else set priority and volume
//--------------------------------------------------------------------------
//
AudioSourcePriority
audio_source_priority;
AudioControlValue
audio_source_volume_scale;
if (audio_source->IsAudioSourceClipped(GetAudioHead()))
{
//
// If it is a transient source then ignore request
//
if (audio_source->GetAudioRenderType() == TransientAudioRenderType)
{
#ifdef LAB_ONLY
sourceClippedCount++;
#endif
return;
}
audio_source_priority = audio_source->GetAudioSourcePriority();
audio_source_volume_scale = 0.0f;
}
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
audio_source_volume_scale = audio_source->CalculateSourceVolumeScale();
}
//
//--------------------------------------------------------------------------
// If this a transient source and volume is lower than threshold
// 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" << 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
)
{
#ifdef LAB_ONLY
sourceClippedCount++;
#endif
return;
}
//
//--------------------------------------------------------------------------
// Create audio weight based on priority and volume
// Add audio event
//--------------------------------------------------------------------------
//
AudioWeighting
audio_weight(audio_source_priority, audio_source_volume_scale);
AudioEvent
*audio_event;
audio_event = new AudioEvent(audio_source, message);
Register_Object(audio_event);
audioEventSocket.AddValue(audio_event, audio_weight);
}
//
//#############################################################################
// ProcessAudioRequestMessage
//#############################################################################
//
Logical
AudioRenderer::ProcessAudioRequestMessage()
{
//
// Process high priority, high volume event
//
AudioEventIterator
iterator(&audioEventSocket);
AudioEvent
*audio_event;
Logical stuff = False;
while ((audio_event = iterator.GetCurrent()) != NULL)
{
stuff = True;
Check(audio_event);
audio_event->Process();
//return True;
}
return stuff;
}
//
//#############################################################################
// FlushAudioMessages
//#############################################################################
//
void
AudioRenderer::FlushAudioMessages(AudioSource *audio_source)
{
Check(this);
Check(audio_source);
//
// Process matching events
//
AudioEventIterator
iterator(&audioEventSocket);
AudioEvent
*audio_event;
while ((audio_event = iterator.ReadAndNext()) != NULL)
{
Check(audio_event);
if (audio_event->targetReceiver.GetCurrent() == audio_source)
{
if (audio_event->messageToSend->controlID == StopAudioControlID)
{
audio_event->Process();
}
else
{
Unregister_Object(audio_event);
delete audio_event;
}
}
}
}
//
//#############################################################################
// MakeAudioHead
//#############################################################################
//
AudioHead*
AudioRenderer::MakeAudioHead()
{
return new AudioHead;
}
//
//#############################################################################
// StartEntityEffectImplementation
//#############################################################################
//
void
AudioRenderer::StartEntityEffectImplementation(
Entity *parent_entity,
DamageZone *damage_zone,
ResourceDescription::ResourceID resource_ID
)
{
SET_AUDIO_RENDERER();
Check(this);
Check(parent_entity);
Check(damage_zone);
Verify(resource_ID != ResourceDescription::NullResourceID);
//
//--------------------------------------------------------------------------
// Get the audio resource for this effect
//--------------------------------------------------------------------------
//
ResourceDescription *audio_resource_description;
Check(application);
Check(application->GetResourceFile());
audio_resource_description =
application->GetResourceFile()->SearchList(
resource_ID,
ResourceDescription::AudioStreamListResourceType
);
if (audio_resource_description == NULL)
{
CLEAR_AUDIO_RENDERER();
return;
}
Check(audio_resource_description);
//
//--------------------------------------------------------------------------
// Get the resource ID for the model resource for the audio effect entity
//--------------------------------------------------------------------------
//
ResourceDescription *model_resource_description;
Check(application);
Check(application->GetResourceFile());
Check(audio_resource_description);
model_resource_description =
application->GetResourceFile()->SearchList(
audio_resource_description->resourceID,
ResourceDescription::ModelListResourceType
);
if (model_resource_description == NULL)
{
CLEAR_AUDIO_RENDERER();
return;
}
Check(model_resource_description);
model_resource_description->Lock();
audio_resource_description->Lock();
//
//--------------------------------------------------------------------------
// Get the entity segment
//--------------------------------------------------------------------------
//
Entity *linked_entity;
AudioRepresentation audio_representation;
EntitySegment *parent_entity_segment;
linked_entity = GetLinkedEntity();
Check(linked_entity);
audio_representation =
(AudioRepresentation)parent_entity->GetAudioRepresentation(
linked_entity
);
parent_entity_segment = damage_zone->GetCurrentEffectSite(
(audio_representation == InternalAudioRepresentation) ?
DamageZone::InternalAudioEffectSite :
DamageZone::ExternalAudioEffectSite
);
Check(parent_entity_segment);
//
//--------------------------------------------------------------------------
// Create the audio effect entity with this resource
//--------------------------------------------------------------------------
//
JointedMover *jointed_mover;
Verify(parent_entity->IsDerivedFrom(JointedMover::ClassDerivations));
jointed_mover = Cast_Object(JointedMover*, parent_entity);
Check(jointed_mover);
AudioEntity::MakeMessage
make_message(
model_resource_description->resourceID,
jointed_mover,
parent_entity_segment
);
#if DEBUG_LEVEL>0
AudioEntity *audio_entity =
#endif
AudioEntity::Make(&make_message);
Register_Object(audio_entity);
model_resource_description->Unlock();
audio_resource_description->Unlock();
CLEAR_AUDIO_RENDERER();
}
//~~~~~~~~~~~~~~~~~~~~~~~~ AudioRenderer profile bits ~~~~~~~~~~~~~~~~~~~~~~~~~
#if defined(TRACE_AUDIO_RENDERER)
BitTrace Audio_Renderer("Audio Renderer");
#endif
#if defined(TRACE_AUDIO_RENDERER_CREATE_OBJECTS)
BitTrace Audio_Renderer_Create_Objects("Audio Renderer Create Objects");
#endif
#if defined(TRACE_AUDIO_RENDERER_DESTROY_OBJECTS)
BitTrace Audio_Renderer_Destroy_Objects("Audio Renderer Destroy Objects");
#endif
#if defined(TRACE_AUDIO_RENDERER_START_HANDLER)
BitTrace Audio_Renderer_Start_Handler("Audio Renderer Start Handler");
#endif
#if defined(TRACE_AUDIO_RENDERER_STOP_HANDLER)
BitTrace Audio_Renderer_Stop_Handler("Audio Renderer Stop Handler");
#endif
#if defined(TRACE_AUDIO_RENDERER_EXECUTE)
BitTrace Audio_Renderer_Execute("Audio Renderer Execute");
#endif
//#############################################################################
//############################## AudioEvent #############################
//#############################################################################
MemoryBlock
AudioEvent::AllocatedMemory(sizeof(Event), AUDIOEVENT_MEMORYBLOCK_ALLOCATION, AUDIOEVENT_MEMORYBLOCK_ALLOCATION, "AudioEvents");
//
//#############################################################################
//#############################################################################
//
AudioEvent::AudioEvent(
AudioSource *target,
AudioSource::RequestMessage *message
):
targetReceiver(this)
{
Check(target);
Check(message);
//
// Store the message
//
size_t long_size = (message->messageLength+3)>>2;
messageToSend = (AudioSource::RequestMessage*)new long[long_size];
Check_Pointer(messageToSend);
Register_Pointer(messageToSend);
Mem_Copy(
messageToSend,
message,
message->messageLength,
long_size*sizeof(long)
);
//
// Store the target receiver
//
targetReceiver.Add(target);
}
//
//#############################################################################
//#############################################################################
//
AudioEvent::~AudioEvent()
{
Unregister_Pointer(messageToSend);
delete messageToSend;
}
//
//#############################################################################
//#############################################################################
//
void
AudioEvent::ReleaseLinkHandler(
Socket*,
Plug*
)
{
Unregister_Object(this);
delete this;
}