///////////////////////////////////////////////////////////////////////////////
/// @file deSound.hpp
///
/// @brief Destiny Sound System Data Structures and Classes
///
/// @author paradoxnj
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Jan 2002
/// @author paradoxnj
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

#ifndef DESOUND_H
#define DESOUND_H

//Destiny Includes
//#include "deFileSystem.hpp"
#include "deResource.hpp"
//#include "deMath.hpp"

//DLL Interface
#if defined(DESOUND_DLL_EXPORTS) || defined(DESTINY3D_EXPORT_ALL)
#	define DESOUND_API				extern "C" DEDLL_EXPORT
#elif defined(DESTINY3D_STATIC_LINK)
#	define DESOUND_API				extern "C"
#else
#	define DESOUND_API				extern "C" DEDLL_IMPORT
#endif

#ifdef USING_DESTINY3D
#ifdef _DEBUG
#	ifdef DESTINY3D_STATIC_LINK
#		pragma comment(lib, "deSound_sd")
#	else
#		pragma comment(lib, "deSoundd")
#	endif //DESTINY3D_STATIC_LINK
#else
#	ifdef DESTINY3D_STATIC_LINK
#		pragma comment(lib, "deSound_s")
#	else
#		pragma comment(lib, "deSound")
#	endif //DESTINY3D_STATIC_LINK
#endif //_DEBUG
#endif //USING_DESTINY3D

class IdeSoundSystem;

//The sound factory functions
DESOUND_API IdeSoundSystem *IdeSoundSystem_CreateDirectSound(HWND hWnd);
DESOUND_API IdeSoundSystem *IdeSoundSystem_CreateEAX(HWND hWnd);
DESOUND_API int IdeSoundData_GetInterfaceID();

//System Includes
typedef struct tWAVEFORMATEX WAVEFORMATEX;

//Some temporary typedefs
typedef unsigned char							uint8;

//Typedefs to lessen typing
typedef unsigned int							u_int;
typedef unsigned short							u_short;
typedef unsigned long							u_long;

//Constants
#define MAX_STRING								255
#define MAX_BUFFERS								20

//Sound FX Types
typedef enum deSFX_Type
{
	DESFX_TYPE_CHORUS = 0,
	DESFX_TYPE_GARGLE,
	DESFX_TYPE_ECHO,
	DESFX_TYPE_DISTORTION,
	DESFX_TYPE_COMPRESSOR,
	DESFX_TYPE_FLANGER,
	DESFX_TYPE_PARAMEQ,
	DESFX_TYPE_REVERB,

	DESFX_ENUM
} deSFX_Type;

//Sound FX Ranges
#define DESFX_GARGLE_RATEHZ_MIN							1
#define DESFX_GARGLE_RATEHZ_MAX							1000

#define DESFX_CHORUS_WAVE_TRIANGLE						0
#define DESFX_CHORUS_WAVE_SIN							1

#define DESFX_CHORUS_WETDRYMIX_MIN						0.0f
#define DESFX_CHORUS_WETDRYMIX_MAX						100.0f
#define DESFX_CHORUS_DEPTH_MIN							0.0f
#define DESFX_CHORUS_DEPTH_MAX							100.0f
#define DESFX_CHORUS_FEEDBACK_MIN						-99.0f
#define DESFX_CHORUS_FEEDBACK_MAX						99.0f
#define DESFX_CHORUS_FREQUENCY_MIN						0.0f
#define DESFX_CHORUS_FREQUENCY_MAX						10.0f
#define DESFX_CHORUS_DELAY_MIN							0.0f
#define DESFX_CHORUS_DELAY_MAX							20.0f
#define DESFX_CHORUS_PHASE_MIN							0
#define DESFX_CHORUS_PHASE_MAX							4

#define DESFX_CHORUS_PHASE_NEG_180						0
#define DESFX_CHORUS_PHASE_NEG_90						1
#define DESFX_CHORUS_PHASE_ZERO							2
#define DESFX_CHORUS_PHASE_90							3
#define DESFX_CHORUS_PHASE_180							4

#define DESFX_FLANGER_WAVE_TRIANGLE						0
#define DESFX_FLANGER_WAVE_SIN							1

#define DESFX_FLANGER_WETDRYMIX_MIN						0.0f
#define DESFX_FLANGER_WETDRYMIX_MAX						100.0f
#define DESFX_FLANGER_FREQUENCY_MIN						0.0f
#define DESFX_FLANGER_FREQUENCY_MAX						10.0f
#define DESFX_FLANGER_DEPTH_MIN							0.0f
#define DESFX_FLANGER_DEPTH_MAX							100.0f
#define DESFX_FLANGER_PHASE_MIN							0
#define DESFX_FLANGER_PHASE_MAX							4
#define DESFX_FLANGER_FEEDBACK_MIN						-99.0f
#define DESFX_FLANGER_FEEDBACK_MAX						99.0f
#define DESFX_FLANGER_DELAY_MIN							0.0f
#define DESFX_FLANGER_DELAY_MAX							4.0f

#define DESFX_FLANGER_PHASE_NEG_180						0
#define DESFX_FLANGER_PHASE_NEG_90						1
#define DESFX_FLANGER_PHASE_ZERO						2
#define DESFX_FLANGER_PHASE_90							3
#define DESFX_FLANGER_PHASE_180							4

#define DESFX_ECHO_WETDRYMIX_MIN						0.0f
#define DESFX_ECHO_WETDRYMIX_MAX						100.0f
#define DESFX_ECHO_FEEDBACK_MIN							0.0f
#define DESFX_ECHO_FEEDBACK_MAX							100.0f
#define DESFX_ECHO_LEFTDELAY_MIN						1.0f
#define DESFX_ECHO_LEFTDELAY_MAX						2000.0f
#define DESFX_ECHO_RIGHTDELAY_MIN						1.0f
#define DESFX_ECHO_RIGHTDELAY_MAX						2000.0f
#define DESFX_ECHO_PANDELAY_MIN							0
#define DESFX_ECHO_PANDELAY_MAX							1

#define DESFX_DISTORTION_GAIN_MIN						-60.0f
#define DESFX_DISTORTION_GAIN_MAX						0.0f
#define DESFX_DISTORTION_EDGE_MIN						0.0f
#define DESFX_DISTORTION_EDGE_MAX						100.0f
#define DESFX_DISTORTION_POSTEQCENTERFREQUENCY_MIN		100.0f
#define DESFX_DISTORTION_POSTEQCENTERFREQUENCY_MAX		8000.0f
#define DESFX_DISTORTION_POSTEQBANDWIDTH_MIN			100.0f
#define DESFX_DISTORTION_POSTEQBANDWIDTH_MAX			8000.0f
#define DESFX_DISTORTION_PRELOWPASSCUTOFF_MIN			100.0f
#define DESFX_DISTORTION_PRELOWPASSCUTOFF_MAX			8000.0f

#define DESFX_COMPRESSOR_GAIN_MIN						-60.0f
#define DESFX_COMPRESSOR_GAIN_MAX						60.0f
#define DESFX_COMPRESSOR_ATTACK_MIN						0.01f
#define DESFX_COMPRESSOR_ATTACK_MAX						500.0f
#define DESFX_COMPRESSOR_RELEASE_MIN					50.0f
#define DESFX_COMPRESSOR_RELEASE_MAX					3000.0f
#define DESFX_COMPRESSOR_THRESHOLD_MIN					-60.0f
#define DESFX_COMPRESSOR_THRESHOLD_MAX					0.0f
#define DESFX_COMPRESSOR_RATIO_MIN						1.0f
#define DESFX_COMPRESSOR_RATIO_MAX						100.0f
#define DESFX_COMPRESSOR_PREDELAY_MIN					0.0f
#define DESFX_COMPRESSOR_PREDELAY_MAX					4.0f

#define DESFX_PARAMEQ_CENTER_MIN						80.0f
#define DESFX_PARAMEQ_CENTER_MAX						16000.0f
#define DESFX_PARAMEQ_BANDWIDTH_MIN						1.0f
#define DESFX_PARAMEQ_BANDWIDTH_MAX						36.0f
#define DESFX_PARAMEQ_GAIN_MIN							-15.0f
#define DESFX_PARAMEQ_GAIN_MAX							15.0f

#define DESFX_REVERB_INGAIN_MIN							-96.0f
#define DESFX_REVERB_INGAIN_MAX							0.0f
#define DESFX_REVERB_INGAIN_DEFAULT						0.0f
#define DESFX_REVERB_REVERBMIX_MIN						-96.0f
#define DESFX_REVERB_REVERBMIX_MAX						0.0f
#define DESFX_REVERB_REVERBMIX_DEFAULT					0.0f
#define DESFX_REVERB_REVERBTIME_MIN						0.001f
#define DESFX_REVERB_REVERBTIME_MAX						3000.0f
#define DESFX_REVERB_REVERBTIME_DEFAULT					1000.0f
#define DESFX_REVERB_HIGHFREQRTRATIO_MIN				0.001f
#define DESFX_REVERB_HIGHFREQRTRATIO_MAX				0.999f
#define DESFX_REVERB_HIGHFREQRTRATIO_DEFAULT			0.001f

//Forward class declarations
class deSoundData;
class IdeSoundSystem;
class IdeSoundBuffer;
class deSFXManager;

//Forward struct declarations
typedef struct deSoundCfg						deSoundCfg;
typedef struct deSFX_Chorus						deSFX_Chorus;
typedef struct deSFX_Gargle						deSFX_Gargle;
typedef struct deSFX_Echo						deSFX_Echo;
typedef struct deSFX_Distortion					deSFX_Distortion;
typedef struct deSFX_Compressor					deSFX_Compressor;
typedef struct deSFX_Reverb						deSFX_Reverb;
typedef struct deSFX_ParamEQ					deSFX_ParamEQ;

//Gargle FX Settings
typedef struct deSFX_Gargle
{
	DWORD				m_RateHz;
	DWORD				m_WaveShape;
} deSFX_Gargle;

//Chorus FX Settings
typedef struct deSFX_Chorus
{
	float				m_WetDryMix;
	float				m_Depth;
	float				m_Feedback;
	float				m_Frequency;
	long				m_WaveForm;
	float				m_Delay;
	long				m_Phase;
} deSFX_Chorus;

//Flanger FX Settings
typedef struct deSFX_Flanger
{
	float				m_WetDryMix;
	float				m_Depth;
	float				m_FeedBack;
	float				m_Frequency;
	long				m_WaveForm;
	float				m_Delay;
	long				m_Phase;
} deSFX_Flanger;

//Echo FX Settings
typedef struct deSFX_Echo
{
	float				m_WetDryMix;
	float				m_Feedback;
	float				m_LeftDelay;
	float				m_RightDelay;
	long				m_PanDelay;
} deSFX_Echo;

//Distortion FX Settings
typedef struct deSFX_Distortion
{
	float				m_Gain;
	float				m_Edge;
	float				m_PostEQCenterFrequency;
	float				m_PostEQBandwidth;
	float				m_PreLowPassCutoff;
} deSFX_Distortion;

//Compressor FX Settings
typedef struct deSFX_Compressor
{
	float				m_Gain;
	float				m_Attack;
	float				m_Release;
	float				m_Threshold;
	float				m_Ratio;
	float				m_Predelay;
} deSFX_Compressor;

//Parametric EQ FX Settings
typedef struct deSFX_ParamEQ
{
	float				m_Center;
	float				m_Bandwidth;
	float				m_Gain;
} deSFX_ParamEQ;

//Reverb FX Settings
typedef struct deSFX_Reverb
{
	float				m_InGain;
	float				m_ReverbMix;
	float				m_ReverbTime;
	float				m_HighFreqRTRatio;
} deSFX_Reverb;

//The PCM Data Interface
//class IdeSoundData : virtual public IdeResourceBase
DE3D_INTERFACE(IdeSoundData, IdeResourceBase)
{
protected:
	virtual ~IdeSoundData()		{}

public:
	enum interface_t
	{
		iface_IdeSoundData,
		iface_WAV,
		iface_OGG,
		iface_32Bit=0x7fffffff
	};

	virtual deBoolean			Initialize(const char *filename) = 0;
	virtual void				Destroy() = 0;

	virtual deBoolean			AtEndOfStream() = 0;
	virtual void				SetPosition(long NewPos) = 0;

	virtual int					GetDataChunk(void *ptr, long size, s32 DataOffset = -1) = 0;
	virtual uint8				*GetAllData() = 0;

	virtual int					GetType() = 0;

	virtual void				GetFormat(WAVEFORMATEX *format) = 0;
	virtual u32					GetLength() = 0;
};

//The sound system interface
//class IdeSoundSystem : virtual public IdeRefCountBase
DE3D_INTERFACE(IdeSoundSystem, IdeRefCountBase)
{
protected:
	virtual ~IdeSoundSystem()	{}

public:
	enum interface_t
	{
		iface_IdeSoundSystem,
		iface_DirectSound,
		iface_EAX,
		iface_32Bit=0x7fffffff
	};

	virtual void				*GetInterface(int interface_id) = 0;

	virtual deBoolean			Initialize(HWND hWnd) = 0;
	virtual void				Destroy() = 0;

	virtual IdeSoundBuffer		*CreateSoundBuffer(IdeSoundData *sndData) = 0;

	virtual float				GetRollOffFactor() = 0;
	virtual float				GetDopplerFactor() = 0;
	virtual float				GetDistanceFactor() = 0;

	virtual void				SetRollOffFactor(float factor) = 0;
	virtual void				SetDopplerFactor(float factor) = 0;
	virtual void				SetDistanceFactor(float factor) = 0;

	virtual deBoolean			GetListenerPosition(float *x, float *y, float *z) = 0;
	virtual deBoolean			GetListenerPosition(deVec3d *pos) = 0;

	virtual deBoolean			GetListenerVelocity(float *x, float *y, float *z) = 0;
	virtual deBoolean			GetListenerVelocity(deVec3d *vel) = 0;

	virtual deBoolean			GetListenerOrientation(float *Fx, float *Fy, float *Fz, float *Tx, float *Ty, float *Tz) = 0;
	virtual deBoolean			GetListenerOrientation(deVec3d *Front, deVec3d *Top) = 0;

	virtual void				SetListenerPosition(float x, float y, float z) = 0;
	virtual void				SetListenerPosition(deVec3d pos) = 0;

	virtual void				SetListenerVelocity(float x, float y, float z) = 0;
	virtual void				SetListenerVelocity(deVec3d vel) = 0;
	
	virtual void				SetListenerOrientation(float Fx, float Fy, float Fz, float Tx, float Ty, float Tz) = 0;
	virtual void				SetListenerOrientation(deVec3d Front, deVec3d Top) = 0;
};

//Sound Configuration Struct
typedef struct deSoundCfg
{
	long						Volume;
	long						Pan;
	long						Freq;

	int							Repeats;

	deVec3d						Position;
	deVec3d						Velocity;
	
	deVec3d						Cone_Orientation;

	float						Dist_Min;
	float						Dist_Max;

	float						ConeAngle_Inner;
	float						ConeAngle_Outer;

	float						ConeVolume_Outside;
} deSoundCfg;

//The sound object class
//class IdeSoundBuffer : virtual public IdeRefCountBase
DE3D_INTERFACE(IdeSoundBuffer, IdeRefCountBase)
{
protected:
	virtual ~IdeSoundBuffer()	{}

public:
	enum interface_t
	{
		iface_IdeSoundBuffer,
		iface_DirectSound,
		iface_EAX,
		iface_32Bit=0x7fffffff
	};

	virtual void				*GetInterface(int interface_id) = 0;

	virtual deBoolean			Initialize(IdeSoundSystem *ss, IdeSoundData *data) = 0;
	virtual deBoolean			Destroy() = 0;

	virtual deBoolean			ApplySettings() = 0;

	virtual void				GetConfig(deSoundCfg &Cfg) = 0;
	virtual void				SetConfig(deSoundCfg Cfg) = 0;

	virtual deBoolean			SetVolume(long vol) = 0;
	virtual deBoolean			SetPan(long pan) = 0;
	virtual deBoolean			SetFrequency(long freq) = 0;

	virtual long				GetVolume() = 0;
	virtual long				GetPan() = 0;
	virtual long				GetFrequency() = 0;

	virtual deBoolean			Play(deBoolean loop = deFALSE) = 0;
	virtual deBoolean			Update() = 0;

	virtual deBoolean			Stop(deBoolean rewind = deTRUE) = 0;
	virtual deBoolean			IsPlaying() = 0;
};

#endif
