//////////////////////////////////////////////////////////////////////////////
//
// Asura_XAudio2.h
//
// Copyright (c) 2008 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////

#if defined ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#if !defined __ASURA_XAUDIO2_H__
#define __ASURA_XAUDIO2_H__

#if defined ASURA_USE_AUDIO_SYSTEM

#define ASURA_USE_XAUDIO_OCCLUSION

/******************************************************************************/
/* Included Files                                                             */
/******************************************************************************/

// Asura Platform-independent
#include "Sound/Asura_Audio_DSP.h"
#include "Sound/Asura_Audio_System.h"
#include "Sound/Asura_XAudio2_Voice.h"

// Misc
#include <xapofx.h>
#include <xaudio2.h>
#include <xaudio2fx.h>
#include <xapo.h>

// Temp. Needed for type check on XAUDIO2_BUFFER::pAudioData and SetOutputVoices(). Once all
// projects are on at least the March 2009 SDK this can all go
#include "Core/Asura_MemoryManagement_DebugOff.h"
#include <d3dx9.h>
#include "Core/Asura_MemoryManagement_DebugOn.h"

#if (defined D3DX_SDK_VERSION && D3DX_SDK_VERSION >= 40) || (defined _XDK_VER && _XDK_VER >= 7978)
	#define NOVEMBER_2008_SDK
#endif

#if (defined D3DX_SDK_VERSION && D3DX_SDK_VERSION >= 41) || (defined _XDK_VER && _XDK_VER >= 8276)
	#define MARCH_2009_SDK
#endif

/******************************************************************************/
/* Classes                                                                    */
/******************************************************************************/

struct Asura_XAudio2_StreamCallbacks;

class Asura_Chunk_Stream;
class Asura_VolumeGroup;
class Asura_XAudio2_Buffer;
class Asura_XAudio2_Stream;
class Asura_XAPO_DSP_Monitor_Params;

template< typename T > class Asura_ResourceSet;
template< typename T > class Asura_TrackingHandlePool;

////////////////////////////////////////////////////////////////////////////////
//
// Asura_XAudio2
//
// Asura implementation of XAudio2. Intended to be used by PC and 360
//
////////////////////////////////////////////////////////////////////////////////

class Asura_XAudio2
{
public:


	// Core

	static void Initialise();
	static void Reset();
	static void Shutdown();
	static void Update();

	static IXAudio2MasteringVoice* GetMasteringVoice() { return s_pxMasteringVoice; }
	static IXAudio2SubmixVoice* GetReverbVoiceWithDSP() { return s_pxReverbVoiceWithDSP; }
	static IXAudio2SubmixVoice* GetReverbVoiceNoDSP() { return s_pxReverbVoiceNoDSP; }
	static IXAudio2SubmixVoice* GetDSPVoice( const u_int u ) { return s_apxDSPVoices[u]; }

	static u_int GetDeviceNumChannels() { return s_uDeviceNumChannels; }
	static u_int GetDeviceChannelMask() { return s_uDeviceChannelMask; }

	static Asura_Audio_System::Speakers GetIndependentSpeaker( const u_int uXAudio2Speaker );

	static void* Platform_Allocate( const WORD usFormatTag, const u_int uSize );
	static void Platform_Deallocate( const WORD usFormatTag, void* const pBuffer );

	static u_int GetOutputSampleRate () { return s_uDeviceSampleRate; }

	// Buffers

	static Asura_XAudio2_Buffer* CreateBuffer( const char* const szFilename, bool& bAlreadyExisted );
	static Asura_XAudio2_Buffer* GetBuffer( const Asura_Hash_ID uHash );

	#if defined ASURA_TOOLS
		static bool IsWaveLoaded( const char* const szWave );
		static void ForceWaveToBeLoaded( const Asura_Hash_ID uWave );
		static void ReloadWave( const Asura_Hash_ID uWave, const bool bForceReloadNow );
		static void SetWaveLooping( const Asura_Hash_ID uWave, const bool bLoop );
	#endif

	#if defined ASURA_AUDIO_STORE_FILENAMES
		static const char* GetWaveFilename( const Asura_Hash_ID uWave );
	#endif

	// Voices

	static Asura_Handle CreateVoice	( const Asura_Hash_ID uWave
									, const bool bFilter
									, const bool bMusic
									, const Asura_Hash_ID xDSPChain = ASURA_HASH_ID_UNSET );

	static Asura_Handle CreateVoice	( const WAVEFORMATEX& xFmt
									, const bool bFilter
									, const bool bMusic
									, const Asura_Hash_ID xDSPChain = ASURA_HASH_ID_UNSET ); 

	static Asura_Handle CreateStreamingVoice	( const Asura_Hash_ID uStreamHash
												, const bool bFilter
												, const bool bMusic
												, const float fTimeOffset
												, const Asura_Hash_ID xDSPChain = ASURA_HASH_ID_UNSET );

	static Asura_Handle CreateSubmixVoice	( const bool bFilter
											, const bool bMusic
											, const Asura_Hash_ID xDSPChain = ASURA_HASH_ID_UNSET );

	static Asura_Handle CreateWrapperVoice	( IXAudio2SourceVoice* const pxSourceVoice );

	static void DestroyVoice( const Asura_Handle iVoiceHandle );
	static Asura_XAudio2_Voice* GetVoice( const Asura_Handle iVoiceHandle );

	// DSP

	static IXAPO* CreateAPO( const Asura_Audio_DSPType );
	static void CreateDSPChain( const Asura_Hash_ID uChainHash, IXAudio2Voice* pxVoice, u_int uChannels );

	#if defined ASURA_TOOLS
	static void GetMonitorBuffer		( char* &pBuffer, u_int &uChannels, u_int &uFrames );
	static void ReadyForMoreMonitorData	( );
	#endif

	static void SetMasterDSP( const Asura_Hash_ID uDSPChain, const float fFadeTime );

	// Streams

	static Asura_XAudio2_Stream* GetStream( const Asura_Handle iHandle );

	static IXAudio2* GetEngine() {return s_pxEngine;};

protected:

	static Asura_XAudio2_Voice* CreateVoiceInternal( Asura_Handle& iHandle );

	static IXAudio2SourceVoice* CreateXAudioSource( const WAVEFORMATEX& xFmt, const bool bFilter,
		const bool bMusic, IXAudio2VoiceCallback* const pxCallback );

	static IXAudio2SubmixVoice* CreateXAudioSubmix( const bool bFilter, const bool bMusic );

	static void ThreadFunc_PrepareStreamingVoice( void* pData, const u_int uDataSize );

	static IXAudio2* s_pxEngine;
	static IXAudio2MasteringVoice* s_pxMasteringVoice;

	static IXAudio2SubmixVoice* s_pxReverbVoiceWithDSP;
	static IXAudio2SubmixVoice* s_pxReverbVoiceNoDSP;
	static IUnknown* s_apxReverbAPOs[2];
	static XAUDIO2FX_REVERB_PARAMETERS s_xReverbParams;

	static IXAudio2SubmixVoice* s_apxDSPVoices[2];
	static u_int s_uCurrDSPVoice;
	static float s_fDSPFadeTimer;
	static float s_fDSPFadeDuration;

	static u_int s_uDeviceNumChannels;
	static u_int s_uDeviceChannelMask;
	static u_int s_uDeviceSampleRate;

	static Asura_ResourceSet< Asura_XAudio2_Buffer > s_xBuffers;

	static Asura_TrackingHandlePool< Asura_XAudio2_Voice > s_xVoices;
	static Asura_TrackingHandlePool< Asura_XAudio2_Stream > s_xStreamPool;

	#ifdef ASURA_TOOLS
	static char*			s_pMonitorBuffer;
	static volatile bool	s_bMonitorBufferReady;
	static u_int			s_uMonitorBufferChannels;
	static u_int			s_uMonitorBufferFrames;
	static Asura_XAPO_DSP_Monitor_Params s_xMonitorParams;
	#endif
};

#endif // defined ASURA_USE_AUDIO_SYSTEM

#endif // !defined __ASURA_XAUDIO2_H__
