#include "SNDinc.h"
 
#include "sndres.h"
 
#if defined(_DLL_COMPILATION_MODE)
#include "snddll.h"
#else
#ifdef USE_DBG_MODULE
#include "snddbg.h"
#endif
#endif
 
#include "sndplay.h"
#include "sndvirt.h"
#include "sndxd.h"
 
//#define DEBUG_OUTPUT_SNDVIRT

#ifdef DEBUG_OUTPUT_SNDVIRT
#include <crtdbg.h>
#endif
 
 
/*liste des modules de voies virtuelles*/
static virtual_module_list virtual_modules;
static SndBool virtual_module_list_init=FALSE;
 
/*static virtual_module vmodule;*/
 
/*liste des voies virtuelles = id retournes par PlayVitual*/
/*static virtual_voice_list virtual_voices;*/
/*liste des voies physique = id retournes par PlaySnd*/
/*static audible_voice_list audible_voices;*/
/*liste des voies desallouees*/
/*static dead_voice_list dead_voices;*/
 
/*à chaque element de audible_voices correspond un element dans virtual_voices*/
/*certains elements de virtual_voices n'ont pas de pendant dans audible_voices (sons virtuels)*/
/*l'ordonnancement est le meme dans les 2 listes*/
 
 
#define INSTANCE_MAX 0x10000000
 
 
void check_integrity(SND_tdhVirtualModule pmodule)
{
	p_audible_voice	audible;
	p_virtual_voice voice;
	p_dead_voice dead;
	int i,j;
 
	SNDLST2_M_DynamicForEachElementOf(&pmodule->virtual_voices.pList,voice,i)
	{
		/*coherence de la liste*/
		if (i>=SNDLST2_M_DynamicGetNumberOfElements(&pmodule->virtual_voices.pList))
			snd_assert(0);
 
		/*coherence des references liste*/
		if ((voice->audible) && (voice->audible->voice!=voice))
			snd_assert(0);
 
		SNDLST2_M_DynamicForEachElementOf(&pmodule->dead_voices.pList,dead,j)
		{
			/*unr voie ne peut etre virtual et dead*/
			if (dead->voice==voice)
				snd_assert(0);
		}
	}
	if (i!=SNDLST2_M_DynamicGetNumberOfElements(&pmodule->virtual_voices.pList))
			snd_assert(0);
 
	SNDLST2_M_DynamicForEachElementOf(&pmodule->audible_voices.pList,audible,i)
	{
		if ((i>=SNDLST2_M_DynamicGetNumberOfElements(&pmodule->audible_voices.pList))
			|| (audible->voice->audible!=audible))
			snd_assert(0);
	}
	if (i!=SNDLST2_M_DynamicGetNumberOfElements(&pmodule->audible_voices.pList))
			snd_assert(0);
}
 
/*raj du champ soundparam*/
void raj_soundparam(virtual_voice* pVoice,SoundParam* par)
{
	int size;
 
	if (par)
		size=SND_M_lGetSizeOfSoundParam(par);
	else
		size=0;
 
	if (size)
	{
		if (size!=pVoice->lSizeParam)
		{
			if (pVoice->pstParam)
				pVoice->pstParam=SND_fn_pvReAllocSndEx(E_ucSndBlockMain,pVoice->pstParam,size);
			else
				pVoice->pstParam=SND_fn_pvMallocSndEx(E_ucSndBlockMain,size);
		}
		pVoice->lSizeParam=size;
		memcpy(pVoice->pstParam,par,size);
	}
	else
	{
		if (pVoice->pstParam)
		{
			SND_fn_vFreeSndEx(E_ucSndBlockMain,pVoice->pstParam);
			pVoice->pstParam=NULL;
			pVoice->lSizeParam=0;
		}
	}
}
 
/*transfert d'une voie morte de pmodule->virtual_voices vers pmodule->dead_voices*/
dead_voice* add_dead_voice(SND_tdhVirtualModule pmodule,virtual_voice* pVoice)
{
	p_dead_voice dead;
 
	dead=SND_fn_pvMallocSndEx(E_ucSndBlockMain,sizeof(dead_voice));
	SNDLST2_M_DynamicInitElement(dead);
	dead->voice=pVoice;
	SNDLST2_M_DynamicAddTail(&pmodule->dead_voices.pList,dead);
 
#ifdef DEBUG_OUTPUT_SNDVIRT
	_RPT2(_CRT_WARN,"VD %x new (VV=%x)\n",dead,pVoice);
#endif
	return dead;
}
 
/*destruction d'une voie morte = le haut-niveau a pris note de la mort du son*/
void erase_dead_voice_from_list(dead_voice* pDead)
{
	SNDLST2_M_DynamicIsolate(pDead);
	SND_fn_vFreeSndEx(E_ucSndBlockMain,pDead);
 
#ifdef DEBUG_OUTPUT_SNDVIRT
	_RPT2(_CRT_WARN,"VD %x destroy (VV=%x)\n",pDead,pDead->voice);
#endif
}
 
/*replace une voie audible à se place*/
void reinsert_audible_voice(SND_tdhVirtualModule pmodule,p_audible_voice audible)
{
	p_virtual_voice voice;
	p_audible_voice tmp_audible;
 
	/*-parcours en ariere pour retrouver la voie virtuelle audible precedent _voice*/
	voice=SNDLST2_M_DynamicGetPrevElement(audible->voice);
	while ((voice!=NULL) && (voice->audible==NULL))
	{
		voice=SNDLST2_M_DynamicGetPrevElement(voice);
	}
	/*-voice->audible pointe alors sur l'elemenet apres lequel il faut inserer audible*/
	if (voice==NULL)
	{/*audible est inserer au debut de la liste*/
		SNDLST2_M_DynamicAddHead(&pmodule->audible_voices.pList,audible);
	}
	else
	{/*audible est inserer apres voice->audible*/
		tmp_audible=SNDLST2_M_DynamicGetNextElement(voice->audible);
		SNDLST2_M_DynamicInsertBetween(audible,voice->audible,tmp_audible);
	}
 
#ifdef DEBUG_OUTPUT_SNDVIRT
	_RPT2(_CRT_WARN,"VA %x reinserted (VV=%x)\n",audible,audible->voice);
#endif
}
 
/*creation d'une voie audible -> lancement du son*/
/*l'ordonnacement des 2 listes doit etre le meme*/
/*si audible1<audible2 alors audible1->voice<audible2->voice*/
p_audible_voice add_audible_voice(SND_tdhVirtualModule pmodule,p_virtual_voice _voice)
{
	p_audible_voice audible;
	SND_td_pfn_vSoundCallback fn_callback;
	long par_callback;
 
	audible=SND_fn_pvMallocSndEx(E_ucSndBlockMain,sizeof(audible_voice));
	SNDLST2_M_DynamicInitElement(audible);
	audible->voice=_voice;
 
	/*insertion de audible*/
	reinsert_audible_voice(pmodule,audible);
 
	if (SND_fn_bIsResourceLoopingSxd(_voice->tduRes))
	{/*callback will be called "manually" by SNDVIRT*/
		fn_callback=NULL;
		par_callback=0;
		_voice->bHardCallback=FALSE;
	}
	else
	{/*calbacl will be called by hard-mixer*/
		fn_callback=_voice->pfnCallback;
		par_callback=_voice->lParamCallback;
		_voice->bHardCallback=TRUE;
	}
 
	_voice->lVoice=(*(pmodule->stPtrFunctions.pfn_lPlaySxd))(_voice->tduRes,_voice->pstParam,_voice->lPrio,fn_callback,par_callback);
 
#ifdef DEBUG_OUTPUT_SNDVIRT
	_RPT2(_CRT_WARN,"VV %x began audible (VA=%x)\n",_voice,audible);
#endif
	return audible;
}
 
/*desctruction d'une voie audible -> arret du son*/
void del_audible_voice(SND_tdhVirtualModule pmodule,p_audible_voice audible)
{
#ifdef DEBUG_OUTPUT_SNDVIRT
	_RPT2(_CRT_WARN,"VA %x died (VV=%x)\n",audible,audible->voice);
#endif
 
	SNDLST2_M_DynamicIsolate(audible);
	audible->voice->audible=NULL;
	if (audible->voice->lVoice!=C_PLAY_FAILED)
		(*(pmodule->stPtrFunctions.pfn_vStopSxd))(audible->voice->lVoice);
 
	SND_fn_vFreeSndEx(E_ucSndBlockMain,audible);
}
 
/*retourne une voie virtuelle  (par recyclage d'une voie dead, ou malloc)*/
/*	la creation de la voie audible sera faite plus tard*/
p_virtual_voice get_virtual_voice(SND_tdhVirtualModule pmodule)
{
	p_virtual_voice voice;
	p_dead_voice dead;
 
	if ((dead=SNDLST2_M_DynamicGetFirstElement(&pmodule->dead_voices.pList))!=NULL)
	{/*recyclage*/
		voice=dead->voice;
		erase_dead_voice_from_list(dead);
	}
	else
	{/*new voice*/
		voice=SND_fn_pvMallocSndEx(E_ucSndBlockMain,sizeof(virtual_voice));
		voice->bUsed=FALSE;
	}
 
	SNDLST2_M_DynamicInitElement(voice);
	SNDLST2_M_DynamicAddTail(&pmodule->virtual_voices.pList,voice);
	voice->lVoice=C_PLAY_FAILED;
	voice->audible=NULL;
	voice->pstParam=NULL;
	voice->lSizeParam=0;
	voice->dead=NULL;
 
#ifdef DEBUG_OUTPUT_SNDVIRT
	_RPT1(_CRT_WARN,"VV %x new\n",voice);
#endif
	return voice;
}
 
/*destruction du contenu de pVoice*/
void purge_virtual_voice(SND_tdhVirtualModule pmodule,virtual_voice* pVoice)
{
	SNDLST2_M_DynamicIsolate(pVoice);
	if (pVoice->audible)
		del_audible_voice(pmodule,pVoice->audible);
	pVoice->lVoice=C_PLAY_FAILED;
	if (pVoice->pstParam)
	{
		SND_fn_vFreeSndEx(E_ucSndBlockMain,pVoice->pstParam);
		pVoice->pstParam=NULL;
		pVoice->lSizeParam=0;
	}
 
#ifdef DEBUG_OUTPUT_SNDVIRT
	_RPT1(_CRT_WARN,"VV %x purged\n",pVoice);
#endif
}
 
/*desctruction de la voie virtuelle->destrcution dela voie audible*/
void del_virtual_voice(SND_tdhVirtualModule pmodule,virtual_voice* pVoice)
{
	purge_virtual_voice(pmodule,pVoice);
	SND_fn_vFreeSndEx(E_ucSndBlockMain,pVoice);
 
#ifdef DEBUG_OUTPUT_SNDVIRT
	_RPT1(_CRT_WARN,"VV %x deleted\n",pVoice);
#endif
}
 
/*predestruction de la voie virtuelle; destruction uniquement si on peut  prevenir le haut-niveau*/
/*transfert de virtual_list vers dead_list*/
void kill_virtual_voice(SND_tdhVirtualModule pmodule,virtual_voice* pVoice)
{
	purge_virtual_voice(pmodule,pVoice);
	/*voice has never been used->you can delete it*/
	if (pVoice->bUsed)
		pVoice->dead=add_dead_voice(pmodule,pVoice);
	else
		del_virtual_voice(pmodule,pVoice);
 
#ifdef DEBUG_OUTPUT_SNDVIRT
	_RPT1(_CRT_WARN,"VV %x killed\n",pVoice);
#endif
}
 
/*remet une virtual voices à sa place quand on sait qu'elle est mal placee*/
void resort_virtual_voice(SND_tdhVirtualModule pmodule,p_virtual_voice _voice)
{
	p_virtual_voice pVoice,tmp_voice;
 
	SNDLST2_M_DynamicIsolate(_voice);
	if (_voice->audible)
	{
		SNDLST2_M_DynamicIsolate(_voice->audible);
	}
 
	pVoice=SNDLST2_M_DynamicGetFirstElement(&pmodule->virtual_voices.pList);
 
	/*classement selon la priorite*/
	while ((pVoice!=NULL) && (pVoice->lPrio>_voice->lPrio))
	{
		pVoice=SNDLST2_M_DynamicGetNextElement(pVoice);
	}
 
	if ((pVoice!=NULL) && (pVoice->lPrio==_voice->lPrio))
	{/*classement selon la norme*/
		while ((pVoice!=NULL) && (pVoice->rNorme>_voice->rNorme))
		{
			pVoice=SNDLST2_M_DynamicGetNextElement(pVoice);
		}
 
		if ((pVoice!=NULL) && (pVoice->rNorme==_voice->rNorme))
		{/*classement selon l'instance*/
			while ((pVoice!=NULL) && (pVoice->lInstance>_voice->lInstance))
			{
				pVoice=SNDLST2_M_DynamicGetNextElement(pVoice);
			}
		}
	}
 
	if (pVoice==NULL)
	{/*la derniere place ira tres bien*/
		SNDLST2_M_DynamicAddTail(&pmodule->virtual_voices.pList,_voice);
	}
	else
	{/*_voice avant pVoice*/
		tmp_voice=SNDLST2_M_DynamicGetPrevElement(pVoice);
		SNDLST2_M_DynamicInsertBetween(_voice,tmp_voice,pVoice);
	}
 
	if (_voice->audible)
		reinsert_audible_voice(pmodule,_voice->audible);
 
#ifdef DEBUG_OUTPUT_SNDVIRT
	_RPT1(_CRT_WARN,"VV %x resorted\n",_voice);
#endif
}
 
 
/*relance-arret des sons associes aux voies virtuelles*/
void synchro_virtual_voice(SND_tdhVirtualModule pmodule)
{
	p_virtual_voice pVoice,pVoiceFirstMute,pVoiceLastAudible;
	p_audible_voice pAudible,pAudibleNext;
	int i;
 
	/*recherche de la 1° voix à etre muette (pVoiceFirstMute);si NULL, pas ne nouvelles voix mutees*/
	pVoice=SNDLST2_M_DynamicGetFirstElement(&pmodule->virtual_voices.pList);
	i=0;
	while (pVoice && i<pmodule->g_lNbSxdAudible)
	{
		pVoice=SNDLST2_M_DynamicGetNextElement(pVoice);
		i++;
	}
	pVoiceFirstMute=pVoice;
	if (pVoiceFirstMute)
		pVoiceLastAudible=SNDLST2_M_DynamicGetPrevElement(pVoiceFirstMute);
	else
		pVoiceLastAudible=SNDLST2_M_DynamicGetLastElement(&pmodule->virtual_voices.pList);
 
	/*1-arreter tous les audible dont le virtual est de rang >g_lNbSxdAudible*/
	/*recherche du 1° audible a stoppe*/
	while (pVoice && !pVoice->audible)
	{
		pVoice=SNDLST2_M_DynamicGetNextElement(pVoice);
	}
	if (pVoice)
	{
		pAudible=pVoice->audible;
	}
	else
		pAudible=NULL;
 
	/*pAudible est le 1° son no more audible*/
	while (pAudible!=NULL)
	{
		pAudibleNext=SNDLST2_M_DynamicGetNextElement(pAudible);
 
		if (!SND_fn_bIsResourceLoopingSxd(pAudible->voice->tduRes))
			kill_virtual_voice(pmodule,pAudible->voice);
		else
			del_audible_voice(pmodule,pAudible);
 
		pAudible=pAudibleNext;
	}
 
	/*2-relancer tous les virtuals de rang inferieur non encore audible*/
	pVoice=pVoiceLastAudible;
	while (pVoice!=NULL)
	{
		if (!pVoice->audible && !pVoice->bPaused)
		{/*ATTENTION!! ne pas refaire Play si la voie est virtuellement en Pause*/
			pVoice->audible=add_audible_voice(pmodule,pVoice);
		}
 
		pVoice=SNDLST2_M_DynamicGetPrevElement(pVoice);
	}
}
 
/*destruction du contenu de voice_good et transfert de voice_bad dans voice_good, puis destruction de voice_bad*/
/*ne pas toucher au audible de voice_bad*/
/*utilise dans le cas ou PlayVirt renvoie 2 fois la meme valeur pour signifier que */
/*	la 1° instance du son est finie*/
/*retourne la voie virtuelle raj*/
p_virtual_voice replace_virtual_voice(SND_tdhVirtualModule pmodule,p_virtual_voice voice_good,p_virtual_voice voice_bad)
{
	voice_good->lVoice=C_PLAY_FAILED;
	purge_virtual_voice(pmodule,voice_good);
 
	SNDLST2_M_DynamicIsolate(voice_bad);
	memcpy(voice_good,voice_bad,sizeof(virtual_voice));
 
	voice_bad->audible=NULL;
	voice_bad->pstParam=NULL;
	voice_bad->lSizeParam=0;
	kill_virtual_voice(pmodule,voice_bad);
 
	if (voice_good->audible)
		voice_good->audible->voice=voice_good;
 
	resort_virtual_voice(pmodule,voice_good);
 
	synchro_virtual_voice(pmodule);
 
#ifdef DEBUG_OUTPUT_SNDVIRT
	_RPT2(_CRT_WARN,"VV %x replaced %x\n",voice_good,voice_bad);
#endif
	return voice_good;
}
 
/************************************************
	Fonctions publiques
************************************************/
long SND_fn_lPlaySxdVirtual(SND_tdhVirtualModule pmodule,tduRefRes res,SoundParam *par,long prio,SND_td_pfn_vSoundCallback fn_callback,long par_callback)
{
	p_audible_voice pAudible;
	p_virtual_voice pVoice,voice;
	p_dead_voice	pDead;
	int i;
	SndBool	bReplaced=FALSE;
 
	/*pre-attribution d'une valeur pour pVoice (pourra changer jusqu'au return)*/
	pVoice=get_virtual_voice(pmodule);
 
	pVoice->rNorme=SND_fn_rGetNormeSxd(par);
	if (pmodule->g_lInstance>=INSTANCE_MAX)
	{/*g_lInstance is too high->reduce every previous values of lInstance*/
		SNDLST2_M_DynamicForEachElementOf(&pmodule->virtual_voices.pList,voice,i)
		{
			voice->lInstance=max(0,voice->lInstance-INSTANCE_MAX/2);
		}
		pmodule->g_lInstance=INSTANCE_MAX/2;
	}
	pVoice->lInstance=pmodule->g_lInstance++;
	pVoice->lPrio=prio;
	pVoice->pfnCallback=fn_callback;
	pVoice->lParamCallback=par_callback;
	pVoice->bHardCallback=FALSE;
	pVoice->tduRes=res;
	pVoice->lSizeParam=SND_M_lGetSizeOfSoundParam(par);
	pVoice->pstParam=SND_fn_pvMallocSndEx(E_ucSndBlockMain,pVoice->lSizeParam);
	memcpy(pVoice->pstParam,par,pVoice->lSizeParam);
	pVoice->bPaused=FALSE;
 
	resort_virtual_voice(pmodule,pVoice);
 
	synchro_virtual_voice(pmodule);
 
	/*PlaySxdWave à echoue OU son non bouclant et non audible -> PlaySxdVirtual echouera*/
	if ((pVoice->audible && pVoice->lVoice==C_PLAY_FAILED)
		|| (!pVoice->audible && !SND_fn_bIsResourceLoopingSxd(pVoice->tduRes)))
	{/*on ne lancera jamais le son*/
		kill_virtual_voice(pmodule,pVoice);
 
		check_integrity(pmodule);
		return C_PLAY_FAILED;
	}
 
	/*check des reliquats SxdWave*/
	SNDLST2_M_DynamicForEachElementOf(&pmodule->audible_voices.pList,pAudible,i)
	{
		if ((pAudible->voice->lVoice==pVoice->lVoice) && (pAudible->voice!=pVoice))
		{/*une voie s'est eteinte, on va donc la detruire*/
			pVoice=replace_virtual_voice(pmodule,pAudible->voice,pVoice);
			bReplaced=TRUE;
			break;
		}
	}
 
	if (!bReplaced)
	{
		/*recyclage d'une (eventuelle) dead_voice*/
		if ((pDead=SNDLST2_M_DynamicGetFirstElement(&pmodule->dead_voices.pList))!=NULL)
		{
			pVoice=replace_virtual_voice(pmodule,pDead->voice,pVoice);
			erase_dead_voice_from_list(pDead);
			bReplaced=TRUE;
		}
	}
 
	pVoice->bUsed=TRUE;
 
#ifdef DEBUG_OUTPUT_SNDVIRT
	_RPT1(_CRT_WARN,"Play VV %x done**********\n",pVoice);
#endif
	check_integrity(pmodule);
	#ifdef SUPERVISATER
	dbgSND_fn_vRajListesSxdVirtual2(pmodule);
	#endif
 
	return (long)pVoice;
}
 
void SND_fn_vRemoveCallbackSxdVirtual(SND_tdhVirtualModule pmodule,long voice)
{
	p_virtual_voice pVoice=(p_virtual_voice)voice;
 
	if ((pVoice->audible) && (pVoice->bHardCallback))
		(*(pmodule->stPtrFunctions.pfn_vRemoveCallbackSxd))(pVoice->lVoice);
	pVoice->pfnCallback=NULL;
}
 
SndBool	SND_fn_bSetParamSxdVirtual(SND_tdhVirtualModule pmodule,long voice,SoundParam *par)
{
	p_virtual_voice pVoice=(p_virtual_voice)voice;
	SndBool	bRet;
 
	if (pVoice->dead)
	{
		bRet=FALSE;
	}
	else
	{
		if (pVoice->audible)
			bRet=(*(pmodule->stPtrFunctions.pfn_bSetParamSxd))(pVoice->lVoice,par);
		else
			bRet=TRUE;
	}
 
	if (bRet==FALSE)
	{/*destruction de la voie virtuelle*/
		if ((!pVoice->audible) && (pVoice->pfnCallback) && (!pVoice->bHardCallback))
			(*pVoice->pfnCallback)(pVoice->lParamCallback);
		if (pVoice->dead)
			erase_dead_voice_from_list(pVoice->dead);
		pVoice->lVoice=C_PLAY_FAILED;
		del_virtual_voice(pmodule,pVoice);
	}
	else
	{/*raj du soundParam*/
		raj_soundparam(pVoice,par);
		pVoice->rNorme=SND_fn_rGetNormeSxd(par);
		resort_virtual_voice(pmodule,pVoice);
	}
 
#ifdef DEBUG_OUTPUT_SNDVIRT
	_RPT2(_CRT_WARN,"VV %x Tested(SetParam) and return %d**********\n",pVoice,bRet);
#endif
	return bRet;
}
 
SndBool	SND_fn_bTestIsPlayingSxdVirtual(SND_tdhVirtualModule pmodule,long voice)
{
	virtual_voice* pVoice=(p_virtual_voice)voice;
	SndBool	bRet;
 
	if (pVoice->dead)
	{
		bRet=FALSE;
	}
	else
	{
		if (pVoice->audible)
			bRet=(*(pmodule->stPtrFunctions.pfn_bTestIsPlayingSxd))(pVoice->lVoice);
		else
			bRet=TRUE;
	}
 
	if (bRet==FALSE)
	{/*destruction de la voie virtuelle*/
		if ((!pVoice->audible) && (pVoice->pfnCallback) && (!pVoice->bHardCallback))
			(*pVoice->pfnCallback)(pVoice->lParamCallback);
		if (pVoice->dead)
			erase_dead_voice_from_list(pVoice->dead);
		pVoice->lVoice=C_PLAY_FAILED;
		del_virtual_voice(pmodule,pVoice);
	}
#ifdef DEBUG_OUTPUT_SNDVIRT
	_RPT2(_CRT_WARN,"VV %x Tested and return %d**********\n",pVoice,bRet);
#endif
 
	return bRet;
}
 
void SND_fn_vStopSxdVirtual(SND_tdhVirtualModule pmodule,long voice)
{
	virtual_voice* pVoice=(p_virtual_voice)voice;
 
	if (pVoice->dead)
		erase_dead_voice_from_list(pVoice->dead);
	if (pVoice->audible)
		del_audible_voice(pmodule,pVoice->audible);
 
	if ((pVoice->pfnCallback) && (!pVoice->bHardCallback))
		(*pVoice->pfnCallback)(pVoice->lParamCallback);
 
 
	del_virtual_voice(pmodule,pVoice);
 
	synchro_virtual_voice(pmodule);
 
	check_integrity(pmodule);
 
	#ifdef SUPERVISATER
	dbgSND_fn_vRajListesSxdVirtual2(pmodule);
	#endif
#ifdef DEBUG_OUTPUT_SNDVIRT
	_RPT1(_CRT_WARN,"VV %x Stoped done **********\n",voice);
#endif
}
 
void SND_fn_vPauseSxdVirtual(SND_tdhVirtualModule pmodule,long voice)
{
	virtual_voice* pVoice=(p_virtual_voice)voice;
 
	pVoice->bPaused=TRUE;
 
	if (pVoice->audible)
		(*(pmodule->stPtrFunctions.pfn_vPauseSxd))(pVoice->lVoice);
}
 
void SND_fn_vResumeSxdVirtual(SND_tdhVirtualModule pmodule,long voice)
{
	p_virtual_voice pVoice=(p_virtual_voice)voice;
 
	pVoice->bPaused=FALSE;
 
	if (pVoice->audible)
		(*(pmodule->stPtrFunctions.pfn_vResumeSxd))(pVoice->lVoice);
	else /*maybe, the virtual voice may start again*/
		synchro_virtual_voice(pmodule);
}
 
 
SndReal	SND_fn_rGetPosSxdVirtual(SND_tdhVirtualModule pmodule,long voice)
{
	p_virtual_voice pVoice=(p_virtual_voice)voice;
 
	if (pVoice->audible)
		return (*(pmodule->stPtrFunctions.pfn_rGetPosSxd))(pVoice->lVoice);
	else
		return SND_C_POS_UNKNOWN;
}
 
SndReal	SND_fn_rGetLengthSxdVirtual(SND_tdhVirtualModule pmodule,long voice)
{
	p_virtual_voice pVoice=(p_virtual_voice)voice;
 
	if (pVoice->audible)
		return (*(pmodule->stPtrFunctions.pfn_rGetLengthSxd))(pVoice->lVoice);
	else
		return SND_C_LENGTH_UNKNOWN;
}
 
 
SND_tdhVirtualModule SND_fn_lInitSxdVirtual(long nb_audible,ptr_virtualfunction *functions)
{
	SND_tdhVirtualModule pmodule;
 
	if (!virtual_module_list_init)
	{
		virtual_module_list_init=TRUE;
		SNDLST2_M_DynamicInitAnchor(&virtual_modules.pList);
	}
 
	pmodule=SND_fn_pvMallocSndEx(E_ucSndBlockMain,sizeof(virtual_module));
 
	SNDLST2_M_DynamicInitElement(pmodule);
	SNDLST2_M_DynamicAddTail(&virtual_modules.pList,pmodule);
 
	SNDLST2_M_DynamicInitAnchor(&pmodule->dead_voices.pList);
	SNDLST2_M_DynamicInitAnchor(&pmodule->audible_voices.pList);
	SNDLST2_M_DynamicInitAnchor(&pmodule->virtual_voices.pList);
 
	pmodule->g_lInstance=0;
	pmodule->g_lNbSxdAudible=nb_audible;
 
	memcpy(&pmodule->stPtrFunctions,functions,sizeof(pmodule->stPtrFunctions));
 
	return pmodule;
}
 
SndBool	SND_fn_bTestInitSxdVirtual(SND_tdhVirtualModule pmodule)
{
	return TRUE;
}
 
void SND_fn_vDesInitSxdVirtual(SND_tdhVirtualModule pmodule)
{
	SNDLST2_M_DynamicIsolate(pmodule);
 
	SND_fn_vFreeSndEx(E_ucSndBlockMain,pmodule);
}
 
void SND_fn_vSynchroSxdVirtual(SND_tdhVirtualModule pmodule)
{
	synchro_virtual_voice(pmodule);
 
	check_integrity(pmodule);
 
	#ifdef SUPERVISATER
	dbgSND_fn_vRajListesSxdVirtual2(pmodule);
	#endif
}
 
/*dynamically change the number of audible voices*/
void SND_fn_vChangeNbVoiceWishedSxdVirtual(SND_tdhVirtualModule module,long nb_audible)
{
	module->g_lNbSxdAudible=nb_audible;
}
 
