Files
arcattackandClaude Opus 4.8 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>
2026-07-05 21:03:40 -05:00

1524 lines
38 KiB
C++

#include "munga.h"
#pragma hdrstop
#include "audcmp.h"
#include "audsrc.h"
#include "random.h"
#include "controls.h"
#include "objstrm.h"
#include "subsystm.h"
#include "namelist.h"
//#############################################################################
//######################### AudioMessageWatcher #########################
//#############################################################################
//
//#############################################################################
//#############################################################################
//
AudioMessageWatcher::AudioMessageWatcher(
PlugStream *stream,
Entity *entity
):
AudioComponent(stream),
audioComponentSocket(NULL),
messageTap(NULL)
{
Check(stream);
Check(entity);
//
// HACK - Get simulation pointer using names
//
Simulation *simulation;
CString subsystem_name;
MemoryStream_Read(stream, &subsystem_name);
if ((simulation = entity->FindSubsystem(subsystem_name)) == NULL)
{
#if DEBUG_LEVEL>0
{
CString entity_name("Entity");
if (!(subsystem_name == entity_name))
{
Dump(subsystem_name);
}
Verify(subsystem_name == entity_name);
}
#else
{
CString entity_name("Entity");
if (!(subsystem_name == entity_name))
{
DEBUG_STREAM <<
"MessageWatcher::MessageWatcher - subsystem " <<
subsystem_name <<
"\n";
Fail("MessageWatcher::MessageWatcher - subsystem not found\n");
}
}
#endif
simulation = entity;
}
Check(simulation);
//
// Get message id
//
Receiver::MessageID message_ID;
MemoryStream_Read(stream, &message_ID);
//
// Get audio component, control ID, control value
//
AudioComponent *audio_component;
PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component);
MemoryStream_Read(stream, &controlID);
MemoryStream_Read(stream, &controlValue);
audioComponentSocket.Add(audio_component);
//
// Make the message tap
//
messageTap =
MakeMessageTap(
simulation->GetDerivation(),
(ScanCallback)&AudioMessageWatcher::MessageTapScanCallback,
message_ID,
simulation
);
Register_Object(messageTap);
entity->AddAudioComponent(this);
#if DEBUG_LEVEL>0
verifyReceiver = simulation;
verifyMessageID = message_ID;
#endif
}
//
//#############################################################################
//#############################################################################
//
AudioMessageWatcher::~AudioMessageWatcher()
{
Unregister_Object(messageTap);
delete messageTap;
}
//
//#############################################################################
//#############################################################################
//
void
AudioMessageWatcher::BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
)
{
AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID);
//
// HACK - Store simulation pointer using names
//
MEM_STRM_WRITE_ENTRY(*stream, name_list, CString, subsystem);
//
// Store message ID
//
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, message_ID);
//
// Store audio_component, control ID, control value
//
CString audio_component_name("audio_component");
PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_component_name);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, control_ID);
MEM_STRM_WRITE_ENTRY(*stream, name_list, AudioControlValue, control_value);
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioMessageWatcher::TestInstance() const
{
Component::TestInstance();
if (messageTap != NULL)
{
Check(messageTap);
}
Check(&audioComponentSocket);
return True;
}
//
//#############################################################################
//#############################################################################
//
#if DEBUG_LEVEL>0
void
AudioMessageWatcher::MessageTapScanCallback(
Receiver::Message *message,
Receiver *receiver
)
#else
void
AudioMessageWatcher::MessageTapScanCallback(
Receiver::Message *message,
Receiver*
)
#endif
{
Check(this);
Check(message);
Check(receiver);
Verify(verifyReceiver == receiver);
Verify(verifyMessageID == message->messageID);
//
// Send the audio control message
//
if (DoesMessageMatch(message))
{
Check(audioComponentSocket.GetCurrent());
#if 1
audioComponentSocket.GetCurrent()->ReceiveControl(
controlID,
controlValue
);
#else
audioComponentSocket.GetCurrent()->PostReceiveControl(
controlID,
controlValue
);
#endif
}
}
//
//#############################################################################
//#############################################################################
//
void
AudioMessageWatcher::ReceiveControl(
AudioControlID,
AudioControlValue
)
{
}
//#############################################################################
//################# AudioControlsButtonMessageWatcher ###################
//#############################################################################
//
//#############################################################################
//#############################################################################
//
AudioControlsButtonMessageWatcher::AudioControlsButtonMessageWatcher(
PlugStream *stream,
Entity *entity
):
AudioMessageWatcher(stream, entity)
{
}
//
//#############################################################################
//#############################################################################
//
AudioControlsButtonMessageWatcher::~AudioControlsButtonMessageWatcher()
{
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioControlsButtonMessageWatcher::DoesMessageMatch(
Receiver::Message *message
)
{
Check(this);
Check(message);
ReceiverDataMessageOf<ControlsButton> *controls_button_message =
Cast_Object(
ReceiverDataMessageOf<ControlsButton>*,
message
);
Check(controls_button_message);
return (controls_button_message->dataContents > 0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioControlSend ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
AudioControlSend::~AudioControlSend()
{
}
//
//#############################################################################
//#############################################################################
//
AudioControlSend::AudioControlSend(
PlugStream *stream,
Entity *entity
):
AudioComponent(stream)
{
AudioComponent *audio_component;
AudioControlID control_ID;
AudioControlValue control_value;
PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component);
MemoryStream_Read(stream, &control_ID);
MemoryStream_Read(stream, &control_value);
Check(entity);
entity->AddAudioComponent(this);
Check(audio_component);
#if 1
audio_component->ReceiveControl(control_ID, control_value);
#else
audio_component->PostReceiveControl(control_ID, control_value);
#endif
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlSend::BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
)
{
AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID);
//
// Store fields
//
CString audio_component_name("audio_component");
PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_component_name);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, control_ID);
MEM_STRM_WRITE_ENTRY(*stream, name_list, AudioControlValue, control_value);
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlSend::ReceiveControl(
AudioControlID,
AudioControlValue
)
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioControlSplitter ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
AudioControlSplitter::AudioControlSplitter(
PlugStream *stream,
Entity *entity
):
AudioComponent(stream),
audioComponentSocket(NULL)
{
int i, number_of_entries;
MemoryStream_Read(stream, &number_of_entries);
for (i = 0; i < number_of_entries; i++)
{
AudioComponent *audio_component;
PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component);
Check(audio_component);
audioComponentSocket.Add(audio_component);
audio_component->AddWatcher(this);
}
Check(entity);
entity->AddAudioComponent(this);
}
//
//#############################################################################
//#############################################################################
//
AudioControlSplitter::~AudioControlSplitter()
{
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlSplitter::BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
)
{
AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID);
//
// Count number of entries
//
int number_of_entries = 0;
NameList::Entry *entry;
Check(name_list);
entry = name_list->GetFirstEntry();
while (entry != NULL)
{
Check(entry);
if (entry->IsName("audio_component"))
number_of_entries++;
entry = entry->GetNextEntry();
}
//
// Store entries
//
MemoryStream_Write(stream, &number_of_entries);
Check(name_list);
entry = name_list->GetFirstEntry();
while (entry != NULL)
{
Check(entry);
if (entry->IsName("audio_component"))
{
CString object_name;
ObjectID object_ID;
Check_Pointer(entry->GetChar());
object_name = entry->GetChar();
Check(stream);
object_ID = stream->FindObjectID(object_name);
if (object_ID == NullObjectID)
{
std::cout << "AudioControlSplitter::BuildFromPage - object_name == ";
std::cout << object_name << "\n";
Fail("AudioControlSplitter::BuildFromPage - object_ID == NullObjectID");
}
Verify(object_ID != NullObjectID);
MemoryStream_Write(stream, &object_ID);
}
entry = entry->GetNextEntry();
}
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioControlSplitter::TestInstance() const
{
AudioComponent::TestInstance();
Check(&audioComponentSocket);
return True;
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlSplitter::ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
)
{
Check(this);
//
// Send to all of the components in the socket
//
SChainIteratorOf<AudioComponent*> iterator(&audioComponentSocket);
AudioComponent *audio_component;
Check(&iterator);
while ((audio_component = iterator.ReadAndNext()) != NULL)
{
Check(audio_component);
audio_component->ReceiveControl(control_ID, control_value);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioControlMixer ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
AudioControlMixer::~AudioControlMixer()
{
}
//
//#############################################################################
//#############################################################################
//
AudioControlMixer::AudioControlMixer(
PlugStream *stream,
Entity *entity
):
AudioComponent(stream),
audioComponentSocket(NULL)
{
AudioComponent *audio_component;
AudioControlID first_input_control_ID;
AudioControlID last_input_control_ID;
AudioControlID output_control_ID;
PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component);
MemoryStream_Read(stream, &first_input_control_ID);
MemoryStream_Read(stream, &last_input_control_ID);
MemoryStream_Read(stream, &output_control_ID);
AudioControlMixerX(
audio_component,
entity,
first_input_control_ID,
last_input_control_ID,
output_control_ID
);
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlMixer::BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
)
{
AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID);
//
// Store fields
//
CString audio_component_name("audio_component");
PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_component_name);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, first_input_control_ID);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, last_input_control_ID);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, output_control_ID);
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlMixer::AudioControlMixerX(
AudioComponent *audio_component,
Entity *entity,
AudioControlID first_input_control_ID,
AudioControlID last_input_control_ID,
AudioControlID output_control_ID
)
{
//
// Set up the control mix parameters
//
firstInputControlID = first_input_control_ID;
outputControlID = output_control_ID;
Verify(last_input_control_ID > first_input_control_ID);
numberOfInputs = last_input_control_ID - first_input_control_ID + 1;
Verify(numberOfInputs <= AUDIO_CONTROL_MIXER_MAX_CONTROLS);
for (int i = 0; i < numberOfInputs; i++)
{
Verify(i >= 0 && i < AUDIO_CONTROL_MIXER_MAX_CONTROLS);
controlValueArray[i] = 0.0f;
}
//
// Remember the audio component to mix to and add this
// component to the entity
//
Check(audio_component);
audioComponentSocket.Add(audio_component);
audio_component->AddWatcher(this);
Check(entity);
entity->AddAudioComponent(this);
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioControlMixer::TestInstance() const
{
AudioComponent::TestInstance();
Check(&audioComponentSocket);
return True;
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlMixer::ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
)
{
Check(this);
//
// Index the controller into the mix table
//
int index = control_ID - firstInputControlID;
if (index >= 0 && index < numberOfInputs)
{
//
// Set the control value
//
Verify(index >= 0 && index < AUDIO_CONTROL_MIXER_MAX_CONTROLS);
controlValueArray[index] = control_value;
//
// Mix the new control value
//
AudioControlValue mixed_value = 0.0f;
for (int i = 0; i < numberOfInputs; i++)
{
Verify(i >= 0 && i < AUDIO_CONTROL_MIXER_MAX_CONTROLS);
mixed_value += controlValueArray[i];
}
Check(audioComponentSocket.GetCurrent());
audioComponentSocket.GetCurrent()->ReceiveControl(
outputControlID,
mixed_value
);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioControlMultiplier ~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
AudioControlMultiplier::~AudioControlMultiplier()
{
}
//
//#############################################################################
//#############################################################################
//
AudioControlMultiplier::AudioControlMultiplier(
PlugStream *stream,
Entity *entity
):
AudioComponent(stream),
audioComponentSocket(NULL)
{
AudioComponent *audio_component;
AudioControlID first_input_control_ID;
AudioControlID last_input_control_ID;
AudioControlID output_control_ID;
PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component);
MemoryStream_Read(stream, &first_input_control_ID);
MemoryStream_Read(stream, &last_input_control_ID);
MemoryStream_Read(stream, &output_control_ID);
AudioControlMultiplierX(
audio_component,
entity,
first_input_control_ID,
last_input_control_ID,
output_control_ID
);
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlMultiplier::BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
)
{
AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID);
//
// Store fields
//
CString audio_component_name("audio_component");
PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_component_name);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, first_input_control_ID);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, last_input_control_ID);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, output_control_ID);
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlMultiplier::AudioControlMultiplierX(
AudioComponent *audio_component,
Entity *entity,
AudioControlID first_input_control_ID,
AudioControlID last_input_control_ID,
AudioControlID output_control_ID
)
{
//
// Set up the control mix parameters
//
firstInputControlID = first_input_control_ID;
outputControlID = output_control_ID;
Verify(last_input_control_ID > first_input_control_ID);
numberOfInputs = last_input_control_ID - first_input_control_ID + 1;
Verify(numberOfInputs <= AUDIO_CONTROL_MULTIPLIER_MAX_CONTROLS);
for (int i = 0; i < numberOfInputs; i++)
{
Verify(i >= 0 && i < AUDIO_CONTROL_MULTIPLIER_MAX_CONTROLS);
controlValueArray[i] = 1.0f;
}
//
// Remember the audio component to mix to and add this
// component to the entity
//
Check(audio_component);
audioComponentSocket.Add(audio_component);
audio_component->AddWatcher(this);
Check(entity);
entity->AddAudioComponent(this);
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioControlMultiplier::TestInstance() const
{
AudioComponent::TestInstance();
Check(&audioComponentSocket);
return True;
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlMultiplier::ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
)
{
Check(this);
//
// Index the controller into the mix table
//
int index = control_ID - firstInputControlID;
if (index >= 0 && index < numberOfInputs)
{
//
// Set the control value
//
Verify(index >= 0 && index < AUDIO_CONTROL_MULTIPLIER_MAX_CONTROLS);
controlValueArray[index] = control_value;
//
// Multiply the new control value
//
AudioControlValue mult_value = 1.0f;
for (int i = 0; i < numberOfInputs; i++)
{
Verify(i >= 0 && i < AUDIO_CONTROL_MULTIPLIER_MAX_CONTROLS);
mult_value *= controlValueArray[i];
}
Check(audioComponentSocket.GetCurrent());
audioComponentSocket.GetCurrent()->ReceiveControl(
outputControlID,
mult_value
);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioControlSmoother ~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
AudioControlSmoother::~AudioControlSmoother()
{
}
//
//#############################################################################
//#############################################################################
//
AudioControlSmoother::AudioControlSmoother(
PlugStream *stream,
Entity *entity
):
AudioComponent(stream),
audioComponentSocket(NULL)
{
//
// Get audio component
//
AudioComponent *audio_component;
PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component);
//
// Get audio control id, sample size, and initial fill value
//
size_t number_of_samples;
AudioControlValue initial_fill_value;
AudioControlID control_ID;
MemoryStream_Read(stream, &control_ID);
MemoryStream_Read(stream, &number_of_samples);
MemoryStream_Read(stream, &initial_fill_value);
audioControlAverage.SetSize(number_of_samples, initial_fill_value);
AudioControlSmootherX(
audio_component,
entity,
control_ID
);
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlSmoother::BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
)
{
AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID);
//
// Store audio component
//
CString audio_component_name("audio_component");
PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_component_name);
//
// Store audio control id, sample size, and initial fill value
//
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, control_ID);
MEM_STRM_WRITE_ENTRY(*stream, name_list, size_t, number_of_samples);
AudioControlValue initial_fill_value = 0.0f;
if (name_list->FindData("initial_fill_value") != NULL)
{
Check_Pointer(name_list->FindData("initial_fill_value"));
Convert_From_Ascii(
(const char *)name_list->FindData("initial_fill_value"),
&initial_fill_value
);
}
MemoryStream_Write(stream, &initial_fill_value);
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlSmoother::AudioControlSmootherX(
AudioComponent *audio_component,
Entity *entity,
AudioControlID control_ID
)
{
controlID = control_ID;
//
// Remember the audio component and add this
// component to the entity
//
Check(audio_component);
audioComponentSocket.Add(audio_component);
audio_component->AddWatcher(this);
Check(entity);
entity->AddAudioComponent(this);
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioControlSmoother::TestInstance() const
{
AudioComponent::TestInstance();
Check(&audioComponentSocket);
Check(&audioControlAverage);
return True;
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlSmoother::ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
)
{
Check(this);
if (control_ID == controlID)
{
audioControlAverage.Add(control_value);
Check(audioComponentSocket.GetCurrent());
audioComponentSocket.GetCurrent()->ReceiveControl(
controlID,
audioControlAverage.CalculateOlympicAverage()
);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioResourceSelector ~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
AudioResourceSelector::~AudioResourceSelector()
{
}
//
//#############################################################################
//#############################################################################
//
AudioResourceSelector::AudioResourceSelector(
PlugStream *stream,
Entity *entity
):
AudioComponent(stream),
audioSourceSocket(NULL)
{
AudioSource *audio_source;
AudioResourceIndex *audio_resource_index;
AudioControlID control_ID;
AudioControlValue min_control_value;
AudioControlValue max_control_value;
Logical dump_value;
PlugStream_ReadObjectIDAndFindPlug(stream, &audio_source);
PlugStream_ReadObjectIDAndFindPlug(stream, &audio_resource_index);
MemoryStream_Read(stream, &control_ID);
MemoryStream_Read(stream, &min_control_value);
MemoryStream_Read(stream, &max_control_value);
MemoryStream_Read(stream, &dump_value);
AudioResourceSelectorX(
audio_source,
entity,
audio_resource_index,
control_ID,
min_control_value,
max_control_value,
dump_value
);
}
//
//#############################################################################
//#############################################################################
//
void
AudioResourceSelector::BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
)
{
AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID);
//
// Store fields
//
CString audio_source_name("audio_source");
PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_source_name);
CString audio_resource_index_name("audio_resource_index");
PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_resource_index_name);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, control_ID);
MEM_STRM_WRITE_ENTRY(*stream, name_list, AudioControlValue, min_control_value);
MEM_STRM_WRITE_ENTRY(*stream, name_list, AudioControlValue, max_control_value);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Logical, dump_value);
}
//
//#############################################################################
//#############################################################################
//
void
AudioResourceSelector::AudioResourceSelectorX(
AudioSource *audio_source,
Entity *entity,
AudioResourceIndex *audio_resource_index,
AudioControlID control_ID,
AudioControlValue min_control_value,
AudioControlValue max_control_value,
Logical dump_value
)
{
controlID = control_ID;
minControlValue = min_control_value;
maxControlValue = max_control_value;
dumpValue = dump_value;
Check(audio_resource_index);
audioResourceIndex = audio_resource_index;
Check(audio_source);
audioSourceSocket.Add(audio_source);
audio_source->AddWatcher(this);
Check(entity);
entity->AddAudioComponent(this);
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioResourceSelector::TestInstance() const
{
AudioComponent::TestInstance();
Check(&audioSourceSocket);
Check(audioResourceIndex);
return True;
}
//
//#############################################################################
//#############################################################################
//
void
AudioResourceSelector::ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
)
{
Check(this);
if (control_ID == controlID)
{
AudioComponent *audio_component;
AudioSource *audio_source;
audio_component = audioSourceSocket.GetCurrent();
audio_source = Cast_Object(AudioSource*, audio_component);
Check(audio_source);
if (audio_source->GetAudioSourceState() == StoppedAudioSourceState)
{
AudioResource *audio_resource;
int index;
Clamp(control_value, minControlValue, maxControlValue);
Verify(!Small_Enough(maxControlValue - minControlValue));
index =
( ((Scalar)audioResourceIndex->GetSize()-1.0f) *
(control_value - minControlValue) /
(maxControlValue - minControlValue) ) + 0.5f;
#if DEBUG_LEVEL>0
if (!(index >= 0 && index < audioResourceIndex->GetSize()))
{
Dump(control_value);
Dump(index);
Dump(audioResourceIndex->GetSize());
}
#endif
Verify(index >= 0 && index < audioResourceIndex->GetSize());
#if DEBUG_LEVEL>0
if (dumpValue)
{
Tell("index:" << index);
Tell("; size: " << audioResourceIndex->GetSize() << "\n");
}
#endif
audio_resource = audioResourceIndex->GetAudioResource(index);
Check(audio_resource);
audio_source->SetAudioResource(audio_resource);
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioSampleAndHold ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
AudioSampleAndHold::AudioSampleAndHold(
PlugStream *stream,
Entity *entity
):
AudioComponent(stream),
audioComponentSocket(NULL)
{
AudioComponent *audio_component;
AudioControlID control_ID;
Scalar seconds;
AudioTime sample_duration;
Scalar min_value;
Scalar max_value;
//
// audio_component
//
PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component);
//
// control_ID, sample_duration
//
MemoryStream_Read(stream, &control_ID);
MemoryStream_Read(stream, &seconds);
sample_duration = seconds;
//
// min_value, max_value
//
MemoryStream_Read(stream, &min_value);
MemoryStream_Read(stream, &max_value);
AudioSampleAndHoldX(
audio_component,
entity,
control_ID,
sample_duration,
min_value,
max_value
);
}
//
//#############################################################################
//#############################################################################
//
void
AudioSampleAndHold::BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
)
{
AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID);
//
// audio_component
//
CString audio_component_name("audio_component");
PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_component_name);
//
// control_ID, sample_duration
//
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, control_ID);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Scalar, sample_duration);
//
// min_value, max_value
//
Scalar min_value = 0.0f;
Scalar max_value = 1.0f;
if (name_list->FindData("min_value") != NULL)
{
Convert_From_Ascii(
(const char *)name_list->FindData("min_value"),
&min_value
);
}
if (name_list->FindData("max_value") != NULL)
{
Convert_From_Ascii(
(const char *)name_list->FindData("max_value"),
&max_value
);
}
Verify(max_value > min_value);
MemoryStream_Write(stream, &min_value);
MemoryStream_Write(stream, &max_value);
}
//
//#############################################################################
//#############################################################################
//
void
AudioSampleAndHold::AudioSampleAndHoldX(
AudioComponent *audio_component,
Entity *entity,
AudioControlID audio_control_ID,
const AudioTime &sample_duration,
Scalar min_value,
Scalar max_value
)
{
audioControlID = audio_control_ID;
currentValue = 0.0f;
nextSampleTime = AudioTime::Now();
sampleDuration = sample_duration;
Verify(max_value > min_value);
minValue = min_value;
maxValue = max_value;
Check(audio_component);
audioComponentSocket.Add(audio_component);
audio_component->AddWatcher(this);
Check(entity);
entity->AddAudioComponent(this);
}
//
//#############################################################################
//#############################################################################
//
AudioSampleAndHold::~AudioSampleAndHold()
{
}
//
//#############################################################################
//#############################################################################
//
void
AudioSampleAndHold::Execute()
{
Check(this);
AudioComponent::Execute();
if (AudioTime::Now() > nextSampleTime)
{
SampleAndHold();
}
}
//
//#############################################################################
//#############################################################################
//
void
AudioSampleAndHold::ReceiveControl(
AudioControlID control_ID,
AudioControlValue
)
{
Check(this);
if (control_ID == StartAudioControlID)
{
SampleAndHold();
}
}
//
//#############################################################################
//#############################################################################
//
void
AudioSampleAndHold::SampleAndHold()
{
Check(this);
Scalar random_sample = Random;
Verify(0.0f <= random_sample && random_sample <= 1.0f);
Verify(maxValue > minValue);
currentValue = minValue + random_sample * (maxValue - minValue);
nextSampleTime = AudioTime::Now();
nextSampleTime += sampleDuration;
Check(audioComponentSocket.GetCurrent());
audioComponentSocket.GetCurrent()->ReceiveControl(
audioControlID,
currentValue
);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioLFO ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
AudioLFO::AudioLFO(
PlugStream *stream,
Entity *entity
):
AudioComponent(stream),
audioComponentSocket(NULL)
{
AudioComponent *audio_component;
AudioControlID control_ID;
AudioLFOWaveForm wave_form;
Scalar the_period;
AudioControlValue min_value;
AudioControlValue max_value;
Logical dump_value;
//
// audio_component
//
PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component);
//
// control_ID, wave_form, period
//
MemoryStream_Read(stream, &control_ID);
MemoryStream_Read(stream, &wave_form);
MemoryStream_Read(stream, &the_period);
//
// min_value, max_value, dump_value
//
MemoryStream_Read(stream, &min_value);
MemoryStream_Read(stream, &max_value);
MemoryStream_Read(stream, &dump_value);
AudioLFOX(
audio_component,
entity,
control_ID,
wave_form,
the_period,
min_value,
max_value,
dump_value
);
}
//
//#############################################################################
//#############################################################################
//
void
AudioLFO::BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
)
{
AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID);
//
// audio_component
//
CString audio_component_name("audio_component");
PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_component_name);
//
// control_ID, wave_form, period
//
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, control_ID);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, wave_form);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Scalar, period);
//
// min_value, max_value
//
MEM_STRM_WRITE_ENTRY(*stream, name_list, Scalar, min_value);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Scalar, max_value);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Logical, dump_value);
}
//
//#############################################################################
//#############################################################################
//
void
AudioLFO::AudioLFOX(
AudioComponent *audio_component,
Entity *entity,
AudioControlID audio_control_ID,
AudioLFOWaveForm wave_form,
Scalar the_period,
AudioControlValue min_value,
AudioControlValue max_value,
Logical dump_value
)
{
Check(audio_component);
audioComponentSocket.Add(audio_component);
audio_component->AddWatcher(this);
audioControlID = audio_control_ID;
waveForm = wave_form;
minValue = min_value;
maxValue = max_value;
Verify(max_value > min_value);
period = the_period;
startTime = AudioTime::Now();
dumpValue = dump_value;
Check(entity);
entity->AddAudioComponent(this);
}
//
//#############################################################################
//#############################################################################
//
AudioLFO::~AudioLFO()
{
}
//
//#############################################################################
//#############################################################################
//
void
AudioLFO::Execute()
{
Check(this);
AudioComponent::Execute();
Generate();
}
//
//#############################################################################
//#############################################################################
//
void
AudioLFO::ReceiveControl(
AudioControlID control_ID,
AudioControlValue
)
{
Check(this);
if (control_ID == StartAudioControlID)
{
Generate();
}
}
//
//#############################################################################
//#############################################################################
//
void
AudioLFO::Generate()
{
Check(this);
//
// HACK - For now, everything is sinusoidal
//
// res = sin( (now-start) * (PI/period) )
// val = min + ( 0.5 * (res+1) ) * (max - min)
//
Scalar time_factor;
Scalar sample;
Scalar current_value;
time_factor = AudioTime::Now();
Verify(!Small_Enough((Scalar)period));
time_factor = (time_factor - (Scalar)startTime) / (Scalar)period;
sample = (sin(time_factor * PI) + 1.0f) * 0.5f;
Verify(0.0f <= sample && sample <= 1.0f);
Verify(maxValue > minValue);
current_value = minValue + sample * (maxValue - minValue);
#if DEBUG_LEVEL>0
if (dumpValue)
{
Dump(current_value);
}
#endif
Check(audioComponentSocket.GetCurrent());
audioComponentSocket.GetCurrent()->ReceiveControl(
audioControlID,
current_value
);
}