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>
1536 lines
38 KiB
C++
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
|
|
);
|
|
}
|