/*
//////////////////////////////////////////////////////////
//              Module SNDPLAY Version 2.0                                              //
//////////////////////////////////////////////////////////
*/
 
#include "SNDinc.h"
 
 
#ifdef DEBUG_SON
#include <string.h>
#endif
 
#if defined(_DLL_COMPILATION_MODE)
#include "snddll.h"
#else
#include "sndcd.h"
#include "sndmidi.h"
#ifndef DISABLE_MULTIWAV
#include "sndxd.h"
#else
#include "sndxdwav.h"
#endif
#endif
 
#ifndef DISABLE_RECORD
#include "sndrec.h"
#endif
 
#include "sndres.h"
#include "sndplay.h"
#include "sndtheme.h"
#include "sndseq.h"
#include "sndspace.h"
#include "sndrndom.h"
#include "sndswtch.h"
 
#ifndef NO_ACP_SOUND
 
/*---------------- fonctions privees --------------------*/
 
typedef void SND_CALL td_fn_vPauseFunc(long);
typedef void SND_CALL td_fn_vResumeFunc(long);
typedef SndBool SND_CALL td_fn_bSetParamFunc(long,SoundParam*);
typedef void SND_CALL td_fn_vStopFunc(long);
typedef SndReal SND_CALL td_fn_rGetPosFunc(long);
typedef SndBool SND_CALL td_fn_bTestIsPlayingFunc(long);
 
typedef struct _td_st_Func
{
	td_fn_vPauseFunc *pfnPause;
	td_fn_vResumeFunc *pfnResume;
	td_fn_bSetParamFunc *pfnSetParam;
	td_fn_vStopFunc *pfnStop;
	td_fn_rGetPosFunc *pfnGetPos;
	td_fn_bTestIsPlayingFunc *pfnTestIsPlaying;
} td_st_Func;
 
/*global array storing function pointer for each ressource type (to avoid switch)*/
static td_st_Func a_fnFunc[NB_TYPES_RESOURCES]
={
	{NULL,NULL,NULL,NULL,NULL,NULL},
	{SND_fn_vPauseSxd,SND_fn_vResumeSxd,SND_fn_bSetParamSxd,SND_fn_vStopSxd,SND_fn_rGetPosSxd,SND_fn_bTestIsPlayingSxd},
	{SND_fn_vPauseMidi,SND_fn_vResumeMidi,SND_fn_bSetParamMidi,SND_fn_vStopMidi,SND_fn_rGetPosMidi,SND_fn_bTestIsPlayingMidi},
#ifndef DISABLE_CD
	{SND_fn_vPauseCD,SND_fn_vResumeCD,SND_fn_bSetParamCD,SND_fn_vStopCD,SND_fn_rGetPosCD,SND_fn_bTestIsPlayingCD},
#else
	{NULL,NULL,NULL,NULL,NULL,NULL},
#endif
#ifndef DISABLE_SEQUENCE
	{SND_fn_vPauseSeq,SND_fn_vResumeSeq,SND_fn_bSetParamSeq,SND_fn_vStopSeq,SND_fn_rGetPosSeq,SND_fn_bTestIsPlayingSeq},
#else
	{NULL,NULL,NULL,NULL,NULL,NULL},
#endif
	{NULL,NULL,NULL,NULL,NULL,NULL},
#ifndef DISABLE_SPLIT
	{SND_fn_vPauseSplit,SND_fn_vResumeSplit,SND_fn_bSetParamSplit,SND_fn_vStopSplit,SND_fn_rGetPosSplit,SND_fn_bTestIsPlayingSplit},
#else
	{NULL,NULL,NULL,NULL,NULL,NULL},
#endif
	{NULL,NULL,NULL,NULL,NULL,NULL},
	{SND_fn_vPauseSwitch,SND_fn_vResumeSwitch,SND_fn_bSetParamSwitch,SND_fn_vStopSwitch,SND_fn_rGetPosSwitch,SND_fn_bTestIsPlayingSwitch},
	{NULL,NULL,NULL,NULL,NULL,NULL},
	{SND_fn_vPauseRandom,SND_fn_vResumeRandom,SND_fn_bSetParamRandom,SND_fn_vStopRandom,SND_fn_rGetPosRandom,SND_fn_bTestIsPlayingRandom},
#ifndef DISABLE_THEME
	{SND_fn_vPauseTheme,SND_fn_vResumeTheme,SND_fn_bSetParamTheme,SND_fn_vStopTheme,SND_fn_rGetPosTheme,SND_fn_bTestIsPlayingTheme},
#else
	{NULL,NULL,NULL,NULL,NULL,NULL},
#endif
}
;
 
 
typedef struct {
        long            voice_sxd;  /*voie bas-niveau associee*/
        tduRefRes       res;                /*ressource associee*/
/*        long            prio;               */
        SndBool_field_decl(free);               /*si TRUE, infos non valides, element disponible*/
        SndBool_field_decl(association_running); /*TRUE si en cours d'allocation (entre preassocie et associe/desassocie)*/
		SndBool_field_decl(bTransition);	/*TRUE si voie PlayTransition, FALSE si PlaySnd*/
        SndBool			bValid;
        SndBool*        pbValid;        /*ptr sur le Booleen à mettre à FALSE en cas de reattribution frauduleuse*/
		long			lPauseInstance;	/*0 si pas en pause, sinon Id de l'instane de Pause responsable*/
/*        td_fn_vPauseFunc    *fnPause;*/
/*        td_fn_vResumeFunc   *fnResume;*/
/*        td_fn_bSetParamFunc *fnSetParam;*/
/*        td_fn_vStopFunc     *fnStop;*/
/*        td_fn_rGetPosFunc	*fnGetPos;*/
/*		td_fn_bTestIsPlayingFunc *fnTestIsPlaying;*/
} voice_description;
 
#define NB_VOICE_MAX 64
static voice_description voice_snd[NB_VOICE_MAX];
 
/*
//---pour le type switch
typedef struct {
        long            voice_snd;              //voie associee à l'element valide
        tduRefRes       res_switch;             //ressource switch associee
        tduRefRes       res_current;            //element valide
        long            prio;
        SndBool         bValid; //FALSE si voice_snd valid
        SndBool         *pbValid; //mettre à FALSE à la liberetion de la voie
        SndBool         free;   //si TRUE, infos non valides, element disponible
} switch_description;
 
#define NB_SWITCH_MAX 32
switch_description switch_snd[NB_SWITCH_MAX];
*/
 
#ifndef DISABLE_SPLIT
/*---pour le type split*/
typedef struct _active_plage *p_active_plage;
 
SNDLST2_M_DynamicUseListOf(p_active_plage);
 
typedef struct _active_plage {
        long                voice_snd;  /*voie associe à la plage*/
        tdstRangeSplitMem*  pRange;        /*ressource associee*/
        SndBool             bValid;     /*FALSE si voice_snd invalid*/
        SNDLST2_M_DynamicElementDeclaration(p_active_plage)        /*insertion dans la liste ACP*/
} active_plage;
 
typedef struct _split_description {
        tduRefRes       res_split;             /*ressource split associee*/
        long            prio;
        SndBool         *pbValid; /*mettre à FALSE à la liberetion de la voie*/
        SndBool         free;   /*si TRUE, infos non valides, element disponible*/
        SNDLST2_M_DynamicAnchorDeclaration(p_active_plage) pList;
} split_description;
 
#define NB_SPLIT_MAX 32
static split_description split_snd[NB_SPLIT_MAX];
#endif /*DISABLE_SPLIT*/
 
static SndBool g_iInitSxd,g_iInitCD,g_iInitMidi; /*codes de retour des InitXXX*/
 
tduRefRes SND_RES_FANTOME={(unsigned long)SND_C_RES_FANTOME_PTR};
 
static int g_lCurrentGlobalPauseInstance=1;/*id de la prochaine instance de Pause*/
 
/*---- fonctions de gestion de SoundParam*/
/*
long SND_fn_lGetSizeOfSoundParam(SoundParam* _pObj)
{
    return (sizeof(SoundParam)+(_pObj->iNbLinks-NB_LINK)*sizeof(MicroLink)+sizeof(RollOffParam));
}
*/
 
#ifndef NB_MICRO_MAX
/*---- cree une structure SoundParam dont le champ iNbLink est VALIDE*/
SoundParam* SND_fn_pCreateSoundParam(int nb_micro)
{
    SoundParam* tmp;
 
    tmp=SND_fn_pvMallocSndEx(E_ucSndBlockMain,
		SND_M_lGetSizeOfSoundParamFromNbLink(nb_micro));
    tmp->iNbLinks=nb_micro;
 
    return tmp;
}
 
void SND_fn_vDestroySoundParam(SoundParam* _pObj)
{
    SND_fn_vFreeSndEx(E_ucSndBlockMain,_pObj);
}
#endif 
 
void SND_fn_vCopySoundParam(SoundParam*_pDest,SoundParam* _pSrc)
{
    memcpy(_pDest,_pSrc,SND_M_lGetSizeOfSoundParam(_pSrc));
}
 
 

/*----renvoie la liste des voies*/
void liste_of_voices(char* texte,long size)
{
#ifdef DEBUG_SON
        SndBool no_voices=TRUE;
/*        SndBool no_switch=TRUE;*/
        SndBool no_split=TRUE;
#ifndef DISABLE_SPLIT
        p_active_plage plage;
		int j;
#endif
        int i;
        char temp[128];
 
        texte[0]='\0';
        for (i=0;i<NB_VOICE_MAX;i++)
        {
            if (!voice_snd[i].free)
            {
                no_voices=FALSE;
                sprintf(temp,"Vsnd %X (Vsxd:%X-",&voice_snd[i],voice_snd[i].voice_sxd);
                strncat(texte,temp,size-strlen(texte)-1);
                                if (voice_snd[i].res.pstPtr!=NULL)
                                {
                                        sprintf(temp,"res:%d-",voice_snd[i].res.pstPtr->Id);
                                        strncat(texte,temp,size-strlen(texte)-1);
                                        switch (voice_snd[i].res.pstPtr->eType)
                                        {
                                        case TYPE_INVALID: strncat(texte,"INVALID !!!!!)\xd\xa",size-strlen(texte)-1);break;
                                        case TYPE_SAMPLE: strncat(texte,"wav)\xd\xa",size-strlen(texte)-1);break;
                                        case TYPE_MIDI: strncat(texte,"midi)\xd\xa",size-strlen(texte)-1);break;
                                        case TYPE_CDAUDIO: strncat(texte,"cdA)\xd\xa",size-strlen(texte)-1);break;
                                        case TYPE_SEQUENCE: strncat(texte,"seq)\xd\xa",size-strlen(texte)-1);break;
                                        case TYPE_SWITCH: strncat(texte,"switch)\xd\xa",size-strlen(texte)-1);break;
                                        case TYPE_SPLIT: strncat(texte,"split)\xd\xa",size-strlen(texte)-1);break;
										case TYPE_RANDOM: strncat(texte,"random)\xd\xa",size-strlen(texte)-1);break;
                                        default: strncat(texte,"??)\xd\xa",size-strlen(texte)-1);break;
                                        }
                                }
                                else 
                                {
                                        strncat(texte,"NULL)\xd\xa",size-strlen(texte)-1);
                                }
            }
        }
 
        if (no_voices)
        {
          strcpy(texte,"Aucune voie active\xd\xa");
        }
 
        /*------liste des switch*/
        /*
        for (i=0;i<NB_SWITCH_MAX;i++)
        {
                if (!switch_snd[i].free)
                {
                    if (no_switch)
                    {
                            strcpy(temp,"Switchs:\n");
                            strncat(texte,temp,min(strlen(temp),size-strlen(texte)-1));
                    }
                    no_switch=FALSE;
                    sprintf(temp,"V %X (Vsnd:%X-Ele:%d)\n",&switch_snd[i],switch_snd[i].voice_snd,switch_snd[i].res_current);
                    strncat(texte,temp,min(strlen(temp),size-strlen(texte)-1));
                }
        }
 
        if (no_switch)
                {
                strcpy(temp,"Aucun switch actif\n");
                strncat(texte,temp,min(strlen(temp),size-strlen(texte)-1));
                }
        */
#ifndef DISABLE_SPLIT
        /*-----liste des splits*/
        for (i=0;i<NB_SPLIT_MAX;i++)
        {
                if (!split_snd[i].free)
                {
                    if (no_split)
                    {
                            strcpy(temp,"Splits:\xd\xa");
                            strncat(texte,temp,size-strlen(texte)-1);
                    }
                    no_split=FALSE;
                    sprintf(temp,"V %X (",&split_snd[i]);
                    strncat(texte,temp,size-strlen(texte)-1);
 
                    SNDLST2_M_DynamicForEachElementOf(&(split_snd[i].pList),plage, j)
                    {
                        sprintf(temp,"V%X (res %X)-",plage->voice_snd,plage->pRange->uRes.pstPtr);
                        strncat(texte,temp,size-strlen(texte)-1);
                    }
 
                    if (j==0)
                    {
                        sprintf(temp,"no range");
                        strncat(texte,temp,size-strlen(texte)-1);
                    }
                    sprintf(temp,")\xd\xa");
                    strncat(texte,temp,size-strlen(texte)-1);
                }
        }
#endif /*DISABLE_SPLIT*/
        if (no_split)
                {
                strcpy(temp,"Aucun split actif");
                strncat(texte,temp,size-strlen(texte)-1);
                }
#endif /*DEBUG_SON*/
}
  
/*--------trouver un candidat à un associe_snd et le reserve*/
long pre_associe_snd(void)
{
        int i;
 
        /*trouver une association libre...*/
        i=0;
        for (i=0;i<NB_VOICE_MAX;i++)
                if (voice_snd[i].free) break;
 
        if (i==NB_VOICE_MAX)
        {/*trop de voies*/
                SND_M_DisplayErrorEx(E_uwSndTooManyVoices,"",SNDERR_DISPLAY_IF_WANTED);
                return C_PLAY_FAILED;
        }
        else
        {
                voice_snd[i].free=FALSE;
                voice_snd[i].association_running=TRUE;
                voice_snd[i].bValid=TRUE;
                voice_snd[i].voice_sxd=C_PLAY_FAILED;
                return (long)(&voice_snd[i]);
        }
}
 
void annule_pre_associe_snd(long voice)
{
        ((voice_description*)voice)->free=TRUE;
		((voice_description*)voice)->pbValid=NULL;
}
 
/*-------libere une voie Hi*/
void desassocie_snd(long voice)
{
        if (((voice_description*)voice)->pbValid!=NULL)
		{
			*(((voice_description*)voice)->pbValid)=FALSE;
			((voice_description*)voice)->pbValid=NULL;
		}
        ((voice_description*)voice)->free=TRUE;
}
 
/*brise la reference de SNDPLAY vers SOUND3D*/
void invalidate_ptrvalid_snd(long voice)
{
	((voice_description*)voice)->pbValid=NULL;
}
 
/*-------associe une voie Hi à la voie Low retournee et à la ressource justifiant la voie Hi (pas celle justifiant la voie Low)*/
/* en profite pour faire une carbage-nettoyage*/
long associe_snd(long id_asso,long voice_sxd,tduRefRes res,long prio,SndBool* valid,SndBool transition)
{
        int i;
        voice_description* voice_local;/*syn. de &voice_snd[i]*/
 
        /*nettoyage des voies reattribuees trop vite*/
        for (i=0,voice_local=&voice_snd[0];i<NB_VOICE_MAX;i++,voice_local++)
        {
                if ((voice_local->free==FALSE) && 
                        (((voice_local->voice_sxd==C_PLAY_FAILED) && (voice_local->association_running==FALSE))
                        || ((voice_sxd!=C_PLAY_FAILED) && (voice_local->voice_sxd==voice_sxd) && (res.pstPtr->eType==voice_local->res.pstPtr->eType))
                        || (!voice_local->bValid)))
                {/*double attribution frauduleuse=l'ancienne doit etre detruite*/
                        desassocie_snd((long)voice_local);
                }
        }
 
        /*creer la nouvelle association*/
        if (voice_sxd!=C_PLAY_FAILED)
        {
                ((voice_description*)id_asso)->voice_sxd=voice_sxd;
                ((voice_description*)id_asso)->res=res;
/*                ((voice_description*)id_asso)->prio=prio;*/
                ((voice_description*)id_asso)->free=FALSE;
                ((voice_description*)id_asso)->association_running=FALSE;
                ((voice_description*)id_asso)->bValid=TRUE;
                ((voice_description*)id_asso)->pbValid=valid;
                ((voice_description*)id_asso)->bTransition=transition;
                ((voice_description*)id_asso)->lPauseInstance=0;
                if (((voice_description*)id_asso)->pbValid)
                    *(((voice_description*)id_asso)->pbValid)=TRUE;
				if (res.pstPtr!=SND_RES_FANTOME.pstPtr)
				{
/*					((voice_description*)id_asso)->fnPause=a_fnPauseFunc[res.pstPtr->eType];*/
/*					((voice_description*)id_asso)->fnResume=a_fnResumeFunc[res.pstPtr->eType];*/
/*					((voice_description*)id_asso)->fnSetParam=a_fnSetParamFunc[res.pstPtr->eType];*/
/*					((voice_description*)id_asso)->fnStop=a_fnStopFunc[res.pstPtr->eType];*/
/*					((voice_description*)id_asso)->fnGetPos=a_fnGetPosFunc[res.pstPtr->eType];*/
/*					((voice_description*)id_asso)->fnTestIsPlaying=a_fnTestIsPlayingFunc[res.pstPtr->eType];*/
				}
				else
				{
/*					((voice_description*)id_asso)->fnPause=NULL;*/
/*					((voice_description*)id_asso)->fnResume=NULL;*/
/*					((voice_description*)id_asso)->fnSetParam=NULL;*/
/*					((voice_description*)id_asso)->fnStop=NULL;*/
/*					((voice_description*)id_asso)->fnGetPos=NULL;*/
/*					((voice_description*)id_asso)->fnTestIsPlaying=NULL;*/
				}
 
                return (long)(id_asso);
        }
        else
        {
                ((voice_description*)id_asso)->free=TRUE;
				((voice_description*)id_asso)->pbValid=NULL;
                return C_PLAY_FAILED;
        }
}
 
/**************************************************************/
/**********  Gestion des SWITCH                               */
/**************************************************************/
/*----------------------------------------------------------------
        Trouver une association libre et la reserve
        retourne l'id de l'association candidate
-----------------------------------------------------------------*/
/*
long pre_associe_switch()
{
        int i;
 
        //trouver une association libre...
        i=0;
        for (i=0;i<NB_SWITCH_MAX;i++)
                if (switch_snd[i].free==TRUE) break;
 
        if (i==NB_SWITCH_MAX)
        {//... ou en creer une nouvelle
            SND_M_DisplayError(E_uwSndTooManySwitchs,"");
                        return 0;
        }
        else
        {
                switch_snd[i].free=FALSE;
                switch_snd[i].bValid=TRUE;
                switch_snd[i].voice_snd=C_PLAY_FAILED;
                return (long)(&switch_snd[i]);
        }
}
 
//-------libere une voie Hi
void desassocie_switch(long voice)
{
        ((switch_description*)voice)->free=TRUE;
        if (((switch_description*)voice)->pbValid) *(((switch_description*)voice)->pbValid)=FALSE;
}
 
//-------associe une voie Hi à la voie Low retournee et à la ressource justifiant la voie Hi (pas celle justifiant la voie Low)
// Entrees:voice=id de l'asso à creer (retourne par un precedent appel à pre_associe)
//      voice_snd=voie bas-niveau à associee
//      res_switch=resource switch associee
//      res_current=resource bas-niveau activee
//      prio=prio du PlaySnd originel
//      valid=à mettre à FALSE si le switch se desactive
//  Sortie:id effectif de l'asso
long associe_switch(long voice,long par_voice_snd,tduRefRes res_switch,tduRefRes res_current,long prio,SndBool *valid)
{
        switch_description *switch_asso;
        int i;
 
        //----garbage collector
        for (i=0,switch_asso=&switch_snd[0];i<NB_SWITCH_MAX;i++,switch_asso++)
        {
                if ((!switch_asso->free) && 
                        (((switch_asso->voice_snd==par_voice_snd) && (switch_asso->res_current.pstPtr->Id==res_current.pstPtr->Id))
                        || (!switch_asso->bValid)))
                {
                        desassocie_switch((long)switch_asso);
                }
        }
 
        //---------------
        if (par_voice_snd!=C_PLAY_FAILED)
        {
                //creer la nouvelle association
                ((switch_description*)voice)->free=FALSE;
                ((switch_description*)voice)->voice_snd=par_voice_snd;
                ((switch_description*)voice)->res_switch=res_switch;
                ((switch_description*)voice)->res_current=res_current;
                ((switch_description*)voice)->prio=prio;
                ((switch_description*)voice)->bValid=TRUE;
                ((switch_description*)voice)->pbValid=valid;
 
                return voice;
        }
        else
        {
                ((switch_description*)voice)->free=TRUE;
                return C_PLAY_FAILED;
        }
}
*/
 
#ifndef DISABLE_SPLIT
/**************************************************************/
/**********  Gestion des SPLIT                                */
/**************************************************************/
/*ajouter une plage invalide à un split actif*/
active_plage* add_active_plage(long voice)
{
    p_active_plage plage;
 
    plage=SND_fn_pvMallocSndEx(E_ucSndBlockMain,sizeof(active_plage));
    SNDLST2_M_DynamicInitElement(plage);
    plage->pRange=NULL;
    SNDLST2_M_DynamicAddTail(&(((split_description*)voice)->pList),plage);
 
    return plage;
}
 
/*supprimer une plage invalide à un split actif*/
void sup_active_plage(p_active_plage plage)
{
    SNDLST2_M_DynamicIsolate(plage);
    SND_fn_vFreeSndEx(E_ucSndBlockMain,plage);
}
 
/*supprimer un split invalide*/
void desassocie_split(long voice)
{
        ((split_description*)voice)->free=TRUE;
        if (((split_description*)voice)->pbValid)
		{
			*(((split_description*)voice)->pbValid)=FALSE;
			((split_description*)voice)->pbValid=NULL;
		}
}
 
/*-------associe une voie split à une voie SND*/
/* Entrees:res_split=resource split associee*/
/*      prio=prio du PlaySnd originel*/
/*      valid=à mettre à FALSE si le split se desactive*/
/*  Sortie:id effectif de l'asso*/
long associe_split(tduRefRes res_split,long prio,SndBool *valid)
{
        split_description *voice;
        p_active_plage plage,next_plage;
        int i,j;
 
        /*----garbage collector*/
        for (i=0,voice=&split_snd[0];i<NB_SPLIT_MAX;i++,voice++)
        {
            if (!voice->free)
            {
                SNDLST2_M_DynamicForEachMovingElementOf( &voice->pList, plage, next_plage, j)
                {
                    if (!plage->bValid)
                        sup_active_plage(plage);
                }
            }
        }
 
        /*trouver une association libre...*/
        for (i=0;i<NB_SPLIT_MAX;i++)
                if (split_snd[i].free) break;
 
        if (i==NB_SPLIT_MAX)
        {/*... ou en creer une nouvelle*/
            SND_M_DisplayErrorEx(E_uwSndTooManySplits,"",SNDERR_DISPLAY_IF_WANTED);
            return C_PLAY_FAILED;
        }
        /*else*/
        voice=&split_snd[i];
 
        /*creer la nouvelle association*/
        voice->free=FALSE;
        voice->res_split=res_split;
        voice->prio=prio;
        voice->pbValid=valid;
        SNDLST2_M_DynamicInitAnchor(&voice->pList);
 
        return (long)voice;
}
 
/*obtenir les parametres dynamiques pour une plage*/
void get_plage_param(tdstRangeSplitMem* range,SoundParam* par,SoundParam* par_plage)
{
    SND_fn_vCopySoundParam(par_plage,par);
    par_plage->iFlags|=(/*C_SOUNDPARAM_COEF_VOL | */C_SOUNDPARAM_COEF_FREQ);
 
    par_plage->Freq=SND_fn_rMulRealRealSnd(par->Freq,range->rCoefPitch);
    if ((par->Freq<=range->rPitchA) || (par->Freq>=range->rPitchD))
    {
        par_plage->ucVol=0;
        return;
    }
    if ((par->Freq>=range->rPitchB) && (par->Freq<=range->rPitchC))
    {
        par_plage->ucVol=(unsigned char)(((int)par->ucVol*(int)range->ucVolume)>>7);
        return;
    }
    if ((par->Freq<range->rPitchB)/* && (par->Freq>range->rPitchA)*/) 
    {
        par_plage->ucVol=(unsigned char)SND_fn_rMulRealRealSnd(par->Freq-range->rPitchA,range->rCoefMagAB);
        return;
    }
    if ((par->Freq>range->rPitchC)/* && (par->Freq<range->rPitchD)*/) 
    {
        par_plage->ucVol=(unsigned char)SND_fn_rMulRealRealSnd(par->Freq-range->rPitchD,range->rCoefMagCD);
        return;
    }
}
 
/*obtenir le nombre de plages actives*/
long get_active_plage(long voice)
{
    p_active_plage plage;
    int i;
 
    SNDLST2_M_DynamicForEachElementOf(&((split_description*)voice)->pList, plage, i)
    {/*pour chacune des voies actuellement effectivement active  */
    }
 
    return i;
}
 
#define NB_RANGE_WISHED_MAX 10
/*----raj des plages d'un split*/
long raj_active_plage(long voice,SoundParam* par)
{
    int i,j;
    tduRefRes res_split;
    p_active_plage plage,next_plage;
    tdstRangeSplitMem* range;
    tdstRangeSplitMem* range_wished[NB_RANGE_WISHED_MAX];
    p_active_plage checked_range[NB_RANGE_WISHED_MAX];
    int nb_range_wished=0;
    SoundParam *p_par_plage;
#ifdef NB_MICRO_MAX
    SoundParam par_plage;
#endif
 
#ifdef NB_MICRO_MAX
	p_par_plage=&par_plage;
	par_plage.iNbLinks=par->iNbLinks;
#else
    p_par_plage=SND_fn_pCreateSoundParam(par->iNbLinks);
#endif
 
    if ((voice==C_PLAY_FAILED) || ((split_description*)voice)->free)
        return 0;
 
    res_split=((split_description*)voice)->res_split;
 
    /*etablir la liste des ranges qui doivent etre actifs*/
    SNDLST2_M_StaticForEachElementOf( &(res_split.pstPtr->uRes.stSplit.stRangeList), range, i)
    {
        if ((range->rPitchA<=par->Freq) && (range->rPitchD>=par->Freq))
        {
            range_wished[nb_range_wished++]=range;
        }
    }
 
    /*init checked_range*/
    for (i=0;i<nb_range_wished;i++)
        checked_range[i]=NULL;
 
    /*virer les ranges qui ne sont plus actifs*/
    SNDLST2_M_DynamicForEachMovingElementOf(&(((split_description*)voice)->pList) , plage, next_plage, i)
    {/*pour chacune des voies actuellement effectivement active  */
        j=0;
        while ((plage->pRange!=range_wished[j]) && (j<nb_range_wished)) j++;
        if (j==nb_range_wished)
        {/*voie à desactiver*/
            if (plage->bValid)
            {
                plage->bValid=FALSE;
                SND_fn_vStopSnd(plage->voice_snd);
            }
            sup_active_plage(plage);
        }
        else
            checked_range[j]=plage;
    }
 
    /*lancement des nouvelles voies + raj des voies toujours actives*/
    for (i=0;i<nb_range_wished;i++)
    {
        if (checked_range[i]!=NULL)
        {/*la plage etait dejà active*/
            get_plage_param(range_wished[i],par,p_par_plage);
            if (checked_range[i]->bValid)
                checked_range[i]->bValid=SND_fn_bSetParamSnd(checked_range[i]->voice_snd,p_par_plage);
            else
                sup_active_plage(checked_range[i]);
        }
        else
        {/*nouvelle plage*/
            plage=add_active_plage(voice);
            plage->pRange=range_wished[i];
            get_plage_param(plage->pRange,par,p_par_plage);
            plage->voice_snd=SND_fn_lPlaySnd(range_wished[i]->uRes,p_par_plage,((split_description*)voice)->prio,NULL,0,&(plage->bValid));
        }
    }
 
#ifndef NB_MICRO_MAX
    SND_fn_vDestroySoundParam(p_par_plage);
#endif
 
    return nb_range_wished;
}
#endif /*DISABLE_SPLIT*/
 
/*************************************************************/
/**********  Fonctions publiques  ****************************/
/*************************************************************/
/*---------------------------------------------------*/
/*----initialize a BlockMem and make it operational*/
 
/*----initialize a BlockMem and make it operational*/
/*
void SND_fn_vLoadResFromDiskSnd(tdstBlockResourceDisk* disk,tdstBlockResourceMem* mem)
{
        switch (disk->eType)
        {
        case TYPE_SAMPLE:
                SND_fn_vLoadResFromDiskSxd(disk,mem);
                break;            
        case TYPE_MIDI:
                SND_fn_vLoadResFromDiskMidi(disk,mem);
                break;
        default:
                //no binaries data ->convert is sufficient
                SND_fn_vConvertOneResDiskToMem(disk,mem,NULL);           
        }
}
*/
 
#if !defined(NO_ACP_SCRIPT)
/*this function must be defined in Script/Hybrid or DLL mode*/
/* ***********************************************************************/
/* * SND_fn_bLoadResFromDiskScript:                                                                             **/
/* * Initializes a BlocResourceMem      according to a BlockResourceDisk,       **/
/* * with respect to the script mode.                                                                   **/
/* ***********************************************************************/
SndBool SND_fn_bLoadResScriptSnd(tdstBlockResourceDisk* disk,tdstBlockResourceMem* mem)
{
	/*init minimunm pour le mode fake*/
	mem->eType=disk->eType;
 
        switch (disk->eType)
        {
        case TYPE_SAMPLE:
                return(SND_fn_bLoadResScriptSxd(disk,mem));
                break;            
        case TYPE_MIDI:
                return(SND_fn_bLoadResScriptMidi(disk,mem));
                break;
#ifndef DISABLE_CD
        case TYPE_CDAUDIO:
                return(SND_fn_bLoadResScriptCd(disk,mem));
                break;            
#endif
#ifndef DISABLE_SEQUENCE
        case TYPE_SEQUENCE:
                return(SND_fn_bLoadResScriptSeq(disk,mem));
                break;            
#endif
        case TYPE_SWITCH:
                return(SND_fn_bLoadResScriptSwitch(disk,mem));
                break;            
#ifndef DISABLE_SPLIT
        case TYPE_SPLIT:
                return(SND_fn_bLoadResScriptSplit(disk,mem));
                break;            
#endif
        case TYPE_THEME:
                return(SND_fn_bLoadResScriptTheme(disk,mem));
                break;            
        case TYPE_RANDOM:
                return(SND_fn_bLoadResScriptRandom(disk,mem));
                break;            
        default: /* ERROR! UNKNOWN RES TYPE;*/
                SND_M_DisplayError(E_uwSndInvalidTypeOfResource,"");
                return FALSE;
                break;            
        }
}
#endif
 
#ifndef NO_ACP_LDBIN
/* ***************************************************************************/
/* * SND_fn_bLoadResFromDiskBinary:                                                                                     **/
/* * Initializes a BlocResourceMem      according to a BlockResourceDisk,               **/
/* * with respect to the Binary mode.                                                                           **/
/* * Returns true if the associated data must be freed after load(SoundXd)      **/
/* ***************************************************************************/
SndBool SND_fn_bLoadResBinarySnd(tdstBlockResourceDisk* disk,tdstBlockResourceMem* mem,char *pDataBloc)
{
	/*init minimunm pour le mode fake*/
	mem->eType=disk->eType;
 
        switch (disk->eType)
        {
        case TYPE_SAMPLE:
                return(SND_fn_bLoadResBinarySxd(disk,mem,pDataBloc));
                break;            
        case TYPE_MIDI:
                return(SND_fn_bLoadResBinaryMidi(disk,mem,pDataBloc));
                break;
#ifndef DISABLE_CD
        case TYPE_CDAUDIO:
                return(SND_fn_bLoadResBinaryCd(disk,mem,pDataBloc));
                break;
#endif
#ifndef DISABLE_SEQUENCE
        case TYPE_SEQUENCE:
                return(SND_fn_bLoadResBinarySeq(disk,mem,pDataBloc));
                break;   
#endif
        case TYPE_SWITCH_OLD:
                return(SND_fn_bLoadResBinarySwitchOld(disk,mem,pDataBloc));
                break;            
        case TYPE_SWITCH:
                return(SND_fn_bLoadResBinarySwitch(disk,mem,pDataBloc));
                break;            
#ifndef DISABLE_SPLIT
        case TYPE_SPLIT:
                return(SND_fn_bLoadResBinarySplit(disk,mem,pDataBloc));
                break;            
#endif
#ifndef DISABLE_THEME
        case TYPE_THEME:
                return(SND_fn_bLoadResBinaryTheme(disk,mem,pDataBloc));
                break;            
#endif
        case TYPE_RANDOM:
                return(SND_fn_bLoadResBinaryRandom(disk,mem,pDataBloc));
                break;            
        default: /* ERROR! UNKNOWN RES TYPE;*/
                SND_M_DisplayError(E_uwSndInvalidTypeOfResource,"");
                return FALSE;
                break;            
        }
}
 
#endif /* NO_ACP_LDBIN*/
 
/*----stop all low-level resources for the block resource to allow call to SND_fn_vUnLoadResSnd*/
void SND_fn_vStopBeforeUnLoadResSnd(tdstBlockResourceMem* mem)
{
	int i;
 
    for (i=0;i<NB_VOICE_MAX;i++)
        if (!voice_snd[i].free && voice_snd[i].res.pstPtr==mem && voice_snd[i].bValid)
		{
			if (voice_snd[i].bTransition)
				SND_fn_vStopTransitionSnd((long)&voice_snd[i]);
			else
				SND_fn_vStopSnd((long)&voice_snd[i]);
		}
}
 
/*----free all low-level resources for the block resource*/
void SND_fn_vUnLoadResSnd(tdstBlockResourceMem* mem)
{
	switch (mem->eType)
    {
    case TYPE_SAMPLE:
        SND_fn_vUnLoadResSxd(mem);
        break;
#ifndef DISABLE_MIDI
    case TYPE_MIDI:
        SND_fn_vUnLoadResMidi(mem);
        break;
#endif
#ifndef DISABLE_THEME
	case TYPE_THEME:
		SND_fn_vUnLoadResTheme(mem);
		break;
#endif
    }
	mem->eType=TYPE_INVALID;
}
 
 
#ifndef DISABLE_SPLIT
/*--- init des champs du block tdstRangeSplitMem charge*/
void SND_fn_vInitRangeSplit(tdstRangeSplitMem* pRange)
{
    if (pRange->rPitchB-pRange->rPitchA!=0)
        pRange->rCoefMagAB=SND_fn_rDivRealRealSnd(pRange->ucVolume,pRange->rPitchB-pRange->rPitchA);
    else
        pRange->rCoefMagAB=M_IntToRealSnd(1);
    if (pRange->rPitchC-pRange->rPitchD!=0)
        pRange->rCoefMagCD=SND_fn_rDivRealRealSnd(pRange->ucVolume,pRange->rPitchC-pRange->rPitchD);
    else
        pRange->rCoefMagCD=M_IntToRealSnd(1);
}
 
 
/*--- gestion des ressource Split*/
long SND_fn_lPlaySplit(tduRefRes num_res,SoundParam* par,long prio,SND_td_pfn_vSoundCallback fn_callback,long par_callback,SndBool* valid)
{
    long voice;
    long nb_active_plage;
 
    snd_assert(num_res.pstPtr->eType==TYPE_SPLIT);
 
    voice=associe_split(num_res,prio,valid);
 
    nb_active_plage=raj_active_plage(voice,par);
    if (!nb_active_plage && !num_res.pstPtr->uRes.stSplit.bStayActive)
    {/*aucune voie active->desactivation de la voie*/
        desassocie_split(voice);
        return C_PLAY_FAILED;
    }
    else
        return voice;
}
 
SndBool SND_CALL SND_fn_bSetParamSplit(long voice,SoundParam* par)
{
    long nb_active_plage;
 
    nb_active_plage=raj_active_plage(voice,par);
    if (!nb_active_plage && !((split_description*)voice)->res_split.pstPtr->uRes.stSplit.bStayActive)
    {/*aucune voie active->desactivation de la voie*/
        desassocie_split(voice);
        return FALSE;
    }
    else
        return voice;
}
 
SndBool SND_CALL SND_fn_bTestIsPlayingSplit(long voice)
{
    if (!get_active_plage(voice) && !((split_description*)voice)->res_split.pstPtr->uRes.stSplit.bStayActive)
        return FALSE;
    else
        return TRUE;
}
 
void SND_CALL SND_fn_vStopSplit(long voice)
{
    p_active_plage plage,next_plage;
    int i;
 
    SNDLST2_M_DynamicForEachMovingElementOf(&((split_description*)voice)->pList, plage, next_plage, i)
    {/*pour chacune des voies actuellement effectivement active  */
        if (plage->bValid)
        {   
            plage->bValid=FALSE;
            SND_fn_vStopSnd(plage->voice_snd);
        }
        sup_active_plage(plage);
    }
 
    desassocie_split(voice);
 
}
 
void SND_CALL SND_fn_vPauseSplit(long voie)
{
}
 
void SND_CALL SND_fn_vResumeSplit(long voie)
{
}
 
void SND_fn_vRemoveCallbackSplit(long voie)
{
}
 
void SND_fn_vConvertResDiskToMemSplit(tdstBlockResourceDisk* disk,tdstBlockResourceMem* mem,void* ptrBegin)
{
        mem->Id=disk->Id;
        mem->eType=disk->eType;
        mem->eStorage=disk->eStorage;
        mem->ucVolume=disk->ucVolume;
        mem->bIsLoaded=TRUE;
        
        /*partie specifique au type de ressource*/
        mem->uRes.stSplit.ulNbRanges = disk->uRes.stSplit.ulNbRanges;
        mem->uRes.stSplit.bStayActive= disk->uRes.stSplit.bStayActive;
 
}
 
#ifndef NO_ACP_SCRIPT
SndBool SND_fn_bLoadResScriptSplit(tdstBlockResourceDisk *disk,tdstBlockResourceMem *mem)
{
        SND_fn_vConvertResDiskToMemSplit(disk,mem,NULL);
        return TRUE;
}
#endif
 
#ifndef NO_ACP_LDBIN
 
SndBool SND_fn_bLoadResBinarySplit(tdstBlockResourceDisk *_pBRDisk,tdstBlockResourceMem *_pBRMem,char *pDataBloc)
{
        tdstRangeSplitMem *pRangeArray,*pRange;
        
        int iPos;
        /* Convert the ulDataOffset member to a pointer:*/
        pRangeArray=(tdstRangeSplitMem *)(pDataBloc + _pBRDisk->ulDataOffset);
 
        /* Set pointers to range list:*/
        /*SNDLST2_M_StaticSetFirstElement(&_pBRMem->uRes.stSplit.stRangeList,pRangeArray);*/
        SNDLST2_M_StaticSetMember(&_pBRMem->uRes.stSplit.stRangeList,hFirstElement,pRangeArray);
        /*SNDLST2_M_StaticSetMember( &_pBRMem->uRes.stSplit.stRangeList, hFirstElement, pRangeArray);*/
        SNDLST2_M_StaticSetMember(&_pBRMem->uRes.stSplit.stRangeList, lNumberOfElements, _pBRDisk->uRes.stSplit.ulNbRanges);
 
        /* Reset pointers in range:*/
        SNDLST2_M_StaticForEachElementOf( &_pBRMem->uRes.stSplit.stRangeList, pRange, iPos)
        {
            pRange->uRes.pstPtr=SND_fn_pGetBinRes(pRange->uRes.Id);
            SND_fn_vInitRangeSplit(pRange);
        }
 
        SND_fn_vConvertResDiskToMemSplit(_pBRDisk,_pBRMem,NULL);
        return FALSE;
}
 
#endif /* NO_ACP_LDBIN*/
 
/*---------------------------------------------------------*/
/*	GetPos: retourne la position "theorique" de la ressource*/
/*			exprime en seconde depuis le debut*/
/*			different du temps absolu (car pitch, derive..)*/
/*	Entree: voie concernee*/
/*	Sortie: temps en S (SndReal)*/
/*----------------------------------------------------------*/
SndReal SND_CALL SND_fn_rGetPosSplit(long voie)
{
	return SND_C_POS_UNKNOWN;
}
 
/*---------------------------------------------------------*/
/*	GetLength: retourne la duree "theorique" de la ressource*/
/*			exprime en seconde (constant pour une ressource donnee)*/
/*	Entree: voie concernee*/
/*	Sortie: duree en S (SndReal)*/
/*----------------------------------------------------------*/
SndReal SND_CALL SND_fn_rGetLengthSplit(long voie)
{
	return SND_C_POS_UNKNOWN;
}

SndBool  SND_fn_bSetResourceStaticVolumeSplit(tdstBlockResourceMem* pstRes,unsigned char ucVolume)
{
	pstRes->ucVolume=ucVolume;

	return TRUE;
}


#endif /*DISABLE_SPLIT*/
 
/*---------------- fonctions publiques generales ------------------*/
void pre_initSnd()
{
        int i;
 
        /*----*/
        for (i=0;i<NB_VOICE_MAX;i++)
                voice_snd[i].free=TRUE;
        /*
        for (i=0;i<NB_SWITCH_MAX;i++)
                switch_snd[i].free=TRUE;
        */
#ifndef DISABLE_SPLIT
        for (i=0;i<NB_SPLIT_MAX;i++)
                split_snd[i].free=TRUE;
#endif
		/*
        //----
        for (i=0;i<NB_TYPES_RESOURCES;i++)
                switch (i)
                {
                case TYPE_INVALID:
                case TYPE_SWITCH_OLD://obsolete
				case TYPE_THEME_OLD://obsolete
                    //type invalid !!!! - never use it                   
                        a_fnPauseFunc[i]=NULL;
                        a_fnResumeFunc[i]=NULL;
                        a_fnSetParamFunc[i]=NULL;
                        a_fnStopFunc[i]=NULL;
                        a_fnGetPosFunc[i]=NULL;
                        a_fnTestIsPlayingFunc[i]=NULL;
                        break;
                case TYPE_SWITCH:
                        a_fnPauseFunc[i]=SND_fn_vPauseSwitch;
                        a_fnResumeFunc[i]=SND_fn_vResumeSwitch;
                        a_fnSetParamFunc[i]=SND_fn_bSetParamSwitch;
                        a_fnStopFunc[i]=SND_fn_vStopSwitch;
                        a_fnGetPosFunc[i]=SND_fn_rGetPosSwitch;
                        a_fnTestIsPlayingFunc[i]=SND_fn_bTestIsPlayingSwitch;
                        break;
                case TYPE_RANDOM:
                        a_fnPauseFunc[i]=SND_fn_vPauseRandom;
                        a_fnResumeFunc[i]=SND_fn_vResumeRandom;
                        a_fnSetParamFunc[i]=SND_fn_bSetParamRandom;
                        a_fnStopFunc[i]=SND_fn_vStopRandom;
                        a_fnGetPosFunc[i]=SND_fn_rGetPosRandom;
                        a_fnTestIsPlayingFunc[i]=SND_fn_bTestIsPlayingRandom;
                        break;
                case TYPE_SAMPLE:
                        a_fnPauseFunc[i]=SND_fn_vPauseSxd;
                        a_fnResumeFunc[i]=SND_fn_vResumeSxd;
                        a_fnSetParamFunc[i]=SND_fn_bSetParamSxd;
                        a_fnStopFunc[i]=SND_fn_vStopSxd;
                        a_fnGetPosFunc[i]=SND_fn_rGetPosSxd;
                        a_fnTestIsPlayingFunc[i]=SND_fn_bTestIsPlayingSxd;
                        break;
                case TYPE_MIDI:
                        a_fnPauseFunc[i]=SND_fn_vPauseMidi;
                        a_fnResumeFunc[i]=SND_fn_vResumeMidi;
                        a_fnSetParamFunc[i]=SND_fn_bSetParamMidi;
                        a_fnStopFunc[i]=SND_fn_vStopMidi;
                        a_fnGetPosFunc[i]=SND_fn_rGetPosMidi;
                        a_fnTestIsPlayingFunc[i]=SND_fn_bTestIsPlayingMidi;
                        break;
                case TYPE_CDAUDIO:
#ifndef DISABLE_CD
                        a_fnPauseFunc[i]=SND_fn_vPauseCD;
                        a_fnResumeFunc[i]=SND_fn_vResumeCD;
                        a_fnSetParamFunc[i]=SND_fn_bSetParamCD;
                        a_fnStopFunc[i]=SND_fn_vStopCD;
                        a_fnGetPosFunc[i]=SND_fn_rGetPosCD;
                        a_fnTestIsPlayingFunc[i]=SND_fn_bTestIsPlayingCD;
#endif
                        break;
                case TYPE_SEQUENCE:
#ifndef DISABLE_SEQUENCE
                        a_fnPauseFunc[i]=SND_fn_vPauseSeq;
                        a_fnResumeFunc[i]=SND_fn_vResumeSeq;
                        a_fnSetParamFunc[i]=SND_fn_bSetParamSeq;
                        a_fnStopFunc[i]=SND_fn_vStopSeq;
                        a_fnGetPosFunc[i]=SND_fn_rGetPosSeq;
                        a_fnTestIsPlayingFunc[i]=SND_fn_bTestIsPlayingSeq;
#endif
                        break;
                case TYPE_SPLIT:
#ifndef DISABLE_SPLIT
                        a_fnPauseFunc[i]=SND_fn_vPauseSplit;
                        a_fnResumeFunc[i]=SND_fn_vResumeSplit;
                        a_fnSetParamFunc[i]=SND_fn_bSetParamSplit;
                        a_fnStopFunc[i]=SND_fn_vStopSplit;
                        a_fnGetPosFunc[i]=SND_fn_rGetPosSplit;
                        a_fnTestIsPlayingFunc[i]=SND_fn_bTestIsPlayingSplit;
#endif
                        break;
                case TYPE_THEME:
                        a_fnPauseFunc[i]=SND_fn_vPauseTheme;
                        a_fnResumeFunc[i]=SND_fn_vResumeTheme;
                        a_fnSetParamFunc[i]=SND_fn_bSetParamTheme;
                        a_fnStopFunc[i]=SND_fn_vStopTheme;
                        a_fnGetPosFunc[i]=SND_fn_rGetPosTheme;
                        a_fnTestIsPlayingFunc[i]=SND_fn_bTestIsPlayingTheme;
                        break;
                default:
                        SND_M_DisplayError(E_uwSndInvalidTypeOfResource,"");
                        break;
                }//switch
				*/
}
 
/*------------------------------------------------------------------*/
/*      InitSnd: init du module de traitement des ressources*/
/*      Entree: neant*/
/*      Sortie: code de retour (C_INIT_FAILED,C_INIT_OK ou C_INIT_RUNNING)*/
/*------------------------------------------------------------------*/
int SND_fn_iInitSnd(SND_tdstInitStruct *pInitStruct)
{
		RollOffParam rolloff;
 
		pre_initSnd();
 
        /*----*/
        g_iInitSxd=SND_fn_iInitSxd(pInitStruct);
 
		/*set default RollOff for Sxd*/
		SND_fn_vGetDefaultRollOff(&rolloff);
		SND_fn_vSetDefaultRollOffSxd(&rolloff);
 
	    g_iInitMidi=SND_fn_iInitMidi(pInitStruct);
 
/* CD init is not done at the beginning in the script version: */
#if !defined(SND_SCRIPT_VERSION) && !defined(DISABLE_CD)
		g_iInitCD=SND_fn_iInitCD(pInitStruct);
#endif	/*SND_SCRIPT_VERSION*/
 
#ifndef DISABLE_RECORD
		SND_fn_iInitRecord(pInitStruct);
#endif
 
#ifndef DISABLE_SEQUENCE
        SND_fn_iInitSeq();
#endif
#ifndef DISABLE_THEME
		SND_fn_vInitTheme();
#endif
 
        return C_INIT_OK;
}
 
/*------------------------------------------------------------*/
/*      SND_fn_vSetDefaultRollOffSnd:change default RollOff value*/
/*      Parameter:new RollOff values*/
/*      Sortie:neant*/
/*------------------------------------------------------------*/
void SND_fn_vSetDefaultRollOffSnd(RollOffParam *rolloff)
{
	SND_fn_vSetDefaultRollOff(rolloff);
	SND_fn_vSetDefaultRollOffSxd(rolloff);
}
 
/*------------------------------------------------------------*/
/*      SetDopplerFactorSnd:change Doppler effect range*/
/*      Entree:new factor for Doppler effect (1.0=normal effect=physicallly realistic*/
/*				0.0=no doppler effect*/
/*      Sortie:neant*/
/*------------------------------------------------------------*/
void SND_fn_vSetDopplerFactorSnd(SndReal factor)
{
	SND_fn_vSetDopplerFactor(factor);
	SND_fn_vSetDopplerFactorSxd(factor);
}
 
 
/*-------------------------------------------------------------------------*/
/*      PlaySnd: jouer une ressource*/
/*      Entrees: res=ressource concernee*/
/*              par=parametres sonores au lancement*/
/*              prio=niveau de priorite*/
/*              fct=fonction de callback*/
/*      Sortie: voie attribuee à la ressource*/
/*--------------------------------------------------------------------------*/
long SND_fn_lPlaySnd(tduRefRes res,SoundParam* par,long prio,SND_td_pfn_vSoundCallback fn_callback,long par_callback,SndBool* valid)
{
        long voice_sxd;
        long pre_voice_snd;
 
        if ((pre_voice_snd=pre_associe_snd())==C_PLAY_FAILED)
			return C_PLAY_FAILED;
 
        switch (res.pstPtr->eType)
        {
                        case TYPE_SAMPLE:
                                voice_sxd=SND_fn_lPlaySxd(res,par,prio,fn_callback,par_callback);
                                break;
                        case TYPE_MIDI:
                                voice_sxd=SND_fn_lPlayMidi(res,par,prio,fn_callback,par_callback);
                                break;
#ifndef DISABLE_CD
                        case TYPE_CDAUDIO:
                                voice_sxd=SND_fn_lPlayCD(res,par,prio,fn_callback,par_callback);
                                break;
#endif
#ifndef DISABLE_SEQUENCE
                        case TYPE_SEQUENCE:
                                voice_sxd=SND_fn_lPlaySeq(res,par,prio,fn_callback,par_callback,&((voice_description*)pre_voice_snd)->bValid);
                                break;
#endif
#ifndef DISABLE_SPLIT
                        case TYPE_SPLIT:
                                voice_sxd=SND_fn_lPlaySplit(res,par,prio,fn_callback,par_callback,&((voice_description*)pre_voice_snd)->bValid);
                                break;
#endif
#ifndef DISABLE_THEME
                        case TYPE_THEME:
                                voice_sxd=SND_fn_lPlayTheme(C_PLAY_FAILED,res,par,prio,fn_callback,par_callback,&((voice_description*)pre_voice_snd)->bValid);
                                break;
#endif
                        case TYPE_RANDOM:
                                voice_sxd=SND_fn_lPlayRandom(res,par,prio,fn_callback,par_callback);
                                break;
                        case TYPE_SWITCH:
                                voice_sxd=SND_fn_lPlaySwitch(res,par,prio,fn_callback,par_callback);
                                break;
                        case TYPE_THEME_OLD:/*obsolete*/
                        case TYPE_SWITCH_OLD:/*obsolete*/
                        default:
                                SND_M_DisplayError(E_uwSndInvalidTypeOfResource,"");
                                voice_sxd=C_PLAY_FAILED;
        }
 
        return associe_snd(pre_voice_snd,voice_sxd,res,prio,valid,FALSE);
}
 
/*---------------------------------------------------------*/
/*      SetParamSnd: modifier les parametres sonores d'une ressource*/
/*      Entrees:voie=voie associee à la ressource*/
/*              par=nouveaux parametres*/
/*      Sortie:FALSE si ressource treminee, TRUE sinon*/
/*----------------------------------------------------------*/
SndBool SND_CALL SND_fn_bSetParamSnd(long voie,SoundParam* par)
{
        SndBool ret;
 
 
		ret=(*a_fnFunc[((voice_description*)voie)->res.pstPtr->eType].pfnSetParam)(((voice_description*)voie)->voice_sxd,par);
/*        ret=((voice_description*)voie)->fnSetParam(((voice_description*)voie)->voice_sxd,par);*/
        if (ret==FALSE)
                desassocie_snd(voie);
 
        return ret;
}
 
/*-----------------------------------------------------*/
/*      TestIsPlayingSnd: test si uneressource est terminee*/
/*      Entree:voie=voie associee à la ressource*/
/*      Sortie:FALSE si ressource terminee, TRUE sinon*/
/*-------------------------------------------------------*/
SndBool SND_fn_bTestIsPlayingSnd(long voie)
{
        SndBool ret;
 
		ret=(*a_fnFunc[((voice_description*)voie)->res.pstPtr->eType].pfnTestIsPlaying)(((voice_description*)voie)->voice_sxd);
/*        ret=((voice_description*)voie)->fnTestIsPlaying(((voice_description*)voie)->voice_sxd);*/
        if (ret==FALSE)
                desassocie_snd(voie);
 
        return ret;
}
 
/*------------------------------------------------------*/
/*      StopSnd: stopper une ressource*/
/*      Entree:voie=voie asociee à la ressource*/
/*      Sortie:neant*/
/*-------------------------------------------------------*/
void SND_CALL SND_fn_vStopSnd(long voie)
{
	if (!((voice_description*)voie)->free)
		//check if voice has not yet been stopped
		(*a_fnFunc[((voice_description*)voie)->res.pstPtr->eType].pfnStop)(((voice_description*)voie)->voice_sxd);
 
    desassocie_snd(voie);
    return;
}
 
/*------------------------------------------------------*/
/*      PauseSnd: suspendre une ressource*/
/*      Entree:voie=voie asociee à la ressource*/
/*      Sortie:neant*/
/*-------------------------------------------------------*/
void SND_CALL SND_fn_vPauseSnd(long voie)
{
	(*a_fnFunc[((voice_description*)voie)->res.pstPtr->eType].pfnPause)(((voice_description*)voie)->voice_sxd);
/*    ((voice_description*)voie)->fnPause(((voice_description*)voie)->voice_sxd);*/
}
 
/*------------------------------------------------------*/
/*      ResumeSnd: reprendre une ressource*/
/*      Entree:voie=voie asociee à la ressource*/
/*      Sortie:neant*/
/*-------------------------------------------------------*/
void SND_CALL SND_fn_vResumeSnd(long voie)
{
	(*a_fnFunc[((voice_description*)voie)->res.pstPtr->eType].pfnResume)(((voice_description*)voie)->voice_sxd);
/*        ((voice_description*)voie)->fnResume(((voice_description*)voie)->voice_sxd);*/
}
 
/*--------------------------------------------------*/
/*      RemoveCallbackSnd: annule une callback en attent*/
/*      Entree:voies sur laquelle la callback est en attent*/
/*---------------------------------------------------*/
void SND_fn_vRemoveCallbackSnd(long voie)
{
        switch (((voice_description*)voie)->res.pstPtr->eType)
        {
        case TYPE_SAMPLE:
                SND_fn_vRemoveCallbackSxd(((voice_description*)voie)->voice_sxd);
                break;
        case TYPE_MIDI:
                SND_fn_vRemoveCallbackMidi(((voice_description*)voie)->voice_sxd);
                break;
#ifndef DISABLE_CD
        case TYPE_CDAUDIO:
                SND_fn_vRemoveCallbackCD(((voice_description*)voie)->voice_sxd);
                break;
#endif
#ifndef DISABLE_SEQUENCE
        case TYPE_SEQUENCE:
                SND_fn_vRemoveCallbackSeq(((voice_description*)voie)->voice_sxd);
                break;
#endif
#ifndef DISABLE_SPLIT
        case TYPE_SPLIT:
                SND_fn_vRemoveCallbackSplit(((voice_description*)voie)->voice_sxd);
                break;
#endif
#ifndef DISABLE_THEME
        case TYPE_THEME:
                SND_fn_vRemoveCallbackTheme(((voice_description*)voie)->voice_sxd);
                break;
#endif
        case TYPE_SWITCH:
                SND_fn_vRemoveCallbackSwitch(((voice_description*)voie)->voice_sxd);
                break;
        case TYPE_RANDOM:
                SND_fn_vRemoveCallbackRandom(((voice_description*)voie)->voice_sxd);
                break;
        case TYPE_SWITCH_OLD:
        default:
                SND_M_DisplayError(E_uwSndInvalidTypeOfResource,"");
                break;
        }
 
        return;
}
 
void SND_fn_vPauseAllSnd(void)
{
    voice_description* voie;
    int i;
 
    for (i=0,voie=&voice_snd[0];i<NB_VOICE_MAX;i++,voie++)
    {
		if (voie->bValid && !voie->free && !voie->lPauseInstance)
		{
			voie->lPauseInstance=g_lCurrentGlobalPauseInstance;
 
			if (voie->bTransition)
				SND_fn_vPauseTransitionSnd((long)voie);
			else
				SND_fn_vPauseSnd((long)voie);
		}
    }
	
	g_lCurrentGlobalPauseInstance++;
}
 
void SND_fn_vResumeAllSnd(void)
{
    voice_description* voie;
    int i;
 
	g_lCurrentGlobalPauseInstance--;
 
    for (i=0,voie=&voice_snd[0];i<NB_VOICE_MAX;i++,voie++)
    {
        if (voie->bValid && !voie->free && (voie->lPauseInstance<=g_lCurrentGlobalPauseInstance))
		{
			voie->lPauseInstance=0;
 
			if (voie->bTransition)
	            SND_fn_vResumeTransitionSnd((long)voie);
			else
	            SND_fn_vResumeSnd((long)voie);
		}
    }
}
 
/*------------------------------------------------------*/
/*      SetSoundVolumeSnd: changer le volume des ressources sample*/
/*      Entree:new_vol=nouveau volume (format MIDI)*/
/*      Sortie:neant*/
/*-------------------------------------------------------*/
void SND_fn_vSetSoundVolumeSnd(char new_vol)
{
        SND_fn_vSetSoundVolumeSxd(new_vol);
}
 
/*------------------------------------------------------*/
/*      GetSoundVolumeSnd: obtenir le volume des ressources sample*/
/*      Entree:neant*/
/*      Sortie:volume au format midi*/
/*-------------------------------------------------------*/
unsigned char SND_fn_ucGetSoundVolumeSnd(void)
{
        return SND_fn_ucGetSoundVolumeSxd();
}
 
/*------------------------------------------------------*/
/*      SetStereoSnd: mise en stereo des sons de sorties*/
/*      Entree:TRUE pour passer en stereo, FALSE pour mono*/
/*      Sortie:neant*/
/*-------------------------------------------------------*/
void SND_fn_vSetStereoSnd(SndBool active)
{
        /*SND_fn_vSetStereoMusic(active);*/
        SND_fn_vSetStereoSxd(active);
}
 
/*------------------------------------------------------*/
/*      GetStereoSnd: obtenir le mode stereo*/
/*      Entree:neant*/
/*      Sortie:TRUE si sortie stereo, FALSE si mono*/
/*-------------------------------------------------------*/
SndBool SND_fn_bGetStereoSnd(void)
{
        return SND_fn_bGetStereoSxd();
}
 
/*------------------------------------------------------*/
/*      IsMusicPlayingSnd: obtenir le mode stereo*/
/*      Entree:neant*/
/*      Sortie:TRUE s'il y a theme actuellement en cours, FALSE sinon*/
/*-------------------------------------------------------*/
SndBool SND_fn_bIsMusicPlayingSnd(void)
{
        return SND_fn_bAnyPlayingTheme();
}

/*------------------------------------------------------*/
/*      SetReevrseStereoSnd: inverse la steraoeo*/
/*      Entree:neant*/
/*-------------------------------------------------------*/
void SND_fn_vSetReverseStereoSnd(SndBool active)
{
	SND_fn_vSetReverseStereoSxd(active);
}
 
/*------------------------------------------------------*/
/*      GetStereoSnd: obtenir l'orientation de la stereo*/
/*      Entree:neant*/
/*      Sortie:TRUE si stereo normale, FALSE si inverse*/
/*-------------------------------------------------------*/
SndBool SND_fn_bGetReverseStereoSnd(void)
{
	return SND_fn_bGetReverseStereoSxd();
}
 
 
/*------------------------------------------------------*/
/*      TestInitSnd: test la fin de l'init asynchrone*/
/*      Entree:neant*/
/*      Sortie:FALSE tant que l'init n'est pas finie*/
/*-------------------------------------------------------*/
SndBool SND_fn_bTestInitSnd(void)
{
        return (SND_fn_bTestInitSxd()
#ifndef DISABLE_CD
			&& SND_fn_bTestInitCD()
#endif
			&& SND_fn_bTestInitMidi());
}
 
/*------------------------------------------------------*/
/*      DesInitSnd: desiniter le module de traitement des ressources*/
/*      Entree:neant*/
/*      Sortie:neant*/
/*-------------------------------------------------------*/
void SND_fn_vDesInitSnd(void)
{
#ifndef DISABLE_THEME
	SND_fn_vDesInitTheme();
#endif
#ifndef DISABLE_SEQUENCE
	SND_fn_vDesInitSeq();
#endif
#ifndef DISABLE_RECORD
	SND_fn_vDesInitRecord();
#endif
#ifndef DISABLE_CD
	if (g_iInitCD==C_INIT_OK) SND_fn_vDesInitCD();
#endif
	if (g_iInitMidi==C_INIT_OK) SND_fn_vDesInitMidi();
    if (g_iInitSxd==C_INIT_OK) SND_fn_vDesInitSxd();
}
 
/*------------------------------------------------------*/
/*      InitBnkSnd: initialiser une banque de ressources*/
/*      Entree:num=designation de la banque*/
/*      Sortie:code de retour(C_INIT_FAILED,C_INIT_RUNNING ou C_INIT_OK*/
/*-------------------------------------------------------*/
int SND_fn_iInitBnkSnd(long num)
{
        /*
        init_music=SND_fn_iInitBnkMusic(num);
 
        if (init_music==C_INIT_FAILED)
        {
                SND_fn_vDesInitBnkSxd(num);
                return C_INIT_FAILED;
        }
 
        if ((init_music==C_INIT_RUNNING) || (init_sxd==C_INIT_RUNNING))
                return C_INIT_RUNNING;
        */
 
        return C_INIT_OK;
}
 
/*------------------------------------------------------*/
/*      TestInitBnkSnd:tester la fin de l'init asynchrone d'une banque*/
/*      Entree:num=designation de labanque en cours de chargement*/
/*      Sortie:FALSE tant que la banque n'est pas operationnelle*/
/*-------------------------------------------------------*/
SndBool SND_fn_bTestInitBnkSnd(long num)
{
        return TRUE;
}
 
/*------------------------------------------------------*/
/*      DesInitBnkSnd: relacher une banque*/
/*      Entree:num=designation de la banque*/
/*      Sortie:neant*/
/*-------------------------------------------------------*/
void SND_fn_vDesInitBnkSnd(long num)
{
}
 
/*------------------------------------------------------*/
/*      DesInitAllBnkSnd: relacher toutes les banques*/
/*      Entree:neant*/
/*      Sortie:neant*/
/*-------------------------------------------------------*/
void SND_fn_vDesInitAllBnkSnd(void)
{
}
 
/*------------------------------------------------------*/
/*      SetEffectSnd: installer un effet sonore*/
/*      Entree:id=designation de l'effet*/
/*      Sortie:neant*/
/*-------------------------------------------------------*/
void SND_fn_vSetEffectSnd(long id)
{
        SND_fn_vSetEffectSxd(id);
}
 
/*------------------------------------------------------*/
/*      CreateMicroSnd: ajouter un micro à la liste*/
/*      Entree:sndID=id associe au micro*/
/*              par=parametres du micro*/
/*      Sortie:neant*/
/*-------------------------------------------------------*/
long SND_fn_lCreateMicroSnd(MicroParam *par)
{
        return SND_fn_lCreateMicroSxd(par);
}
 
/*------------------------------------------------------*/
/*      DestroyMicroSnd: retirer un micro à la liste*/
/*      Entree:sndID=id associe au micro*/
/*      Sortie:neant*/
/*-------------------------------------------------------*/
void SND_fn_vDestroyMicroSnd(long sndId)
{
        SND_fn_vDestroyMicroSxd(sndId);
}
 
/*------------------------------------------------------*/
/*      SetMicroParamSnd: modifier les parametres d'un micro */
/*      Entree:sndID=id associe au micro*/
/*              par=parametres du micro*/
/*      Sortie:neant*/
/*-------------------------------------------------------*/
void SND_fn_vSetMicroParamSnd(long sndId,MicroParam *par)
{
        SND_fn_vSetMicroParamSxd(sndId,par);
}
 
 
 
 
/******************** THEMES ********************************************/
/*------------------------------------------------------------------------*/
/*  PlayTransitionSnd:lance un theme*/
/*  Entrees:FirstRes=ressource de la 1° part*/
/*      NextRes=ressource prevue pour la prochaine transition*/
/*      transition_callback=fct à appeler à chaque tra,sition*/
/*  Retour=id du theme*/
/*------------------------------------------------------------------------*/
long SND_fn_lPlayTransitionSnd(tduRefRes FirstRes,tduRefRes NextRes,SND_td_pfn_vSoundCallback transition_callback,long param_callback,SoundParam* par)
{
    long voice_sxd;
    long pre_voice_snd;
 
    if ((pre_voice_snd=pre_associe_snd())==C_PLAY_FAILED)
		return C_PLAY_FAILED;
 
	switch (FirstRes.pstPtr->eType)
	{
#ifndef DISABLE_THEME_WAVE
	case TYPE_SAMPLE:
        voice_sxd=SND_fn_lPlayTransitionExSxd(FirstRes,NextRes,transition_callback,param_callback,par);
		break;
#endif /* DISABLE_THEME_WAVE*/
#ifndef DISABLE_THEME_MIDI
	case TYPE_MIDI:
        voice_sxd=SND_fn_lPlayTransitionMidi(FirstRes,NextRes,transition_callback,param_callback,par);
		break;
#endif /* DISABLE_THEME_MIDI*/
	default:
        SND_M_DisplayError(E_uwSndInvalidTypeOfResource,"");
        voice_sxd=C_PLAY_FAILED;
		break;
	}
 
    return associe_snd(pre_voice_snd,voice_sxd,FirstRes,0,NULL,TRUE);
}
 
SndBool SND_fn_bSetParamTransitionSnd(long voice,SoundParam *par)
{
    SndBool ret;
 
    switch (((voice_description*)voice)->res.pstPtr->eType)
	{
#ifndef DISABLE_THEME_WAVE
	case TYPE_SAMPLE:
        ret=SND_fn_bSetParamTransitionSxd(((voice_description*)voice)->voice_sxd,par);
		break;
#endif /* DISABLE_THEME_WAVE*/
#ifndef DISABLE_THEME_MIDI
	case TYPE_MIDI:
        ret=SND_fn_bSetParamTransitionMidi(((voice_description*)voice)->voice_sxd,par);
		break;
#endif /* DISABLE_THEME_MIDI*/
	default:
        SND_M_DisplayError(E_uwSndInvalidTypeOfResource,"");
        ret=FALSE;
		break;
	}
 
    if (ret==FALSE)
		desassocie_snd(voice);
 
    return ret;
}
 
/*------------------------------------------------------------------------*/
/*  SetNextTransitionSnd:modifie la ressource prevue pour untheme actif*/
/*  Entrees:voice=voie du theme*/
/*      NewRes=ressource prevue à la prochaine transition*/
/*  Retour=TRUE si OK,FALSE si theme HS*/
/*------------------------------------------------------------------------*/
SndBool SND_fn_bSetNextTransitionSnd(long voice,tduRefRes new_res)
{
    SndBool ret;
 
    switch (((voice_description*)voice)->res.pstPtr->eType)
	{
#ifndef DISABLE_THEME_WAVE
	case TYPE_SAMPLE:
        ret=SND_fn_bSetNextTransitionSxd(((voice_description*)voice)->voice_sxd,new_res);
		break;
#endif /* DISABLE_THEME_WAVE*/
#ifndef DISABLE_THEME_MIDI
	case TYPE_MIDI:
        ret=SND_fn_bSetNextTransitionMidi(((voice_description*)voice)->voice_sxd,new_res);
		break;
#endif /* DISABLE_THEME_MIDI*/
	default:
        SND_M_DisplayError(E_uwSndInvalidTypeOfResource,"");
        ret=FALSE;
		break;
	}
 
	/* code de retour non defini
    if (ret==FALSE)
		desassocie_snd(voice);
		*/
	((voice_description*)voice)->res.pstPtr=new_res.pstPtr;
 
    return ret;
}
 
SndBool SND_fn_bDoTransitionWithFadeSnd(long voice,tduRefRes new_res)
{
    SndBool ret;
 
    switch (((voice_description*)voice)->res.pstPtr->eType)
	{
#ifndef DISABLE_THEME_WAVE
	case TYPE_SAMPLE:
        ret=SND_fn_bDoTransitionWithFadeSxd(((voice_description*)voice)->voice_sxd,new_res);
		break;
#endif /* DISABLE_THEME_WAVE*/
#ifndef DISABLE_THEME_MIDI
	case TYPE_MIDI:
        ret=SND_fn_bDoTransitionWithFadeMidi(((voice_description*)voice)->voice_sxd,new_res);
		break;
#endif /* DISABLE_THEME_MIDI*/
	default:
        SND_M_DisplayError(E_uwSndInvalidTypeOfResource,"");
        ret=FALSE;
		break;
	}
 
	/* code de retour non defini
    if (ret==FALSE)
		desassocie_snd(voice);
		*/
	((voice_description*)voice)->res.pstPtr=new_res.pstPtr;
    return ret;
}

SndBool SND_fn_bDoTransitionWithFadeSnd2( long voice, tduRefRes new_res, SndReal rDuration )
{
	register voice_description* pstVoice;
    SndBool                     ret;
 
	pstVoice = (voice_description*)voice;
    switch( pstVoice->res.pstPtr->eType ) {
#ifndef DISABLE_THEME_WAVE
	case TYPE_SAMPLE:
        ret = SND_fn_bDoTransitionWithFadeSxd2( pstVoice->voice_sxd, new_res, rDuration );
		break;
#endif /* DISABLE_THEME_WAVE*/
#ifndef DISABLE_THEME_MIDI
	case TYPE_MIDI:
        ret = SND_fn_bDoTransitionWithFadeMidi2( pstVoice->voice_sxd, new_res, rDuration );
		break;
#endif /* DISABLE_THEME_MIDI*/
	default:
        SND_M_DisplayError(E_uwSndInvalidTypeOfResource,"");
        ret = FALSE;
		break;
	}
 
	/* code de retour non defini
    if (ret==FALSE)
		desassocie_snd(voice);
		*/
 
    return ret;
}
 
/*------------------------------------------------------------------------*/
/*  Stoppe brutalement un theme en cours*/
/*  Entrees:voice=voie du theme*/
/*  Retour:neant*/
/*------------------------------------------------------------------------*/
void SND_fn_vStopTransitionSnd(long voice)
{
	if (!((voice_description*)voice)->free)
	{//check if voice has not yet been stopped
		switch (((voice_description*)voice)->res.pstPtr->eType)
		{
	#ifndef DISABLE_THEME_WAVE
		case TYPE_SAMPLE:
			SND_fn_vStopTransitionSxd(((voice_description*)voice)->voice_sxd);
			break;
	#endif /* DISABLE_THEME_WAVE*/
	#ifndef DISABLE_THEME_MIDI
		case TYPE_MIDI:
			SND_fn_vStopTransitionMidi(((voice_description*)voice)->voice_sxd);
			break;
	#endif /* DISABLE_THEME_MIDI*/
		default:
			SND_M_DisplayError(E_uwSndInvalidTypeOfResource,"");
			break;
		}
	}
    desassocie_snd(voice);
    return;
}
 
/*------------------------------------------------------------------------*/
/*  Resume un theme en cours*/
/*  Entrees:voice=voie du theme*/
/*  Retour:neant*/
/*------------------------------------------------------------------------*/
void SND_fn_vResumeTransitionSnd(long voice)
{
    switch (((voice_description*)voice)->res.pstPtr->eType)
	{
#ifndef DISABLE_THEME_WAVE
	case TYPE_SAMPLE:
	    SND_fn_vResumeTransitionSxd(((voice_description*)voice)->voice_sxd);
		break;
#endif /* DISABLE_THEME_WAVE*/
#ifndef DISABLE_THEME_MIDI
	case TYPE_MIDI:
	    SND_fn_vResumeTransitionMidi(((voice_description*)voice)->voice_sxd);
		break;
#endif /* DISABLE_THEME_MIDI*/
	default:
        SND_M_DisplayError(E_uwSndInvalidTypeOfResource,"");
		break;
	}
}
 
/*------------------------------------------------------------------------*/
/*  Pauseun theme en cours*/
/*  Entrees:voice=voie du theme*/
/*  Retour:neant*/
/*------------------------------------------------------------------------*/
void SND_fn_vPauseTransitionSnd(long voice)
{
    switch (((voice_description*)voice)->res.pstPtr->eType)
	{
#ifndef DISABLE_THEME_WAVE
	case TYPE_SAMPLE:
	    SND_fn_vPauseTransitionSxd(((voice_description*)voice)->voice_sxd);
		break;
#endif /* DISABLE_THEME_WAVE*/
#ifndef DISABLE_THEME_MIDI
	case TYPE_MIDI:
	    SND_fn_vPauseTransitionMidi(((voice_description*)voice)->voice_sxd);
		break;
#endif /* DISABLE_THEME_MIDI*/
	default:
        SND_M_DisplayError(E_uwSndInvalidTypeOfResource,"");
		break;
	}
}
 
/*------------------------------------------*/
/* relache-reprise a chaud des drivers*/
/*-------------------------------------------*/
void SND_fn_vReleaseDriverSnd(void)
{
#ifndef DISABLE_CD
	SND_fn_vReleaseDriverCD();
#endif
	SND_fn_vReleaseDriverMidi();
	SND_fn_vReleaseDriverSxd();
}
 
void SND_fn_vRestoreDriverSnd(void)
{
	SND_fn_vRestoreDriverSxd();
	SND_fn_vRestoreDriverMidi();
#ifndef DISABLE_CD
	SND_fn_vRestoreDriverCD();
#endif
}
 
void SND_fn_vForceReleaseDriverSnd(void)
{
	SND_fn_vForceReleaseDriverSxd();
}
 
void SND_fn_vForceRestoreDriverSnd(void)
{
	SND_fn_vForceRestoreDriverSxd();
}
 
/*------------------------------------------*/
/* obtenir la position courante de la voie */
/*	different du temps abslou (derive, pitch ..)*/
/*-------------------------------------------*/
SndReal SND_CALL SND_fn_rGetPosSnd(long voie)
{
	if (((voice_description*)voie)->bValid)
		return (*a_fnFunc[((voice_description*)voie)->res.pstPtr->eType].pfnGetPos)(((voice_description*)voie)->voice_sxd);
/*		return ((voice_description*)voie)->fnGetPos(((voice_description*)voie)->voice_sxd);*/
	else
		return SND_C_POS_ENDED;
}
 
/*---------------------------------------------------------*/
/*	GetLength: retourne la duree "theorique" de la ressource*/
/*			exprime en seconde (constant pour une ressource donnee)*/
/*	Entree: voie concernee*/
/*	Sortie: duree en S (SndReal)*/
/*----------------------------------------------------------*/
SndReal SND_CALL SND_fn_rGetLengthSnd(long voie)
{
	if (((voice_description*)voie)->bValid)
        switch (((voice_description*)voie)->res.pstPtr->eType)
        {
        case TYPE_SAMPLE:
                return SND_fn_rGetLengthSxd(((voice_description*)voie)->voice_sxd);
                break;
        case TYPE_MIDI:
                return SND_fn_rGetLengthMidi(((voice_description*)voie)->voice_sxd);
                break;
#ifndef DISABLE_CD
		case TYPE_CDAUDIO:
                return SND_fn_rGetLengthCD(((voice_description*)voie)->voice_sxd);
                break;
#endif
#ifndef DISABLE_SEQUENCE
        case TYPE_SEQUENCE:
                return SND_fn_rGetLengthSeq(((voice_description*)voie)->voice_sxd);
                break;
#endif
#ifndef DISABLE_SPLIT
        case TYPE_SPLIT:
                return SND_fn_rGetLengthSplit(((voice_description*)voie)->voice_sxd);
                break;
#endif
#ifndef DISABLE_THEME
        case TYPE_THEME:
                return SND_fn_rGetLengthTheme(((voice_description*)voie)->voice_sxd);
                break;
#endif
		case TYPE_RANDOM:
                return SND_fn_rGetLengthRandom(((voice_description*)voie)->voice_sxd);
                break;
		case TYPE_SWITCH:
                return SND_fn_rGetLengthSwitch(((voice_description*)voie)->voice_sxd);
                break;
        case TYPE_SWITCH_OLD:
		default:
                SND_M_DisplayError(E_uwSndInvalidTypeOfResource,"");
				return SND_C_LENGTH_UNKNOWN;
                break;
        }
	else
				return SND_C_LENGTH_UNKNOWN;
}
 
/*---------------------------------------------------------*/
/*	GetTargetLabel: retourne le label designant la tareget*/
/*	Entree: name=nom cible*/
/*		nb_char=taille maxi de la cible*/
/*----------------------------------------------------------*/
void SND_fn_vGetTargetLabelSnd(char* name,int nb_char)
{
	SND_fn_vGetTargetLabelSxd(name,nb_char);
}
 
void SND_fn_vSetupTargetSnd(void)
{
	SND_fn_vSetupTargetSxd();
}
 
SndBool SND_fn_bCanSetupTargetSnd(void)
{
	return SND_fn_bCanSetupTargetSxd();
}
 
#ifndef DISABLE_BUFFER_CLIENT
 
long SND_fn_lCreateNewBufferSnd(unsigned long nb_samples,unsigned short uwResolution,unsigned short uwNbChannels,unsigned long ulFreq,SoundParam* par,td_pfn_vRefreshBufferClient callback,long user_id)
{
	return SND_fn_lCreateNewBufferSxd(nb_samples,uwResolution,uwNbChannels,ulFreq,par,callback,user_id);
}
 
void	SND_fn_vDeleteBufferSnd(long id_buffer)
{
	SND_fn_vDeleteBufferSxd(id_buffer);
}
 
void SND_fn_vPauseBufferSnd(long id_buffer)
{
	SND_fn_vPauseBufferSxd(id_buffer);
}
 
void SND_fn_vResumeBufferSnd(long id_buffer)
{
	SND_fn_vResumeBufferSxd(id_buffer);
}
 
SndReal SND_fn_rGetPosBufferSnd(long id_buffer)
{
	return SND_fn_rGetPosBufferSxd(id_buffer);
}
 
long SND_fn_lCreateNewBufferExSnd(SND_tdstFormat* pformat,SND_tdstCallback* pCallback,SoundParam* par,long user_id)
{
	return SND_fn_lCreateNewBufferExSxd(pformat,pCallback,par,user_id);
}
 
long SND_fn_lGetPosBufferExSnd(long id_buffer)
{
	return SND_fn_lGetPosBufferExSxd(id_buffer);
}
 
long SND_fn_lPushBufferExSnd(long id_buffer,SND_tdstStackBuffer* pStack)
{
	return SND_fn_lPushBufferExSxd(id_buffer,pStack);
}
 
void SND_fn_vSetParamBufferSnd(long id_buffer,SoundParam* par)
{
	SND_fn_vSetParamBufferSxd(id_buffer,par);
}
 
#endif /* DISABLE_BUFFER_CLIENT*/
 
void SND_fn_vSynchroSnd()
{
	SND_fn_vSynchroSxd();
#ifndef DISABLE_CD
	SND_fn_vSynchroCD();
#endif
	SND_fn_vSynchroMidi();
#ifdef DREAMCAST
	sdSysServer();
#endif
}
 
SndBool SND_fn_bCheckVersionResourceSnd(tdstBlockResourceDisk* disk)
{
        switch (disk->eType)
        {
                        case TYPE_SAMPLE:
                                return SND_fn_bCheckVersionResourceSxd(disk);
                                break;
                        case TYPE_MIDI:
                                return SND_fn_bCheckVersionResourceMidi(disk);
                                break;
#ifndef DISABLE_CD
                        case TYPE_CDAUDIO:
                                return SND_fn_bCheckVersionResourceCD(disk);
                                break;
#endif
                        default:
								return TRUE;
                                break;
        }
}
 
/***********************************************************************
	SND_fn_tduGetLowestResourceSnd:
		get the lowest resource associated with an other one (ie get effective resource choosen by a SWITCH)
	In: uHighRes=high level resource (ie SWITCH)
		par=dynamic parameters to be used for evaluation
		eval=TRUE if new evaluation nedded for RANDOM; FALSE if used previously done evaluation
	Out:low-level resource associated
******************************************************************************/
tduRefRes SND_fn_tduGetLowestResourceSnd(tduRefRes uHighRes,SoundParam* par,SndBool eval)
{
	if (uHighRes.pstPtr==SND_C_RES_FANTOME_PTR) return uHighRes;
 
	switch (uHighRes.pstPtr->eType)
	{
	case TYPE_SAMPLE:
	case TYPE_MIDI:
	case TYPE_CDAUDIO:
	case TYPE_SEQUENCE:
	case TYPE_THEME:
		return uHighRes;
	case TYPE_RANDOM:
		return SND_fn_tduGetLowestResourceRandom(uHighRes,par,eval);
	case TYPE_SWITCH:
		return SND_fn_tduGetLowestResourceSwitch(uHighRes,par,eval);
	case TYPE_SPLIT:
	case TYPE_INVALID:
	default:
		SND_M_DisplayError(E_uwSndInvalidTypeOfResource,"");
        return SND_RES_FANTOME;
	}
}


 
long	SND_fn_lGetNbVoiceOptimumSnd()
{
	return SND_fn_lGetNbVoiceOptimumSxd();
}
 
long	SND_fn_lGetNbVoiceWishedSnd()
{
	return SND_fn_lGetNbVoiceWishedSxd();
}
 
void	SND_fn_vSetNbVoiceWishedSnd(long nb)
{
	SND_fn_vSetNbVoiceWishedSxd(SND_fn_eGetMainFormatSxd(),nb);
}
 
/*----------------------------------------*/
#ifndef DISABLE_RECORD
/*----------SNDREC*/
SndBool	SND_fn_bTestFormatRecordSnd(SND_tdstFormat* pformat,int flags)
{
#ifndef DISABLE_RECORD
	return SND_fn_bTestFormatRecord(pformat,flags);
#else
	return FALSE;
#endif
}
 
long		SND_fn_lCreateBufferRecordSnd(SND_tdstFormat* pformat,SND_tdstCallback* pCallback)
{
#ifndef DISABLE_RECORD
	return SND_fn_lCreateBufferRecord(pformat,pCallback);
#else
	return C_PLAY_FAILED;
#endif
}
 
SndBool	SND_fn_bIsBufferFullDuplexRecordSnd(long id_buffer)
{
#ifndef DISABLE_RECORD
	return SND_fn_bIsBufferFullDuplexRecord(id_buffer);
#else
	return FALSE;
#endif
}
 
SndBool	SND_fn_bStartRecordSnd(long id_buffer)
{
#ifndef DISABLE_RECORD
	return SND_fn_bStartRecord(id_buffer);
#else
	return FALSE;
#endif
}
 
void		SND_fn_vStopRecordSnd(long id_buffer)
{
#ifndef DISABLE_RECORD
	SND_fn_vStopRecord(id_buffer);
#endif
}
 
SndBool	SND_fn_bIsWorkingRecordSnd(long id_buffer)
{
#ifndef DISABLE_RECORD
	return SND_fn_bIsWorkingRecord(id_buffer);
#else
	return FALSE;
#endif
}
 
long SND_fn_lPushBufferToRecordSnd(long id_buffer,void* ptr,int size_ptr)
{
#ifndef DISABLE_RECORD
	return SND_fn_lPushBufferToRecord(id_buffer,ptr,size_ptr);
#else
	return FALSE;
#endif
}
 
unsigned char SND_fn_ucGetInstantVuMeterRecordSnd(void)
{
#ifndef DISABLE_RECORD
	return SND_fn_ucGetInstantVuMeterRecord();
#else
	return 0;
#endif
}
#endif
 
tduRefRes SND_fn_uGenerateResourceSnd(void* data,SND_tdstFormat* pformat,SndBool loop)
{
#if !defined(GAMECONSOLE) && !defined(GENERIC) 
	tdstBlockResourceMem* pstResMem;
	tdstBlockResourceDisk stResDisk;
#endif
	tduRefRes uRes;
 
#if !defined(GAMECONSOLE) && !defined(GENERIC) 
	memset(&stResDisk,0,sizeof(stResDisk));
    stResDisk.eType=TYPE_SAMPLE;
 
	switch (pformat->eZip)
	{
	case SAMPLE_PCM:
		stResDisk.ulDataSize=pformat->uFormat.stPCM.ulNbSamples;
		if (pformat->uFormat.stPCM.uwResolution==16)
			stResDisk.ulDataSize<<=1;
		if (pformat->uFormat.stPCM.uwNbChannels==2)
			stResDisk.ulDataSize<<=1;
		break;
	default:
        SND_M_DisplayError(E_uwSndInvalidTypeOfResource,"");
		return SND_RES_FANTOME;
	}
 
	stResDisk.eStorage=TYPE_MEGAFILE;
	stResDisk.ulDataOffset=0;
	stResDisk.ucVolume=127;
	stResDisk.uRes.stSample.bPitchable=TRUE;
	stResDisk.uRes.stSample.bVolable=TRUE;
	stResDisk.uRes.stSample.bPanable=TRUE;
	stResDisk.uRes.stSample.bSpacable=TRUE;
	stResDisk.uRes.stSample.bReverbable=TRUE;
	stResDisk.uRes.stSample.bStream=FALSE;
	stResDisk.uRes.stSample.bLoop=loop;
	stResDisk.uRes.stSample.ulStartLoop=0;
	stResDisk.uRes.stSample.ulLoopLength=stResDisk.ulDataSize;
	stResDisk.uRes.stSample.ulFreq=pformat->uFormat.stPCM.ulFreq;
	stResDisk.uRes.stSample.uwResolution=pformat->uFormat.stPCM.uwResolution;
	stResDisk.uRes.stSample.uwNbChannels=pformat->uFormat.stPCM.uwNbChannels;
	stResDisk.uRes.stSample.eZip=SAMPLE_PCM;
 
	pstResMem=SND_fn_pvMallocSndEx(E_ucSndBlockMain,sizeof(tdstBlockResourceMem));
	memset(pstResMem,0,sizeof(pstResMem));
 
	SND_fn_vConvertResDiskToMemSxd(&stResDisk,pstResMem,data);
 
	uRes.pstPtr=pstResMem;
#else
	uRes.pstPtr=SND_C_RES_FANTOME_PTR;
#endif
 
	return uRes;
}
 
void SND_fn_vDestroyResourceSnd(tduRefRes uRes)
{
#if !defined(GAMECONSOLE) && !defined(GENERIC) 
	SND_fn_vStopBeforeUnLoadResSnd(uRes.pstPtr);
	SND_fn_vUnLoadResSnd(uRes.pstPtr);
 
	SND_fn_vFreeSndEx(E_ucSndBlockMain,uRes.pstPtr);
#endif
}


/***********************************************************************
	SND_fn_bSetResourceStaticVolumeSnd:
		change the volume for a specific resource given its Editor ID
******************************************************************************/
SndBool  SND_fn_bSetResourceStaticVolumeSnd(tdstBlockResourceMem* pstRes,unsigned char ucVolume)
{
	if (pstRes!=NULL)
	{
		switch (pstRes->eType)
		{
		case TYPE_SAMPLE: 
			return SND_fn_bSetResourceStaticVolumeSxd(pstRes,ucVolume);
			break;
#ifndef DISABLE_MIDI
		case TYPE_MIDI: 
			return SND_fn_bSetResourceStaticVolumeMidi(pstRes,ucVolume);
			break;
#endif
#ifndef DISABLE_CD
		case TYPE_CDAUDIO: 
			return SND_fn_bSetResourceStaticVolumeCD(pstRes,ucVolume);
			break;
#endif
#ifndef DISABLE_SEQUENCE
		case TYPE_SEQUENCE: 
			return SND_fn_bSetResourceStaticVolumeSeq(pstRes,ucVolume);
			break;
#endif
		case TYPE_SWITCH: 
			return SND_fn_bSetResourceStaticVolumeSwitch(pstRes,ucVolume);
			break;
#ifndef DISABLE_SPLIT
		case TYPE_SPLIT: 
			return SND_fn_bSetResourceStaticVolumeSplit(pstRes,ucVolume);
			break;
#endif
		case TYPE_RANDOM: 
			return SND_fn_bSetResourceStaticVolumeRandom(pstRes,ucVolume);
			break;
#ifndef DISABLE_THEME
		case TYPE_THEME: 
			return SND_fn_bSetResourceStaticVolumeTheme(pstRes,ucVolume);
			break;
#endif
		}
	}

	return FALSE;
}

 
#endif /*      NO_ACP_SOUND*/
