Files
BT411/engine/MUNGA/AUDCMP.cpp
T
arcattackandClaude Opus 4.8 c4be8d3a07 Audio: footstep volume chain FULLY mapped -- blocked on gait-state id mismatch (task #50)
Chain (every hop verified live): FootStep pulse (SetBodyAnimation, decay in
PerformAndWatch) -> AudioMatchOf match=1 -> Start(2.0) on the FootFall
DirectPatchSource... which the renderer DROPS because its volume is 0:
an AudioControlMixer (outCtl=3/Volume + a second outCtl=5 mixer) feeds the
source, and BOTH mixer inputs are 0 -- nothing ever sends them.

Eliminated as senders (all traced): AudioScaleOf scales (29 total, none target
the mixer), AudioControlMultiplier (one instance, other target), Random/
AudioSampleAndHold (RNG verified WORKING -- varied samples; RANDOM.cpp is in
the build, the self-init ctor runs).

HYPOTHESIS [T4, next session]: the mixer inputs are fed by AudioStateTriggers
on AnimationState keyed to the AUTHORED gait-clip ids (walk 2/3, run 8/9 =
per-gait footstep volume).  Our runtime body SM walks in states 12<->13 --
which the recovered MechAnimationState enum names RightStandToReverse/
LeftStandToReverse.  If the authored audio expects 2/3 for forward walk, the
runtime clip NUMBERING in the reconstructed gait SM is offset from the
authentic ids -- a locomotion-layer mismatch with implications beyond audio
(the audio config is an independent witness to the true clip numbering).
Verify via the AudioStateTrigger configs on the AnimationState watcher
(trigcfg dump exists) and cross-check the SetBodyAnimation clip table.

New diagnostics: [snh] SampleAndHold sends, [mix] mixer forwards with input
index + sum, [scalecfg] authored scale bindings/boundaries, [volset].

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 00:01:58 -05:00

1536 lines
38 KiB
C++

#include <cstdlib>
#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());
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
);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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());
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
);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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());
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
);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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
);
}