Files
RP412/MUNGA_L4/L4AUDRND.cpp
T
CydandClaude Opus 5 ce1b0ab9c3 Sounds fade, dull and doppler with distance again
The OpenAL port kept the whole authored audio model and then threw most of
its output away. Every frame the engine computed a distance-attenuation
curve, a high-frequency rolloff, doppler cents, a reverb level and a
front/rear placement, and every one of those consumers had been commented
out when the two AWE32 cards were replaced. What reached the speakers was
OpenAL's own defaults instead: a straight-line fade to silence, no
filtering, doppler at the wrong constants with an inverted velocity, no
reverb, and every cockpit sound dead centre.

Restored, per AUDIO.INI, which is byte-identical to the file that shipped
in August 1995:

  - the authored knee/rolloff distance curve, replacing AL_LINEAR_DISTANCE.
    This also un-blinds the transient cull, the voice-steal weighting and
    the mix ducking, which all key off it and were treating far sources as
    full presence
  - the CC7 squared volume law; writing the scale linearly ran everything
    about 6 dB hot at mid-scale
  - brightness and distance muffling, and the wet-exterior/dry-cockpit
    reverb split, both through a new OpenAL EFX bridge
  - doppler on the moving-source path only, as the original had it
  - front/rear placement from the authored position enum

The larger find is that AL_PITCH was never called anywhere in the tree, so
the entire pitch chain was inert - not only doppler but pitch_mix_offset,
which our own sequences author 97 times. Doppler alone would have changed
nothing audible.

Note pitch is applied for parity with the BT engine but is identity here:
our content predates NoteAudioControlID, so every source runs at note 60.

Builds clean on VS2022 Release|Win32. Smoke-tested against vRIO on COM1 -
reaches gameplay and holds a steady frame loop. ALC_EXT_EFX is present on
the build machine with all nine entry points, so the filter and reverb work
is live rather than inert. Not yet listened to on the pod, which is the
real test: the volume law changes the level of everything.

docs/SOUND.md documents the original two-card quadraphonic design, where
the surviving original assets are, and what remains.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 23:00:37 -05:00

1427 lines
36 KiB
C++

#include "mungal4.h"
#pragma hdrstop
#include "l4audrnd.h"
#include "l4audefx.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);
//
//----------------------------------------------------------------------
// 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);
//
//----------------------------------------------------------------------
// 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);
//
// FIDELITY (docs/SOUND.md F9/F11): bring up the EFX bridge that carries
// the authored brightness/distance lowpass and the wet-exterior reverb
// send. Needs the context current, and the reverb gain has already been
// read from AUDIO.INI into the head above. Inert without ALC_EXT_EFX.
//
EFX_Initialize(audio_head->GetGlobalReverbScale());
}
//
//----------------------------------------------------------------------
// 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