   //
// Tools_Mode_Sound.cpp
//
// Created by Kevin Lea - 26/06/2001 16:14:18
// 
// Copyright (C) 2001 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"
#include "Sound/Tools_Mode_Sound.h"

#include "Camera/Asura_Camera.h"
#include "Core/Asura_NameTree.h"     // for used sound file list
#include "Core/Asura_TextureManagement.h"
#include "Core/Asura_UserInput.h"
#include "FileAccess/Asura_FileAccess.h"
#include "Interface/Asura_Cursor.h"
#include "Interface/Asura_Dialog.h"
#include "Interface/Asura_Menubar.h"
#include "Interface/Asura_Menubar_System.h"
#include "Interface/Asura_Overlay.h"
#include "Interface/Asura_Overlay_System.h"
#include "Mesh/Asura_Mesh.h"
#include "Rendering/Asura_Module.h"
#include "Rendering/Asura_Text_Output.h"
#include "Rendering/Asura_Viewport.h"
#include "Sound/Asura_Audio_System.h"
#include "Sound/Asura_ModuleReverb_System.h"
#include "Sound/Asura_Sound.h"
#include "Sound/Asura_Sound_Event_Storage.h"
#include "Sound/Asura_StreamingBackgroundSound_System.h"

#include "Mesh/Tools_PlatformMesh_System.h"
#include "Sound/Tools_Dialogue_System.h"


#include "BinkPC/bink.h"

#if defined( _WIN64)
	#undef BinkSoundUseDirectSound
	#define BinkSoundUseDirectSound( _A)
	
	#undef BinkGoto
	#define BinkGoto( _A, _B, _C)
	
	#undef BinkWait
	#define BinkWait( _A) (false)
	
	#undef BinkDoFrame
	#define BinkDoFrame( _A)
	
	#undef BinkNextFrame
	#define BinkNextFrame( _A)
	
	#undef BinkOpen
	#define BinkOpen( _A, _B) (NULL)
	
	#undef BinkClose
	#define BinkClose( _A)
	
	#undef BinkPause
	#define BinkPause( _A, _B)
	
	#undef BinkSetVolume
	#define BinkSetVolume( _A, _B, _C)
#endif


#include "Tools_System.h"
#include "Tools_Overlays.h"
#include "Entity/Tools_Entity_Object.h"
#include "Lighting/Tools_LightSets.h"
#include "Load&Save/Tools_SaveAsura.h"
#include "Load&Save/Tools_ModeDataFile.h"
#include "Load&Save/Tools_Sound_Export.h"
#include "Misc/Tools_Module_Selection.h"
#include "Misc/Tools_Timed_Messages.h"
#include "Misc/Tools_Modal_Overlay.h"
#include "Misc/Tools_Help.h"
#include "Misc/Tools_Render.h"
#include "Objects/Tools_Object_System.h"
#include "PC/FileSystem/Tools_FileSystem.h"
#include "Sound/Conversion/EncVag.h"//for BLKSIZ define
#include "Sound/Tools_PickSound.h"
#include "Sound/Tools_Phonon_Object.h"
#include "Sound/Tools_Sound_PS2Settings.h"
#include "Sound/Tools_StreamingBackgroundSound_Object.h"
#include "Sound/Tools_SoundEvent_System.h"
#include "Sound/Tools_PickSoundEvent_Overlay.h"
#include "Sound/Tools_SoundMixer_Overlay.h"
#include "Sound/Tools_Sound_System.h"
#include "Sound/Tools_SoundConversionPreview.h"
#ifdef ASURA_USE_REVERBVOLUME_SYSTEM
#include "Sound/Tools_ReverbVolume.h"
#endif



///////////////////////////////////////////////////////////////////////////////////////

Asura_Vector_2 Tools_Mode_Sound::ModeOverlayPosition;
Asura_Vector_2 Tools_Mode_Sound::PhononPropertiesOverlayPosition;
u_int Tools_Mode_Sound::s_uPhononPropertiesOverlayMinimised = 0;


List<Tools_Phonon_Object*> Tools_Mode_Sound::PhononList;

u_int Tools_Mode_Sound::s_PCSoundSize = 0;
u_int Tools_Mode_Sound::s_PS2SoundSize = 0;
u_int Tools_Mode_Sound::s_PS3SoundSize = 0;
u_int Tools_Mode_Sound::s_Xbox360SoundSize = 0;

bool Tools_Mode_Sound::AllFilesCounted;
bool Tools_Mode_Sound::s_bSoundSizeValid = false;
Asura_TemplateHashTree<ToolsSoundData>* Tools_Mode_Sound::s_pxSoundDataTree;


bool Tools_Mode_Sound::HideIcons;
bool Tools_Mode_Sound::ShowOuterRadius;
bool Tools_Mode_Sound::s_bIsInitialised = false;


int Tools_Mode_Sound::s_iCurrentReverbType = 0;
bool Tools_Mode_Sound::s_bHighlightCurrentReverb = true;

int Tools_Mode_Sound::s_iSubMode = Tools_Mode_Sound::SUBMODE_PHONON;
int Tools_Mode_Sound::s_iRequestedSubMode = Tools_Mode_Sound::SUBMODE_PHONON;

bool Tools_Mode_Sound::s_bChanged = false;

static const char* NoSoundSelectedText = "* No Sound Selected";
static const char* NoFilenameAvailableText = "* Filename not available";

static Asura_Handle g_iMenuHandle = ASURA_INVALID_HANDLE;

static bool g_bPlatformSampleRatesChanged;
static int g_aiPlatformSampleRates[TOOLS_PLATFORM_NUM_PLATFORMS];

static bool g_bPlatformCompressionQualityChanged = false;
static int g_aiDefaultPlatformCompressionQuality[TOOLS_PLATFORM_NUM_PLATFORMS];
static int g_aiPlatformCompressionQuality[TOOLS_PLATFORM_NUM_PLATFORMS][TSS_QUALITY_NUM_ENTRIES];

static bool g_bMemoryLimitChanged = false;
static u_int g_MemoryLimit = 30;	// in MB

float Tools_Mode_Sound::s_fSBSDefaultVolume;
Asura_Hash_ID Tools_Mode_Sound::s_uSBSDefaultMixer;
bool Tools_Mode_Sound::s_bSBSPerLightSetFlagChanged = false;
bool Tools_Mode_Sound::s_bLightSetChanged = false;

#ifdef ASURA_USE_REVERBVOLUME_SYSTEM
Tools_ReverbVolume_Editor* Tools_Mode_Sound::s_pxReverbVolumeEditor;
#endif

///////////////////////////////////////////////////////////////////////////////////////

// AUDIOTODO: This reverb stuff can all go

#ifndef ASURA_USE_AUDIO_SYSTEM

static const int g_iNumberOfReverbTypes = Asura_Sound_System::ASURA_REVERB_ID_MAX;

static int g_aiReverbTypeValues[g_iNumberOfReverbTypes] = 
{
	Asura_Sound_System::ASURA_REVERB_ID_NONE,
	Asura_Sound_System::ASURA_REVERB_ID_STONEROOM,
	Asura_Sound_System::ASURA_REVERB_ID_ROOM,
	Asura_Sound_System::ASURA_REVERB_ID_AUDITORIUM,
	Asura_Sound_System::ASURA_REVERB_ID_STONECORRIDOR,
	Asura_Sound_System::ASURA_REVERB_ID_HALLWAY,
	Asura_Sound_System::ASURA_REVERB_ID_SEWERPIPE,
};

static const char* g_apszReverbTypeNames[g_iNumberOfReverbTypes] =
{
	"none",
	"small room",
	"medium room",
	"large room",
	"small hall",
	"medium hall",
	"pipe",
};

#endif // #ifndef ASURA_USE_AUDIO_SYSTEM

static const char* g_apszSoundModeHelpStrings [] =
{
	"Reverb Editing :",
	"",
	"F :           Apply the current reverb type to selected modules",
	"Shift+F :     Reset reverb to default on selected modules",
	"9 :           Previous reverb type",
	"0 :           Next reverb type",
	NULL
};

const char* g_aszCompressionQualityStrings[] =	// This should match the TOOLS_SOUND_SAMPLE_QUALITY enum
{
	"Perfect",
	"High",
	"Medium",
	"Low",
	"Very Low"
};

///////////////////////////////////////////////////////////////////////////////////////

void Tools_Mode_Sound::QuickSave(void)
{
	Tools_SaveAsura::SaveSounds();
	Tools_SoundEvent_System::SaveModified();
}

bool Tools_Mode_Sound::IsModified()
{
	if(Tools_SoundEvent_System::IsModified()) return true;
	#ifdef ASURA_USE_DIALOGUE_SYSTEM
	if(Tools_Dialogue_System::IsModified()) return true;
	#endif
	
	return Tools_SaveAsura::IsSoundsModified();
}

void Tools_Mode_Sound::Initialise(void)
{
	HideIcons = false;
	ShowOuterRadius = true;

	s_iSubMode = SUBMODE_PHONON;
	s_iRequestedSubMode = SUBMODE_PHONON;

    // Create the menubar.
    g_iMenuHandle = Asura_Menubar_System::CreateMenuSection();
    Asura_Menubar_Title* title;

    title = Asura_Menubar_System::AddTitle( g_iMenuHandle, "Overlays" );
    title->AddItem( "Module Selection", Tools_Module_Selection::ToggleSelectionOverlay, Tools_Module_Selection::SelectionOverlayIsOn,IsReverbEditing );

	s_pxSoundDataTree = new Asura_TemplateHashTree<struct ToolsSoundData>;
	
	Tools_Mode_Sound::ModeOverlayPosition = Asura_Vector_2(0,3);
	Tools_Mode_Sound::PhononPropertiesOverlayPosition = Asura_Vector_2(30,20);

	for( int iPlat = 0; iPlat < TOOLS_PLATFORM_NUM_PLATFORMS; iPlat++ )
	{
		g_aiPlatformSampleRates[iPlat] = Tools_SoundEvent_System::GetPlatformSampleRate(iPlat);

		g_aiDefaultPlatformCompressionQuality[iPlat] = Tools_SoundEvent_System::GetDefaultPlatformCompressionQuality(iPlat);
	
		for( int iQual = 0; iQual < TSS_QUALITY_NUM_ENTRIES; ++iQual )
		{
			g_aiPlatformCompressionQuality[ iPlat ][ iQual ] = Tools_SoundEvent_System::GetPlatformCompressionQuality( iPlat, iQual );
		}
	}

	g_MemoryLimit = Tools_SoundEvent_System::GetMemoryLimit();

	#ifdef ASURA_USE_REVERBVOLUME_SYSTEM
	s_pxReverbVolumeEditor = new Tools_ReverbVolume_Editor();
	#endif

	//load values from .dat file
	TransferModeData(TOOLSMODEDATAFILE_LOAD);

	#ifdef ASURA_USE_DIALOGUE_SYSTEM
	if(Tools_Dialogue_System::OverlayShouldBeOpen()) Tools_Dialogue_System::CreateOverlay();
	#endif

	CreateSoundModeOverlay();

	Tools_Object_System::EnableAllControls(true);

	//create tools objects for each phonon
    CreatePhononToolsObjects();
       
//	Tools_Entity_Object::CreateAllObjects();
//	HideEntities(true);

	UpdateSoundSize();

    s_bIsInitialised = true;

	//add help
	Tools_Help::AddHelpTopic("Sound Mode",g_apszSoundModeHelpStrings);

	static bool s_bFirstTime = true;
	if(s_bFirstTime)
	{
		s_bFirstTime = false;
		//RAR 13/09/2006 Check for sound event errors if this is the first time in sound mode
		Tools_SoundEvent_System::Verify(true);
	}

	//Warn if any of the mute options are in place
	if(Tools_Sound_System::AreAnyMixersMuted() || Tools_Sound_System::IsMutePhonon() || Tools_Sound_System::IsMuteStreaming() || Tools_Sound_System::IsDontLoadWavs())
	{
		char szMessage[500] = "Warning.\nThe following mute options are enabled :\n";
		if(Tools_Sound_System::AreAnyMixersMuted()) strcat(szMessage,"Some mixers are muted.\n");
		if(Tools_Sound_System::IsMuteStreaming()) strcat(szMessage,"Mute streaming.\n");
		if(Tools_Sound_System::IsMutePhonon()) strcat(szMessage,"Mute phonons.\n");
		if(Tools_Sound_System::IsDontLoadWavs()) strcat(szMessage,"Dont load wavs.\n");
		ShowMessageOverlay(szMessage);		
	}


}

void Tools_Mode_Sound::CreatePhononToolsObjects()
{
	if(PhononList.size())
	{
		//already created
		Asura_Assert(PhononList.size() == Asura_Phonon_System::GetNumberOfPhonons(),"Phonon list out of sync");
		return;
	}

	
	for(int i=0;i<Asura_Phonon_System::GetNumberOfPhonons();i++)
	{
		new Tools_Phonon_Object(Asura_Phonon_System::GetPhononByIndex(i));
	}

	Tools_Phonon_Object::RemoveDudSoundControllers();
}

void Tools_Mode_Sound::Shutdown(void)
{
	ChangeSubMode(SUBMODE_PHONON);//revert back to phonon placement before shutting down

	#ifdef ASURA_USE_REVERBVOLUME_SYSTEM
	delete s_pxReverbVolumeEditor;
	s_pxReverbVolumeEditor = 0;
	#endif


	//save values to .dat file
	TransferModeData(TOOLSMODEDATAFILE_SAVE);
	
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_MODE);
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_PHONONPROPERTIES);
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_VOLUMESCALE);

	#ifdef ASURA_USE_DIALOGUE_SYSTEM
	Tools_Dialogue_System::CloseOverlays();
	#endif


	Tools_Object_System::DeleteAllModeSpecific();
    //DestroyPhononToolsObjects();

	delete s_pxSoundDataTree;
	s_pxSoundDataTree = 0;

	Tools_Object_System::EnableAllControls(false);


//	Tools_System::ModeExit();
    s_bIsInitialised = false;

    //shutdown the menu
	if( g_iMenuHandle != ASURA_INVALID_HANDLE )
	{
		Asura_Menubar_System::DestroyMenuSection( g_iMenuHandle );
		g_iMenuHandle = ASURA_INVALID_HANDLE;
	}

	Tools_Help::RemoveHelpTopic("Sound Mode");

}

void Tools_Mode_Sound::DestroyPhononToolsObjects()
{
	//clear out the phonon object list
	while(PhononList.size())
	{
		Tools_Object_System::DeleteObject(PhononList.first_entry());
	}
}

void Tools_Mode_Sound::Update()
{
	if(g_bPlatformSampleRatesChanged)
	{
		g_bPlatformSampleRatesChanged = false;
		//update copies in tools sound event system
		for(int i=0;i<TOOLS_PLATFORM_NUM_PLATFORMS;i++)
		{
			Tools_SoundEvent_System::SetPlatformSampleRate(i,g_aiPlatformSampleRates[i]);
		}
		Tools_SoundEvent_System::SetGlobalSettingsModified();
		InvalidateSoundSize();
	}

	if(g_bPlatformCompressionQualityChanged)
	{
		g_bPlatformCompressionQualityChanged = false;
		//update copies in tools sound event system
		for( int iPlat = 0; iPlat < TOOLS_PLATFORM_NUM_PLATFORMS; ++iPlat )
		{
			Tools_SoundEvent_System::SetDefaultPlatformCompressionQuality(iPlat, g_aiDefaultPlatformCompressionQuality[ iPlat ] );
			for( int iQual = 0; iQual < TSS_QUALITY_NUM_ENTRIES; ++iQual )
			{
				Tools_SoundEvent_System::SetPlatformCompressionQuality(iPlat, iQual, g_aiPlatformCompressionQuality[ iPlat ][ iQual ] );
			}
		}
		Tools_SoundConversionPreview::InvalidateFiles();
		Tools_SoundEvent_System::SetGlobalSettingsModified();
		InvalidateSoundSize();
	}

	if (g_bMemoryLimitChanged)
	{
		g_bMemoryLimitChanged = false;
		Tools_SoundEvent_System::SetMemoryLimit(g_MemoryLimit);
		Tools_SoundEvent_System::SetGlobalSettingsModified();
		InvalidateSoundSize();
	}

	if(s_iSubMode != s_iRequestedSubMode)
	{
		//switch to/from reverb editing
		ChangeSubMode(s_iRequestedSubMode);
	}
	if(!s_bSoundSizeValid)
	{
		UpdateSoundSize();
	}

	HandleKeyboard();

	

	if(s_bLightSetChanged)
	{
		if(s_iSubMode == SUBMODE_BACKGROUNDSOUND)
		{
			//get new values for the default sound
			CopyDefaultSBSFromAsura();

		}
		s_bLightSetChanged = false;
	}

	if(s_bSBSPerLightSetFlagChanged)
	{
		CopyDefaultSBSFromAsura();
		s_bSBSPerLightSetFlagChanged = false;
	}


	if(s_iSubMode == SUBMODE_REVERB)
	{
	    #ifdef ASURA_USE_REVERBVOLUME_SYSTEM
		s_pxReverbVolumeEditor->Update();
		#else
	    Tools_Module_Selection::Update();
		#endif
	}

	if(s_bChanged)
	{
		if(s_iSubMode == SUBMODE_BACKGROUNDSOUND)
		{
			//copy values back into asura data
			CopyDefaultSBSToAsura();
		}
        
        Tools_SaveAsura::SetSoundsModified();
		s_bChanged = false;
	}
	

	//update visibility of phonon objects
	Tools_Object_System::SetTypeHidden(TOT_Phonon,ObjectHideFlag_Mode,HideIcons || s_iSubMode == SUBMODE_BACKGROUNDSOUND);

	#ifdef ASURA_USE_DIALOGUE_SYSTEM
	Tools_Dialogue_System::Update();
	#endif

}

void Tools_Mode_Sound::HandleKeyboard()
{
	if(Asura_Overlay_System::OverlaysHaveKeyboardFocus()) return;
	if(Asura_UserInput::KeyPressed(ASURA_KEYID_ALT)) return;

	if(s_iSubMode == SUBMODE_REVERB)
	{
		#if !defined(ASURA_USE_REVERBVOLUME_SYSTEM) && !defined(ASURA_USE_AUDIO_SYSTEM)
		if(Asura_UserInput::KeyPressed(ASURA_KEYID_CTRL))
		{
		}
		if(Asura_UserInput::KeyPressed(ASURA_KEYID_SHIFT))
		{
			if(Asura_UserInput::DebouncedKeyPressed('f'))// 'Shift + F' remove reverb
			{
				RemoveReverb();
			}
		}
		else
		{
			if(Asura_UserInput::DebouncedKeyPressed('f'))// 'F' Apply reverb
			{
				ApplyReverb();
			}
			if(Asura_UserInput::DebouncedKeyPressed('9'))
			{
				PreviousReverbType();
			}
			if(Asura_UserInput::DebouncedKeyPressed('0'))
			{
				NextReverbType();
			}
		}
		#endif //ifndef ASURA_USE_REVERBVOLUME_SYSTEM
	}
	else
	{
	}
}

void Tools_Mode_Sound::RenderWorld_PostToneMap(void)
{
	if(s_iSubMode == SUBMODE_REVERB)
	{
		#ifdef ASURA_USE_REVERBVOLUME_SYSTEM
		s_pxReverbVolumeEditor->RenderWorld();
		#else
		//highlight modules with current reverb type
		if(s_bHighlightCurrentReverb)
		{
			for(int i=0;i<Asura_Module_System::GetNumberOfModules();i++)
			{
				if(Asura_ModuleReverb_System::GetModuleReverbType(i)==s_iCurrentReverbType)
				{
		        	Tools_Render::RenderMeshOutline( i, 0xFF00FF00u );
				}
			}
		}

		Tools_Module_Selection::Render();
		#endif
	}
}

void Tools_Mode_Sound::RenderUI(void)
{
	if(s_iSubMode == SUBMODE_REVERB)
	{
		#ifdef ASURA_USE_REVERBVOLUME_SYSTEM
		s_pxReverbVolumeEditor->RenderUI();
		#elif !defined(ASURA_USE_AUDIO_SYSTEM)
	    //show information on module that the cursor is over
    	
		int iModuleIndex = Tools_Module_Selection::GetHighlitModule();
		if(iModuleIndex>=0)
		{
			const Asura_Mesh* pxModuleMesh = Asura_Module_System::GetMeshForModule( iModuleIndex );

			float x,y;
			Asura_Cursor::GetScreenCoords(x,y);
			x++;
			y--;

			Asura_Text_Output::Print( x, y++, 0xff00ff00, 0, "%s", pxModuleMesh->Name.GetString() );

			const char* pszReverbText = GetReverbTypeName(Asura_ModuleReverb_System::GetModuleReverbType(iModuleIndex));
			Asura_Text_Output::Print(x,y++,0xff00ff00,0,"%s", pszReverbText);
		}
		#endif
	}
	
	float printx = (float)Asura_Viewport::GetWidth()/2;
	float printy = 0;
	Asura_Text_Output::ConvertPixelsToPrintCoords(printx,printy);
	printy+=3.0f;

	unsigned int uColour = 0xffffffff;
	const unsigned int uColourWhite = 0xffffffff;
	const unsigned int uColourRed = 0xffff0000;

	u_int iProjectMemLimit = Tools_SoundEvent_System::GetMemoryLimit() * 1024 * 1024;

	uColour = (s_PCSoundSize > iProjectMemLimit) ? uColourRed : uColourWhite;
	Asura_Text_Output::Print(printx,printy,uColour,ASURA_TEXT_FORMAT_RIGHTJUSTIFIED,"PC Sounds :");
	Asura_Text_Output::Print(printx,printy++,uColour,ASURA_TEXT_FORMAT_LEFTJUSTIFIED," %d%s k",s_PCSoundSize/1024,AllFilesCounted ? "" : "+");

	#ifdef ASURA_USE_AUDIO_SYSTEM
	uColour = (s_PS3SoundSize > iProjectMemLimit) ? uColourRed : uColourWhite;
	Asura_Text_Output::Print(printx,printy,uColour,ASURA_TEXT_FORMAT_RIGHTJUSTIFIED,"PS3 Sounds :");
	Asura_Text_Output::Print(printx,printy++,uColour,ASURA_TEXT_FORMAT_LEFTJUSTIFIED," %d%s k",s_PS3SoundSize/1024,AllFilesCounted ? "" : "+");

	uColour = (s_Xbox360SoundSize > iProjectMemLimit) ? uColourRed : uColourWhite;
	Asura_Text_Output::Print(printx,printy,uColour,ASURA_TEXT_FORMAT_RIGHTJUSTIFIED,"Xbox 360 Sounds :");
	Asura_Text_Output::Print(printx,printy++,uColour,ASURA_TEXT_FORMAT_LEFTJUSTIFIED," %d%s k",s_Xbox360SoundSize/1024,AllFilesCounted ? "" : "+");
	#else
	uColour = (s_PS2SoundSize > iProjectMemLimit) ? uColourRed : uColourWhite;
	Asura_Text_Output::Print(printx,printy,uColour,ASURA_TEXT_FORMAT_RIGHTJUSTIFIED,"PS2 Sounds :");
	Asura_Text_Output::Print(printx,printy++,uColour,ASURA_TEXT_FORMAT_LEFTJUSTIFIED," %d%s k",s_PS2SoundSize/1024,AllFilesCounted ? "" : "+");
	#endif
	
}

void Tools_Mode_Sound::TransferModeData(int mode)
{
	//open the file
	Tools_ModeDataFile file("PhononMode.dat",mode);

	//tranfer the data
	//(none of these should be removed , and new data should go on the end, otherwise
	//the files will get screwed up)
	file.Transfer(ModeOverlayPosition);
	file.Transfer(PhononPropertiesOverlayPosition);
}




void Tools_Mode_Sound::CreateSoundModeOverlay(void)
{
	Asura_Overlay* pxOverlay;
	pxOverlay = new Asura_Overlay("Sound Mode",false,&ModeOverlayPosition);
	Asura_Vector_2 xOffset = Asura_Vector_2(1.0f,3.0f);
	
	Asura_Dialog* pxDialog;

	for(u_int i=0; i<Tools_LightSets::GetNumGroups(); i++)
	{
		pxDialog = new Tools_LightSet_Dialog(xOffset,i,0,&s_bLightSetChanged, Tools_LightSets::GetGroupName(i));
		pxDialog->SetHelpText("Sets the current light set to view. Sounds that aren't members of the set will be muted.\nOnly light sets that have been marked as used can be selected.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::DefaultSpacing();
	}
	xOffset.y += Asura_Dialog::LargeSpacing() - Asura_Dialog::DefaultSpacing();

	Tools_PlatformMesh_System::AddOverlayControls(pxOverlay, xOffset);
	xOffset.y += Asura_Dialog::LargeSpacing() - Asura_Dialog::DefaultSpacing();
	
	//Tab control
	Asura_Tabs_Dialog* pxTabsDialog = new Asura_Tabs_Dialog(xOffset,0,0);
	pxOverlay->AddDialog(pxTabsDialog);
	xOffset.y = pxTabsDialog->m_xMaxCoord.y + 1.0f;

	//redirect all subsequent dialogs to the tab dialog
	pxOverlay->SetCurrentParentDialog(pxTabsDialog);	
	
	float fTabsStartY = xOffset.y;
	float fTabsEndY = xOffset.y;

	//Main Tab
	pxTabsDialog->AddTab("Main");

	static char* s_apszSubModeStrings[] =
	{
		"Phonon",
		"Reverb",
		"Streaming Sound",
	};

	static char* s_apszSubModeHelpStrings[] =
	{
		"Submode for placing sounds in the environment.",
		"Submode for editing reverb settings on modules.",
		"Submode for defining streaming background sounds.",

	};
	static int s_iSubModeListOffset = 0;

	pxDialog = new Asura_Dialog("Submode :",xOffset);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += 1.0f;

	Asura_List_Dialog* pxList = new Asura_List_Dialog(xOffset,s_apszSubModeStrings,&s_iSubModeListOffset,&s_iRequestedSubMode,SUBMODE_NUMSUBMODES,SUBMODE_NUMSUBMODES,NULL);
	pxDialog = pxList;
	pxList->SetListHelpStrings(s_apszSubModeHelpStrings);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += 5.0f;


	


	if(s_iSubMode == SUBMODE_REVERB)
	{
		#if !(defined ASURA_USE_REVERBVOLUME_SYSTEM) && !(defined ASURA_USE_AUDIO_SYSTEM)
		pxDialog = new Asura_Tickbox_Dialog("Highlight Current Reverb",xOffset,&(Tools_Mode_Sound::s_bHighlightCurrentReverb));
		pxDialog->SetHelpText("Highlight all modules using the current reverb setting with a green outline.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Function_Dialog("",xOffset,SelectDefaultReverbType);
		pxDialog->SetHelpText("Select the default reverb type that will be used in all modules that haven't had a specific one set..");
		pxDialog->m_iControlID = DialogID_DefaultReverb;
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Function_Dialog("",xOffset,SelectCurrentReverbType);
		pxDialog->SetHelpText("Change the currently selected reverb type.");
		pxDialog->m_iControlID = DialogID_CurrentReverb;
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::DefaultSpacing();
		#endif
	
	}
	else if(s_iSubMode == SUBMODE_PHONON)
	{
		pxDialog = new Asura_Tickbox_Dialog("Hide Icons",xOffset,&(Tools_Mode_Sound::HideIcons));
		pxDialog->SetHelpText("Hide the icons/objecs that are used for the placed sounds.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::DefaultSpacing();
		
		pxDialog = new Asura_Tickbox_Dialog("Show Range",xOffset,&(Tools_Mode_Sound::ShowOuterRadius));
		pxDialog->SetHelpText("Draws a sphere/cube showing the extents of the selected sound.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::DefaultSpacing();

		xOffset.y+=0.25f;



		Tools_SoundEvent_System::AddOverlayControls(pxOverlay,xOffset);
		xOffset.y += Asura_Dialog::LargeSpacing()-Asura_Dialog::DefaultSpacing();


		pxDialog = new Asura_Function_Dialog("Create Phonon",xOffset,CreatePhonon);
		pxDialog->SetHelpText("Create and select a new phonon.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::DefaultSpacing();

		Tools_Object_System::AddMissionFileTickbox(pxOverlay, xOffset);


		pxDialog = new Asura_Function_Dialog("Find By Event",xOffset,FindPhononsByEvent);
		pxDialog->SetHelpText("Find all placed sounds using a specified event.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Function_Dialog("Find Ref. To Wav",xOffset,FindReferencesToWav);
		pxDialog->SetHelpText("Finds samples and events that use a specified wav file.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Function_Dialog("Find Unused Events",xOffset,Tools_SoundEvent_System::FindUnusedEventsAndSamples);
		pxDialog->SetHelpText("This scans through the exports in a specified directory and determines which events and samples aren't used by them.");
		pxOverlay->AddDialog(pxDialog);

		xOffset.x = pxDialog->m_xMaxCoord.x + 1.0f;
		pxDialog = new Asura_Function_Dialog("Delete",xOffset,Tools_SoundEvent_System::DeleteUnusedEventsAndSamples);
		pxDialog->SetIsEnabledFunction(Tools_SoundEvent_System::IsEnabled_DeleteUnusedEventsAndSamples);
		pxDialog->SetHelpText("Deletes the events and samples found by the previous use of 'Find Unused Events'");
		pxOverlay->AddDialog(pxDialog);
		xOffset.x = 1.0f;
		xOffset.y+=Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Function_Dialog("Delete Unused Samples",xOffset,Tools_SoundEvent_System::DeleteUnusedSamples);
		pxDialog->SetHelpText("This will delete any samples that aren't used by any sound events.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::LargeSpacing();



		Tools_Object_System::AddCopyOverlayControls(pxOverlay,xOffset);

		xOffset.y+=Asura_Dialog::LargeSpacing()-Asura_Dialog::DefaultSpacing();
		pxDialog = new Asura_Function_Dialog("Verify",xOffset,VerifySoundEvent);
		pxDialog->SetHelpText("Checks for any problems with the sound events");
		pxOverlay->AddDialog(pxDialog);

		xOffset.y+=Asura_Dialog::DefaultSpacing();
		pxDialog = new Asura_Function_Dialog("Find Missing Files",xOffset,Tools_SoundEvent_System::FindWavFiles);
		pxDialog->SetHelpText("Searches for any missing wav files used by samples to see if they can be found in another directory.");
		pxOverlay->AddDialog(pxDialog);




	}
	else if(s_iSubMode == SUBMODE_BACKGROUNDSOUND)
	{
		//copy values for deafult sound
		CopyDefaultSBSFromAsura();


		
		pxDialog = new Asura_Function_Dialog("",xOffset,SelectDefaultStreamingSound);
		pxDialog->SetHelpText("Select the sound to be played when not in any streaming sound volume.");
		pxDialog->m_iControlID = DialogID_Filename;
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Function_Dialog("Clear Default",xOffset,ClearDefaultStreamingSound);
		pxDialog->SetHelpText("Clear the default sound.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_Numerical_Dialog("Volume",xOffset,&s_fSBSDefaultVolume,0.01f,1.5f,0.01f,"%.02f",&s_bChanged);
		pxDialog->SetHelpText("Volume for the default sound.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::DefaultSpacing();

		pxDialog = new Tools_SoundMixerHash_Dialog(xOffset,8,&s_uSBSDefaultMixer,&s_bChanged);
		pxDialog->SetHelpText("The mixer to use for the default sound.\nIf set to *Default* then the 'Streaming Sounds' mixer will be used");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::LargeSpacing();

		pxDialog = new Asura_FlagTickbox_Dialog("Stop During Music",xOffset,&Asura_StreamingBackgroundSound_System::s_uFlags,ASURA_STREAMINGSOUNDSYSTEMFLAG_STOPDURINGMUSIC,&s_bChanged);
		pxDialog->SetHelpText("Stops all streaming background sounds whenever music starts playing.\nIf not checked , then sounds may still be stopped if needed to release enough sound handles for the music.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::DefaultSpacing();

		pxDialog = new Asura_FlagTickbox_Dialog("Default Per Light Set",xOffset,&Asura_StreamingBackgroundSound_System::s_uFlags,ASURA_STREAMINGSOUNDSYSTEMFLAG_DEFAULTPERLIGHTSET,&s_bSBSPerLightSetFlagChanged);
		pxDialog->SetHelpText("If ticked then the properties for the default sound are set seperately for each light set.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::LargeSpacing();

			  
		
		pxDialog = new Asura_Function_Dialog("Create Streaming Sound",xOffset,Tools_StreamingBackgroundSound_Object::Create);
		pxDialog->SetHelpText("Create and select a new background streaming sound.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::LargeSpacing();

		Tools_Object_System::AddCopyOverlayControls(pxOverlay,xOffset);

		xOffset.y+=Asura_Dialog::LargeSpacing() - Asura_Dialog::DefaultSpacing();
		pxDialog = new Asura_Function_Dialog("Write Report", xOffset, WriteStreamingSoundReport);
		pxDialog->SetHelpText("Writes a text file listing the streaming sounds used in the environment");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();

	}

	//End of main tab
	if(xOffset.y > fTabsEndY) fTabsEndY = xOffset.y;

	//Sample rates tab
	pxTabsDialog->AddTab("Sample Quality");
	xOffset.y = fTabsStartY;

	for(int i=0;i<TOOLS_PLATFORM_NUM_PLATFORMS;i++)
	{
		if(Tools_SoundEvent_System::DoesPlatformUseSampleRate(i))
		{
			pxDialog = new Asura_Numerical_Dialog(Tools_Platform::GetPlatformName(i),xOffset,&g_aiPlatformSampleRates[i], 1,99999,1,"%d",&g_bPlatformSampleRatesChanged);
			pxDialog->SetHelpText("The default maximum sample rate to use when exporting sounds to this platform");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();
		}
	}

	// Compression quality
	for(int iPlat = 0; iPlat < TOOLS_PLATFORM_NUM_PLATFORMS; ++iPlat )
	{
		if( Tools_SoundEvent_System::DoesPlatformUseCompressionQuality( iPlat ) )
		{
			xOffset.y+=Asura_Dialog::LargeSpacing();

			Asura_String xPrompt = Asura_String( "Compression quality (" ) + Tools_Platform::GetPlatformName( iPlat ) + Asura_String( ")" );
			pxDialog = new Asura_Dialog( xPrompt.GetString(), xOffset );
			pxOverlay->AddDialog( pxDialog );

			int iLowerRange = 0;
			int iUpperRange = 0;

			switch( iPlat )
			{
				case TOOLS_PLATFORM_XBOX360:	
				{
					xPrompt = "Value is xma 'quality' (0 - 100)";
					iLowerRange = 0;
					iUpperRange = 100;
				}
				break;

				case TOOLS_PLATFORM_PS3:
				{
					xPrompt = "Value is MP3 kbps (32 - 320)";
					iLowerRange = 32;
					iUpperRange = 320;
				}
				break;

				default:
				{
					xPrompt = "";
				}
			}

			if( !xPrompt.IsBlank() )
			{
				xOffset.y+=Asura_Dialog::DefaultSpacing();
				pxDialog = new Asura_Dialog( xPrompt.GetString(), xOffset );
				pxOverlay->AddDialog( pxDialog );
			}

			xOffset.y+=Asura_Dialog::DefaultSpacing();

			xOffset.x += 1.0f;
			pxDialog = new Asura_DropDown_List_Dialog	( xOffset
														, g_aszCompressionQualityStrings
														, &g_aiDefaultPlatformCompressionQuality[iPlat]
														, TSS_QUALITY_NUM_ENTRIES
														, TSS_QUALITY_NUM_ENTRIES
														, 0
														, &g_bPlatformCompressionQualityChanged
														, "Default" );
			pxDialog->SetHelpText("This defines the compression quality to use for any samples that have been set to use the default");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::LargeSpacing();
			xOffset.x -= 1.0f;



			for( int iQual = 0; iQual < TSS_QUALITY_NUM_ENTRIES; ++iQual )
			{
				pxDialog = new Asura_Numerical_Dialog	( g_aszCompressionQualityStrings[iQual]
														, xOffset
														, &g_aiPlatformCompressionQuality[iPlat][iQual]
														, iLowerRange
														, iUpperRange
														, 1
														, "%d"
														, &g_bPlatformCompressionQualityChanged );
				pxDialog->SetHelpText("The platform specific compression quality to use for this setting");
				pxOverlay->AddDialog(pxDialog);
				xOffset.y+=Asura_Dialog::DefaultSpacing();
			}
		}
	}

	//End of Sample rate tab
	if(xOffset.y > fTabsEndY) fTabsEndY = xOffset.y;

	// Memory Limit tab
	{
		pxTabsDialog->AddTab("Memory Limit");
		xOffset.y = fTabsStartY;

		pxDialog = new Asura_Numerical_Dialog("Memory Limit (MB)", xOffset, &g_MemoryLimit, 1, 200 , 1, "%d", &g_bMemoryLimitChanged);
		pxDialog->SetHelpText("The maximum sound memory limit for this project (all platforms)");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::DefaultSpacing();

		//End of Memory Limit tab
		if(xOffset.y > fTabsEndY) fTabsEndY = xOffset.y;
	}

	//End of tabs
	pxOverlay->SetCurrentParentDialog(0);
	static u_int s_uSelectedTab = 0;
	pxTabsDialog->SetSelectedTabPointer(&s_uSelectedTab);
	xOffset.y = fTabsEndY + 1.0f;



	
	pxOverlay->m_uID = TOOLS_OVERLAY_MODE;

	Asura_Overlay_System::SubmitNewOverlay(pxOverlay,false);

	UpdateSoundModeOverlay();
}

void Tools_Mode_Sound::UpdateSoundModeOverlay()
{
	Asura_Overlay* pxOverlay = Asura_Overlay_System::GetOverlay(TOOLS_OVERLAY_MODE);
	if(!pxOverlay) return;

	char szText[200];
	if(s_iSubMode == SUBMODE_REVERB)
	{
		#if !defined(ASURA_USE_REVERBVOLUME_SYSTEM) && !defined(ASURA_USE_AUDIO_SYSTEM)
		//update 'default reverb type'
		const char* pszReverbText = GetReverbTypeName(Asura_ModuleReverb_System::GetDefaultReverbType());
		Asura_PrintfToBfr(szText,"Default Reverb : %s",200,true,pszReverbText);
		pxOverlay->UpdateDialogLabel(DialogID_DefaultReverb,szText);

		//update 'current reverb type'
		pszReverbText = GetReverbTypeName(s_iCurrentReverbType);
		Asura_PrintfToBfr(szText,"Current Reverb : %s",200,true,pszReverbText);
		pxOverlay->UpdateDialogLabel(DialogID_CurrentReverb,szText);
		#endif

	}
	else if(s_iSubMode == SUBMODE_BACKGROUNDSOUND)
	{
		const Asura_String& xFilename = Asura_StreamingBackgroundSound_System::GetDefaultSound()->m_xFilename;
	
		//update filename
		if(xFilename.IsBlank())
		{
			strcpy(szText,"Default : None");
		}
		else
		{
			Asura_String xName;
			xFilename.SplitFilename(0,&xName,0);

			Asura_PrintfToBfr(szText,"Default : %s",200,true,xName.GetString());
		}
		pxOverlay->UpdateDialogLabel(DialogID_Filename,szText);
	}
}




void Tools_Mode_Sound::CreatePhonon()
{
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_PHONONPROPERTIES);

	Asura_Phonon* pxPhonon = CreateDefaultPhonon();

	if (pxPhonon)
	{
		//create a new tools object for this phonon
		Tools_Phonon_Object* phononObject = new Tools_Phonon_Object(pxPhonon);
		Tools_Object_System::SelectObject(phononObject);
		phononObject->Orientation = *Asura_Camera::GetOrientation();

		
		if(phononObject->PickSound())
		{
            phononObject->SetModified();
		}
		else
		{
			phononObject->Destroy();
		}
	}
	else
	{
		Tools_Object_System::SelectObject(0);
	}
}

Asura_Phonon* Tools_Mode_Sound::CreateDefaultPhonon()
{

	Asura_Phonon* pxPhonon = Asura_Phonon_System::AllocatePhonon(Tools_Object_System::ShouldCreateNewObjectsInMissionFile());

	if (pxPhonon)
	{
        //strcpy( UserPhononSoundName, NoSoundSelectedText );
		Asura_Phonon xTempPhonon;
		xTempPhonon.Initialise();

		xTempPhonon.m_uEventHashID = 0;
        xTempPhonon.m_xPosition = *Asura_Camera::GetPosition();
		xTempPhonon.m_xInitialPosition = xTempPhonon.m_xPosition;
		xTempPhonon.m_fInnerRadius = 5.0f;
		xTempPhonon.m_fOuterRadius = 20.0f;
		xTempPhonon.m_xOrient = Asura_Maths::IdentityQuat;
		xTempPhonon.m_bUseOrient = false;


        // (MH - 12.06.2002) 
        xTempPhonon.m_bUseCuboidFalloff = false;
        xTempPhonon.m_bStartsActive = true;

        xTempPhonon.m_xInnerCuboidRadius = Asura_Vector_3(5.0f,5.0f,5.0f);
        xTempPhonon.m_xOuterCuboidRadius = Asura_Vector_3(10.0f,10.0f,10.0f);

        xTempPhonon.m_bHasChanged = true;
        xTempPhonon.m_bIsActive = true;
		xTempPhonon.m_bRetriggerable = false;
			
		xTempPhonon.m_bUseClipVolume = false;
		xTempPhonon.m_bInvertClipVolume = false;


		xTempPhonon.m_bUseRetriggerRadius = false;
		xTempPhonon.m_bUseRetriggerBoundingBox = false;
		xTempPhonon.m_fRetriggerRadius = 0.0f;
		xTempPhonon.m_xRetriggerBoundingBox.Zero();

		xTempPhonon.m_uLightSets = Tools_LightSets::GetLightSetsForNewObject(xTempPhonon.m_xPosition);
	
		pxPhonon->Set(xTempPhonon);
		pxPhonon->Activate();
    
	}
	else
	{
		Tools_Timed_Message_System::AddMessage( 0xff0000, "Unable to allocate any more phonons." );
	}

	return pxPhonon;
}



void Tools_Mode_Sound::UpdateSoundSize()
{
	// Get a list of all sounds used by phonons
	// This does not take into account static sounds loaded onto skins for example.
	#ifdef ASURA_USE_AUDIO_SYSTEM
	List<Asura_Hash_ID> xSoundList;
	#else
	List<int> xSoundList;
	#endif

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

		const Asura_Sound_Event *pxEvent = pxPhonon->GetEvent();
		if(pxEvent)
		{
			// exclude events flagged as global sounds
			if (!pxEvent->IsGlobalSound())
			{
				#ifdef ASURA_USE_AUDIO_SYSTEM
				Tools_SoundEvent_System::ListSamplesUsedByEvent(pxPhonon->GetEvent(),xSoundList);
				#else
				Tools_SoundEvent_System::ListSoundIDsUsedByEvent(pxPhonon->GetEvent(),xSoundList);
				#endif
			}
		}
	}

	s_PCSoundSize = 0;
	s_PS2SoundSize = 0;
	s_PS3SoundSize = 0;
	s_Xbox360SoundSize = 0;
	AllFilesCounted = true;

	#ifdef ASURA_USE_AUDIO_SYSTEM
	LIF<Asura_Hash_ID> xSoundLIF(&xSoundList);
	#else
	LIF<int> xSoundLIF(&xSoundList);
	#endif

	//Add up the sizes of the listed sounds
	for(;!xSoundLIF.done(); xSoundLIF.next())
	{
		#ifdef ASURA_USE_AUDIO_SYSTEM
		Asura_Hash_ID eSoundID = (Asura_Hash_ID)xSoundLIF();
		#else
		Asura_Sound_ID eSoundID = (Asura_Sound_ID)xSoundLIF();
		#endif

		const char* szFilename = NULL;

		#ifdef ASURA_USE_AUDIO_SYSTEM

		Asura_Hash_ID uHash;
		const Asura_Sound_Sample* pxSample = Asura_Sound_Event_Storage::GetSampleByHash(eSoundID);
		if (pxSample)
		{
			uHash = pxSample->GetWaveHash();
			szFilename = Asura_Audio_System::GetWaveFilename(uHash);
			if (!szFilename)
			{
				Asura_Assertf(szFilename, ("Unable to find filename for WAV hash\"0x%X\"", uHash));
				continue;
			}
		}
		else
		{
			Asura_Assertf(pxSample, ("Unable to find sample for hash \"0x%X\"", eSoundID));
			continue;
		}

		#else

		szFilename = Asura_Sound_System::GetFileNameFromSoundID(eSoundID);
		Asura_Assert(szFilename,"");

		//find/create a sound data entry for this sound
		Asura_Hash_ID uHash = Asura_GetHashID(szFilename);

		#endif
		
		ToolsSoundData* pxSoundData = s_pxSoundDataTree->GetDataByHash(uHash);
		if(!pxSoundData)
		{
			pxSoundData = s_pxSoundDataTree->AddNode(uHash);
			pxSoundData->Initialise(eSoundID,szFilename);
		}
		else
		{
			Asura_Assert(!pxSoundData->m_xFilename.Compare(szFilename),"Two different wav files have the same hash ID");
		}

		if(pxSoundData && pxSoundData->m_bValid)
		{
			// PC sound size
			s_PCSoundSize += pxSoundData->m_iDataChunkSize;

			#ifdef ASURA_USE_AUDIO_SYSTEM
			// PS3 sound size
			{
				int iQuality = pxSample->GetCompressionQuality(TOOLS_PLATFORM_PS3);
				// Quality in bytes per sec
				iQuality = (1024 * Tools_SoundEvent_System::GetPlatformCompressionQuality(TOOLS_PLATFORM_PS3, iQuality)) / 8;
				float fSoundLength = (float) pxSoundData->m_iSamples / (float) pxSoundData->m_iFrequency;
				s_PS3SoundSize += (u_int) (fSoundLength * iQuality);
			}

			// Xbox 360 sound size
			{
				int iQuality = pxSample->GetCompressionQuality(TOOLS_PLATFORM_XBOX360);
				// This is a quality setting 1-100
				iQuality = Tools_SoundEvent_System::GetPlatformCompressionQuality(TOOLS_PLATFORM_XBOX360, iQuality);
				//
				// JCT - Estimate XMA compression ratio based on average values from graph in article:
				// "XMA Aesthetics, Quality, and Artifacts (Or, How I Learned to Stop Worrying and Love the Compression)"
				//
				float fCompressionRatio = 1.0f - (((float) iQuality) / 100.0f);
				fCompressionRatio = (fCompressionRatio * 10.5f) + 3.0f;
				
				s_Xbox360SoundSize += (int) ((float) pxSoundData->m_iDataChunkSize / fCompressionRatio);
			}

			#else

			//add up the file size for this sound
			int iPS2Frequency = Tools_Sound_PS2Settings::GetFrequency(szFilename);
			if(!iPS2Frequency) iPS2Frequency = Tools_SoundEvent_System::GetSampleRate(TOOLS_PLATFORM_PS2,szFilename);
			if(!iPS2Frequency) iPS2Frequency = TOOLS_DEFAULT_MAX_PS2_FREQUENCY;

			//determine number of samples for vag file
			int iSamples = pxSoundData->m_iSamples;
			if(pxSoundData->m_iFrequency > iPS2Frequency)
			{
				iSamples = (int)(iSamples * ((float)iPS2Frequency / pxSoundData->m_iFrequency));
			}
			//must be a multiple of 28
			iSamples += BLKSIZ-1;
			iSamples -= iSamples%BLKSIZ;

			//each block of 28 samples becomes 16 bytes in the vag
			s_PS2SoundSize += (iSamples/BLKSIZ)*16;

			#endif	// ASURA_USE_AUDIO_SYSTEM
		}
		else
		{
			AllFilesCounted = false;
		}
	}

	s_bSoundSizeValid = true;
}


void Tools_Mode_Sound::ChangeSubMode(int iSubMode)
{
	if(iSubMode == s_iSubMode) return;

	//handle cleanup of previous submode
	switch(s_iSubMode)
	{
		case SUBMODE_PHONON :
			LeavePhononMode();
			break;

		case SUBMODE_REVERB :
			LeaveReverbMode();
			break;

		case SUBMODE_BACKGROUNDSOUND :
			LeaveBackgroundMode();
			break;


		default :
			Asura_Assert(0,"Unknown submode");
			break;
	}
	
	
	
 	s_iSubMode = s_iRequestedSubMode = iSubMode;


	//initialise new submode
	switch(s_iSubMode)
	{
		case SUBMODE_PHONON :
			EnterPhononMode();
			break;

		case SUBMODE_REVERB :
			EnterReverbMode();
			break;

		case SUBMODE_BACKGROUNDSOUND :
			EnterBackgroundMode();
			break;


		default :
			Asura_Assert(0,"Unknown submode");
			break;
	}

	//update the main mode overlay
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_MODE);
	CreateSoundModeOverlay();


}
void Tools_Mode_Sound::EnterPhononMode()
{
	//Phonon mode is the default state of things , so doesn't have any extra initialisation
	//at the moment
}

void Tools_Mode_Sound::LeavePhononMode()
{
	//Phonon mode is the default state of things , so doesn't have any extra shutdown
	//at the moment
}


void Tools_Mode_Sound::EnterReverbMode()
{
	#ifdef ASURA_USE_REVERBVOLUME_SYSTEM
	s_pxReverbVolumeEditor->StartEditing();
	#else
	//disable object editing controls
	Tools_Object_System::SelectObject(0);
	Tools_Object_System::EnableAllControls(false);

	//enable module selection
	Tools_Module_Selection::Activate();
	#endif
}

void Tools_Mode_Sound::LeaveReverbMode()
{
	#ifdef ASURA_USE_REVERBVOLUME_SYSTEM
	s_pxReverbVolumeEditor->EndEditing();
	#else
	//enabled object editing
	Tools_Object_System::EnableAllControls(true);

	//disable module selection
	Tools_Module_Selection::Deactivate();
	#endif
}

void Tools_Mode_Sound::EnterBackgroundMode()
{
	//create the tools objects for the background sounds
	Tools_StreamingBackgroundSound_Object::CreateAllObjects();
}

void Tools_Mode_Sound::LeaveBackgroundMode()
{
	//delete the tools objects
	Tools_StreamingBackgroundSound_Object::DeleteAllObjects();
}

#ifndef ASURA_USE_AUDIO_SYSTEM

const char* Tools_Mode_Sound::GetReverbTypeName(int iReverbType)
{
	if(iReverbType == ASURA_REVERB_USE_DEFAULT) return "Use Default";

	for(int i=0;i<g_iNumberOfReverbTypes;i++)
	{
		if(g_aiReverbTypeValues[i] == iReverbType)
		{
			return g_apszReverbTypeNames[i];
		}
	}

	return "*Unknown Type*";
}

bool Tools_Mode_Sound::SelectReverbType(const char* pszTitle,int* piReverbType)
{
	Asura_Assert(piReverbType,"");

	ListSelection_Overlay xOverlay(pszTitle);

	//add al the reverb types to the overlay
	for(int i=0;i<g_iNumberOfReverbTypes;i++)
	{
		xOverlay.AddItem(g_apszReverbTypeNames[i],g_aiReverbTypeValues[i]);
	}

	if(!xOverlay.DoModal()) return false;

	*piReverbType = xOverlay.GetSelectionData();
	return true;
	
}

void Tools_Mode_Sound::SelectCurrentReverbType()
{
	if(SelectReverbType("Select current reverb type",&s_iCurrentReverbType))
	{
		UpdateSoundModeOverlay();
	}
}

void Tools_Mode_Sound::SelectDefaultReverbType()
{
	int iReverbType;
	if(SelectReverbType("Select environment default reverb type",&iReverbType))
	{
		Asura_ModuleReverb_System::SetDefaultReverbType(iReverbType);
		Tools_SaveAsura::SetSoundsModified();
		UpdateSoundModeOverlay();
	}
}

void Tools_Mode_Sound::PreviousReverbType()
{
	//get the current reverb type index
	int iCurrentIndex = g_iNumberOfReverbTypes;
	for(int i=0;i<g_iNumberOfReverbTypes;i++)
	{
		if(s_iCurrentReverbType == g_aiReverbTypeValues[i])
		{
			iCurrentIndex = i;
			break;
		}
	}
	//select the previous one
	iCurrentIndex--;
	if(iCurrentIndex == -1) iCurrentIndex = g_iNumberOfReverbTypes-1;

	s_iCurrentReverbType = g_aiReverbTypeValues[iCurrentIndex];
	UpdateSoundModeOverlay();
}

void Tools_Mode_Sound::NextReverbType()
{
	//get the current reverb type index
	int iCurrentIndex = -1;
	for(int i=0;i<g_iNumberOfReverbTypes;i++)
	{
		if(s_iCurrentReverbType == g_aiReverbTypeValues[i])
		{
			iCurrentIndex = i;
			break;
		}
	}
	//select the next one
	iCurrentIndex++;
	if(iCurrentIndex == g_iNumberOfReverbTypes) iCurrentIndex = 0;

	s_iCurrentReverbType = g_aiReverbTypeValues[iCurrentIndex];
	UpdateSoundModeOverlay();
}


void Tools_Mode_Sound::ApplyReverb()
{
    const List<int>* pxSelectedList = Tools_Module_Selection::GetSelectionList();
	if(!pxSelectedList->size())
	{
		Tools_Timed_Message_System::AddMessage( 0xffffff, "Can't apply reverb: no modules selected." );
		return;
	}

	if(!Asura_ModuleReverb_System::HasModuleDataBeenAllocated())
	{
		//allocate storage for module reverb
		Asura_ModuleReverb_System::AllocateModuleData(Asura_Module_System::GetNumberOfModules());
	}

	//set reverb type for all selected modules
	for(CLIF<int> xSelectedLIF(pxSelectedList);!xSelectedLIF.done();xSelectedLIF.next())
	{
		Asura_ModuleReverb_System::SetModuleReverbType(xSelectedLIF(),s_iCurrentReverbType);
	}

	Tools_Timed_Message_System::AddMessage( 0xffffff, "%s applied to %d module(s).",GetReverbTypeName(s_iCurrentReverbType),pxSelectedList->size() );
	
	Tools_SaveAsura::SetSoundsModified();
}

void Tools_Mode_Sound::RemoveReverb()
{
    const List<int>* pxSelectedList = Tools_Module_Selection::GetSelectionList();
	if(!pxSelectedList->size())
	{
		Tools_Timed_Message_System::AddMessage( 0xffffff, "Can't remove reverb: no modules selected." );
		return;
	}

	//reset reverb type for selected modules to default
	for(CLIF<int> xSelectedLIF(pxSelectedList);!xSelectedLIF.done();xSelectedLIF.next())
	{
		Asura_ModuleReverb_System::SetModuleReverbType(xSelectedLIF(),s_iCurrentReverbType);
	}

	Tools_Timed_Message_System::AddMessage( 0xffffff, "Reverb for %d module(s) reset to default.",pxSelectedList->size() );
	
	Tools_SaveAsura::SetSoundsModified();
}

#endif // #ifndef ASURA_USE_AUDIO_SYSTEM

void Tools_Mode_Sound::FindPhononsByEvent()
{
	Tools_PickSoundEvent_Overlay xOverlay("Find phonons using which sound?");
	Asura_Hash_ID uHash = xOverlay.DoModal(0);
	if(xOverlay.WasCancelled()) return;

	List<Tools_Object*> xFindList;
	//add all phonons using the selected sound to the list
	for(LIF<Tools_Phonon_Object*> xPhononLIF(&PhononList);!xPhononLIF.done();xPhononLIF.next())
	{
		if(xPhononLIF()->GetPhonon()->m_uEventHashID == uHash)
		{
			xFindList.add_entry(xPhononLIF());
		}
	}
	const Asura_Sound_Event* pxEvent = Asura_Sound_Event_Storage::FindEvent(uHash);

	if(pxEvent)
	{
		u_int uInitialPos = Tools_MessageLog::GetNextID();
		Tools_SoundEvent_System::FindReferencesToEvent(pxEvent);

		if(Tools_MessageLog::AreThereAnyMessages(Tools_MessageLog::SOUND_EVENT, 0, uInitialPos))
		{
			Tools_MessageLog::ShowOverlay(Tools_MessageLog::SOUND_EVENT,0,uInitialPos);
		}
	}



	Tools_Timed_Message_System::AddMessage(0xffffff,"Looking for phonons using %s...",pxEvent ? pxEvent->GetName() : "no sound");
	Tools_Object_System::SetFindObjectList(xFindList);
}

bool Tools_Mode_Sound::SelectStreamingSound(Asura_String& xFilename)
{
#ifdef ASURA_USE_AUDIO_SYSTEM

	const Asura_Hash_ID uSelectedStream = Tools_Audio_StreamingOverlay::SelectStream();
	if( uSelectedStream == ASURA_HASH_ID_UNSET ) return false;

	const Asura_Audio_StreamInfo* const pxStreamInfo =
		Asura_Audio_System::GetStreamInfo( uSelectedStream );

	if( pxStreamInfo )
	{
		xFilename = pxStreamInfo->m_szFilename;
		return true;
	}
	else
	{
		return false;
	}

#else // ndef ASURA_USE_AUDIO_SYSTEM

	static Asura_String s_xDefaultPath = "Sounds";

	Asura_String xCurrentPath;
	//use the directory of the passed filename if there is one , otherwise use the default directory
	if(!xFilename.IsBlank())
	{
		xFilename.SplitFilename(&xCurrentPath,0,0);
	}
	else
	{
		xCurrentPath = s_xDefaultPath;
	}

	char szFilename[MAX_PATH] = "";
	if(!xFilename.IsNull())
	{
		strcpy(szFilename,xFilename.GetString());
		//change filename to .bik extension
		char* pcDot = strrchr(szFilename,'.');
		if(pcDot) strcpy(pcDot,".bik");
	}
		
	Tools_FileSystem_DialogInfo	xFileSelector;
	xFileSelector.DefaultExtension		= ".BIK";
	xFileSelector.DefaultFilename		= szFilename;
	xFileSelector.DefaultPath			= xCurrentPath.GetString();
	xFileSelector.FileFilter			= "Bink Files\0*.BIK;\0";
	xFileSelector.WindowTitle			= "Select streaming sound";
	xFileSelector.AllowMultipleSelect	= false;

	Asura_String xSelected = Tools_FileSystem::GetLoadFilename( xFileSelector );
	if(xSelected.IsBlank()) return false;

	//replace .bik extension with .wav extension (this is because the PS2 complains if the extension
	//is anything else.... at least I think it does).
	strcpy(szFilename,Asura_FileAccess::PlatformRemoveNetworkOrExecutableDir(xSelected.GetString()));
	char* pcDot = strrchr(szFilename,'.');
	if(pcDot) strcpy(pcDot,".wav");

	xFilename = szFilename;

 	//set the default directory to that given by the selected file
 	xFilename.SplitFilename(&s_xDefaultPath,0,0);

	return true;

#endif // ndef ASURA_USE_AUDIO_SYSTEM
}

int Tools_Mode_Sound::GetChannelsInStreamingSound(const char* pszFilename)
{
	//convert .wav extension to .bik
	char szFilename[MAX_PATH];
	strcpy(szFilename,pszFilename);
	char* pcDot = strrchr(szFilename,'.');
	if(pcDot)  strcpy(pcDot,".bik");

	HBINK pxBink = BinkOpen(szFilename,0);
	int iChannels = 0;
	if(pxBink)
	{
		if(pxBink->bsnd)
		{
			iChannels = pxBink->bsnd->chans;
		}
		BinkClose(pxBink);
	}
	return iChannels;
}

void Tools_Mode_Sound::SelectDefaultStreamingSound()
{
	Asura_String& xFilename = Asura_StreamingBackgroundSound_System::GetDefaultSound()->m_xFilename;
	
	if(Tools_Mode_Sound::SelectStreamingSound(xFilename))
	{
		Asura_StreamingBackgroundSound_System::GetDefaultSound()->m_uFilenameHash = Asura_GetHashID(xFilename.GetString());
		UpdateSoundModeOverlay();
		
		Tools_SaveAsura::SetSoundsModified();

//		Asura_StreamingBackgroundSound_System::StopAll();
	}
}

void Tools_Mode_Sound::ClearDefaultStreamingSound()
{
	Asura_StreamingBackgroundSound_System::GetDefaultSound()->m_xFilename.MakeNull();
	Asura_StreamingBackgroundSound_System::GetDefaultSound()->m_uFilenameHash = ASURA_HASH_ID_UNSET;
	UpdateSoundModeOverlay();
	
	Tools_SaveAsura::SetSoundsModified();

//	Asura_StreamingBackgroundSound_System::StopAll();
}


////////////////////////////////////////////////////////////////////////////////////////////////

#define READ_WAV_FILE(buffer,size)\
ReadFile(inputFile,(long*)buffer,(size),&bytes_read,0);\
if(bytes_read!=(unsigned)(size))\
	goto EndWavFileRead;

typedef struct pwavchunkheader
{
	char chunkName[4];
	int chunkLength;	
} PWAVCHUNKHEADER;

typedef struct pwavriffheader
{
	char type[4];
} PWAVRIFFHEADER;


#ifdef ASURA_USE_AUDIO_SYSTEM
void ToolsSoundData::Initialise(Asura_Hash_ID eSoundID,const char* szFilename)
#else
void ToolsSoundData::Initialise(Asura_Sound_ID eSoundID,const char* szFilename)
#endif
{
	m_bInitialised = true;
	m_xFilename = szFilename;
	m_bValid = false;
	m_eSoundID = eSoundID;

	bool okay = false;
	unsigned long bytes_read;

	char szNetFilename[MAX_PATH];
	Asura_FileAccess::PlatformGetNetworkFilename(szFilename,szNetFilename,MAX_PATH);
	
	//open the the wav file
	HANDLE inputFile = CreateFile(szNetFilename,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_FLAG_RANDOM_ACCESS,0);
	
	if(inputFile == INVALID_HANDLE_VALUE)
	{
		return;
	}

	//read the initial headers
	PWAVCHUNKHEADER myChunkHeader;
	READ_WAV_FILE(&myChunkHeader,sizeof(myChunkHeader));

	if((myChunkHeader.chunkName[0]!='R')||(myChunkHeader.chunkName[1]!='I')||
	   (myChunkHeader.chunkName[2]!='F')||(myChunkHeader.chunkName[3]!='F'))
	{
		goto EndWavFileRead;
	}

	PWAVRIFFHEADER myRiffHeader;
	PCMWAVEFORMAT wavFormat;
	READ_WAV_FILE(&myRiffHeader,sizeof(myRiffHeader));

	if(myRiffHeader.type[0]!='W'||myRiffHeader.type[1]!='A'||myRiffHeader.type[2]!='V'||myRiffHeader.type[3]!='E')
	{
		goto EndWavFileRead;
	}

	//read the wav format chunk
	READ_WAV_FILE(&myChunkHeader,sizeof(myChunkHeader));
	if(myChunkHeader.chunkLength==16)
	{
		/* a standard PCM wave format chunk */
		READ_WAV_FILE(&wavFormat,sizeof(wavFormat));
	}
	else if(myChunkHeader.chunkLength>=18)
	{
		/* an extended PCM wave format chunk */
		WAVEFORMATEX temp;
		READ_WAV_FILE(&temp,sizeof(temp));
		
		wavFormat = *(PCMWAVEFORMAT*)&temp;

		//skip the rest of the chunk
		if(myChunkHeader.chunkLength>18)
		{
			SetFilePointer(inputFile,myChunkHeader.chunkLength-18,0,FILE_CURRENT);
		}

	}


	//now skip until we reach the data chunk
	do
	{
		READ_WAV_FILE(&myChunkHeader,sizeof(myChunkHeader));
		if((myChunkHeader.chunkName[0]=='d')&&(myChunkHeader.chunkName[1]=='a')&&
	   		(myChunkHeader.chunkName[2]=='t')&&(myChunkHeader.chunkName[3]=='a'))
		{
			break;
		}

		SetFilePointer(inputFile,myChunkHeader.chunkLength,0,FILE_CURRENT);

	}while(true);

	myChunkHeader.chunkLength;
	
	okay = true;

EndWavFileRead :

	//finished with the file now
	if(inputFile != INVALID_HANDLE_VALUE) CloseHandle(inputFile);
	if(!okay)
	{
		return;
	}

	m_iDataChunkSize = myChunkHeader.chunkLength;
	m_iFrequency = wavFormat.wf.nSamplesPerSec;

	Asura_Assert(wavFormat.wf.nBlockAlign,"Dodgy wav file");
	Asura_Assert(wavFormat.wf.nChannels,"Dodgy wav file");
	m_iSamples = myChunkHeader.chunkLength/(wavFormat.wf.nBlockAlign*wavFormat.wf.nChannels);

	m_bValid = true;
}


void Tools_Mode_Sound::VerifySoundEvent()
{
	Tools_SoundEvent_System::Verify(false);
}

void Tools_Mode_Sound::FindReferencesToWav()
{
	Tools_SoundEvent_System::FindReferencesToWav();
}


void Tools_Mode_Sound::HideEntities(bool bHide)
{
	//Hide/show all the entities... or rather , everything not normally needed for sound mode
	for(LIF<Tools_Object*> xObjectLIF(&Tools_Object_System::ObjectList);!xObjectLIF.done();xObjectLIF.next())
	{
		int iType = xObjectLIF()->Type;
		if(iType == TOT_StreamingBackgroundSound ||
			iType == TOT_VolumeEdit ||
			iType == TOT_Phonon)
		{
			continue;
		}

		xObjectLIF()->SetHiddenFlag(ObjectHideFlag_Mode,bHide);
	}	
}

void Tools_Mode_Sound::PreMessageBlockEditing()
{
	HideEntities(false);
}

void Tools_Mode_Sound::PostMessageBlockEditing()
{
	HideEntities(true);
}

// void Tools_Mode_Sound::BuildSoundTypeList( ListSelection_Overlay& xList )
// {
// #ifdef ASURA_USE_AXON
// 	static struct StringAndValue
// 	{
// 		const char* m_pszString;
// 		int			m_iValue;
// 
// 	} s_axNodeBehaviours[] =
// 	{
// 		{ "No Type",		AXON_SOUND_TYPE_NO_TYPE },
// 		{ "FootSteps",		AXON_SOUND_TYPE_FOOTSTEP },
// 		{ "Gun Fire",		AXON_SOUND_TYPE_GUNFIRE },
// 		{ "Ricochet",		AXON_SOUND_TYPE_RICOCHET },
// 		{ "Explosion",		AXON_SOUND_TYPE_EXPLOSION },
// 		{ "",				-1 } // terminator
// 	};
// 
// 	StringAndValue* pxEntry = s_axNodeBehaviours;
// 	
// 	while ( pxEntry->m_iValue != -1 )
// 	{
// 		xList.AddItem( pxEntry->m_pszString, pxEntry->m_iValue );
// 		++pxEntry;
// 	}
// #endif
// }

void Tools_Mode_Sound::CopyDefaultSBSToAsura()
{
	Asura_StreamingBackgroundSound_System::GetDefaultSound()->m_fVolume = s_fSBSDefaultVolume;
	Asura_StreamingBackgroundSound_System::GetDefaultSound()->m_uMixer = s_uSBSDefaultMixer;
}

void Tools_Mode_Sound::CopyDefaultSBSFromAsura()
{
	s_fSBSDefaultVolume = Asura_StreamingBackgroundSound_System::GetDefaultSound()->m_fVolume;
	s_uSBSDefaultMixer = Asura_StreamingBackgroundSound_System::GetDefaultSound()->m_uMixer;
	UpdateSoundModeOverlay();
}

void Tools_Mode_Sound::WriteStreamingSoundReport()
{
	const char* szFilename = NULL;

	//ask the user for a filename
	{
		Tools_FileSystem_DialogInfo xInfo;

		xInfo.DefaultExtension = "txt";
		xInfo.DefaultFilename = "StreamingSounds.txt";
		xInfo.DefaultPath = Tools_SaveAsura::GetMainFilename();
		xInfo.FileFilter = "Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
		xInfo.WindowTitle = "Write streaming sound report as:";

		szFilename = Tools_FileSystem::GetSaveFilename(xInfo);
		if(!szFilename) return;
	}

	//make sure the file can be created
	Tools_FileSystem::EnsureDirectoryExists(szFilename);
	FILE* pxFile = fopen(szFilename, "wt");
	if(!pxFile)
	{
		Tools_Timed_Message_System::AddMessage(0xff0000,"Failed to open %s for writing",szFilename);
		return;
	}

	Asura_StringTree xStringTree;

	//get the names of sounds used by the streaming sound objects
	for(int i=0;i<Asura_StreamingBackgroundSound_System::s_iNumberOfSounds;i++)
	{
		const Asura_StreamingBackgroundSound* pxSound = Asura_StreamingBackgroundSound_System::GetSound(i);
		if(pxSound && !pxSound->m_xFilename.IsBlank())
		{
			int iJunkIndex;
			xStringTree.FindNodeIndexByName(pxSound->m_xFilename, true, iJunkIndex);
		}
	}

	//get the names of the default sound(s)
	if(Asura_StreamingBackgroundSound_System::HasDefaultPerLightSet())
	{
		for(Tools_UsedLightSetIterator xIt; !xIt.Done(); xIt.Next())
		{
			const Asura_DefaultStreamingBackgroundSound* pxDefault = Asura_StreamingBackgroundSound_System::GetDefaultSound(xIt.GetCurrent(), false);
			if(pxDefault && !pxDefault->m_xFilename.IsBlank())
			{
				int iJunkIndex;
				xStringTree.FindNodeIndexByName(pxDefault->m_xFilename, true, iJunkIndex);
			}
		}
	}
	else
	{
		const Asura_DefaultStreamingBackgroundSound* pxDefault = Asura_StreamingBackgroundSound_System::GetDefaultSound();
		if(pxDefault && !pxDefault->m_xFilename.IsBlank())
		{
			int iJunkIndex;
			xStringTree.FindNodeIndexByName(pxDefault->m_xFilename, true, iJunkIndex);
		}
	}

	//get all the names from the string tree ,and write them to the file
	int iNumNames = xStringTree.GetNumberOfNodes();
	if(iNumNames)
	{
		const char** pszNameList = new const char*[iNumNames];
		xStringTree.MakeSortedNameList(pszNameList);

		for(int i=0;i<iNumNames;i++)
		{
			fprintf(pxFile, "%s\n", pszNameList[i]);
		}
		delete [] pszNameList;		
	}
	else			
	{
		fprintf(pxFile, "No streaming background sounds are used by this level\n");
	}

	fclose(pxFile);

	Tools_Timed_Message_System::AddMessage(0xffffff,"%s written",szFilename);
}
