Files
arcattackandClaude Opus 4.8 01261d72f3 Audio: add master volume (listener AL_GAIN); default 0.6, BT_AUDIO_VOLUME override (task #50)
The raw AWE32 samples are hot and everything plays at full per-source gain, so the
mix was loud.  Set alListenerf(AL_GAIN) once at device init -- it scales EVERY
source (master volume).  Default 0.6; override with BT_AUDIO_VOLUME=<0.0..1.0+>
(0 = mute, 1 = full, >1 = boost).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 22:18:21 -05:00

1431 lines
37 KiB
C++

#include <cstdlib>
#include "mungal4.h"
#pragma hdrstop
#include "l4audrnd.h"
#include "..\munga\notation.h"
#include "openal/alc.h"
//
//#############################################################################
// L4AudioRenderer
//#############################################################################
//
L4AudioRenderer::L4AudioRenderer(
RendererRate render_rate,
Logical mission_review_mode
):
AudioRenderer(render_rate),
runningAudioSourceSocket(NULL, False),
dormantAudioSourceSocket(NULL),
mixingAudioSourceSocket(NULL, False)
{
missionReviewMode = mission_review_mode;
nextCalculateMixFrame = NullAudioFrameCount;
}
//
//#############################################################################
// ~L4AudioRenderer
//#############################################################################
//
L4AudioRenderer::~L4AudioRenderer()
{
//Close OpenAL
ALCcontext *context = alcGetCurrentContext();
ALCdevice *device = alcGetContextsDevice(context);
alcMakeContextCurrent(NULL);
alcDestroyContext(context);
alcCloseDevice(device);
//
//----------------------------------------------------------------------
// Verify that all of entities have become uninteresting
//----------------------------------------------------------------------
//
#if DEBUG_LEVEL>0
{
RunningSourceIterator iterator(&runningAudioSourceSocket);
Verify(iterator.GetSize() == 0);
}
{
DormantSourceIterator iterator(&dormantAudioSourceSocket);
Verify(iterator.GetSize() == 0);
}
#endif
//
//----------------------------------------------------------------------
// Unload resources
//----------------------------------------------------------------------
//
Check(&audioResourceManager);
// audioResourceManager.UnloadResources(&audioHardware);
//
//----------------------------------------------------------------------
// Close audio hardware
//----------------------------------------------------------------------
//
// Check(&audioHardware);
// audioHardware.Close();
}
//
//#############################################################################
// TestInstance
//#############################################################################
//
Logical
L4AudioRenderer::TestInstance() const
{
AudioRenderer::TestInstance();
Check(&audioHardware);
Check(&runningAudioSourceSocket);
Check(&dormantAudioSourceSocket);
Check(&mixingAudioSourceSocket);
return True;
}
//
//#############################################################################
// Initialize
//#############################################################################
//
void
L4AudioRenderer::Initialize()
{
Check(this);
if (getenv("BT_AUDIO_LOG")) DEBUG_STREAM << "[audio] L4AudioRenderer::Initialize ENTERED\n" << std::flush;
//
//----------------------------------------------------------------------
// Call inherited method
//----------------------------------------------------------------------
//
AudioRenderer::Initialize();
//
//----------------------------------------------------------------------
// Get the audio head
//----------------------------------------------------------------------
//
AudioHead *audio_head = GetAudioHead();
Check(audio_head);
//
//----------------------------------------------------------------------
// Open the audio renderer notation file
//----------------------------------------------------------------------
//
int ret;
CString audio_file_name;
if (missionReviewMode)
{
audio_file_name = "audio\\audiomr.ini";
}
else
{
audio_file_name = "audio\\audio.ini";
}
NotationFile notation_file(audio_file_name);
Check(&notation_file);
if (getenv("BT_AUDIO_LOG")) DEBUG_STREAM << "[audio] notation file opened; about to read scalars\n" << std::flush;
//
//----------------------------------------------------------------------
// Define clipping sphere (m)
//----------------------------------------------------------------------
//
Scalar clipping_radius;
ret = notation_file.GetEntry(
"AudioRenderer",
"clipping_radius",
&clipping_radius
);
if (!ret)
{
Fail("L4AudioRenderer::Initialize - clipping_radius not defined");
}
Check(audio_head);
audio_head->DefineClippingSphere(clipping_radius);
//
//----------------------------------------------------------------------
// Distance to speakers or width of head entity (m)
//----------------------------------------------------------------------
//
Scalar distance_between_ears;
ret = notation_file.GetEntry(
"AudioRenderer",
"distance_between_ears",
&distance_between_ears
);
if (!ret)
{
Fail("L4AudioRenderer::Initialize - distance_between_ears not defined");
}
Check(audio_head);
audio_head->SetDistanceBetweenEars(distance_between_ears);
//
//----------------------------------------------------------------------
// Define amplitude rolloff characteristics
//----------------------------------------------------------------------
//
Scalar amplitude_rolloff;
Scalar amplitude_rolloff_knee;
Scalar amplitude_rolloff_distance_scale;
ret = notation_file.GetEntry(
"AudioRenderer",
"amplitude_rolloff",
&amplitude_rolloff
);
if (!ret)
{
Fail("L4AudioRenderer::Initialize - amplitude_rolloff not defined");
}
ret = notation_file.GetEntry(
"AudioRenderer",
"amplitude_rolloff_distance_scale",
&amplitude_rolloff_distance_scale
);
if (!ret)
{
Fail("L4AudioRenderer::Initialize - amplitude_rolloff_distance_scale not defined");
}
ret = notation_file.GetEntry(
"AudioRenderer",
"amplitude_rolloff_knee",
&amplitude_rolloff_knee
);
if (!ret)
{
Fail("L4AudioRenderer::Initialize - amplitude_rolloff_knee not defined");
}
Check(audio_head);
audio_head->ControlAmplitudeRollOff(
amplitude_rolloff,
amplitude_rolloff_knee,
amplitude_rolloff_distance_scale
);
//
//----------------------------------------------------------------------
// Define high frequency rolloff characteristics
//----------------------------------------------------------------------
//
Scalar high_frequency_rolloff;
Scalar high_frequency_rolloff_knee;
Scalar high_frequency_rolloff_distance_scale;
ret = notation_file.GetEntry(
"AudioRenderer",
"high_frequency_rolloff",
&high_frequency_rolloff
);
if (!ret)
{
Fail("L4AudioRenderer::Initialize - high_frequency_rolloff not defined");
}
ret = notation_file.GetEntry(
"AudioRenderer",
"high_frequency_rolloff_knee",
&high_frequency_rolloff_knee
);
if (!ret)
{
Fail("L4AudioRenderer::Initialize - high_frequency_rolloff_knee not defined");
}
ret = notation_file.GetEntry(
"AudioRenderer",
"high_frequency_rolloff_distance_scale",
&high_frequency_rolloff_distance_scale
);
if (!ret)
{
Fail("L4AudioRenderer::Initialize - high_frequency_rolloff_distance_scale not defined");
}
Check(audio_head);
audio_head->ControlHighFrequencyRollOff(
high_frequency_rolloff,
high_frequency_rolloff_knee,
high_frequency_rolloff_distance_scale
);
//
//----------------------------------------------------------------------
// Define Doppler characterisitics
//----------------------------------------------------------------------
//
Scalar doppler_range;
Scalar speed_of_sound;
ret = notation_file.GetEntry(
"AudioRenderer",
"doppler_range",
&doppler_range
);
if (!ret)
{
Fail("L4AudioRenderer::Initialize - doppler_range not defined");
}
ret = notation_file.GetEntry(
"AudioRenderer",
"speed_of_sound",
&speed_of_sound
);
if (!ret)
{
Fail("L4AudioRenderer::Initialize - speed_of_sound not defined");
}
Check(audio_head);
audio_head->ControlDopplerEffect(
doppler_range,
speed_of_sound
);
//
//----------------------------------------------------------------------
// Define source compression characterisitics
//----------------------------------------------------------------------
//
Scalar compression_exponent;
Scalar compression_scale;
ret = notation_file.GetEntry(
"AudioRenderer",
"compression_exponent",
&compression_exponent
);
if (!ret)
{
Fail("L4AudioRenderer::Initialize - compression_exponent not defined");
}
ret = notation_file.GetEntry(
"AudioRenderer",
"compression_scale",
&compression_scale
);
if (!ret)
{
Fail("L4AudioRenderer::Initialize - compression_scale not defined");
}
Check(audio_head);
audio_head->ControlSourceCompression(
compression_exponent,
compression_scale
);
//
//----------------------------------------------------------------------
// Set ITD difference
//----------------------------------------------------------------------
//
Scalar itd_difference;
ret = notation_file.GetEntry(
"AudioRenderer",
"itd_difference",
&itd_difference
);
if (!ret)
{
Fail("L4AudioRenderer::Initialize - itd_difference not defined");
}
Check(audio_head);
audio_head->SetITDDifference(itd_difference);
//
//----------------------------------------------------------------------
// Set global reverb scale
//----------------------------------------------------------------------
//
Scalar global_reverb_scale;
ret = notation_file.GetEntry(
"AudioRenderer",
"global_reverb_scale",
&global_reverb_scale
);
if (!ret)
{
Fail("L4AudioRenderer::Initialize - global_reverb_scale not defined");
}
Check(audio_head);
audio_head->SetGlobalReverbScale(global_reverb_scale);
//
//----------------------------------------------------------------------
// Initialize the audio hardware
//----------------------------------------------------------------------
//
// Check(&audioHardware);
// audioHardware.Initialize();
//Start OpenAL
ALCdevice *device = alcOpenDevice(NULL);
if (device)
{
ALCcontext *context = alcCreateContext(device,NULL);
alcMakeContextCurrent(context);
// Master volume: AL_GAIN on the listener scales EVERY source. Default 0.6
// (the raw samples are hot); override with BT_AUDIO_VOLUME=<0.0..1.0+>.
float masterVol = 0.6f;
if (const char *v = getenv("BT_AUDIO_VOLUME")) { float f = (float)atof(v); if (f >= 0.0f) masterVol = f; }
alListenerf(AL_GAIN, masterVol);
if (getenv("BT_AUDIO_LOG")) DEBUG_STREAM << "[audio] OpenAL device OPENED + context current; master gain=" << masterVol << "\n" << std::flush;
}
else
{
if (getenv("BT_AUDIO_LOG")) DEBUG_STREAM << "[audio] OpenAL device FAILED to open (alcOpenDevice NULL)\n" << std::flush;
}
//
//----------------------------------------------------------------------
// Preload resources
//----------------------------------------------------------------------
//
Check(&audioResourceManager);
audioResourceManager.PreloadResources(&notation_file);
}
//
//#############################################################################
// NotifyOfNewInterestingEntity
//#############################################################################
//
void
L4AudioRenderer::NotifyOfNewInterestingEntity(Entity *interesting_entity)
{
SET_AUDIO_RENDERER();
SET_AUDIO_RENDERER_CREATE_OBJECTS();
Check(this);
Check(interesting_entity);
Entity *linked_entity = GetLinkedEntity();
Check(linked_entity);
AudioRepresentation audio_representation =
(AudioRepresentation)interesting_entity->GetAudioRepresentation(
linked_entity
);
Check(&audioResourceManager);
audioResourceManager.CreateEntityAudioObjects(
interesting_entity,
audio_representation
);
CLEAR_AUDIO_RENDERER_CREATE_OBJECTS();
CLEAR_AUDIO_RENDERER();
}
//
//#############################################################################
// NotifyOfBecomingUninterestingEntity
//#############################################################################
//
void
L4AudioRenderer::NotifyOfBecomingUninterestingEntity(
Entity *uninteresting_entity
)
{
SET_AUDIO_RENDERER();
SET_AUDIO_RENDERER_DESTROY_OBJECTS();
Check(this);
Check(uninteresting_entity);
Check(&audioResourceManager);
audioResourceManager.DestroyEntityAudioObjects(uninteresting_entity);
CLEAR_AUDIO_RENDERER_DESTROY_OBJECTS();
CLEAR_AUDIO_RENDERER();
}
//
//#############################################################################
// LoadMissionImplementation
//#############################################################################
//
void
L4AudioRenderer::LoadMissionImplementation(Mission*)
{
Check(this);
}
//
//#############################################################################
// ShutdownImplementation
//#############################################################################
//
void
L4AudioRenderer::ShutdownImplementation()
{
Check(this);
}
//
//#############################################################################
// SuspendImplementation
//#############################################################################
//
void
L4AudioRenderer::SuspendImplementation()
{
Check(this);
}
//
//#############################################################################
// ResumeImplementation
//#############################################################################
//
void
L4AudioRenderer::ResumeImplementation()
{
Check(this);
}
//
//#############################################################################
// StartRequest
//#############################################################################
//
void
L4AudioRenderer::StartRequest(L4AudioSource *audio_source)
{
Check(this);
Check(audio_source);
//
//--------------------------------------------------------------------------
// Verify that the source is stopped
//--------------------------------------------------------------------------
//
Verify(audio_source->GetAudioSourceState() == StoppedAudioSourceState);
//
//--------------------------------------------------------------------------
// Request audio resources
//--------------------------------------------------------------------------
//
Logical
resources_available;
/* AudioChannelSet
channel_set_result;*/
SourceSet *source_result = audio_source->GetAudioChannelSet();
resources_available =
RequestAudioResources(
audio_source,
source_result
);
if (!resources_available)
{
if (audio_source->GetAudioRenderType() == SustainedAudioRenderType)
{
//
// Set state to dormant and add the source to the dormant list
//
audio_source->AssignAudioSourceState(DormantAudioSourceState);
dormantAudioSourceSocket.Add(audio_source);
}
return;
}
//
//--------------------------------------------------------------------------
// Start the audio source
//--------------------------------------------------------------------------
//
//
// Update source spatial model
// Set channel set of source
// Source start implementation
// Set state of source to running
//
audio_source->UpdateSpatialModel(GetAudioHead());
audio_source->SetAudioChannelSet(*source_result);
audio_source->StartImplementation();
audio_source->AssignAudioSourceState(RunningAudioSourceState);
//
// Add source to the running list and the mixing list
//
runningAudioSourceSocket.AddValue(
audio_source,
audio_source->CalculateAudioWeighting()
);
if (
audio_source->GetAudioSourceMixPresence() !=
ManualAudioSourceMixPresence
)
{
mixingAudioSourceSocket.AddValue(
audio_source,
audio_source->GetAudioSourceMixPresence()
);
}
#ifdef LAB_ONLY
sourceStartCount++;
#endif
}
//
//#############################################################################
// StopRequest
//#############################################################################
//
void
L4AudioRenderer::StopRequest(L4AudioSource *audio_source)
{
Check(this);
Check(audio_source);
//
//--------------------------------------------------------------------------
// Verify that the source is not stopped
//--------------------------------------------------------------------------
//
Verify(audio_source->GetAudioSourceState() != StoppedAudioSourceState);
//
//--------------------------------------------------------------------------
// If state of the source is dormant or suspended
// Then set source to stop state and remove from dormant list
//--------------------------------------------------------------------------
//
if (
audio_source->GetAudioSourceState() == DormantAudioSourceState ||
audio_source->GetAudioSourceState() == SuspendedAudioSourceState
)
{
//
// Set state of source to stopped
// Verify that source is in dormant list
// Remove source from dormant list
// Verify that source is not in dormant list
//
audio_source->AssignAudioSourceState(StoppedAudioSourceState);
#if DEBUG_LEVEL>0
{
DormantSourceIterator iterator(&dormantAudioSourceSocket);
Verify(iterator.IsPlugMember(audio_source) == True);
}
#endif
PlugIterator remover(audio_source);
remover.RemoveSocket(&dormantAudioSourceSocket);
#if DEBUG_LEVEL>0
{
DormantSourceIterator iterator(&dormantAudioSourceSocket);
Verify(iterator.IsPlugMember(audio_source) == False);
}
#endif
return;
}
//
//--------------------------------------------------------------------------
// Stop the source
//--------------------------------------------------------------------------
//
AudioSourceStopMaintenance(audio_source);
}
//
//#############################################################################
// ExecuteImplementation
//#############################################################################
//
void
L4AudioRenderer::ExecuteImplementation(
RendererComplexity complexity_update,
RendererOrigin::InterestingEntityIterator *iterator
)
{
SET_AUDIO_RENDERER();
SET_AUDIO_RENDERER_EXECUTE();
Check(this);
AudioRenderer::ExecuteImplementation(complexity_update, iterator);
CalculateMix();
RunningSourceCheckup();
// RunningAudioSourceSort();
DormantSourceCheckup();
CLEAR_AUDIO_RENDERER_EXECUTE();
CLEAR_AUDIO_RENDERER();
}
//
//#############################################################################
// CalculateMix
//#############################################################################
//
void
L4AudioRenderer::CalculateMix()
{
SET_AUDIO_CALCULATE_MIX();
//
//--------------------------------------------------------------------------
// Is this the next calculate mix frame
//--------------------------------------------------------------------------
//
#if 0
if (nextCalculateMixFrame > GetAudioFrameCount())
{
CLEAR_AUDIO_CALCULATE_MIX();
return;
}
nextCalculateMixFrame = GetAudioFrameCount() + DefaultAudioFrameDelay;
#endif
//
//--------------------------------------------------------------------------
// Calculate the compression volume scaling
//
// For each source, calculate the amount to scale its volume by
// according to those sources which have a higher mix presence
//--------------------------------------------------------------------------
//
{
AudioControlValue
compression_scale = 1.0f;
AudioControlValue
compression_effect = 0.0f;
AudioSourceMixPresence
current_mix_presence = MedAudioSourceMixPresence;
MixingSourceIterator
iterator(&mixingAudioSourceSocket);
L4AudioSource
*audio_source;
Check(GetAudioHead());
Scalar comp_scale = GetAudioHead()->GetSourceCompressionScale();
Scalar comp_exp = GetAudioHead()->GetSourceCompressionExponent();
//
// Get mix presence of the first source
//
if ((audio_source = iterator.GetCurrent()) != NULL)
{
Check(audio_source);
current_mix_presence = audio_source->GetAudioSourceMixPresence();
}
//
//-----------------------------------------------------------------------
// For each audio source, calculate the compression scale
//-----------------------------------------------------------------------
//
while ((audio_source = iterator.ReadAndNext()) != NULL)
{
Check(audio_source);
//
//--------------------------------------------------------------------
// If the mix presence of this source is greater then the last
// source then we have stepped to a lower mix presence.
//--------------------------------------------------------------------
//
if (
current_mix_presence !=
audio_source->GetAudioSourceMixPresence()
)
{
Verify(
current_mix_presence <
audio_source->GetAudioSourceMixPresence()
);
current_mix_presence = audio_source->GetAudioSourceMixPresence();
//
// Calculate the compression scale for this mix presence
//
// scale = 1 - ((comp_scale*x)^comp_exp)
//
compression_scale =
1.0f - pow(comp_scale * compression_effect, comp_exp);
Verify(compression_scale >= 0.0f && compression_scale <= 1.0f);
}
//
//--------------------------------------------------------------------
// Set the compression scale for this source
//--------------------------------------------------------------------
//
audio_source->SetVolumeCompressionScale(compression_scale);
//
//--------------------------------------------------------------------
// Calculate the compression effect for this source
//--------------------------------------------------------------------
//
AudioControlValue source_compression_effect;
source_compression_effect =
audio_source->CalculateSourceCompressionEffect();
Verify(
source_compression_effect >= 0.0f &&
source_compression_effect <= 1.0f
);
//
//--------------------------------------------------------------------
// Update the compression effect for this mix presence
//--------------------------------------------------------------------
//
compression_effect =
Max(compression_effect, source_compression_effect);
Verify(compression_effect >= 0.0f && compression_effect <= 1.0f);
#if 0
Tell(
"compression_effect " << compression_effect <<
" : compression_scale " << compression_scale << "\n"
);
#endif
}
}
CLEAR_AUDIO_CALCULATE_MIX();
}
//
//#############################################################################
// RunningSourceCheckup
//#############################################################################
//
void
L4AudioRenderer::RunningSourceCheckup()
{
SET_AUDIO_RUNNING_SOURCES();
//
//--------------------------------------------------------------------------
// Iterate through all running sources
//--------------------------------------------------------------------------
//
ChainOf<L4AudioSource*>
resort_socket(NULL);
RunningSourceIterator
running_iterator(&runningAudioSourceSocket);
L4AudioSource
*audio_source;
while ((audio_source = running_iterator.GetCurrent()) != NULL)
{
Check(audio_source);
//
//-----------------------------------------------------------------------
// If the source does not require maintenance then skip it
//-----------------------------------------------------------------------
//
if (!audio_source->RequiresMaintenance(GetAudioHead()))
{
running_iterator.Next();
continue;
}
//Update object position
//
//-----------------------------------------------------------------------
// If the source is clipped then either stop or suspend
//-----------------------------------------------------------------------
//
if (audio_source->IsAudioSourceClipped(GetAudioHead()))
{
if (audio_source->GetAudioRenderType() == TransientAudioRenderType)
{
AudioSourceStopMaintenance(audio_source);
}
else
{
Verify(
audio_source->GetAudioRenderType() ==
SustainedAudioRenderType
);
AudioSourceSuspendMaintenance(audio_source);
}
continue;
}
//
//-----------------------------------------------------------------------
// If the source is finished playing then stop it
//-----------------------------------------------------------------------
//
if (audio_source->IsFinishedPlaying())
{
AudioSourceStopMaintenance(audio_source);
continue;
}
//
//-----------------------------------------------------------------------
// Execute
//-----------------------------------------------------------------------
//
SET_AUDIO_EXECUTE_SOURCES();
audio_source->Execute();
CLEAR_AUDIO_EXECUTE_SOURCES();
//
//-----------------------------------------------------------------------
// Add to resort list if weight has changed
//-----------------------------------------------------------------------
//
if (
audio_source->CalculateAudioWeighting() !=
running_iterator.GetValue()
)
{
running_iterator.Remove();
resort_socket.Add(audio_source);
}
else
{
running_iterator.Next();
}
}
//
//--------------------------------------------------------------------------
// Sort resort socket back into running socket
//--------------------------------------------------------------------------
//
ChainIteratorOf<L4AudioSource*>
resort_iterator(&resort_socket);
while ((audio_source = resort_iterator.ReadAndNext()) != NULL)
{
Check(audio_source);
Verify(running_iterator.IsPlugMember(audio_source) == False);
runningAudioSourceSocket.AddValue(
audio_source,
audio_source->CalculateAudioWeighting()
);
}
CLEAR_AUDIO_RUNNING_SOURCES();
}
//
//#############################################################################
// DormantSourceCheckup
//#############################################################################
//
void
L4AudioRenderer::DormantSourceCheckup()
{
SET_AUDIO_DORMANT_SOURCES();
//
//--------------------------------------------------------------------------
// Assemble the request socket
//--------------------------------------------------------------------------
//
VChainOf<L4AudioSource*, AudioWeighting>
resume_request_socket(NULL, False);
DormantSourceIterator
dormant_iterator(&dormantAudioSourceSocket);
L4AudioSource
*audio_source;
while ((audio_source = dormant_iterator.ReadAndNext()) != NULL)
{
Check(audio_source);
//
// If the suspend gate is not up then it can not resume
//
if (!audio_source->CanResume(GetAudioHead()))
continue;
//
// If the audio source is clipped then it can not resume
//
if (audio_source->IsAudioSourceClipped(GetAudioHead()))
continue;
//
// Add to request socket
//
resume_request_socket.AddValue(
audio_source,
audio_source->CalculateAudioWeighting()
);
}
//
//--------------------------------------------------------------------------
// Iterate through request socket
//--------------------------------------------------------------------------
//
VChainIteratorOf<L4AudioSource*, AudioWeighting>
resume_request_iterator(&resume_request_socket);
while ((audio_source = resume_request_iterator.GetCurrent()) != NULL)
{
Check(audio_source);
//
// Request audio resources
//
/* AudioChannelSet
channel_set_result;*/
SourceSet *source_result = audio_source->GetAudioChannelSet();
if (!RequestAudioResources(audio_source,
source_result)
)
break;
//
// Remove from dormant list and request list
//
PlugIterator remover(audio_source);
remover.RemoveSocket(&dormantAudioSourceSocket);
AudioWeighting audio_weighting = resume_request_iterator.GetValue();
resume_request_iterator.Remove();
//
// Update Spatial model
//
audio_source->UpdateSpatialModel(GetAudioHead());
//
// Set channel set of source
// Source resume implementation
// Set state of source to running
//
audio_source->SetAudioChannelSet(*source_result);
audio_source->ResumeImplementation();
audio_source->AssignAudioSourceState(RunningAudioSourceState);
//
// Put on running socket and mixing socket
//
runningAudioSourceSocket.AddValue(audio_source, audio_weighting);
if (
audio_source->GetAudioSourceMixPresence() !=
ManualAudioSourceMixPresence
)
{
mixingAudioSourceSocket.AddValue(
audio_source,
audio_source->GetAudioSourceMixPresence()
);
}
}
CLEAR_AUDIO_DORMANT_SOURCES();
}
//
//#############################################################################
// AudioSourceStopMaintenance
//#############################################################################
//
void
L4AudioRenderer::AudioSourceStopMaintenance(L4AudioSource *source)
{
Check(source);
Verify(source->GetAudioSourceState() == RunningAudioSourceState);
#if DEBUG_LEVEL>0
{
RunningSourceIterator iterator(&runningAudioSourceSocket);
Verify(iterator.IsPlugMember(source) == True);
}
#endif
source->StopImplementation();
source->AssignAudioSourceState(StoppedAudioSourceState);
source->ReleaseChannels();
PlugIterator remover(source);
remover.RemoveSocket(&runningAudioSourceSocket);
remover.RemoveSocket(&mixingAudioSourceSocket);
#if DEBUG_LEVEL>0
{
RunningSourceIterator iterator(&runningAudioSourceSocket);
Verify(iterator.IsPlugMember(source) == False);
}
#endif
}
//
//#############################################################################
// AudioSourceSuspendMaintenance
//#############################################################################
//
void
L4AudioRenderer::AudioSourceSuspendMaintenance(L4AudioSource *source)
{
Check(source);
Verify(source->GetAudioRenderType() == SustainedAudioRenderType);
Verify(source->GetAudioSourceState() == RunningAudioSourceState);
#if DEBUG_LEVEL>0
{
RunningSourceIterator iterator(&runningAudioSourceSocket);
Verify(iterator.IsPlugMember(source) == True);
}
#endif
source->SuspendImplementation();
source->AssignAudioSourceState(SuspendedAudioSourceState);
source->ReleaseChannels();
PlugIterator remover(source);
remover.RemoveSocket(&runningAudioSourceSocket);
remover.RemoveSocket(&mixingAudioSourceSocket);
#if DEBUG_LEVEL>0
{
RunningSourceIterator iterator(&runningAudioSourceSocket);
Verify(iterator.IsPlugMember(source) == False);
}
#endif
dormantAudioSourceSocket.Add(source);
}
//
//#############################################################################
// RequestAudioResources
//#############################################################################
//
Logical
L4AudioRenderer::RequestAudioResources(
L4AudioSource *audio_source,
SourceSet *source_result
)
{
Check(this);
Check(audio_source);
Check(source_result);
//
//--------------------------------------------------------------------------
// This source must be within the culling volume
//--------------------------------------------------------------------------
//
if (audio_source->IsAudioSourceClipped(GetAudioHead()))
return False;
//
//--------------------------------------------------------------------------
// Request audio channels for this source
//--------------------------------------------------------------------------
//
Logical
resources_available;
source_result = audio_source->GetAudioChannelSet();
Check(source_result);
resources_available =
RequestAudioChannels(
audio_source->GetAudioVoiceCount(),
source_result
);
//
//--------------------------------------------------------------------------
// If audio channels are not available then check running sources for
// lower weight sources
//--------------------------------------------------------------------------
//
if (!resources_available)
{
RunningSourceIterator
iterator(&runningAudioSourceSocket);
L4AudioSource
*running_audio_source;
AudioWeighting
audio_source_weighting;
iterator.Last();
running_audio_source = iterator.GetCurrent();
audio_source_weighting = audio_source->CalculateAudioWeighting();
//
//-----------------------------------------------------------------------
// while
// request for channels is not satisfied and
// there exist running sources that have lower weighting
//-----------------------------------------------------------------------
//
while (
!resources_available &&
running_audio_source != NULL &&
audio_source_weighting < iterator.GetValue() // Actual value is inverted
)
{
Check(running_audio_source);
Verify(
running_audio_source->GetAudioSourcePriority() <=
audio_source->GetAudioSourcePriority()
);
//
//--------------------------------------------------------------------
// Collect Statistics
//--------------------------------------------------------------------
//
#ifdef LAB_ONLY
if (
running_audio_source->GetAudioSourcePriority() <
audio_source->GetAudioSourcePriority()
)
{
resourceStealPriorityCount++;
}
else
{
Verify(
running_audio_source->GetAudioSourcePriority() ==
audio_source->GetAudioSourcePriority()
);
Warn(
running_audio_source->CalculateSourceVolumeScale() >=
audio_source->CalculateSourceVolumeScale()
);
resourceStealVolumeCount++;
}
AudioTime duration_cutoff(0.1f);
if (
running_audio_source->GetCurrentRunningTime() <=
duration_cutoff
)
{
stealShortDurationCount++;
}
resourceStealCount++;
#endif
//
//--------------------------------------------------------------------
// If running source is transient
// Then stop the source
// Else suspend the source
//--------------------------------------------------------------------
//
if (
running_audio_source->GetAudioRenderType() ==
TransientAudioRenderType
)
{
AudioSourceStopMaintenance(running_audio_source);
}
else
{
Verify(
running_audio_source->GetAudioRenderType() ==
SustainedAudioRenderType
);
AudioSourceSuspendMaintenance(running_audio_source);
}
//
//--------------------------------------------------------------------
// Request resources again
//--------------------------------------------------------------------
//
resources_available =
RequestAudioChannels(
audio_source->GetAudioVoiceCount(),
source_result
);
iterator.Last();
running_audio_source = iterator.GetCurrent();
}
}
return resources_available;
}
//
//#############################################################################
// RequestAudioChannels
//#############################################################################
//
Logical
L4AudioRenderer::RequestAudioChannels(
int voices_requested,
SourceSet *source_request
)
{
Check(this);
Check(source_request);
//Do we have enough?
int requested = source_request->count;
bool failed = true;
alGetError();
for (int i = 0; i < requested; i++)
{
if (!alIsSource(source_request->sources[i]))
{
alGenSources(1, source_request->sources + i);
}
}
ALenum error = alGetError();
if (error == AL_NO_ERROR)
{
failed = false;
}
if (failed)
{
return False;
}
return True;
//
//----------------------------------------------------------------------
// Attempt to allocate channels from audio hardware
//----------------------------------------------------------------------
//
/* AudioChannel *channel;
Logical success = False;
AudioCard *front_card = GetFrontCard();
AudioCard *rear_card = GetRearCard();
Check(front_card);
Check(rear_card);
while (True)
{
if (channel_set_request->IsFrontLeftEnabled())
{
if ((channel =
front_card->RequestAudioChannel(voices_requested)) == NULL)
break;
Check(channel);
channel_set_request->SetFrontLeft(channel);
}
if (channel_set_request->IsFrontRightEnabled())
{
if ((channel =
front_card->RequestAudioChannel(voices_requested)) == NULL)
break;
Check(channel);
channel_set_request->SetFrontRight(channel);
}
if (channel_set_request->IsRearLeftEnabled())
{
if ((channel =
rear_card->RequestAudioChannel(voices_requested)) == NULL)
break;
Check(channel);
channel_set_request->SetRearLeft(channel);
}
if (channel_set_request->IsRearRightEnabled())
{
if ((channel =
rear_card->RequestAudioChannel(voices_requested)) == NULL)
break;
Check(channel);
channel_set_request->SetRearRight(channel);
}
success = True;
break;
}
//
//----------------------------------------------------------------------
// If did not succeed then release allocated channels
//----------------------------------------------------------------------
//
if (!success)
{
channel_set_request->ReleaseAll();
return False;
}
//
//----------------------------------------------------------------------
// else, return allocated channels
//----------------------------------------------------------------------
//
return True;*/
}
void L4AudioRenderer::ReleaseSourceSet(SourceSet &sourceSet)
{
for (int i = 0; i < sourceSet.count; i++)
{
ALenum state;
alGetSourcei(sourceSet.sources[i], AL_SOURCE_STATE, &state);
if (state == AL_PLAYING)
{
alSourceStop(sourceSet.sources[i]);
}
}
alDeleteSources(sourceSet.count, sourceSet.sources);
for (int i = 0; i < sourceSet.count; i++)
{
sourceSet.sources[i] = -1;
}
}
//~~~~~~~~~~~~~~~~~~~~~~ L4AudioRenderer profile bits ~~~~~~~~~~~~~~~~~~~~~~~~~
#if defined(TRACE_AUDIO_RENDERER_RUNNING_SOURCES)
BitTrace Audio_Renderer_Running_Sources("Audio Renderer Running Sources");
#endif
#if defined(TRACE_AUDIO_RENDERER_RUNNING_SORT)
BitTrace Audio_Renderer_Running_Sort("Audio Renderer Running Sort");
#endif
#if defined(TRACE_AUDIO_RENDERER_CALCULATE_MIX)
BitTrace Audio_Renderer_Calculate_Mix("Audio Renderer Calculate Mix");
#endif
#if defined(TRACE_AUDIO_RENDERER_EXECUTE_SOURCES)
BitTrace Audio_Renderer_Execute_Sources("Audio Renderer Execute Sources");
#endif
#if defined(TRACE_AUDIO_RENDERER_DORMANT_SOURCES)
BitTrace Audio_Renderer_Dormant_Sources("Audio Renderer Dormant Sources");
#endif