#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);

	//
	//----------------------------------------------------------------------
	// 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);
	}

	//
	//----------------------------------------------------------------------
	// 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
