#include "SNDinc.h"

#include "sndevent.h"
#include "sndres.h"
#include "sndplay.h"

#ifdef _DLL_COMPILATION_MODE
#include "snddll.h"
#else
#include "sndmpeg.h"
#include "sndmidi.h"
#include "sndxd.h"
#include "sndxdapm.h"
#endif

//*****************************************************
//*******		  Global variables		**************
//*****************************************************
#ifndef NO_ACP_LDBIN

#include "sndld_bn.h"
/*
#ifndef NO_ACP_LDBIN

typedef struct _tdstSndBankDescriptorElement *p_tdstSndBankDescriptorElement;

SNDLST2_M_DynamicUseListOf(p_tdstSndBankDescriptorElement);

struct _tdstSndBankDescriptorElement
{
	int iId;					//Id of bank
	unsigned long iLevel;		//level (for StartLoadBank2
	char czFileName[13];		//file name of bank
	//signed long ulDataSize;	//size of
	tdeBankState eState;		//current of bank (loading, to be loaded...) 
	tdstSndBankHead* pData;		//pointer to main data (malloc)
	void *pDataPrimary;			//pointer to primary data (CPA list for Theme, Seq...)
	void *pDataMPEG;			//pointer to MPEG data
	void *pDataMidi;			//pointer to Midi data
	void *pDataSample;			//pointer to Sampel data
	SNDLST2_M_DynamicElementDeclaration(p_tdstSndBankDescriptorElement)
} tdstSndBankDescriptorElement;

typedef struct tdstSndBankDescriptorList_{
		SNDLST2_M_DynamicAnchorDeclaration(p_tdstSndBankDescriptorElement) pList;
} tdstSndBankDescriptorList;
*/

tdstSndBankDescriptorList SND_g_dBankDescriptionList;

//SND_g_dBankDescriptionList describes loaded banks
//struct tdstSndBankDescriptorElement describes a bank 


SndBool fn_bInitBinEvent(SND_tdstBlockEvent *pEvent);


// get file name for bank #_iBankNum
void fn_vGetBankFileName(unsigned long _ulBankNum,char *czFileName,int sizeFileName)
{
	char texte[256];
	sprintf(texte,"bnk_%d.BNM",_ulBankNum);
	strncpy(czFileName,texte,sizeFileName);
}

// return the *SndBankDescriptorElement of bank #_iBankNum if loaded else returns NULL
p_tdstSndBankDescriptorElement fn_pstGetBankDescriptor(int _iBankNum)
{
	p_tdstSndBankDescriptorElement pBankDescr;
	int i;

	SNDLST2_M_DynamicForEachElementOf(&SND_g_dBankDescriptionList.pList,pBankDescr,i)
	{
		if (pBankDescr->iId==_iBankNum) 
		//found
			return pBankDescr;
	}
	//not found
	return NULL;
}





//add a new SndBankDescriptorElement in SndBankDescriptorList for bank #_iBankNum
p_tdstSndBankDescriptorElement fn_pstAddBankDescriptor(int _iBankNum,int level)
{
	p_tdstSndBankDescriptorElement pBankDescr;
	
	pBankDescr=SND_fn_pvMallocSnd(sizeof(tdstSndBankDescriptorElement));
	
	memset(pBankDescr,0,sizeof(tdstSndBankDescriptorElement));
	SNDLST2_M_DynamicInitElement(pBankDescr);
	SNDLST2_M_DynamicAddTail(&SND_g_dBankDescriptionList.pList,pBankDescr);
	pBankDescr->iId=_iBankNum;
	fn_vGetBankFileName(_iBankNum,pBankDescr->czFileName,sizeof(pBankDescr->czFileName));
	pBankDescr->eState=BANK_NOT_LOADED;
	pBankDescr->pData=NULL;
	pBankDescr->pDataPrimary=NULL;
	pBankDescr->pDataMPEG=NULL;
	pBankDescr->pDataMidi=NULL;
	pBankDescr->pDataSample=NULL;
	if (level==BANK_ALL_LEVEL)
		pBankDescr->iLevel=0xFFFFFFFF;
	else
		pBankDescr->iLevel=(1<<level);

	return pBankDescr;
}

// load all data from a bianry bank (descriptor, raw data...), but do not resolve pointers
// return TRUE if succesfull
SndBool fn_bLoadDataBankWithoutResolve(p_tdstSndBankDescriptorElement pBankDescr)
{
	// Data:  |Head |Lists | Prim Data |MPEG  |Midi	| Sample |
	tdstSndBankHead stBankHead;
    unsigned long ulPersistentDataSize;
    unsigned long ulSizeMPEG,ulSizeMidi,ulSizeSample,ulSizeADPCM,ulSizeStreaming;
	
	char czFilePath[256];
	tdhSndFile hFile;
	unsigned long ulOffset,ulOffsetPersistentDataInMem;
	
 	SND_tdstBlockEvent *pEvent;
	tduBlockResource *pRes;

	return FALSE;

	// Set the bank descriptor state:
	pBankDescr->eState=BANK_LOADING;
	
	// Get the complete bank file name:
    SND_fn_vResolveFileName(pBankDescr->czFileName,czFilePath);

	// Load the bank's head from file to memory:
	hFile=SND_fn_hOpenFileReadSnd(czFilePath);
	if (hFile==OPENFILESND_FAILED)
	{
		SND_fn_vDisplayError(E_uwSndCannotOpenFile,czFilePath);
		return FALSE;
	}

	SND_fn_dwReadFileSnd(hFile,sizeof(tdstSndBankHead),&stBankHead);
	
	//get version
	pBankDescr->lBNMCheckVersion=SND_BNM_GETVERSION(&stBankHead);

	// Compute all the blocks sizes:
	ulSizeMPEG=stBankHead.ulOffsetMidi-stBankHead.ulOffsetMPEG;
	ulSizeMidi=stBankHead.ulOffsetSample-stBankHead.ulOffsetMidi;
#ifdef SNDBANK_FORMAT2
	ulSizeSample=stBankHead.ulOffsetADPCM-stBankHead.ulOffsetSample;
	if (pBankDescr->lBNMCheckVersion==SND_BNM_VERSIONCHECK_1)
	{
		ulSizeADPCM=0;
		ulSizeStreaming=0;
	}
	else
	{
		ulSizeADPCM=stBankHead.ulOffsetStreaming-stBankHead.ulOffsetADPCM;
		ulSizeStreaming=stBankHead.ulTotalSize-stBankHead.ulOffsetStreaming;
	}
#else
	ulSizeSample=stBankHead.ulTotalSize-stBankHead.ulOffsetSample;
#endif //SNDBANK_FORMAT2

	// Compute the persistant data size:
	ulPersistentDataSize=stBankHead.ulOffsetMPEG; // Head+Lists+Primary data
	if (!SND_fn_bCanFreeDataMPEG())
			ulPersistentDataSize+=ulSizeMPEG;
	if (!SND_fn_bCanFreeDataMidi())
			ulPersistentDataSize+=ulSizeMidi;
	if (!SND_fn_bCanFreeDataSample())
			ulPersistentDataSize+=ulSizeSample;
#ifdef SNDBANK_FORMAT2
	if (!SND_fn_bCanFreeDataADPCM())
			ulPersistentDataSize+=ulSizeADPCM;
	//streaming data are never loaded
#endif //SNDBANK_FORMAT2


	// Allocate the corresponding memory:
	pBankDescr->pData=(tdstSndBankHead*)SND_fn_pvMallocSnd(ulPersistentDataSize);
	
	// Copy the previously read bank head to its final place:
	memcpy(pBankDescr->pData,&stBankHead,sizeof(tdstSndBankHead));
	
	// Load the Lists & Prim data right after the header:
	SND_fn_dwReadFileSnd(hFile
		,stBankHead.ulOffsetMPEG-sizeof(tdstSndBankHead)
		,(void*)(((char*)pBankDescr->pData)+sizeof(tdstSndBankHead)));

	pBankDescr->pDataPrimary=(void*)(((char*)pBankDescr->pData)+sizeof(tdstSndBankHead));

	ulOffsetPersistentDataInMem=stBankHead.ulOffsetMPEG;

	//Load MPEG datas where necessary
	if (!SND_fn_bCanFreeDataMPEG())	
	{
		pBankDescr->pDataMPEG=(void*)((char*)pBankDescr->pData+ulOffsetPersistentDataInMem);
		ulOffsetPersistentDataInMem+=ulSizeMPEG;
	}
	else
		//allocate a temporary pointer (will be free by ResolvePointer
		if (ulSizeMPEG)
			pBankDescr->pDataMPEG=SND_fn_pvMallocSnd(ulSizeMPEG);
		else
			pBankDescr->pDataMPEG=NULL;
	
	if (ulSizeMPEG)
		SND_fn_dwReadFileSnd(hFile
				,ulSizeMPEG
				,pBankDescr->pDataMPEG);

	//Load Midi datas where necessary
	if (!SND_fn_bCanFreeDataMidi())	
	{
		pBankDescr->pDataMidi=(void*)((char*)pBankDescr->pData+ulOffsetPersistentDataInMem);
		ulOffsetPersistentDataInMem+=ulSizeMidi;
	}
	else
		//allocate a temporary pointer (will be free by ResolvePointer
		if (ulSizeMidi)
			pBankDescr->pDataMidi=SND_fn_pvMallocSnd(ulSizeMidi);
		else
			pBankDescr->pDataMidi=NULL;
	
	if (ulSizeMidi)
		SND_fn_dwReadFileSnd(hFile
				,ulSizeMidi
				,pBankDescr->pDataMidi);

	//Load Sample datas where necessary
	if (!SND_fn_bCanFreeDataSample())	
	{
		pBankDescr->pDataSample=(void*)((char*)pBankDescr->pData+ulOffsetPersistentDataInMem);
		ulOffsetPersistentDataInMem+=ulSizeSample;
	}
	else
		//allocate a temporary pointer (will be free by ResolvePointer
		if (ulSizeSample)
			pBankDescr->pDataSample=SND_fn_pvMallocSnd(ulSizeSample);
		else
			pBankDescr->pDataSample=NULL;
	
	if (ulSizeSample)
		SND_fn_dwReadFileSnd(hFile
				,ulSizeSample
				,pBankDescr->pDataSample);

#ifdef SNDBANK_FORMAT2
	//Load ADPCM datas where necessary
	if (!SND_fn_bCanFreeDataADPCM())	
	{
		pBankDescr->pDataADPCM=(void*)((char*)pBankDescr->pData+ulOffsetPersistentDataInMem);
		ulOffsetPersistentDataInMem+=ulSizeADPCM;
	}
	else
		//allocate a temporary pointer (will be free by ResolvePointer
		if (ulSizeADPCM)
			pBankDescr->pDataADPCM=SND_fn_pvMallocSnd(ulSizeADPCM);
		else
			pBankDescr->pDataADPCM=NULL;
	
	if (ulSizeADPCM)
		SND_fn_dwReadFileSnd(hFile
				,ulSizeADPCM
				,pBankDescr->pDataADPCM);
#endif //SNDBANK_FORMAT2

	//all datas have been loaded
	SND_fn_vCloseFileSnd(hFile); 
	
	// Convert the bank descriptor parent structs from disk to mem:
	ulOffset=(unsigned long )SNDLST2_M_StaticGetFirstElement(&(pBankDescr->pData->stEventList));
	pEvent=(SND_tdstBlockEvent *)((unsigned long )(pBankDescr->pData)+ulOffset);
	SNDLST2_M_StaticSetFirstElement(&(pBankDescr->pData->stEventList),pEvent);

	ulOffset=(unsigned long )SNDLST2_M_StaticGetFirstElement(&(pBankDescr->pData->stResList));
	pRes=(tduBlockResource *)((unsigned long )(pBankDescr->pData)+ulOffset);
	SNDLST2_M_StaticSetFirstElement(&(pBankDescr->pData->stResList),pRes);

	pBankDescr->pDataPrimary=(void*)(((char*)SNDLST2_M_StaticGetFirstElement(&(pBankDescr->pData->stResList))
		+sizeof(tduBlockResource)*SNDLST2_M_StaticGetNumberOfElements(&(pBankDescr->pData->stResList))));

	//things to do later:
	//-init raw datas (call to LoadRes)
	//-correct reference to resources and events (convert bin id to pointer)
	//-free temporary bloc if necessary

	return TRUE;
}

//resolve all pointer used by a binary bank just loaded
SndBool fn_bResolveBankPointer(p_tdstSndBankDescriptorElement pBankDescr)
{
	tdstSndBankHead *pBankHead;
    unsigned long ulSizeMPEG,ulSizeMidi,ulSizeSample,ulSizeADPCM;
	void *pCurBloc=NULL;
	int iPos;
	tdstBlockResourceDisk stBRDisk;
	SndBool bToLoad;
	SndBool bBankOK=TRUE;
	
 	SND_tdstBlockEvent *pEvent;
	tduBlockResource *pRes;

	pBankHead=pBankDescr->pData;
	// Data:  |Head |Lists | Prim Data |MPEG  |Midi	| Sample |
	
	// Compute all the blocks sizes:
	ulSizeMPEG=pBankHead->ulOffsetMidi-pBankHead->ulOffsetMPEG;
	ulSizeMidi=pBankHead->ulOffsetSample-pBankHead->ulOffsetMidi;
#ifdef SNDBANK_FORMAT2
	ulSizeSample=pBankHead->ulOffsetADPCM-pBankHead->ulOffsetSample;
	ulSizeADPCM=pBankHead->ulTotalSize-pBankHead->ulOffsetADPCM;
#else
	ulSizeSample=pBankHead->ulTotalSize-pBankHead->ulOffsetSample;
#endif //SNDBANK_FORMAT2

	// Init Events and resources in this 
	SNDLST2_M_StaticForEachElementOf( &(pBankHead->stEventList), pEvent, iPos)
		fn_bInitBinEvent(pEvent);
	
	SNDLST2_M_StaticForEachElementOf( &(pBankDescr->pData->stResList), pRes, iPos)
	{
		// copy the bloc resource disk in the temporary structure:
		memcpy(&stBRDisk,pRes,sizeof(tdstBlockResourceDisk));
		// Get the appropriate bloc pointer depending on the resource type:
		bToLoad=TRUE;
		switch (stBRDisk.eType)
		{
			case TYPE_SAMPLE:
				if (stBRDisk.uRes.stSample.bStream)
				{//streaming -> no data loaded
					pCurBloc=NULL;
				}
				else
				{
					switch (stBRDisk.uRes.stSample.eZip)
					{
					case SAMPLE_PCM:
						pCurBloc=pBankDescr->pDataSample;
						break;
					case SAMPLE_MPEG:
						pCurBloc=pBankDescr->pDataMPEG;
						break;
					#ifdef SNDBANK_FORMAT2
					case SAMPLE_ADPCM:
						pCurBloc=pBankDescr->pDataADPCM;
						break;
					#endif //SNDBANK_FORMAT2
					default:
						SND_fn_vDisplayError(E_uwSndInvalidStaticParamForResource,"");
						break;
					}
				}
				break;
			case TYPE_MIDI:
				pCurBloc=pBankDescr->pDataMidi;
				break;
			case TYPE_CDAUDIO:
			case TYPE_SEQUENCE:
			case TYPE_SWITCH_OLD:
			case TYPE_SWITCH:
			case TYPE_SPLIT:
			case TYPE_THEME:
			case TYPE_RANDOM:
				pCurBloc=pBankDescr->pDataPrimary;
				break;
			default: // ERROR! UNKNOWN RES TYPE;
				SND_fn_vDisplayError(E_uwSndInvalidTypeOfResource,"");
				pRes->stMem.eType=TYPE_INVALID;
				bToLoad=FALSE;
				bBankOK=FALSE;
//				return FALSE;
				break;            
		}
		// call the load function:
		if (bToLoad)
			SND_fn_bLoadResBinarySnd(&stBRDisk,&pRes->stMem,pCurBloc);
	} 	// End of update of references in resources.

	// Free temporary blocs if necessary
	if (SND_fn_bCanFreeDataMPEG() && pBankDescr->pDataMPEG)
		SND_fn_vFreeSnd(pBankDescr->pDataMPEG);
	pBankDescr->pDataMPEG=NULL;
	if (SND_fn_bCanFreeDataMidi() && pBankDescr->pDataMidi) 
		SND_fn_vFreeSnd(pBankDescr->pDataMidi);
	pBankDescr->pDataMidi=NULL;
	if (SND_fn_bCanFreeDataSample() && pBankDescr->pDataSample) 
		SND_fn_vFreeSnd(pBankDescr->pDataSample);
	pBankDescr->pDataSample=NULL;
#ifdef SNDBANK_FORMAT2
	if (SND_fn_bCanFreeDataADPCM() && pBankDescr->pDataADPCM) 
		SND_fn_vFreeSnd(pBankDescr->pDataADPCM);
	pBankDescr->pDataADPCM=NULL;
#endif //SNDBANK_FORMAT2

	pBankDescr->pDataPrimary=NULL;

	return bBankOK;
}

//resolve pointers used by an event
SndBool fn_bInitBinEvent(SND_tdstBlockEvent *pEvent)
{
		switch (pEvent->eType)
		{
			case EVT_SON_STOP_ALL:
				break;
			case EVT_SON_PLAY:
				if (pEvent->uParams.stPlay.uResource.Id!=SND_INVALID_BINID)
					pEvent->uParams.stPlay.uResource.pstPtr=SND_fn_pGetBinRes(pEvent->uParams.stPlay.uResource.Id);
                else
					pEvent->uParams.stPlay.uResource.pstPtr=NULL;
				break;
			case EVT_SON_STOP:
				if (pEvent->uParams.stStop.uEvt.Id!=SND_INVALID_BINID)
					pEvent->uParams.stStop.uEvt.pstPtr=SND_fn_pGetBinEvent(pEvent->uParams.stStop.uEvt.Id);
                else
					pEvent->uParams.stStop.uEvt.pstPtr=NULL;
				break;
			case EVT_SON_STOP_N_GO:
				if (pEvent->uParams.stStopNGo.uEvtStop.Id!=SND_INVALID_BINID)
					pEvent->uParams.stStopNGo.uEvtStop.pstPtr=SND_fn_pGetBinEvent(pEvent->uParams.stStopNGo.uEvtStop.Id);
                else
					pEvent->uParams.stStop.uEvt.pstPtr=NULL;
				if (pEvent->uParams.stStopNGo.uEvtGo.Id!=SND_INVALID_BINID)
					pEvent->uParams.stStopNGo.uEvtGo.pstPtr=SND_fn_pGetBinEvent(pEvent->uParams.stStopNGo.uEvtGo.Id);
                else
					pEvent->uParams.stStopNGo.uEvtGo.pstPtr=NULL;
				break;
			case EVT_SON_STOP_N_GO_CROSSFADE:
				if (pEvent->uParams.stStopNGoFade.uEvtStop.Id!=SND_INVALID_BINID)
					pEvent->uParams.stStopNGoFade.uEvtStop.pstPtr=SND_fn_pGetBinEvent(pEvent->uParams.stStopNGoFade.uEvtStop.Id);
                else
					pEvent->uParams.stStopNGoFade.uEvtStop.pstPtr=NULL;
				if (pEvent->uParams.stStopNGoFade.uEvtGo.Id!=SND_INVALID_BINID)
					pEvent->uParams.stStopNGoFade.uEvtGo.pstPtr=SND_fn_pGetBinEvent(pEvent->uParams.stStopNGoFade.uEvtGo.Id);
                else
					pEvent->uParams.stStopNGoFade.uEvtGo.pstPtr=NULL;
				break;
			case EVT_SON_PITCH:
			case EVT_SON_VOLUME:
			case EVT_SON_PAN:
				if (pEvent->uParams.stExtraParam.uResource.Id!=SND_INVALID_BINID)
					pEvent->uParams.stExtraParam.uResource.pstPtr=SND_fn_pGetBinRes(pEvent->uParams.stExtraParam.uResource.Id);
                else
					pEvent->uParams.stExtraParam.uResource.pstPtr=NULL;
				break;
			case EVT_SON_EXTRA:
				if (pEvent->uParams.stExtraAll.uResource.Id!=SND_INVALID_BINID)
					pEvent->uParams.stExtraAll.uResource.pstPtr=SND_fn_pGetBinRes(pEvent->uParams.stExtraAll.uResource.Id);
                else
					pEvent->uParams.stExtraAll.uResource.pstPtr=NULL;
				break;
			case EVT_SON_EFFET:
			case EVT_SON_CHANGE_VOLUME:
				//nothing to do
				break;
			default: // ERROR! UNKNOWN RES TYPE;
                SND_fn_vDisplayError(E_uwSndInvalidTypeOfEvent,"");
                return FALSE;
                break;            

		}
		return TRUE;
}

#endif //LDBIN

#ifndef SND_HYBRID_VERSION

//***********************************************************************
//***********************************************************************
//**					Public functions							*****
//***********************************************************************
//***********************************************************************
// GetNumberOfBanks: returns the number of loaded banks

unsigned long SND_fn_ulGetEventBinIdFromPointer(SND_tdstBlockEvent *_pEvent)
{
#ifndef NO_ACP_LDBIN
	p_tdstSndBankDescriptorElement pBankDescr;
	int i,iEventCount,iEventNumber;
	unsigned long ulEventId;
	if (_pEvent==NULL) return 0xFFFFFFFF;
	SNDLST2_M_DynamicForEachElementOf(&SND_g_dBankDescriptionList.pList,pBankDescr,i)
	{
		// Is event in this bank
		SNDLST2_M_StaticWhatElementNumber(_pEvent,&pBankDescr->pData->stEventList,iEventNumber);
		iEventCount=SNDLST2_M_StaticGetNumberOfElements(&pBankDescr->pData->stEventList);
		if ((iEventNumber<0)||(iEventNumber>=iEventCount)) continue;
		// Event found, get bank id:
		ulEventId=pBankDescr->iId;
		ulEventId<<=16; // Store Bank Id in upper part of the unsigned long
		ulEventId+=iEventNumber; // Store Res Pos in lower part of the unsigned long
		return ulEventId;
	}
#endif //NO_ACP_LDBIN
	//not found
	return 0xFFFFFFFF;

}

#endif //SND_HYBRID_VERSION


int SND_CALL SND_fn_iGetNumberOfBanks(void)
{
#ifndef NO_ACP_LDBIN
	return SNDLST2_M_DynamicGetNumberOfElements(&SND_g_dBankDescriptionList.pList);
#else
    return 0;
#endif
}

//GetNumberOfEventInBank: returns the number of events in a bank
int SND_CALL SND_fn_iGetNumberOfEventInBank(int bank)
{
#ifndef NO_ACP_LDBIN
	p_tdstSndBankDescriptorElement pBankDescr;
	
	pBankDescr=fn_pstGetBankDescriptor(bank);

	if (pBankDescr)
		return SNDLST2_M_StaticGetNumberOfElements(&pBankDescr->pData->stEventList);
	else
		return 0;
#else
    return 0;
#endif
}


// InitBankSnd: to be called once before binary functions could be used
void SND_CALL SND_fn_vInitBankSnd(char *czPathName)
{
#ifndef NO_ACP_LDBIN
	SNDLST2_M_DynamicInitAnchor(&SND_g_dBankDescriptionList.pList);
#endif
}


// DesInitBankSnd: to be called once when binary functions are no more used
//		will unLoad all loaded banks
void SND_CALL SND_fn_vDesInitBankSnd(void)
{
#ifndef NO_ACP_LDBIN
	int i;
	p_tdstSndBankDescriptorElement pBank,pBankNext;

	SNDLST2_M_DynamicForEachMovingElementOf(&SND_g_dBankDescriptionList.pList,pBank,pBankNext,i)
	{
		SND_fn_bUnLoadBinaryBank(pBank->iId);
	}
#endif
}

// GetBinEvent: return the pointer to a binary event
//	If event is not loaded, returns NULL
#ifndef SND_HYBRID_VERSION
SND_tdstBlockEvent* SND_CALL SND_fn_pGetBinEvent(unsigned long _ulBinId)
{
#ifndef NO_ACP_LDBIN
	unsigned long ulBankId,ulEventPos;
	tdstSndBankHead* pBank;
	SND_tdstBlockEvent *pEvent;
	p_tdstSndBankDescriptorElement pBankDescr;
	int i;

    if (_ulBinId==0xFFFFFFFF)
        return NULL;

	ulBankId=_ulBinId>>16;
	ulEventPos=_ulBinId&0xFFFF;
	// Get Right bank:
	pBankDescr=fn_pstGetBankDescriptor(ulBankId);

	if (pBankDescr!=NULL)
	{//found !!
		pBank=pBankDescr->pData;
		snd_assert(pBank!=NULL);
		if ((long)ulEventPos<SNDLST2_M_StaticGetNumberOfElements(&pBank->stEventList))
		{
		SNDLST2_M_StaticGetElementNumber(&pBank->stEventList,pEvent,(long)ulEventPos,i);
		}
		else
			pEvent=NULL;
		return(pEvent);
	}
	else
		return NULL;
#else
    return NULL;
#endif
}
#endif

// GetBinRes: returns the pointer to a binary resource
//	If ressource is not loaded, returns NULL
tdstBlockResourceMem* SND_CALL SND_fn_pGetBinRes(unsigned long _ulBinId)
{
#ifndef NO_ACP_LDBIN
	unsigned long ulBankId,ulResPos;
	tdstSndBankHead* pBank;
	tduBlockResource *pRes;
	p_tdstSndBankDescriptorElement pBankDescr;
	int i;

    if (_ulBinId==0xFFFFFFFF)
        return NULL;

	ulBankId=_ulBinId>>16;
	ulResPos=_ulBinId&0xFFFF;
	// Get Right bank:
	pBankDescr=fn_pstGetBankDescriptor(ulBankId);
	if (pBankDescr!=NULL)
	{//found !!
		pBank=pBankDescr->pData;
		snd_assert(pBank!=NULL);
		if ((long)ulResPos<SNDLST2_M_StaticGetNumberOfElements(&pBank->stResList))
		{
		SNDLST2_M_StaticGetElementNumber(&pBank->stResList,pRes,(long)ulResPos,i);
		}
		else
			pRes=NULL;
		return(&pRes->stMem);
	}
	else
		return NULL;
#else
    return NULL;
#endif
}

// StartLoadBanks:Called when the list of loaded bank is about to change
//	After this call, the user must call SND_fn_bInitBank for each bank he want to be loaded
//	At the end, calling EndLoadBanks will load necessary banks, and unload unnecessary banks
SndBool SND_CALL SND_fn_bStartLoadBanks(void)
{
	return SND_fn_bStartLoadBanks2(BANK_ALL_LEVEL);
}

// StartLoadBanks:Called when the list of loaded bank is about to change in one level
//	After this call, the user must call SND_fn_bInitBank for each bank he want to be loaded in this level
//	At the end, calling EndLoadBanks will load necessary banks, and unload unnecessary banks in this level
//	Bank from other level will no change
SndBool SND_CALL SND_fn_bStartLoadBanks2(int level)
{
#ifndef NO_ACP_LDBIN
 	p_tdstSndBankDescriptorElement pBankDescr;
	int i;


	SNDLST2_M_DynamicForEachElementOf(&SND_g_dBankDescriptionList.pList,pBankDescr,i)
	{
		if (level==BANK_ALL_LEVEL)
			pBankDescr->iLevel=0;//all its set to 0
		else
		{
			snd_assert(level<32);
			pBankDescr->iLevel&=~(1<<level);//bit #level set to 0
		}

		if (!pBankDescr->iLevel)
			pBankDescr->eState=BANK_WAITING;
	}

	return TRUE;
#else //SND_LDBIN
    return FALSE;
#endif

}

// InitBank: marks bank as "TO_BE_LOADED"
//	The bank will be loaded only at EndLoadBank call
SndBool SND_CALL SND_fn_bInitBank(int _iBankNum)
{
	return SND_fn_bInitBank2(_iBankNum,BANK_ALL_LEVEL);
}

// InitBank: marks bank as "TO_BE_LOADED"
//	The bank will be loaded only at EndLoadBank call
SndBool SND_CALL SND_fn_bInitBank2(int _iBankNum,int level)
{
#ifndef NO_ACP_LDBIN
	p_tdstSndBankDescriptorElement pBankDescr;


	pBankDescr=fn_pstGetBankDescriptor(_iBankNum);

	if (pBankDescr==NULL)
	{//bank was yet loaded (?)
		pBankDescr=fn_pstAddBankDescriptor(_iBankNum,level);
	}
	else
	{
		if (level==BANK_ALL_LEVEL)
			pBankDescr->iLevel=0xFFFFFFFF;//all bits set to 1
		else
		{
			snd_assert(level<32);
			pBankDescr->iLevel&=(1<<level);//bit #level set to 1
		}
	}

	switch(pBankDescr->eState)
	{
	case BANK_WAITING:
	case BANK_LOADED:
		// bank is yet in memory
		pBankDescr->eState=BANK_LOADED;
		break;
	case BANK_TO_BE_LOADED:
		//confirm bank to be loaded
		break;
	case BANK_NOT_LOADED:
		//babl to be loaded
		pBankDescr->eState=BANK_TO_BE_LOADED;
		break;
	default:
		snd_assert(FALSE);
		break;
	}

	return TRUE;
#else //SNDLDBIN
    return FALSE;
#endif
}

// Ends the changes of loaded banks list
//	loads wished banks if not yet loaded
//	unloads unwished banks if loaded
//	keeps wished banks if yet loaded
SndBool SND_CALL SND_fn_bEndLoadBanks(void)
{
#ifndef NO_ACP_LDBIN
 	p_tdstSndBankDescriptorElement pBankDescr,pBankDescrNext;
	int i;

	//first: load or unload datas
	SNDLST2_M_DynamicForEachMovingElementOf(&SND_g_dBankDescriptionList.pList,pBankDescr,pBankDescrNext,i)
	{
		switch (pBankDescr->eState)
		{
			case BANK_WAITING:
				// We must unload this bank:
				SND_fn_bUnLoadBinaryBank(pBankDescr->iId);
				break;			
			case BANK_TO_BE_LOADED:
				// We must finish this bank's load:
				if (!fn_bLoadDataBankWithoutResolve(pBankDescr))
				{
					SND_fn_bUnLoadBinaryBank(pBankDescr->iId);
				}
				else
					pBankDescr->eState=BANK_LOADING;
				break;	
			case BANK_LOADED:
				//nothing to do
				break;
			default:
				snd_assert(FALSE);
				break;
		}
	}

	//second: resolve pointer
	SNDLST2_M_DynamicForEachElementOf(&SND_g_dBankDescriptionList.pList,pBankDescr,i)
	{
		switch (pBankDescr->eState)
		{
			case BANK_LOADING:
				// We must unload this bank:
				fn_bResolveBankPointer(pBankDescr);
				pBankDescr->eState=BANK_LOADED;
				break;
			case BANK_LOADED:
				//nothing to do
				break;
			default:
				snd_assert(FALSE);
				break;
		}
	}

	return TRUE;
#else //SNDLDBIN
    return FALSE;
#endif
}

// LoadBinaryBank: simply loads a binary bank (only one pass)
SndBool SND_CALL SND_fn_bLoadBinaryBank(int _iBank)
{
#ifndef NO_ACP_LDBIN
	p_tdstSndBankDescriptorElement pBankDescr;

	pBankDescr=fn_pstGetBankDescriptor(_iBank);

	if (pBankDescr==NULL)
		pBankDescr=fn_pstAddBankDescriptor(_iBank,BANK_ALL_LEVEL);

	if (pBankDescr->eState!=BANK_LOADED)
	{
		pBankDescr->eState=BANK_TO_BE_LOADED;
		if (fn_bLoadDataBankWithoutResolve(pBankDescr))
		{
			pBankDescr->eState=BANK_LOADING;
			if (fn_bResolveBankPointer(pBankDescr))
				pBankDescr->eState=BANK_LOADED;
			else
			{
				SND_fn_bUnLoadBinaryBank(_iBank);
				return FALSE;
			}
		}
		else
		{
			SND_fn_bUnLoadBinaryBank(_iBank);
			return FALSE;
		}
	}

	return TRUE;
#else
	return FALSE;
#endif
}

// UnLoadBinaryBank: simply unload a binary bank (only one pass)
//	destroy BankDescriptorElement
SndBool SND_CALL SND_fn_bUnLoadBinaryBank(int _iBank)
{
#ifndef NO_ACP_LDBIN
	p_tdstSndBankDescriptorElement pBankDescr;
	tduBlockResource *pRes;
	int iPos;

	pBankDescr=fn_pstGetBankDescriptor(_iBank);

	if (pBankDescr==NULL)
		return FALSE;

	if (pBankDescr->pData!=NULL)
	{
		SNDLST2_M_StaticForEachElementOf( &(pBankDescr->pData->stResList), pRes, iPos)
		{
			SND_fn_vStopBeforeUnLoadResSnd(&pRes->stMem);
		}

		SNDLST2_M_StaticForEachElementOf( &(pBankDescr->pData->stResList), pRes, iPos)
		{
			SND_fn_vUnLoadResSnd(&pRes->stMem);
		}

		// free the bank:
		SND_fn_vFreeSnd(pBankDescr->pData);
	}

	SNDLST2_M_DynamicIsolate(pBankDescr);
	SND_fn_vFreeSnd(pBankDescr);

	return TRUE;
#else
	return FALSE;
#endif
}

#ifndef NO_ACP_LDBIN

EvtGrpDesc *SND_gs_pEventGroupData=NULL;
unsigned long SND_gs_ulEventGroupCount=0;

EvtGrpDesc *SND_fn_pstGetEventGroupData(void)
{
		return SND_gs_pEventGroupData;
}

void SND_fn_vSetEventGroupData(EvtGrpDesc *_pData)
{
		SND_gs_pEventGroupData=_pData;
}



unsigned long SND_fn_ulGetEventGroupCount(void)
{
	return SND_gs_ulEventGroupCount;
}

void SND_fn_vSetEventGroupCount(unsigned long _ulCount)
{
	SND_gs_ulEventGroupCount=_ulCount;
}

#ifndef SND_HYBRID_VERSION
// BINARY VERSION INIT:
SndBool SND_fn_bInitDataLoadSnd(const char *_szFileTitle)
{
	return TRUE;
}
#endif //SND_HYBRID_VERSION



#endif //NO_ACP_LDBIN


unsigned long SND_fn_ulGetBinIdFromEditorId(unsigned long _ulEvtId)
{
#ifndef NO_ACP_LDBIN
	unsigned long ulEvtGrpId,ulEvtId;
	EvtGrpDesc *pEventGroupElement,*pLastEventGroupElement;
	unsigned long *pData,*pLastData;
	
	// Make sure convertion table has been loaded:
	if (SND_gs_pEventGroupData==NULL) return SND_INVALID_BINID;
	ulEvtGrpId=(_ulEvtId)>>16;
	ulEvtId=_ulEvtId&0xFFFF;

	pEventGroupElement=SND_gs_pEventGroupData;
	pLastEventGroupElement=pEventGroupElement+SND_gs_ulEventGroupCount;
	while (pEventGroupElement<pLastEventGroupElement)
	{
		if (pEventGroupElement->ulId==ulEvtGrpId)
		{
			// Event group found : scan it:
			pData=(unsigned long*)(((char*)pEventGroupElement)+pEventGroupElement->ulOffset);
			pLastData=pData+pEventGroupElement->ulNbEvents*2;
			while (pData<pLastData)
			{
				if ((*pData)==ulEvtId) return (*(pData+1));
				pData+=2;
			}
			return SND_INVALID_BINID;
		}
		pEventGroupElement++;
	}
#endif //NO_ACP_LDBIN
	return SND_INVALID_BINID;
}

SND_tdxHandleToSoundEvent SND_fn_hGetSoundEventHandleFromEditorId(unsigned long _ulEvtId)
{
#ifndef NO_ACP_LDBIN
	unsigned long ulBinId;
	
	ulBinId=SND_fn_ulGetBinIdFromEditorId(_ulEvtId);
	return ((SND_tdxHandleToSoundEvent)SND_fn_pGetBinEvent(ulBinId));
#else NO_ACP_LDBIN
	return NULL;
#endif //NO_ACP_LDBIN
}

#ifdef NO_ACP_LDBIN
unsigned long SND_fn_ulGetEventBinIdFromSectionName(const char *szSectionName)
{
	return SND_INVALID_BINID;
}
#endif

#ifndef SND_HYBRID_VERSION
// Get ptr onto resource from ist editor-id
// return NULL when resource cannot be solved
tdstBlockResourceMem* SND_fn_pstGetResFromEdIdSnd(unsigned long ulEdId)
{
	p_tdstSndBankDescriptorElement	pBankDescr;
	tduBlockResource*			pRes;
	int i,j;

	

	SNDLST2_M_DynamicForEachElementOf(&SND_g_dBankDescriptionList.pList,pBankDescr,i)
	{
		SNDLST2_M_StaticForEachElementOf(&(pBankDescr->pData->stResList),pRes,j)
		{
			if (pRes->stMem.Id==ulEdId)
				return &(pRes->stMem);

		}
	}

	return NULL;
}
#endif
