//
// Asura_Chunk_SoundEvent.cpp
//
// Created by Richard Rice - 10/07/2006
// 
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//
#include "Core/Asura.h"
#include "ChunkSystem/Asura_Chunk_SoundEvent.h"

#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "ChunkSystem/Asura_SaveBlock.h"
#include "Sound/Asura_Audio_System.h"
#include "Sound/Asura_Phonon.h"
#include "Sound/Asura_Sound_Event.h"
#include "Sound/Asura_Sound_Event_Storage.h"
#include "Sound/Asura_Sound_Event_System.h"
#include "Sound/Asura_Sound.h"
#include "Sound/Asura_Sound_Mixer.h"
#if defined(ASURA_USE_STREAMING)
#include "Streaming/Asura_Streaming_System.h"
#endif
#include "Volume/Asura_Volume_Cuboid.h"
#include "Volume/Asura_VolumeGroup.h"


#ifdef ASURA_TOOLS
#include "Load&Save/Tools_SaveAsura.h"
#include "Load&Save/LevelExport/Tools_Level_Export.h"
#include "Sound/Tools_PickSound.h"
#include "Sound/Tools_SoundEvent_System.h"
#endif


/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*-------------------------------**
** Asura_Chunk_SoundEvent_Sample **
**-------------------------------*/

#define ASURA_CHUNK_SOUNDEVENT_SAMPLE_VERSION 5

//Version 1 :
//		Added platform specific settings containing sample rate.
//		RAR 11/08/2006
//Version 2 :
//		Added subcategories.
//		RAR 13/10/2006
//Version 3 :
//		Added autoload flag (for tools).
//		RAR 14/02/2007
//Version 4 :
//		Added duration
//		RAR 17/04/2008
//Version 5 :
//		Removed autoload flag (for tools).
//		RAR 14/02/2007


bool Asura_Chunk_SoundEvent_Sample::Process(Asura_Chunk_Stream& xStream) const
{
	// Is this the correct version?

	if (Version > ASURA_CHUNK_SOUNDEVENT_SAMPLE_VERSION)
	{
		Asura_Assertf(false, ("Unknown chunk version %d for sound sample",Version));
		return false;
	}

	#ifdef ASURA_TOOLS
	//Let tools system know that there has been at least one sample , so it is okay to create files when using SaveAll()
	//RAR 26/10/2006
	Tools_SoundEvent_System::SetEverHadEventsOrSamples();
	#endif


	char acName[128];
	xStream.ReadString(acName,sizeof(acName));



	//Allocate or find the sound sample
	bool bSampleAlreadyExists;
	Asura_Sound_Sample* pxSample = Asura_Sound_Event_Storage::CreateSample(acName, bSampleAlreadyExists);
	Asura_Assert(pxSample, "");

	//make sure the sample doesn't already exist
	if(bSampleAlreadyExists)
	{
#ifdef ASURA_TOOLS
		Asura_Assertf(0,("Sound sample %s already exists",acName));
#endif //#ifdef ASURA_TOOLS
		//probably want to add some logging to file_contents.txt or similar to go along with this
		return false;
	}

	
	//get wav file hash/name
	Asura_Hash_ID uWavHash;
	xStream >> uWavHash;
	#ifdef ASURA_SOUND_INCLUDE_TOOLS_DATA
	char szWavName[256];
	xStream.ReadString(szWavName,sizeof(szWavName));
	#else
	xStream.SkipString();
	#endif

	xStream >> pxSample->m_fVolume;
	xStream >> pxSample->m_fPitch;
	xStream >> pxSample->m_fVolume;
	xStream >> pxSample->m_bLooping;

	if(uWavHash)
	{
		#ifdef ASURA_USE_AUDIO_SYSTEM

			pxSample->m_uWave = uWavHash;

			#ifdef ASURA_TOOLS
			Asura_Audio_System::LoadWave(szWavName, pxSample->GetLooping());
			#endif

		#else

			//get sound ID from hash/filename
			#ifdef ASURA_TOOLS
			pxSample->m_eSoundID = Tools_PickSound::GetSoundIDForSoundEventFilename(szWavName);
			#else
			pxSample->m_eSoundID = Asura_Sound_System::GetSoundIDFromHash(uWavHash);
			#endif

			//assert if we failed to get it
			#ifdef ASURA_SOUND_INCLUDE_TOOLS_DATA
			Asura_Assertf(pxSample->m_eSoundID != ASURA_SID_NO_SOUND,("Failed to find wav %s for sample %s",szWavName,acName));
			#else
			Asura_Assertf(pxSample->m_eSoundID != ASURA_SID_NO_SOUND,("Failed to find wav for sample %s",acName));
			#endif

		#endif
	}
		
	//load/skip tools data
	#ifdef ASURA_SOUND_INCLUDE_TOOLS_DATA
	xStream >> pxSample->m_xSoundType;
	xStream >> pxSample->m_xFilename;
	#else
	xStream.SkipString();
	xStream.SkipString();
	#endif


	if(Version >= 1)
	{
		#ifdef ASURA_TOOLS
		xStream >> pxSample->m_iNumPlatforms;
		if(pxSample->m_iNumPlatforms)
		{
			pxSample->m_pxPlatformSettings = new Asura_Sound_Sample_PlatformSettings[pxSample->m_iNumPlatforms];
			for(int i=0;i<pxSample->m_iNumPlatforms;i++)
			{
				xStream >> pxSample->m_pxPlatformSettings[i].m_iPlatform;
				xStream >> pxSample->m_pxPlatformSettings[i].m_iSampleRate;
			}
		}
		#else
		//Platform settings aren't needed outside of tools
		int iNumPlatforms;
		xStream >> iNumPlatforms;

		const int iPlatformDataSize = sizeof(int) * 2;
		// JAT 29/08/06 - don't skip zero bytes causes an assert on PS2
		const int iSizeInBytes = iNumPlatforms * iPlatformDataSize;
		if ( iSizeInBytes > 0 )
		{
			xStream.Skip( iSizeInBytes );
		}
		#endif
	}

	if(Version >= 2)
	{
		#ifdef ASURA_SOUND_INCLUDE_TOOLS_DATA
		xStream >> pxSample->m_xSoundSubType;
		#else
		xStream.SkipString();
		#endif
	}
	
	if(Version >= 3 && Version < 5)
	{
		bool bJunk;
		xStream >> bJunk;
	}
	if(Version >= 4)
	{
		xStream >> pxSample->m_fDuration;
	}


	return true;
}

bool Asura_Chunk_SoundEvent_Sample::Process(Asura_Handle iFileHandle) const
{
	Asura_Chunk_File_Stream	xStream(iFileHandle);
	return Process(xStream);
}

#ifdef ASURA_TOOLS
void Asura_Chunk_SoundEvent_Sample::Create(const class Asura_Sound_Sample* pxSample,Asura_Chunk_Stream& xStream)
{
	u_int uChunkFlags = 0;

	xStream.WriteChunk_Start(ASURA_CHUNK_SOUNDEVENT_SAMPLE, ASURA_CHUNK_SOUNDEVENT_SAMPLE_VERSION, uChunkFlags);


	xStream << pxSample->m_xSampleName;

	
	//save both the hash and the string for the wav filename
#ifdef ASURA_USE_AUDIO_SYSTEM
	Asura_Hash_ID uWavHash = pxSample->GetWaveHash();
	Asura_String xWavName = Asura_Audio_System::GetWaveFilename(uWavHash);
#else
	Asura_String xWavName = Asura_Sound_System::GetFileNameFromSoundID(pxSample->m_eSoundID);
	Asura_Hash_ID uWavHash = xWavName.IsBlank() ? 0 : Asura_GetHashID(xWavName.GetString());
#endif

	xStream << uWavHash;
	xStream << xWavName;

	xStream << pxSample->m_fVolume;
	xStream << pxSample->m_fPitch;
	xStream << pxSample->m_fVolume;
	xStream << pxSample->m_bLooping;

	xStream << pxSample->m_xSoundType;
	xStream << pxSample->m_xFilename;

	xStream << pxSample->m_iNumPlatforms;
	for(int i=0;i<pxSample->m_iNumPlatforms;i++)
	{
		xStream << pxSample->m_pxPlatformSettings[i].m_iPlatform;
		xStream << pxSample->m_pxPlatformSettings[i].m_iSampleRate;
	}

	xStream << pxSample->m_xSoundSubType;

	xStream << pxSample->m_fDuration;

	xStream.WriteChunk_End();
}

void Asura_Chunk_SoundEvent_Sample::Create(const class Asura_Sound_Sample* pxSample,Asura_SaveBlock* pxSaveBlock)
{
	Asura_Chunk_SaveBlock_Stream xStream(pxSaveBlock);
	Create	(pxSample,xStream);
}


#endif // ASURA_TOOLS


/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*-------------------------------**
** Asura_Chunk_SoundEvent_Event **
**-------------------------------*/

#define ASURA_CHUNK_SOUNDEVENT_EVENT_VERSION 11

//Version 1 :
//		Added endless playback flag.
//		RAR 28/07/2006
//Version 2 :
//		Added event mapping flag..
//		RAR 30/08/2006
//Version 3 :
//		Added subcategories.
//		RAR 13/10/2006
//Version 4 :
//		Added variable playback settings.
//		RAR 13/10/2006
//Version 5 :
//		Add max instance support
//		Added max outer radius for culling
//		RAR 08/08/2007
//Version 6 :
//		Add play probability
//		RAR 04/09/2007
//Version 7 : 
//      Split m_bUseEnvEffects into seperate bools for doppler/reverb/occlusion/dist filter.
//      MH 28/01/2008
//Version 8 : 
//		Added min/max duration. Combined various bools into a bitfield
//		RAR 17/04/2008
//Version 9 :
//		Someone added sound type and didnt update this comment o_o
//Verison 10:
//		Added DSP chain hash
//		TY 26/03/09
//Version 11:
//		Turned "use master DSP" on for old chunks (flags bitfield starts zeroed)
//		AAM 22/04/09

bool Asura_Chunk_SoundEvent_Event::Process(Asura_Chunk_Stream& xStream) const
{
	// Is this the correct version?

	if (Version > ASURA_CHUNK_SOUNDEVENT_EVENT_VERSION)
	{
		Asura_Assertf(false, ("Unknown chunk version %d for sound event",Version));
		return false;
	}

	#ifdef ASURA_TOOLS
	//Let tools system know that there has been at least one event , so it is okay to create files when using SaveAll()
	//RAR 26/10/2006
	Tools_SoundEvent_System::SetEverHadEventsOrSamples();
	#endif


	char acName[128];
	xStream.ReadString(acName,sizeof(acName));

	//Allocate or find the sound event
	bool bEventAlreadyExists;
	Asura_Sound_Event* pxEvent = Asura_Sound_Event_Storage::CreateEvent(acName, bEventAlreadyExists);
	Asura_Assert(pxEvent, "");

	//make sure the event doesn't already exist
	if(bEventAlreadyExists)
	{
		#ifdef ASURA_TOOLS
		Asura_Assertf(0,("Sound evente %s already exists",acName));
		#endif //#ifdef ASURA_TOOLS
		//probably want to add some logging to file_contents.txt or similar to go along with this
		return false;
	}

	xStream >> pxEvent->m_fMinVol;
	xStream >> pxEvent->m_fMaxVol;
	xStream >> pxEvent->m_fMinPitch;
	xStream >> pxEvent->m_fMaxPitch;
	xStream >> pxEvent->m_fMinDelay;
	xStream >> pxEvent->m_fMaxDelay;
	xStream >> pxEvent->m_xSurroundPan.m_fPan;
	xStream >> pxEvent->m_xSurroundPan.m_fFade;
	xStream >> pxEvent->m_fPriority;

	int iTemp;
	xStream >> iTemp;
	ASURA_SOUND_PLAYBACK_TYPE ePlaybackType = (ASURA_SOUND_PLAYBACK_TYPE) iTemp;//gets set in the event after the playables are sorted out
	if(Version >= 8)
	{
		xStream >> pxEvent->m_uFlags;
	}
	else
	{
		//older version saved flags as individual bools
		bool bTemp;
		
		xStream >> bTemp;
		pxEvent->m_bEventLooping = bTemp;

		if (Version < 7)
		{
			// used to all be encompassed in a single variable.
			bool bEnvironmentalEffects;
			xStream >> bEnvironmentalEffects;
			pxEvent->m_bUseOcclusion = bEnvironmentalEffects;
			pxEvent->m_bUseDistanceFilter = bEnvironmentalEffects;
			pxEvent->m_bUseDoppler = bEnvironmentalEffects;
			pxEvent->m_bUseEnvironmentalReverb = bEnvironmentalEffects;
		}
		
		xStream >> bTemp;
		pxEvent->m_bPanOverride = bTemp;
	}
	if(Version >= 1)
	{
		xStream >> pxEvent->m_bEndlessPlayback;
	}

	xStream >> iTemp;
	pxEvent->m_e3dSoundType = (ASURA_3DSOUND_TYPE)iTemp;
	xStream >> pxEvent->m_fInnerRadius;
	xStream >> pxEvent->m_fOuterRadius;

	//playable list
	u_int uNumPlayable;
	xStream >> uNumPlayable;
	if(uNumPlayable)
	{
		#ifdef ASURA_TOOLS
		//In tools we just fill out the playable ID list for now. The pointers to the playables are found later , after
		//everything has been loaded.
		pxEvent->m_xPlayableIDList.SetSize(uNumPlayable);
		for(u_int i=0;i<uNumPlayable;i++)
		{
			Asura_Sound_PlayableID xID;
			xStream >> xID.m_uHashID;
			xStream >> iTemp;
			xID.m_eType = (ASURA_SOUND_PLAYABLE_TYPE) iTemp;
			pxEvent->m_xPlayableIDList[i] = xID;
		}
		#else  //ASURA_TOOLS
		//In game any events/samples that this event depends on should already be loaded , so we can set up the playable
		//list directly.
		pxEvent->m_xPlayableList.SetSize(uNumPlayable);

		u_int uIndex = 0;
		for(u_int i=0;i<uNumPlayable;i++)
		{
			Asura_Sound_PlayableID xID;
			xStream >> xID.m_uHashID;
			xStream >> iTemp;
			xID.m_eType = (ASURA_SOUND_PLAYABLE_TYPE) iTemp;

			const Asura_Sound_Playable* pxPlayable = 0;
			if(xID.m_eType == ASURA_SOUND_PLAYABLE_SAMPLE)
			{
				pxPlayable = Asura_Sound_Event_Storage::FindSample(xID.m_uHashID);
			}
			else
			{
				Asura_Assert(xID.m_eType == ASURA_SOUND_PLAYABLE_EVENT,"");
				pxPlayable = Asura_Sound_Event_Storage::FindEvent(xID.m_uHashID);
			}
			Asura_Assertf(pxPlayable,("Failed to find %s 0x%x for event %s",xID.m_eType == ASURA_SOUND_PLAYABLE_SAMPLE ? "sample" : "event",xID.m_uHashID,acName));
			if(pxPlayable)
			{
				pxEvent->m_xPlayableList[uIndex++] = pxPlayable;
			}
		}
		if(uIndex != uNumPlayable)
		{
			//failed to find some of the events/samples
			pxEvent->m_xPlayableList.Shrink(uIndex);
		}
		#endif //#else ASURA_TOOLS
	}
	//Set playback type via OneByOne so that the prime search thingy will be allocated
	//if needed.
	//RAR 06/10/2006
	pxEvent->SetPlaybackType(ASURA_PT_ONEBYONE);
	pxEvent->SetPlaybackType(ePlaybackType);


	if(pxEvent->m_ePlaybackType == ASURA_PT_VARIABLE)
	{
		xStream >> pxEvent->m_pxVariableParams->m_fMinInterval;
		xStream >> pxEvent->m_pxVariableParams->m_fMaxInterval;
		xStream >> pxEvent->m_pxVariableParams->m_fMinVolumeChangeTime;
		xStream >> pxEvent->m_pxVariableParams->m_fMaxVolumeChangeTime;
		xStream >> pxEvent->m_pxVariableParams->m_fMinPitchChangeTime;
		xStream >> pxEvent->m_pxVariableParams->m_fMaxPitchChangeTime;
	}

	//get the mixer
	char szMixerName[128];
	xStream.ReadString(szMixerName,sizeof(szMixerName));
	#ifdef ASURA_SOUND_INCLUDE_TOOLS_DATA
	pxEvent->m_xMixerChannelName = szMixerName;
	#endif

	Asura_Hash_ID uMixerHash = Asura_GetHashID(szMixerName);
	if(uMixerHash != uMIXER_HASHID_MASTER)
	{
		pxEvent->m_pxMixingChannel = Asura_Sound_Mixer_System::FindChannel(uMixerHash);
		Asura_Assertf(pxEvent->m_pxMixingChannel,("Failed to get mixer %s for event %s",szMixerName,acName));
	}

	//load/skip tools data
	#ifdef ASURA_SOUND_INCLUDE_TOOLS_DATA
	xStream >> pxEvent->m_xEventType;
	xStream >> pxEvent->m_xFilename;
	xStream >> pxEvent->m_bGlobalSound;
	#else
	xStream.SkipString();
	xStream.SkipString();
	bool bJunk;
	xStream >> bJunk;
	#endif

	if(Version >= 2)
	{
		#ifdef ASURA_TOOLS
		xStream >> pxEvent->m_bEventMapping;
		#else
		bool bJunk2;
		xStream >> bJunk2;
		#endif
	}

	if(Version >= 3)
	{
		#ifdef ASURA_SOUND_INCLUDE_TOOLS_DATA
		xStream >> pxEvent->m_xEventSubType;
		#else
		xStream.SkipString();
		#endif
	}

	if(Version >= 5)
	{
		xStream >> pxEvent->m_fMaxOuterRadius;
		xStream >> pxEvent->m_uMaxInstances;
		xStream >> pxEvent->m_uMinFreeVoices;
		xStream >> pxEvent->m_uInstanceGroupID;
		
		#ifdef ASURA_SOUND_INCLUDE_TOOLS_DATA
		xStream >> pxEvent->m_xInstanceGroupName;
		#else
		xStream.SkipString();
		#endif

	}

	if(Version >= 6)
	{
		xStream >> pxEvent->m_ucPlayProbability;
	}
	
	if(Version == 7)
	{
		//Flags added as bools in version 7 ,but now are part of a bitfield in version 8
		bool bTemp;

		xStream >> bTemp;
		pxEvent->m_bUseOcclusion = bTemp;

		xStream >> bTemp;
		pxEvent->m_bUseDistanceFilter = bTemp;

		xStream >> bTemp;
		pxEvent->m_bUseDoppler = bTemp;

		xStream >> bTemp;
		pxEvent->m_bUseEnvironmentalReverb = bTemp;
	}

	if(Version >= 8)
	{
		xStream >> pxEvent->m_fMinDuration;
		xStream >> pxEvent->m_fMaxDuration;
	}
	
	if (Version >= 9)
	{
		xStream >> pxEvent->m_uSoundType;
	}

	if (Version >= 10)
	{
		xStream >> pxEvent->m_uDSPChainHash;
	}

	if (Version < 11)
	{
		// Older chunks would just have this bit set to 0. We want it to default on
		pxEvent->m_bUseMasterDSP = true;
	}

	return true;
}

bool Asura_Chunk_SoundEvent_Event::Process(Asura_Handle iFileHandle) const
{
	Asura_Chunk_File_Stream	xStream(iFileHandle);
	return Process(xStream);
}

#ifdef ASURA_TOOLS
void Asura_Chunk_SoundEvent_Event::Create(const class Asura_Sound_Event* pxEvent,Asura_Chunk_Stream& xStream)
{
	u_int uChunkFlags = 0;

	xStream.WriteChunk_Start(ASURA_CHUNK_SOUNDEVENT_EVENT, ASURA_CHUNK_SOUNDEVENT_EVENT_VERSION, uChunkFlags);

	Asura_WriteToStream_Bitfield_Wrapper<u_int>	xFlagsBitfield (pxEvent->m_uFlags);
	xFlagsBitfield.Add(pxEvent->m_bEventLooping,1);
	xFlagsBitfield.Add(pxEvent->m_bUseOcclusion,1);
	xFlagsBitfield.Add(pxEvent->m_bUseDistanceFilter,1);
	xFlagsBitfield.Add(pxEvent->m_bUseDoppler,1);
	xFlagsBitfield.Add(pxEvent->m_bUseEnvironmentalReverb,1);
	xFlagsBitfield.Add(pxEvent->m_bPanOverride,1);
	xFlagsBitfield.Add(pxEvent->m_bUseMasterDSP,1);
	
	xStream << pxEvent->m_xEventName;

	xStream << pxEvent->m_fMinVol;
	xStream << pxEvent->m_fMaxVol;
	xStream << pxEvent->m_fMinPitch;
	xStream << pxEvent->m_fMaxPitch;
	xStream << pxEvent->m_fMinDelay;
	xStream << pxEvent->m_fMaxDelay;
	xStream << pxEvent->m_xSurroundPan.m_fPan;
	xStream << pxEvent->m_xSurroundPan.m_fFade;
	xStream << pxEvent->m_fPriority;
	xStream << (int)pxEvent->m_ePlaybackType;
	xStream << xFlagsBitfield;
	xStream << pxEvent->IsEndlessPlayback();

	xStream << (int) pxEvent->m_e3dSoundType;
	xStream << pxEvent->m_fInnerRadius;
	xStream << pxEvent->m_fOuterRadius;

	//playable list
	xStream << pxEvent->GetNumPlayableID();
	for(u_int i=0;i<pxEvent->GetNumPlayableID();i++)
	{
		const Asura_Sound_PlayableID& xID = pxEvent->GetPlayableID(i);
		xStream << xID.m_uHashID;
		xStream << (int) xID.m_eType;
	}

	if(pxEvent->m_ePlaybackType == ASURA_PT_VARIABLE)
	{
		xStream << pxEvent->m_pxVariableParams->m_fMinInterval;
		xStream << pxEvent->m_pxVariableParams->m_fMaxInterval;
		xStream << pxEvent->m_pxVariableParams->m_fMinVolumeChangeTime;
		xStream << pxEvent->m_pxVariableParams->m_fMaxVolumeChangeTime;
		xStream << pxEvent->m_pxVariableParams->m_fMinPitchChangeTime;
		xStream << pxEvent->m_pxVariableParams->m_fMaxPitchChangeTime;
	}

	xStream << pxEvent->m_xMixerChannelName;
	xStream << pxEvent->m_xEventType;
	xStream << pxEvent->m_xFilename;
	xStream << pxEvent->m_bGlobalSound;
	xStream << pxEvent->m_bEventMapping;
	xStream << pxEvent->m_xEventSubType;

	xStream << pxEvent->GetMaxOuterRadius();
	xStream << pxEvent->m_uMaxInstances;
	xStream << pxEvent->m_uMinFreeVoices;
	xStream << pxEvent->m_uInstanceGroupID;
	xStream << pxEvent->m_xInstanceGroupName;

	xStream << pxEvent->m_ucPlayProbability;

	xStream << pxEvent->m_fMinDuration;
	xStream << pxEvent->m_fMaxDuration;

	xStream << pxEvent->m_uSoundType;

	xStream << pxEvent->m_uDSPChainHash;
	
	xStream.WriteChunk_End();
}

void Asura_Chunk_SoundEvent_Event::Create(const class Asura_Sound_Event* pxEvent,Asura_SaveBlock* pxSaveBlock)
{
	Asura_Chunk_SaveBlock_Stream xStream(pxSaveBlock);
	Create	(pxEvent,xStream);
}
#endif // ASURA_TOOLS

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*-------------------------------**
** Asura_Chunk_SoundEvent_Mapping **
**-------------------------------*/

#define ASURA_CHUNK_SOUNDEVENT_MAPPING_VERSION 0

bool Asura_Chunk_SoundEvent_Mapping::Process(Asura_Chunk_Stream& xStream) const
{
	// Is this the correct version?

	if (Version > ASURA_CHUNK_SOUNDEVENT_MAPPING_VERSION)
	{
		Asura_Assertf(false, ("Unknown chunk version %d for sound event mapping",Version));
		return false;
	}

	//Read/skip the name
	#ifdef ASURA_SOUND_INCLUDE_TOOLS_DATA
	char acName[128];
	xStream.ReadString(acName,sizeof(acName));
	#else
	xStream.SkipString();
	#endif

	#ifdef ASURA_TOOLS

	Asura_Assert(0,"Shouldn't be loading sound event mappings in tools builds");
	return false;

	#else
 
	Asura_Hash_ID uNewHash;
	xStream >> uNewHash;

	Asura_Hash_ID uExistingHash;
	xStream >> uExistingHash;

	Asura_Sound_Event_Storage::AddEventMapping(uNewHash,uExistingHash);

	return true;
	#endif
}

bool Asura_Chunk_SoundEvent_Mapping::Process(Asura_Handle iFileHandle) const
{
	Asura_Chunk_File_Stream	xStream(iFileHandle);
	return Process(xStream);
}

#ifdef ASURA_TOOLS
void Asura_Chunk_SoundEvent_Mapping::Create(const class Asura_Sound_Event* pxEvent,Asura_Chunk_Stream& xStream)
{
	const Asura_Sound_Event* pxTargetEvent = pxEvent->GetRemappedEvent();
	if(!pxTargetEvent) return;

	u_int uChunkFlags = 0;

	xStream.WriteChunk_Start(ASURA_CHUNK_SOUNDEVENT_MAPPING, ASURA_CHUNK_SOUNDEVENT_MAPPING_VERSION, uChunkFlags);

	//Put name in chunk to help with debugging , and resourcepacker
	xStream << pxEvent->m_xEventName;


	xStream << pxEvent->GetHashID();
	xStream << pxTargetEvent->GetHashID();

	xStream.WriteChunk_End();
}

void Asura_Chunk_SoundEvent_Mapping::Create(const class Asura_Sound_Event* pxEvent,Asura_SaveBlock* pxSaveBlock)
{
	Asura_Chunk_SaveBlock_Stream xStream(pxSaveBlock);
	Create	(pxEvent,xStream);
}
#endif // ASURA_TOOLS

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*------------------------------**
** Asura_Chunk_SoundEvent_Mixer **
**------------------------------*/

#define ASURA_CHUNK_SOUNDEVENT_MIXER_VERSION 7
// Version 1 :
//		Added support for bool "ignore gamespeed pitch changes" 
//		JAT 26/02/07 
// Version 2 :
//		Added priorities to presets
//		PJC 27/09/07
// Version 3 :
//		Added support for bools "use reverb" and "use distance filter"
//		AP 4/10/07 ish
// Version 4 :
//		Added bools for occlusion and doppler
//		MH 28.1.08
// Version 5 :
//		Added DSP chain hash ID, only referenced by new audio system
//		AAM 05/08/08
// Version 6 :
//		Removed per-chain DSP hash, and added master DSP instead
//		AAM 06/11/08
// Version 7 :
//		Added bool for master DSP
//		AAM 22/04/09

bool Asura_Chunk_SoundEvent_Mixer::Process(Asura_Chunk_Stream& xStream) const
{
	// Is this the correct version?

	if (Version > ASURA_CHUNK_SOUNDEVENT_MIXER_VERSION)
	{
		Asura_Assertf(false, ("Unknown chunk version %d for sound mixers",Version));
		return false;
	}

	//make sure mixers haven't already been loaded
	Asura_Sound_Mixer* pxMixerInstance = Asura_Sound_Mixer_System::s_pxInstance;
	if(pxMixerInstance->m_xChannelsArray.Size())
	{
		Asura_Assert(!pxMixerInstance->m_xChannelsArray.Size(),"Mixer channels already loaded?");
		return false;
	}

	#ifdef ASURA_TOOLS
	//Let tools system know that there has been at least one mixer , so it is okay to create files when using SaveAll()
	//RAR 26/10/2006
	Tools_SoundEvent_System::SetEverHadMixers();
	#endif



	xStream >> Asura_Sound_Mixer_System::s_pxInstance->m_fMasterVolume;
	u_int uNumChannels;
	xStream >> uNumChannels;

	//allocate channel array
	pxMixerInstance->m_xChannelsArray.Clear();
	pxMixerInstance->m_xChannelsArray.SetSize(uNumChannels);
		
	#ifdef ASURA_TOOLS
	//Prevents the channels array from being resized by the tools implementation of AddChannelToTree
	Asura_Sound_Mixer_System::s_bIsLoading = true;
	#endif


	for(u_int i=0;i<uNumChannels;i++)
	{
		char acName[128];
		xStream.ReadString(acName,sizeof(acName));
		// (MH - 28.03.2008) hacky way to detect code mixers. Should have a Tools tickbox and a flag in the chunk.
		bool bIsCodeMixer = !strnicmp(acName, "code_", 5);

		//allocate the channel and read the rest in
		Asura_Sound_Mixer_Channel* pxChannel = new Asura_Sound_Mixer_Channel(acName);
		pxChannel->m_bCodeMixer = bIsCodeMixer;
		pxMixerInstance->m_xChannelsArray[i] = pxChannel;

		//output mixer channel
		char szOutputMixer[128];
		xStream.ReadString(szOutputMixer,sizeof(szOutputMixer));
		pxChannel->SetOutputMixerName(szOutputMixer);

		Asura_Sound_Mixer_Channel_Settings xSettings;

		xStream >> xSettings.m_fVolume;
		xStream >> xSettings.m_xSurroundPan.m_fPan;
		xStream >> xSettings.m_xSurroundPan.m_fFade;
		xStream >> xSettings.m_bPanOverride;
		xStream >> xSettings.m_bMute;
		xStream >> xSettings.m_bSolo;

		// JAT 26/02/07 - for Version 1 and above get the ignore game speed pitch bool
		xSettings.m_bIgnoreGameSpeedPitch = false;
		xSettings.m_bUseDistanceFilter = true;
		xSettings.m_bUseReverb = true;

		if ( Version >= 1 )
		{
			xStream >> xSettings.m_bIgnoreGameSpeedPitch;
		}

		if ( Version >= 3 )
		{
			xStream >> xSettings.m_bUseReverb;
			xStream >> xSettings.m_bUseDistanceFilter;
		}

		if ( Version >= 4 )
		{
			xStream >> xSettings.m_bUseDoppler;
			xStream >> xSettings.m_bUseOcclusion;
		}

		if( Version == 5 )
		{
			// (AAM - 06.11.2008) Removed per-channel DSP
			xStream.Skip( sizeof( Asura_Hash_ID ) );
		}

		if( Version >= 7 )
		{
			xStream >> xSettings.m_bUseMasterDSP;
		}

		pxChannel->Set(xSettings,0.0f);
	}

	#ifdef ASURA_TOOLS
	Asura_Sound_Mixer_System::s_bIsLoading = false;
	#endif

	// load in the presets
	u_int uNumberOfPresets;
	xStream >> uNumberOfPresets;
	for (u_int u = 0; u < uNumberOfPresets; ++u)
	{
		char acName[128];
		xStream.ReadString(acName,sizeof(acName));

		Asura_Sound_Mixer_Preset* pxPreset = new Asura_Sound_Mixer_Preset(acName);	// Looks leaked... it's not... constructor registers it

		xStream >> pxPreset->m_fMasterVolume;
		
		u_int uNumPresetChannels;
		xStream >> uNumPresetChannels;
		pxPreset->m_xChannelsArray.SetSize(uNumPresetChannels);

		for (u_int uChannel = 0; uChannel < uNumPresetChannels; ++uChannel)
		{
			pxPreset->m_xChannelsArray[uChannel] = new Asura_Sound_Mixer_ChannelPreset();
#ifdef ASURA_SOUND_INCLUDE_TOOLS_DATA
			xStream >> pxPreset->m_xChannelsArray[uChannel]->m_xChannelName;
#else
			xStream.SkipString();
#endif
			xStream >> pxPreset->m_xChannelsArray[uChannel]->m_uChannelHashID;
			xStream >> pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_fVolume;;
			xStream >> pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_xSurroundPan.m_fPan;
			xStream >> pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_xSurroundPan.m_fFade;
			xStream >> pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bPanOverride;
			xStream >> pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bMute;
			xStream >> pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bSolo;

			// JAT 26/02/07 - for Version 1 and above get the ignore game speed pitch bool
			pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bIgnoreGameSpeedPitch = false;
			pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bUseReverb = true;
			pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bUseDistanceFilter = true;
			pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bUseDoppler = true;
			pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bUseOcclusion = true;
			pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bUseMasterDSP = true;

			if ( Version >= 1 )
			{
				xStream >> pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bIgnoreGameSpeedPitch;
			}

			if ( Version >= 3 )
			{
				xStream >> pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bUseReverb;
				xStream >> pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bUseDistanceFilter;
			}

			if ( Version >= 4 )
			{
				xStream >> pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bUseDoppler;
				xStream >> pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bUseOcclusion;
			}

			if( Version == 5 )
			{
				// (AAM - 06.11.2008) Removed per-channel DSP
				xStream.Skip( sizeof( Asura_Hash_ID ) );
			}

			if( Version >= 7 )
			{
				xStream >> pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bUseMasterDSP;
			}
		}

		if (Version >= 2)
		{
			xStream >> pxPreset->m_ucPriority;
			xStream >> pxPreset->m_fFadeInTime;
			xStream >> pxPreset->m_fFadeOutTime;
			xStream >> pxPreset->m_fLifeTime;
		}

		if (Version >= 6)
		{
			// (AAM - 06.11.2008) Added per-preset master DSP instead
			xStream >> pxPreset->m_uDSPChain;
		}
	}

	// set the "default" preset if there is one
	Asura_Sound_Mixer_System::SetPresetInternal( uMIXER_HASHID_DEFAULT, 0.0f );

	return true;
}

bool Asura_Chunk_SoundEvent_Mixer::Process(Asura_Handle iFileHandle) const
{
	Asura_Chunk_File_Stream	xStream(iFileHandle);
	return Process(xStream);
}

#ifdef ASURA_TOOLS
void Asura_Chunk_SoundEvent_Mixer::Create(Asura_Chunk_Stream& xStream)
{
	u_int uChunkFlags = 0;
	xStream.WriteChunk_Start( ASURA_CHUNK_SOUNDEVENT_MIXER, ASURA_CHUNK_SOUNDEVENT_MIXER_VERSION, uChunkFlags );

	u_int uNumChannels = Asura_Sound_Mixer_System::GetNumberOfChannels();

	xStream << Asura_Sound_Mixer_System::s_pxInstance->m_fMasterVolume;
	xStream << uNumChannels;

	List<const Asura_Sound_Mixer_Channel*> xChannelList;
	if(uNumChannels)
	{
		//Attempt to save the channels in an order that will result in a balanced tree on reload. RAR 17/08/2006
		for(Asura_TemplateHashTree_SaveIterator xIt(uNumChannels);!xIt.Done();xIt.Next())
		{
			const Asura_Sound_Mixer_Channel* pxInputChannel = 0;
			const Asura_Sound_Mixer_Channel* pxChannel = Asura_Sound_Mixer_System::GetChannelByIndex(xIt.GetCurrent());

			while(pxChannel && !xChannelList.contains(pxChannel))
			{
				if(pxInputChannel)
				{
					xChannelList.add_entry_before(pxChannel,pxInputChannel);
				}
				else
				{
					xChannelList.add_entry(pxChannel);
				}
				pxInputChannel = pxChannel;
				pxChannel = pxChannel->m_pxOutput;
			}
		}
			
		Asura_Assert(xChannelList.size() == (int)uNumChannels,"Error saving mixers");
	}

	for(LIF<const Asura_Sound_Mixer_Channel*> xChannelLIF(&xChannelList);!xChannelLIF.done();xChannelLIF.next())
	{
		const Asura_Sound_Mixer_Channel* pxChannel = xChannelLIF();

		xStream << pxChannel->m_xName;
		xStream << pxChannel->m_xOutputMixer;

		//Write out the destination of any fades , rather than the current values
		xStream << pxChannel->m_fFadeEndVolume;
		xStream << pxChannel->m_xSettings.m_xSurroundPan.m_fPan;
		xStream << pxChannel->m_xSettings.m_xSurroundPan.m_fFade;
		xStream << pxChannel->m_xSettings.m_bPanOverride;
		xStream << pxChannel->m_bFadeToMute;
		xStream << pxChannel->m_bFadeToSolo;

		// JAT 26/02/07 - for Version 1 and above get the ignore game speed pitch bool
		xStream << pxChannel->m_xSettings.m_bIgnoreGameSpeedPitch;

		// Version 3
		xStream << pxChannel->m_xSettings.m_bUseReverb;
		xStream << pxChannel->m_xSettings.m_bUseDistanceFilter;

		// Version 4
		xStream << pxChannel->m_xSettings.m_bUseDoppler;
		xStream << pxChannel->m_xSettings.m_bUseOcclusion;

		// Version 5
		// (AAM - 06.11.2008) Removed per-channel DSP

		// Version 7
		xStream << pxChannel->m_xSettings.m_bUseMasterDSP;
	}

	// write out the presets
	u_int uNumberOfPresets = Asura_Sound_Mixer_System::GetNumberOfPresets();
	xStream << uNumberOfPresets;
	for (u_int u = 0; u < uNumberOfPresets; ++u)
	{
		const Asura_Sound_Mixer_Preset* pxPreset = Asura_Sound_Mixer_System::GetPresetByIndex(u);
		xStream << pxPreset->m_xName;

		xStream << pxPreset->m_fMasterVolume;

		u_int uNumChannels = pxPreset->m_xChannelsArray.Size();
		xStream << uNumChannels;

		for (u_int uChannel = 0; uChannel < uNumChannels; ++uChannel)
		{
			xStream << pxPreset->m_xChannelsArray[uChannel]->m_xChannelName;
			xStream << pxPreset->m_xChannelsArray[uChannel]->m_uChannelHashID;
			xStream << pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_fVolume;;
			xStream << pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_xSurroundPan.m_fPan;
			xStream << pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_xSurroundPan.m_fFade;
			xStream << pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bPanOverride;
			xStream << pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bMute;
			xStream << pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bSolo;

			// JAT 26/02/07 - for Version 1 and above get the ignore game speed pitch bool
			xStream << pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bIgnoreGameSpeedPitch;

			// Version 3
			xStream << pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bUseReverb;
			xStream << pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bUseDistanceFilter;

			// Version 4
			xStream << pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bUseDoppler;
			xStream << pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bUseOcclusion;

			// Version 5
			// (AAM - 06.11.2008) Removed per-channel DSP

			// Version 7
			xStream << pxPreset->m_xChannelsArray[uChannel]->m_xSettings.m_bUseMasterDSP;
		}

		// PJC 27/09/07 - for Version 2 and above
		xStream << pxPreset->m_ucPriority;
		xStream << pxPreset->m_fFadeInTime;
		xStream << pxPreset->m_fFadeOutTime;
		xStream << pxPreset->m_fLifeTime;

		// Version 6
		xStream << pxPreset->m_uDSPChain;
	}

	xStream.WriteChunk_End();
}

void Asura_Chunk_SoundEvent_Mixer::Create(Asura_SaveBlock* pxSaveBlock)
{
	Asura_Chunk_SaveBlock_Stream xStream(pxSaveBlock);
	Create(xStream);
}


#endif // ASURA_TOOLS


/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*-------------------------------**
** Asura_Chunk_SoundEvent_Phonon **
**-------------------------------*/



#define ASURA_CHUNK_SOUNDEVENT_PHONON_VERSION 3

bool Asura_Chunk_SoundEvent_Phonon::Process(Asura_Chunk_Stream& xStream) const
{
	// Is this the correct version?

	if (Version > ASURA_CHUNK_SOUNDEVENT_PHONON_VERSION)
	{
		Asura_Assertf(false, ("Unknown chunk version %d for sound event phonone",Version));
		return false;
	}


	#ifdef ASURA_TOOLS
	bool bHasToolsData = (Flags & ChunkFlag_HasToolsData) ? true : false;
	if(!bHasToolsData)
	{
		Asura_Assertf(bHasToolsData,("Phonon chunk doesn't have tools data"));
		return false;
	}
	#endif

	int iNumberOfPhonons;
	xStream >> iNumberOfPhonons;
	
	for(int i=0; i<iNumberOfPhonons; i++)
	{
		Asura_Guid uGuid;
		xStream >> uGuid;

		#if defined(ASURA_USE_STREAMING) && !defined(ASURA_TOOLS)
		uGuid = Asura_Streaming_System::MakeCurrentMasterZoneGuid(uGuid);
		#endif	// defined(ASURA_USE_STREAMING) && !defined(ASURA_TOOLS)


		Asura_Phonon* pxPhonon = Asura_Phonon_System::AllocatePhonon(uGuid);
		if(pxPhonon)
		{
			ProcessSinglePhonon(pxPhonon,xStream);
			#ifdef ASURA_TOOLS
			Asura_Assert(!pxPhonon->BelongsToMissionFile() || Tools_SaveAsura::IsEditingMission(),"Found a phonon flagged as belonging to a mission while not editing a mission file.\nThis will be lost when the file is next saved.");
			#endif
		}
	}
		
	return true;
}

#ifdef ASURA_TOOLS
Asura_Phonon* Asura_Chunk_SoundEvent_Phonon::ProcessSinglePhonon(const char* pcChunkBuffer,Asura_Guid uOldGuid,Asura_Guid uNewGuid, bool bMissionFile) const
{
	// Is this the correct version?
	if (Version > ASURA_CHUNK_SOUNDEVENT_PHONON_VERSION)
	{
		Asura_Assertf(false, ("Unknown chunk version %d for sound event phonon",Version));
		return 0;
	}

	Asura_Chunk_Memory_Stream xStream(Size-sizeof(Asura_Chunk_SoundEvent_Phonon),pcChunkBuffer);

	int iNumberOfPhonons;
	xStream >> iNumberOfPhonons;

	//search for the desired phonon
	for(int i=0; i<iNumberOfPhonons; i++)
	{
		Asura_Guid uGuid;
		xStream >> uGuid;
		if(uGuid != uOldGuid)
		{
			//wrong guid, so extract into a temporary phonon to skip past it
			Asura_Phonon xTemp;
			xTemp.Initialise();
			ProcessSinglePhonon(&xTemp,xStream);
		}
		else
		{
			//This is the phonon we want
			Asura_Phonon* pxPhonon;
			if(uNewGuid == ASURA_GUID_UNREGISTERED)
				pxPhonon = Asura_Phonon_System::AllocatePhonon(bMissionFile);
			else
				pxPhonon = Asura_Phonon_System::AllocatePhonon(uNewGuid);

			if(pxPhonon) ProcessSinglePhonon(pxPhonon,xStream);

			return pxPhonon;
		}
	}

	//failed to find phonon
	return 0;

}
#endif

void Asura_Chunk_SoundEvent_Phonon::ProcessSinglePhonon(Asura_Phonon* pxPhonon,Asura_Chunk_Stream& xStream) const
{
	bool bHasToolsData = (Flags & ChunkFlag_HasToolsData) ? true : false;

    //Read in the event. Only bother storing the hash Id if in tools though.
    Asura_Hash_ID uEventHashID;
    xStream >> uEventHashID;
	#ifdef ASURA_TOOLS
	pxPhonon->m_uEventHashID = uEventHashID;
	#endif
	if(uEventHashID)
	{
		pxPhonon->m_pxEvent = Asura_Sound_Event_Storage::FindEvent(uEventHashID);
	}

	xStream >> pxPhonon->m_xPosition;
	#ifdef ASURA_TOOLS
	pxPhonon->m_xInitialPosition = pxPhonon->m_xPosition;
	#endif

	xStream >> pxPhonon->m_bUseOrient;
	xStream >> pxPhonon->m_xOrient;

	xStream >> pxPhonon->m_fInnerRadius;
	xStream >> pxPhonon->m_fOuterRadius;
    xStream >> pxPhonon->m_xInnerCuboidRadius;
    xStream >> pxPhonon->m_xOuterCuboidRadius;

	xStream >> pxPhonon->m_bUseCuboidFalloff;
	xStream >> pxPhonon->m_bStartsActive;
	xStream >> pxPhonon->m_bRetriggerable;

	xStream >> pxPhonon->m_bUseClipVolume;
	xStream >> pxPhonon->m_bInvertClipVolume;
	if(Version >= 2)
	{
		pxPhonon->m_pxClipVolume->ReadFromChunkStream(xStream);
	}
	else
	{
		//convert old volumes
		Asura_OrientedVolume xTempOrientedVolume;
		xStream >> xTempOrientedVolume.m_xBox;
		if(Version >= 1)
		{
			xStream >> xTempOrientedVolume.m_xOrient;
		}
		else
		{
			xTempOrientedVolume.m_xOrient = Asura_Maths::IdentityQuat;
		}
		if(pxPhonon->m_bUseClipVolume)
		{
			Asura_Volume_Cuboid* pxVolume = new Asura_Volume_Cuboid(xTempOrientedVolume.m_xBox, xTempOrientedVolume.m_xOrient);
			pxPhonon->m_pxClipVolume->AddVolume(pxVolume);
		}
	}

	xStream >> pxPhonon->m_bUseRetriggerRadius;
	xStream >> pxPhonon->m_fRetriggerRadius;

	xStream >> pxPhonon->m_bUseRetriggerBoundingBox;
	xStream >> pxPhonon->m_xRetriggerBoundingBox;

	if(bHasToolsData)
	{
		#ifdef ASURA_TOOLS
		xStream >> pxPhonon->m_uLightSets;
		xStream >> pxPhonon->m_uTemplateGuid;
		xStream >> pxPhonon->m_xName;
		if(Version >= 3) xStream >> pxPhonon->m_uPlatforms;
		#else
		xStream.Skip(8);//skip light sets and template guid
		xStream.SkipString();//skip name
		if(Version >= 3) xStream.Skip(4);//skip platforms
		#endif
	}

	pxPhonon->m_bIsActive = pxPhonon->m_bStartsActive;
	pxPhonon->m_bHasChanged = true;

	pxPhonon->CalculateLargestRadius();
}

bool Asura_Chunk_SoundEvent_Phonon::Process(Asura_Handle iFileHandle) const
{
	Asura_Chunk_File_Stream	xStream(iFileHandle);
	return Process(xStream);
}

#ifdef ASURA_TOOLS
void Asura_Chunk_SoundEvent_Phonon::Create(Asura_Chunk_Stream& xStream, bool bMissionFile)
{
	u_int uChunkFlags = 0;

	bool bSaveToolsData = !Tools_Level_Export::IsExport();
	if(bSaveToolsData) uChunkFlags |= ChunkFlag_HasToolsData;

	xStream.WriteChunk_Start(ASURA_CHUNK_SOUNDEVENT_PHONON, ASURA_CHUNK_SOUNDEVENT_PHONON_VERSION, uChunkFlags);

	int iNumberOfPhonons = Asura_Phonon_System::GetNumberOfPhonons();

	//Count the number of phonons to save. RAR 14/06/2006
	int iNumberToSave = 0;
	for(int i=0; i<iNumberOfPhonons; i++)
	{
		const Asura_Phonon * pxPhonon = Asura_Phonon_System::GetPhononByIndex(i);

        if(Tools_Level_Export::IsExport())
		{
			//Exclude phonons that aren't part of the current light set during level exports. RAR 14/06/2006
			if(!pxPhonon->IsMemberOfCurrentLightSet()) continue;
			if(!pxPhonon->IsEnabledForPlatform(Tools_Level_Export::s_eExportType)) continue;
		}
		else
		{
			//Exclude phonons according to whether they are in the mission or common file.
			//This distinction is ignored for level exports , since the single file for the export gets the phonons for both
			//RAR 16/01/2008
			if(bMissionFile != pxPhonon->BelongsToMissionFile()) continue;
		}
		iNumberToSave++;
	}
	xStream << iNumberToSave;

	//RAR 08/03/2006 For recentreing during level exports :
	const Asura_Vector_3& xPositionOffset = Tools_Level_Export::GetExportCentre();

	for(int i=0; i<iNumberOfPhonons; i++)
	{
		const Asura_Phonon * pxPhonon = Asura_Phonon_System::GetPhononByIndex(i);

        if(Tools_Level_Export::IsExport())
		{
			//Exclude phonons that aren't part of the current light set during level exports. RAR 14/06/2006
			if(!pxPhonon->IsMemberOfCurrentLightSet()) continue;
			if(!pxPhonon->IsEnabledForPlatform(Tools_Level_Export::s_eExportType)) continue;

		}
		else
		{
			//Exclude phonons according to whether they are in the mission or common file.
			//This distinction is ignored for level exports , since the single file for the export gets the phonons for both
			//RAR 16/01/2008
			if(bMissionFile != pxPhonon->BelongsToMissionFile()) continue;
		}


        xStream << static_cast<u_int>( pxPhonon->GetGuid() );

        xStream << pxPhonon->m_uEventHashID;
		xStream << pxPhonon->m_xInitialPosition - xPositionOffset;

		xStream << pxPhonon->m_bUseOrient;
		xStream << pxPhonon->m_xOrient;

		xStream << pxPhonon->m_fInnerRadius;
		xStream << pxPhonon->m_fOuterRadius;
        xStream << pxPhonon->m_xInnerCuboidRadius;
        xStream << pxPhonon->m_xOuterCuboidRadius;

		xStream << pxPhonon->m_bUseCuboidFalloff;
		xStream << pxPhonon->m_bStartsActive;
		xStream << pxPhonon->m_bRetriggerable;

		xStream << pxPhonon->m_bUseClipVolume;
		xStream << pxPhonon->m_bInvertClipVolume;

		if(xPositionOffset != Asura_Maths::ZeroVector3)
		{
			//make a copy of the volumes so they can be displaced
			Asura_VolumeGroup xClipVolumeCopy;
			xClipVolumeCopy.Copy(pxPhonon->m_pxClipVolume);
			xClipVolumeCopy.DisplaceVolumes(-xPositionOffset);
			xClipVolumeCopy.WriteToChunkStream(xStream);
		}
		else
		{
			pxPhonon->m_pxClipVolume->WriteToChunkStream(xStream);
		}

		xStream << pxPhonon->m_bUseRetriggerRadius;
		xStream << pxPhonon->m_fRetriggerRadius;

		xStream << pxPhonon->m_bUseRetriggerBoundingBox;
		Asura_Bounding_Box xBB = pxPhonon->m_xRetriggerBoundingBox;
		xBB.Displace(-xPositionOffset);
		xStream << xBB;


		if(bSaveToolsData)
		{
			xStream << pxPhonon->m_uLightSets;
			xStream << pxPhonon->m_uTemplateGuid;
			xStream << pxPhonon->m_xName;
			xStream << pxPhonon->m_uPlatforms;
		}
	}


	xStream.WriteChunk_End();
}

void Asura_Chunk_SoundEvent_Phonon::Create(Asura_SaveBlock* pxSaveBlock, bool bMissionFile)
{
	Asura_Chunk_SaveBlock_Stream xStream(pxSaveBlock);
	Create	(xStream, bMissionFile);
}
#endif // ASURA_TOOLS

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*---------------------------------------**
** Asura_Chunk_SoundEvent_GlobalSettings **
**---------------------------------------*/

#define ASURA_CHUNK_SOUNDEVENT_GLOBALSETTINGS_VERSION 0


bool Asura_Chunk_SoundEvent_GlobalSettings::Process(Asura_Chunk_Stream& xStream) const
{
	// Is this the correct version?

	if (Version > ASURA_CHUNK_SOUNDEVENT_GLOBALSETTINGS_VERSION)
	{
		Asura_Assertf(false, ("Unknown chunk version %d for global sound settings",Version));
		return false;
	}

	u_int uDefaultMaxInstances;
	xStream >> uDefaultMaxInstances;
	Asura_Sound_Event_System::SetDefaultMaxInstances(uDefaultMaxInstances);

	return true;
}

bool Asura_Chunk_SoundEvent_GlobalSettings::Process(Asura_Handle iFileHandle) const
{
	Asura_Chunk_File_Stream	xStream(iFileHandle);
	return Process(xStream);
}

#ifdef ASURA_TOOLS 

void Asura_Chunk_SoundEvent_GlobalSettings::Create(Asura_Chunk_Stream& xStream)
{
	u_int uChunkFlags = 0;
	xStream.WriteChunk_Start(ASURA_CHUNK_SOUNDEVENT_GLOBALSETTINGS, ASURA_CHUNK_SOUNDEVENT_GLOBALSETTINGS_VERSION, uChunkFlags);

	xStream << Asura_Sound_Event_System::GetDefaultMaxInstances();

	xStream.WriteChunk_End();
}

void Asura_Chunk_SoundEvent_GlobalSettings::Create(Asura_SaveBlock* pxSaveBlock)
{
	Asura_Chunk_SaveBlock_Stream xStream(pxSaveBlock);
	Create(xStream);
}


#endif // ASURA_TOOLS


/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*--------------------------------------------**
** Asura_Chunk_SoundEvent_ToolsGlobalSettings **
**--------------------------------------------*/

// TY - 10.02.09 - Version 1 -> added compression quality settings
// JCT - 16.03.09 - Version 2 -> Added memory limit
// RAR - 04.03.09 - Version 3 -> Added default compression quality
#define ASURA_CHUNK_SOUNDEVENT_TOOLSGLOBALSETTINGS_VERSION 3

#ifdef ASURA_TOOLS //Whole chunk is tools only

bool Asura_Chunk_SoundEvent_ToolsGlobalSettings::Process(Asura_Chunk_Stream& xStream) const
{
	// Is this the correct version?

	if (Version > ASURA_CHUNK_SOUNDEVENT_TOOLSGLOBALSETTINGS_VERSION)
	{
		Asura_Assertf(false, ("Unknown chunk version %d for tools global sound settings",Version));
		return false;
	}

	//Determine the number of platforms saved
	int iNumPlatforms;
	xStream >> iNumPlatforms;

	Asura_Assert(iNumPlatforms<=TOOLS_PLATFORM_NUM_PLATFORMS,"Unexpected number of platforms in global settings chunk");

	//load as much as we can
	int iNumToLoad = Asura_Maths::Min(iNumPlatforms,static_cast<int>(TOOLS_PLATFORM_NUM_PLATFORMS));
	for(int i=0;i<iNumToLoad;i++)
	{
		xStream >> Tools_SoundEvent_System::s_aiPlatformSampleRates[i];
	}
	//and skip any excess
	if(iNumPlatforms > iNumToLoad)
	{
		xStream.Skip(sizeof(int) * (iNumPlatforms - iNumToLoad));
	}

	if( Version >= 1 )
	{
		ASURA_STATIC_ASSERT( TSS_QUALITY_NUM_ENTRIES == 5 );

		for( int iPlat = 0; iPlat < iNumToLoad ; ++iPlat )
		{
			for( int iQual = 0; iQual < TSS_QUALITY_NUM_ENTRIES ; ++iQual )
			{
				xStream >> Tools_SoundEvent_System::s_aiPlatformCompressionRates[iPlat][iQual];
			}
		}

		//and skip any excess
		if(iNumPlatforms > iNumToLoad)
		{
			xStream.Skip( sizeof(int) * TSS_QUALITY_NUM_ENTRIES * (iNumPlatforms - iNumToLoad) );
		}
	}

	if( Version >= 2 )
	{
		xStream >> Tools_SoundEvent_System::s_uMemoryLimit;
	}

	if( Version >= 3 )
	{
		for( int iPlat = 0; iPlat < iNumToLoad ; ++iPlat )
		{
			xStream >> Tools_SoundEvent_System::s_aiPlatformCompressionQuality[iPlat];
		}

		//and skip any excess
		if(iNumPlatforms > iNumToLoad)
		{
			xStream.Skip( sizeof(int) * (iNumPlatforms - iNumToLoad) );
		}
	}


	return true;
}

bool Asura_Chunk_SoundEvent_ToolsGlobalSettings::Process(Asura_Handle iFileHandle) const
{
	Asura_Chunk_File_Stream	xStream(iFileHandle);
	return Process(xStream);
}

void Asura_Chunk_SoundEvent_ToolsGlobalSettings::Create(Asura_Chunk_Stream& xStream)
{
	u_int uChunkFlags = 0;
	xStream.WriteChunk_Start(ASURA_CHUNK_SOUNDEVENT_TOOLSGLOBALSETTINGS, ASURA_CHUNK_SOUNDEVENT_TOOLSGLOBALSETTINGS_VERSION, uChunkFlags);

	xStream << (int)TOOLS_PLATFORM_NUM_PLATFORMS;
	for(int i=0;i<TOOLS_PLATFORM_NUM_PLATFORMS;i++)
	{
		xStream << Tools_SoundEvent_System::s_aiPlatformSampleRates[i];
	}

	for( int iPlat = 0; iPlat < TOOLS_PLATFORM_NUM_PLATFORMS ; ++iPlat )
	{
		for( int iQual = 0; iQual < TSS_QUALITY_NUM_ENTRIES ; ++iQual )
		{
			xStream << Tools_SoundEvent_System::s_aiPlatformCompressionRates[iPlat][iQual];
		}
	}

	xStream << Tools_SoundEvent_System::s_uMemoryLimit;

	for( int iPlat = 0; iPlat < TOOLS_PLATFORM_NUM_PLATFORMS ; ++iPlat )
	{
		xStream << Tools_SoundEvent_System::s_aiPlatformCompressionQuality[iPlat];
	}

	xStream.WriteChunk_End();
}

void Asura_Chunk_SoundEvent_ToolsGlobalSettings::Create(Asura_SaveBlock* pxSaveBlock)
{
	Asura_Chunk_SaveBlock_Stream xStream(pxSaveBlock);
	Create(xStream);
}


#endif // ASURA_TOOLS

//eof
