Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

425 lines
13 KiB
C++

//===========================================================================//
// File: AudioRenderer.cpp //
// Project: MUNGA Brick: Video Renderer //
// Contents: Abstracted Base Video Renderer //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 03/04/97 JTR Initial coding. //
//---------------------------------------------------------------------------//
// Copyright (C) 1997, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include "AdeptHeaders.hpp"
#include "SpatializedCommand.hpp"
#include "AudioRenderer.hpp"
#include "SpatializedChannel.hpp"
#include "AudioSample.hpp"
#include "Interface.hpp"
//##########################################################################
//######################### SpatializedCommand #######################
//##########################################################################
SpatializedCommand::ClassData*
SpatializedCommand::DefaultData = NULL;
MemoryBlock*
SpatializedCommand::s_AllocatedMemory = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void SpatializedCommand::InitializeClass(
size_t block_count,
size_t block_delta
)
{
Verify(!s_AllocatedMemory);
s_AllocatedMemory =
new MemoryBlock(
sizeof(SpatializedCommand),
block_count,
block_delta,
"SpatializedCommand",
g_LibraryHeap
);
Register_Object(s_AllocatedMemory);
Verify(!DefaultData);
DefaultData =
new ClassData(
SpatializedCommandClassID,
"Adept::SpatializedCommand",
BaseClass::DefaultData
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void SpatializedCommand::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
Unregister_Object(s_AllocatedMemory);
delete s_AllocatedMemory;
s_AllocatedMemory = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void SpatializedCommand::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
SpatializedCommand* SpatializedCommand::Create(
int type,
const ResourceID &hint_ID,
Stuff::Scalar priority,
Stuff::Scalar volume,
Stuff::Scalar min_restart,
Stuff::Scalar min_replace,
const Point3D &position,
const Vector3D &velocity,
Stuff::Scalar min_deviation,
Stuff::Scalar near_clip,
Stuff::Scalar min_range,
Stuff::Scalar max_range,
Stuff::Scalar far_clip
)
{
return new SpatializedCommand(
DefaultData,
type,
hint_ID,
priority,
volume,
min_restart,
min_replace,
position,
velocity,
min_deviation,
near_clip,
min_range,
max_range,
far_clip
);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
SpatializedCommand::SpatializedCommand(
ClassData *class_data,
int type,
const ResourceID &sample_ID,
Stuff::Scalar priority,
Stuff::Scalar volume,
Stuff::Scalar min_restart,
Stuff::Scalar min_replace,
const Point3D &position,
const Vector3D &velocity,
Stuff::Scalar min_deviation,
Stuff::Scalar near_clip,
Stuff::Scalar min_range,
Stuff::Scalar max_range,
Stuff::Scalar far_clip
):
AudioCommand(class_data, type, sample_ID, priority, volume, min_restart, min_replace),
m_position(position),
m_velocity(velocity),
m_minDeviation(min_deviation),
m_nearClip(near_clip),
m_minRange(min_range),
m_maxRange(max_range),
m_farClip(far_clip)
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
SpatializedCommand::~SpatializedCommand()
{
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool SpatializedCommand::ConnectToChannel(AudioSample *sample)
{
Check_Object(this);
Check_Object(sample);
AUDIO_RENDER("Execute::NewCommands::SpatializedCommand");
//
//---------------------------
// Compute the command energy
//---------------------------
//
SpatializedChannel *candidate = NULL;
Scalar energy = m_energy = ComputeEnergy(NULL);
Time now = gos_GetElapsedTime();
//
//-----------------------------------------------------------------
// If we aren't going to loop, see if we can be immediately clipped
//-----------------------------------------------------------------
//
if (m_bearing.range<m_nearClip || m_bearing.range>m_farClip)
{
if (m_playMode == gosAudio_PlayOnce)
delete this;
return false;
}
//
//----------------------------------------------------------------------------
// First look through the active channels to see if we can ignore this command
//----------------------------------------------------------------------------
//
ChainIteratorOf<AudioChannel*> active_channels(&sample->m_activeChannels);
AudioChannel *channel;
if (m_playMode == gosAudio_PlayOnce)
{
while ((channel = active_channels.ReadAndNext()) != NULL)
{
SpatializedChannel *spatial = Cast_Object(SpatializedChannel*, channel);
//
//----------------------------------------------------------------------------------
// We now need to calculate the angles to the ear from the old site and the new one.
// If the sound is too different from the one we are looking at, just go on to the
// next sound
//----------------------------------------------------------------------------------
//
Scalar bear_diff = Fabs(spatial->m_bearing.yaw - m_bearing.yaw);
SpatializedCommand *existing_command = Cast_Object(SpatializedCommand*, spatial->m_command);
Check_Object(existing_command);
if (bear_diff > existing_command->m_minDeviation)
continue;
//
//-----------------------------------------------
// If the existing sound could replace us, let it
//-----------------------------------------------
//
Verify(m_playMode != gosAudio_Loop);
if (channel->m_startTime + existing_command->m_minRestartDelay >= now)
{
delete this;
return false;
}
//
//------------------------------------------------------------------------------
// If we are not lower priority than the existing sound, check to see if it is a
// candidate for replacement
//------------------------------------------------------------------------------
//
if (existing_command->m_priority >= m_priority)
{
if (channel->m_startTime + existing_command->m_minReplaceDelay <= now)
{
Scalar temp = channel->m_energy;
if (temp <= energy)
{
candidate = spatial;
energy = temp;
}
}
}
}
}
//
//------------------------------------------------------
// Look for an inactive spatial hooked up to this sample
//------------------------------------------------------
//
ChainIteratorOf<AudioChannel*> inactive_channels(&sample->m_inactiveChannels);
if ((channel = inactive_channels.GetCurrent()) != NULL)
{
Verify(channel->m_playMode != gosAudio_Loop);
channel->Activate(this);
Verify(channel->m_startTime == now);
return true;
}
//
//-------------------------------------------
// Replace the best candidate if there is one
//-------------------------------------------
//
if (candidate)
{
Check_Object(candidate);
Verify(candidate->m_playMode != gosAudio_Loop);
candidate->Stop();
candidate->Activate(this);
Verify(candidate->m_startTime == now);
return true;
}
//
//------------------------------------------------------------------------------------
// Now we search the inactive channel list for our sound type and use the earliest one
//------------------------------------------------------------------------------------
//
Check_Object(AudioRenderer::Instance);
ChannelType &type = AudioRenderer::Instance->m_channelTypes[m_type];
ChainIteratorOf<AudioChannel*> free_channels(&type.m_inactiveChannels);
if ((channel = free_channels.GetCurrent()) != NULL)
{
Check_Object(channel);
Verify(channel->m_playMode != gosAudio_Loop);
channel->SetSample(sample);
channel->Activate(this);
Verify(channel->m_startTime == now);
return true;
}
//
//----------------------------------------------------------------------------------
// Now we search the active channel list for our sound type and use the earliest one
// that also matches the playmode - loops steal loops and one-shots steal one-shots
//----------------------------------------------------------------------------------
//
ChainIteratorOf<AudioChannel*> used_channels(&type.m_activeChannels);
while ((channel = used_channels.ReadAndNext()) != NULL)
{
Check_Object(channel);
if (channel->m_playMode == m_playMode)
{
channel->Stop();
Verify(channel->m_playMode != gosAudio_Loop);
if (channel->m_sample != sample)
channel->SetSample(sample);
channel->Activate(this);
Verify(channel->m_startTime == now);
return true;
}
}
//
//----------------------------------------------------------------------------------
// Now we search the active channel list for our sound type and use the earliest one
//----------------------------------------------------------------------------------
//
used_channels.First();
channel = used_channels.GetCurrent();
Check_Object(channel);
Verify(channel->m_playMode != gosAudio_Loop);
channel->Stop();
if (channel->m_sample != sample)
channel->SetSample(sample);
channel->Activate(this);
Verify(channel->m_startTime == now);
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool SpatializedCommand::AddLoop()
{
Check_Object(this);
//
//-------------------------------------------------
// Hook us up to the loop chain of our channel type
//-------------------------------------------------
//
Check_Object(AudioRenderer::Instance);
ChannelType &type = AudioRenderer::Instance->m_channelTypes[m_type];
type.m_loopCommands.Add(this);
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::Scalar SpatializedCommand::ComputeEnergy(AudioChannel *channel)
{
Check_Object(this);
//
//----------------------------------------------------------------------------
// If we haven't been assigned a channel yet, only distance affects our energy
//----------------------------------------------------------------------------
//
Scalar energy = 0.0f;
if (!channel)
{
LinearMatrix4D ear_to_world = AudioRenderer::Instance->GetInterface()->GetLocalToWorld();
Point3D ear_in_world(ear_to_world);
Vector3D ear_to_command;
ear_to_command.Subtract(m_position, ear_in_world);
m_bearing = ear_to_command;
Scalar energy = 0.0f;
if (m_bearing.range >= m_nearClip && m_bearing.range <= m_farClip)
{
if (m_bearing.range >= m_minRange)
{
if (m_bearing.range >= m_maxRange)
energy = 1.0f;
else
energy = (m_maxRange - m_minRange - m_bearing.range) / (m_maxRange - m_minRange);
}
}
return energy;
}
//
//----------------------------------------------------------------
// Otherwise, our energy decreases over the lifetime of the sample
//----------------------------------------------------------------
//
SpatializedChannel *spatial = Cast_Object(SpatializedChannel*, channel);
m_bearing = spatial->m_bearing;
if (m_bearing.range >= m_nearClip && m_bearing.range <= m_farClip)
{
if (m_bearing.range >= m_minRange)
{
if (m_bearing.range >= m_maxRange)
energy = 1.0f;
else
energy = (m_maxRange - m_minRange - m_bearing.range) / (m_maxRange - m_minRange);
}
}
AudioSample *sample = spatial->m_sample;
Check_Object(sample);
energy *= 1.0f - (static_cast<Scalar>(gos_GetElapsedTime() - channel->m_startTime)/sample->m_sampleInfo.fDuration);
return energy;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void SpatializedCommand::SetPosition(const Point3D &position)
{
Check_Object(this);
m_position = position;
if (m_channel)
{
SpatializedChannel *channel = Cast_Object(SpatializedChannel*, m_channel);
channel->SetPosition(position);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void SpatializedCommand::SetVelocity(const Vector3D &velocity)
{
Check_Object(this);
m_velocity = velocity;
if (m_channel)
{
SpatializedChannel *channel = Cast_Object(SpatializedChannel*, m_channel);
channel->SetVelocity(velocity);
}
}