#ifndef _SNDVIRT3D_H_
#define _SNDVIRT3D_H_
 
#include "sndlst2.h"

//to trace dsbuffer allocation/destruction
#define DEBUG_TRACE_DSBUFFERALLOCATION
//to trace voice usage
#define DEBUG_TRACE_VOICES
 
/*typedefs*/
typedef struct _virtual_module3D *SND_tdhVirtualModule3D;

SNDLST2_M_DynamicUseListOf(SND_tdhVirtualModule3D);
 
typedef struct _virtual_voice3D *p_virtual_voice3D;
 
SNDLST2_M_DynamicUseListOf(p_virtual_voice3D);
 
typedef struct _audible_voice3D *p_audible_voice3D;
 
SNDLST2_M_DynamicUseListOf(p_audible_voice3D);
 
typedef struct _dead_voice3D *p_dead_voice3D;
 
SNDLST2_M_DynamicUseListOf(p_dead_voice3D);
 
typedef struct _virtual_voice_list3D *p_virtual_voice_list3D;
 
typedef struct _allocated_resource3D *p_allocated_resource3D;

SNDLST2_M_DynamicUseListOf(p_allocated_resource3D);
 
typedef struct _virtual_voice3D{
        SndReal rNorme;         /*norme permettant le classement des voies (+/- distance au micro)*/
        long    lPrio;          /*priority level*/
        long    lInstance;      /*instace (+/- ordre d'arrivee)*/
        SND_td_pfn_vSoundCallback pfnCallback;/*fonction de callback haut-niveau (passee à SND_fn_lPlayVirt)*/
        long    lParamCallback;
        tduRefResDX3D   tduRes;         /*ressource virtuellement associee à l voie (passee à SND_fn_lPlayVirt)*/
        long            lSizeParam;     /*taille du suivant*/
        SoundParam*     pstParam;       /*copy du dernier SetParam*/
        SndBool_field_decl(bHardCallback);  /*TRUE if Callback called by hard-leve, FALSE if called by SNDVIRT*/
        SndBool_field_decl(bUsed);          /*FALSE si aucune reference n'a encore ete rendue publique = destrction immediate toleree*/
        SndBool_field_decl(bPaused);        /*TRUE si en pause*/
        SndBool_field_decl(bWaitingLoop);        /*TRUE if transition will occur*/
        /*---*/
        p_audible_voice3D audible;        /*!=NULL si voie audible*/
        p_dead_voice3D    dead;   /*!=NULL si voie audible*/
    SNDLST2_M_DynamicElementDeclaration(p_virtual_voice3D)
} virtual_voice3D;
 
typedef struct _virtual_voice_list3D{
    SNDLST2_M_DynamicAnchorDeclaration(p_virtual_voice3D) pList;
} virtual_voice_list3D;
 
/*liste des audibles*/
typedef struct _audible_voice3D{
        p_virtual_voice3D         voice;
        SndBool                         bCheck;
		p_allocated_resource3D	allocated_res;//associated resource
    SNDLST2_M_DynamicElementDeclaration(p_audible_voice3D)
} audible_voice3D;
 
typedef struct _audible_voice_list3D{
    SNDLST2_M_DynamicAnchorDeclaration(p_audible_voice3D) pList;
} audible_voice_list3D;
 
/*liste des voies tuees (à desallouee ou à reutiliser pour une nouvelle voie*/
typedef struct _dead_voice3D{
        p_virtual_voice3D         voice;
    SNDLST2_M_DynamicElementDeclaration(p_dead_voice3D)
} dead_voice3D;
 
typedef struct _dead_voice_list3D{
    SNDLST2_M_DynamicAnchorDeclaration(p_dead_voice3D) pList;
} dead_voice_list3D;
 
typedef struct _allocated_resource3D{
    tdstBlockResourceMemDX3D   *pstRes3D;         //ressource associated
	SndBool						bValid;			//TRUE if allocated resource may serve for any other audible voice
	p_audible_voice3D			pAudibleVoice;	//audible voice associated (if any)

	//at least Attack or Loop should be not NULL
	//Attack and Loop are both non NULL for looping with attack samples
	//attack3D and loop3d are used if 3D is required
	//if attack!=NULL and 3D required, Attack!=NULL (or 3D creation failled); idem for Loop/Loop3D
	LPDIRECTSOUNDBUFFER Attack;					// attack buffer (never played when looping)
    LPDIRECTSOUNDBUFFER Loop;					// looping buffer 
    LPDIRECTSOUND3DBUFFER Attack3D;				// attack buffer (never played when looping)
    LPDIRECTSOUND3DBUFFER Loop3D;				// looping buffer
	#ifdef USE_EAX
	LPKSPROPERTYSET		AttackEAX;
	LPKSPROPERTYSET		LoopEAX;
	#endif

	//these 2 filed build a link from original BSBuffer to any duplicated buffers
	p_allocated_resource3D	original_resource;//pointer onto original DSBuffer isthis one has been created by duplicat an other one
												//if NULL, this is a original DSbuffer
	p_allocated_resource3D	duplicate_resource;//pointer onto duplicated DSBuffer created from this one 
												//if NULL, there is no more duplicated of this DSBuffer

	DWORD			lLastPitch;					//value of pitch at last update
	DWORD			lLastVolume;				//value of volume at last update

    SNDLST2_M_DynamicElementDeclaration(p_allocated_resource3D)
} allocated_resource3D;
 
typedef struct _allocated_resource3D_list{
    SNDLST2_M_DynamicAnchorDeclaration(p_allocated_resource3D) pList;
} allocated_resource3D_list;
 
/*liste des module Virtual*/
typedef struct _virtual_module3D{
        /*liste des voies virtuelles = id retournes par PlayVitual*/
        virtual_voice_list3D virtual_voices;
        /*liste des voies physique = id retournes par PlaySnd*/
        audible_voice_list3D audible_voices;
        /*liste des voies desallouees*/
        dead_voice_list3D dead_voices;
        long g_lInstance;
		long g_lNbSxdAudible;	//maximum wiche number of voices to be hearable
    SNDLST2_M_DynamicElementDeclaration(SND_tdhVirtualModule3D)
} virtual_module3D;
 

/*functions*/
long SND_fn_lPlaySxdVirtual3D(tduRefRes res,SoundParam *par,long prio,SND_td_pfn_vSoundCallback fn_callback,long par_callback);
void SND_fn_vRemoveCallbackSxdVirtual3D(long voice);
SndBool SND_fn_bSetParamSxdVirtual3D(long voice,SoundParam *par);
SndBool SND_fn_bTestIsPlayingSxdVirtual3D(long voice);
void SND_fn_vStopSxdVirtual3D(long voice);
void SND_fn_vPauseSxdVirtual3D(long voice);
void SND_fn_vResumeSxdVirtual3D(long voice);
void SND_fn_vSynchroSxdVirtual3D();
 
SndReal SND_fn_rGetPosSxdVirtual3D(long voice);
SndReal SND_fn_rGetLengthSxdVirtual3D(long voice);
 
long SND_fn_lInitSxdVirtual3D(long lMaxNumberVoicesHearable);
SndBool SND_fn_bTestInitSxdVirtual3D();
void SND_fn_vDesInitSxdVirtual3D();
 
p_allocated_resource3D fn_pAllocateResource(tdstBlockResourceMemDX3D *mem);
void fn_vDesAllocateResource(p_allocated_resource3D pres3D);

SndBool fn_bCreate2ndBuffer(DSBUFFERDESC *pdsbdesc,char *pcData, LPDIRECTSOUNDBUFFER *pBuffer);
SndBool fn_bDuplicate2ndBuffer(LPDIRECTSOUNDBUFFER buffer, LPDIRECTSOUNDBUFFER *pBuffer);
void fn_vRelease2ndBuffer(LPDIRECTSOUNDBUFFER buffer);

SndBool fn_bTestDSBufferIsActive(p_audible_voice3D voice);

void fn_vGetDSInterfaces(p_allocated_resource3D pres3D);
void fn_vReleaseDSInterfaces(p_allocated_resource3D pres3D);
void fn_vPartiallyReleaseDSInterfaces(p_allocated_resource3D pres3D);

SndBool fn_bStart2ndBuffer(p_allocated_resource3D res3D,SoundParam* par,SndBool bLoop);
void set_param_DSBuffer(p_allocated_resource3D pres3D,SoundParam *par,SndBool bImmediate,SndBool bInconditionnal);
void fn_vStopDSBuffer(p_allocated_resource3D pres3D);

void fn_vStartCallBack(virtual_voice3D* pVoice);

void kill_virtual_voice3D(virtual_voice3D* pVoice);

extern allocated_resource3D_list	g_AllocatedResources;
extern virtual_module3D g_VirtualModule3D;


#endif /*_SNDVIRT3D_H_*/
