/******************************************************************
    CPA-SND : Sound module
        MPEG ressources
******************************************************************/
 
#include "SNDinc.h"
 
#include "sndres.h"
 
#include "sndmpeg.h"
 
#if defined(_DLL_COMPILATION_MODE) 
#include "snddll.h"
#else
#include "sndxd.h"
#endif
 
#ifndef DISABLE_MPEG
#include "mpeg.hxx"
#include <process.h>
#endif /*DISABLE_MPEG*/
 
#ifndef DISABLE_MPEG
extern unsigned char ucVolume[128];
static unsigned long ulIdBufferClient;
extern SndBool bInMPEGDecomp;
static SndBool bIsClientPaused;
static SndBool bIsMPEGReleased;
static SndBool bIsMPEGOk=FALSE;
 
extern SND_tdstMPEGVoice		MPEGvoices[(kNumVoice+1)*2];
extern SND_tdstMPEGVoice		*pSwapVoice[2];		/* Pointeur sur les deux fichiers MPEG à décoder pour un thème*/
tdstBlockResourceMem*			MPEGCurrentRes[(kNumVoice+1)*2]; 

#define M_SND_MPEG_BUFFERFREQ 44100
/*
 * FADE OF 10 SECONDS EXPRESSED IN SNDREAL
 */
#define M_FADE_DURATION_MPEG  M_IntToRealSnd( 4 )
 
 
/*thread lancée à chaque occurence de callback*/
/*int WINAPI start_callback_thread(DWORD *param)*/
#if defined(__WATCOMC__) && (__WATCOMC__<1100)
void start_callback_threadMPEG(callback_paramMPEG *callback_par)
#else
void __cdecl start_callback_threadMPEG(callback_paramMPEG *callback_par)
#endif
{
	(callback_par->fct)(callback_par->param);
 
	GlobalFree(callback_par);
 
	/*return 0;*/
}
/*fct appelée par genere en cas de Callback*/
/**buffer_dispo dans esi*/
void __stdcall start_callbackMPEG(SND_tdstMPEGVoice* pVoice)
{
/*	BUFFER_DISPO *buffer;*/
/*	DWORD id_thread;*/
	callback_paramMPEG *callback_par;
 
	callback_par=GlobalAlloc(GMEM_FIXED,sizeof(callback_paramMPEG));
	callback_par->fct=pVoice->pfnCallBack;
	callback_par->param=pVoice->ulParam;
 
	/*CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)start_callback_thread,param,0,&id_thread);*/
#if defined(__WATCOMC__) && (__WATCOMC__<1100)
        _beginthread(start_callback_threadMPEG,NULL,0,(void*)callback_par);
#else
        _beginthread(start_callback_threadMPEG,0,(void*)callback_par);
#endif
}
 
#endif /*DISABLE_MPEG*/
 
long SND_CALL SND_fn_lPlayMPEG(tduRefRes num_sample,SampleParam *par,long prio,SND_td_pfn_vSoundCallback fn_callback,long par_callback)
{
#ifndef DISABLE_MPEG
        short                   wVolume;
        SND_tdstMPEGVoice       *pVoice;
        tdstSampleMemory        *pMemory;
        tdstSampleStreaming		*pStream;
        tdstTypeSampleMem       *pSample = &(num_sample.pstPtr->uRes.stSample);
 
	if (bIsMPEGOk)
	{
		if (bIsClientPaused) {
			SND_fn_vResumeBufferSxd(ulIdBufferClient);	
			bIsClientPaused = FALSE;
		}
 
		/*_RPT0(_CRT_WARN,"PLAY---------------\n");*/
		if (pSample->bStream) {
                pStream = &(pSample->uData.stStream); 
                pVoice = SND_fn_pSampleAllocateMPEGVoiceFile(pStream->szFileName,pStream->ulOffsetFirst);
                if (pVoice) {
                        if (pSample->bVolable)
                                wVolume = (par->ucVol*num_sample.pstPtr->ucVolume)>>7;
                        else 
                                wVolume = num_sample.pstPtr->ucVolume;
 
                        pVoice->ucVolume = num_sample.pstPtr->ucVolume;
                        pVoice->ucCurrentVolume = (unsigned char)wVolume;
                        pVoice->ucVolumeIndex = ucVolume[wVolume];
                        pVoice->bVolable = pSample->bVolable;
                        if (pVoice->pAssociatedVoice) {
							pVoice->pAssociatedVoice->ucVolume = num_sample.pstPtr->ucVolume;
							pVoice->pAssociatedVoice->ucCurrentVolume = (unsigned char)wVolume;
							pVoice->pAssociatedVoice->ucVolumeIndex = ucVolume[wVolume];
							pVoice->pAssociatedVoice->bVolable = pSample->bVolable;
                        }
                        if (fn_callback) {
							pVoice->pfnCallBack = fn_callback;
                            pVoice->ulParam = par_callback;
                        }
						else
							pVoice->pfnCallBack = NULL;
 
						MPEGCurrentRes[((unsigned long)pVoice-(unsigned long)MPEGvoices)/sizeof(SND_tdstMPEGVoice)]=num_sample.pstPtr;

                        return (long)pVoice;
                } 
        } else {
                pMemory = &(pSample->uData.stMem);
                pVoice = SND_fn_pSampleAllocateMPEGVoiceMem(pMemory->pvPtrFirst,pMemory->ulNbEch);
                if (pVoice) {
                       if (pSample->bVolable)
                                wVolume = (par->ucVol*num_sample.pstPtr->ucVolume)>>7;
                        else 
                                wVolume = num_sample.pstPtr->ucVolume;
 
                        pVoice->ucVolume = num_sample.pstPtr->ucVolume;
                        pVoice->ucCurrentVolume = (unsigned char)wVolume;
                        pVoice->ucVolumeIndex = ucVolume[wVolume];
                        pVoice->bVolable = pSample->bVolable;
                        if (pVoice->pAssociatedVoice) {
							pVoice->pAssociatedVoice->ucVolume = num_sample.pstPtr->ucVolume;
							pVoice->pAssociatedVoice->ucCurrentVolume = (unsigned char)wVolume;
							pVoice->pAssociatedVoice->ucVolumeIndex = ucVolume[wVolume];
							pVoice->pAssociatedVoice->bVolable = pSample->bVolable;
                        }
 
                        if (fn_callback) {
                                pVoice->pfnCallBack = fn_callback;
                                pVoice->ulParam = par_callback;
                        }
						else
                                pVoice->pfnCallBack = NULL;
 
						MPEGCurrentRes[((unsigned long)pVoice-(unsigned long)MPEGvoices)/sizeof(SND_tdstMPEGVoice)]=num_sample.pstPtr;

                        return (long)pVoice;
                } 
	    }
 
	}
	else
		return C_PLAY_FAILED;
#endif /*DISABLE_MPEG*/
    return C_PLAY_FAILED;
}
 
void SND_CALL SND_fn_vRemoveCallbackMPEG(long voice)
{
#ifndef DISABLE_MPEG
        SND_tdstMPEGVoice			*pVoice;
        if (voice && voice!=C_PLAY_FAILED) {
                pVoice = (SND_tdstMPEGVoice*)voice;
                if (pVoice->pfnCallBack) {
                        pVoice->pfnCallBack = NULL;
                        pVoice->ulParam = 0;
                }
        }
#endif /*DISABLE_MPEG*/
}
 
SndBool SND_CALL SND_fn_bSetParamMPEG(long voice,SampleParam *par)
{
#ifndef DISABLE_MPEG
        SND_tdstMPEGVoice       *pVoice;
        short						wInitialVol;
 
        if (voice && voice!=C_PLAY_FAILED) {
                pVoice = (SND_tdstMPEGVoice*)voice;
                if((!pVoice->bIsPlaying)&&(!pVoice->bIsFinishing)) {
					SND_fn_bFreeMPEGVoice(pVoice);  
					if (pVoice->pfnCallBack) {
						start_callbackMPEG(pVoice);
					}
					pVoice->pfnCallBack = NULL;
 
                    return FALSE;
                } else {
                        /* do modifications...*/
                        if (pVoice->bVolable) { 
                                wInitialVol = pVoice->ucVolume;
                                wInitialVol *= par->ucVol;
                                wInitialVol >>= 7;
 
                                pVoice->ucCurrentVolume = (unsigned char)wInitialVol;
                                pVoice->ucVolumeIndex = ucVolume[wInitialVol];
								if (pVoice->pAssociatedVoice)
								{
									pVoice->pAssociatedVoice->ucCurrentVolume = (unsigned char)wInitialVol;
									pVoice->pAssociatedVoice->ucVolumeIndex = ucVolume[wInitialVol];
								}
 
                        }
 
                }
        }
        return TRUE;
#else
    return FALSE;
#endif /*DISABLE_MPEG*/
}
 
SndBool SND_CALL SND_fn_bTestIsPlayingMPEG(long voice)
{
#ifndef DISABLE_MPEG
        SND_tdstMPEGVoice       *pVoice;
        if (voice && voice!=C_PLAY_FAILED) {
                pVoice = (SND_tdstMPEGVoice*)voice;
                if((!pVoice->bIsPlaying)&&(!pVoice->bIsFinishing)) {
					SND_fn_bFreeMPEGVoice(pVoice);  
					if (pVoice->pfnCallBack) {
						start_callbackMPEG(pVoice);
					}
					pVoice->pfnCallBack = NULL;
                    return FALSE;
                } 
        }
        return TRUE;
#else
    return FALSE;
#endif /*DISABLE_MPEG*/
}
 
void SND_CALL SND_fn_vStopMPEG(long voice)
{
#ifndef DISABLE_MPEG
        SND_tdstMPEGVoice       *pVoice;
 
       if (voice && voice!=C_PLAY_FAILED) {
                pVoice = (SND_tdstMPEGVoice*)voice;
				pVoice->bIsPlaying = FALSE;
 
				while(bInMPEGDecomp) {
					Sleep(30);
				}
 
				SND_fn_bFreeMPEGVoice(pVoice);  
				if (pVoice->pfnCallBack) {
					start_callbackMPEG(pVoice);
				}
				pVoice->pfnCallBack = NULL;
 
        }       
#endif /*DISABLE_MPEG*/
}
 
void SND_CALL SND_fn_vPauseMPEG(long voice)
{
#ifndef DISABLE_MPEG
		if (!bIsClientPaused) {
			SND_fn_vPauseBufferSxd(ulIdBufferClient);	
			bIsClientPaused = TRUE;
		}
 
		/*
        if (voice) {
                ((SND_tdstMPEGVoice*)voice)->bIsPaused = TRUE;
        } 
		*/
#endif /*DISABLE_MPEG*/
}
 
void SND_CALL SND_fn_vResumeMPEG(long voice)
{
#ifndef DISABLE_MPEG
		/*on réactive la voie...*/
		/*
        if (voice) {
                ((SND_tdstMPEGVoice*)voice)->bIsPaused = FALSE;
        }       
		*/
 
		/*...puis on relance le buffer client*/
		if (bIsClientPaused) {
			SND_fn_vResumeBufferSxd(ulIdBufferClient);	
			bIsClientPaused = FALSE;
		}
#endif /*DISABLE_MPEG*/
}
 
 
int SND_CALL SND_fn_iInitMPEG(SND_tdstInitStruct *pInitStruct)
{
#ifndef DISABLE_MPEG
	SND_tdstFormat formatclient;
	SND_tdstCallback callback;
	int i;
 
#if defined(_DLL_COMPILATION_MODE)
    SND_DllInitEntryPoints_StaticFunctions((HMODULE)pInitStruct->hProcessInstance );
    SND_DllInitEntryPoints_WavFunctions(SND_hWavModule);
#endif

	for (i=0;i<(kNumVoice+1)*2;i++)
	{
		MPEGCurrentRes[i]=NULL;
	}

    if(SND_fn_bInitMPEG()) {
        if(SND_fn_bStartMPEGEngine()) {  
			formatclient.eZip=SAMPLE_PCM;
			formatclient.uFormat.stPCM.ulNbSamples=0;
			/*formatclient.uFormat.stPCM.ulNbSamples=32*kFrameSize;*/
			formatclient.uFormat.stPCM.uwResolution=16;
			formatclient.uFormat.stPCM.uwNbChannels=2;
//			formatclient.uFormat.stPCM.ulFreq=44100;
			formatclient.uFormat.stPCM.ulFreq=M_SND_MPEG_BUFFERFREQ;
			memset(&callback,0,sizeof(callback));
			callback.eType=BUFFER_SYNCHRONE;
			callback.uCallback.CallbackASynchrone=SND_fn_vRefreshMPEG;
			ulIdBufferClient=SND_fn_lCreateNewBufferExSxd(&formatclient,&callback,NULL,0);
            /*ulIdBufferClient = SND_fn_lCreateNewBufferSxd(32*kFrameSize,16,2,44100,NULL,SND_fn_vRefreshMPEG,0);*/
            /*ulIdBufferClient = SND_fn_lCreateNewBufferSxd(32*kFrameSize,16,2,M_SND_MPEG_BUFFERFREQ,NULL,SND_fn_vRefreshMPEG,0);*/
            bIsMPEGReleased = FALSE;
			bIsClientPaused= FALSE;
			if (ulIdBufferClient==C_PLAY_FAILED)
				return FALSE;
 
			bIsMPEGOk=TRUE;
			return TRUE;
        }
    }
    return FALSE;
#else
    return C_INIT_FAILED;
#endif /*DISABLE_MPEG*/
}
 
SndBool SND_CALL SND_fn_bTestInitMPEG(void)
{
#ifndef DISABLE_MPEG
    return SND_fn_bInitDone();
#else
    return FALSE;    
#endif /*DISABLE_MPEG*/
}
 
void SND_CALL SND_fn_vDesInitMPEG(void)
{
#ifndef DISABLE_MPEG
        SND_fn_vDeleteBufferSxd(ulIdBufferClient);
        SND_fn_bDesInitMPEG();
#endif /*DISABLE_MPEG*/
}
 
 
tduRefRes SND_CALL SND_fn_tdGetResForVoiceMPEG(long voice)
{
    tduRefRes r={0};
    return r;
}
 
 
void SND_CALL SND_fn_vConvertResDiskToMemMPEG(tdstBlockResourceDisk *disk
                                                 ,tdstBlockResourceMem *mem
                                                 ,void* ptrBegin)
{
        snd_assert(disk->eType==TYPE_SAMPLE);
        snd_assert(disk->uRes.stSample.eZip==SAMPLE_MPEG);
 
        mem->Id=disk->Id;
        mem->eType=disk->eType;
        mem->eStorage=disk->eStorage;
        mem->ucVolume=disk->ucVolume;
        mem->bIsLoaded=TRUE;
 
        mem->uRes.stSample.eZip=SAMPLE_MPEG;
#ifndef DISABLE_MPEG
                /*partie spécifique au type de ressource*/
       
        /**/
        mem->uRes.stSample.bPitchable=FALSE;
        mem->uRes.stSample.bVolable=disk->uRes.stSample.bVolable;
        mem->uRes.stSample.bPanable=FALSE;
        mem->uRes.stSample.bSpacable=FALSE;
        mem->uRes.stSample.bReverbable=FALSE;
        mem->uRes.stSample.bStream=disk->uRes.stSample.bStream;
        mem->uRes.stSample.bLoop=FALSE;
        mem->uRes.stSample.ulInc0=0;
        mem->uRes.stSample.uwResolution=16;
        mem->uRes.stSample.uwNbChannels=disk->uRes.stSample.uwNbChannels;
 
        if (disk->uRes.stSample.bStream)
        {/*sample streamé*/
            strcpy(mem->uRes.stSample.uData.stStream.szFileName,disk->uRes.stSample.czFileName);
            mem->uRes.stSample.uData.stStream.ulOffsetFirst=disk->ulDataOffset;
            mem->uRes.stSample.uData.stStream.ulOffsetLoop=0;
            mem->uRes.stSample.uData.stStream.ulOffsetLast=disk->ulDataSize;
        }
        else
        {/*sample non streamé*/
            mem->uRes.stSample.uData.stMem.ulNbEchLoop=0;
            mem->uRes.stSample.uData.stMem.ulNbEch=disk->ulDataSize;
            
            if (ptrBegin!=NULL)
				mem->uRes.stSample.uData.stMem.pvPtrFirst=(void*)((unsigned long)ptrBegin/*+disk->ulDataOffset*/);
            else
                mem->uRes.stSample.uData.stMem.pvPtrFirst=NULL;
        }
        /*le sample est prêt à l'emploi*/
#endif /*DISABLE_MPEG*/
}
 
#if !defined(NO_ACP_SCRIPT) || defined(_DLL_COMPILATION_MODE)
/*this function must be defined in Script/Hybrid or DLL mode*/
SndBool SND_CALL SND_fn_bLoadResScriptMPEG(tdstBlockResourceDisk *disk,tdstBlockResourceMem *mem)
{
#ifndef DISABLE_MPEG
    void* data;
    char file_name[256];
	unsigned long	ulSize;
 
    if (!disk->uRes.stSample.bStream)
        {
		/* for MMX compatibility size should be mod 8*/
		ulSize = disk->ulDataSize;
		ulSize >>= 3;
		ulSize++;
		ulSize <<=3;
 
        data=SND_fn_pvMallocSnd(ulSize);
        SND_fn_vResolveFileName(disk->uRes.stSample.czFileName,file_name);
			if (!SND_fn_bLoadDataInMem(data,disk->ulDataSize,file_name,disk->ulDataOffset))
			{
				SND_fn_vDisplayError(E_uwSndErrorReadingFile,"");
				SND_fn_vFreeSnd(data);
				data=NULL;
			}
        }
        else
            data=NULL;
 
        SND_fn_vConvertResDiskToMemMPEG(disk,mem,data);
 
		/*en script, chaque ressources charge ces propres data (on ne tient pas compte de eStorage)*/
		mem->eStorage=TYPE_EXTERNAL;

 
        return TRUE;
#else
        return FALSE;
#endif /*DISABLE_MPEG*/
}
#endif
 
SndBool SND_CALL SND_fn_bLoadResBinaryMPEG(tdstBlockResourceDisk *disk,tdstBlockResourceMem *mem,char *pDataBloc)
{
#ifndef DISABLE_MPEG
	void* pData;
    char file_name[256];
	unsigned long	ulSize;
 
	if (!disk->uRes.stSample.bStream)
	{	/* Sample is not streaming: must be really loaded in memory*/
		if (disk->eStorage!=TYPE_EXTERNAL)
		{	/* Sample is in the bank: its position is known relatively to the BRMem:*/
			pData=(void *)(pDataBloc +disk->ulDataOffset);
		}
		else 
		{	/* Sample is external: it must be loaded from a file:*/
			ulSize = disk->ulDataSize;
			ulSize >>= 3;
			ulSize++;
			ulSize <<=3;
			pData=SND_fn_pvMallocSnd(ulSize);
			SND_fn_vResolveFileName(disk->uRes.stSample.czFileName,file_name);
			if (!SND_fn_bLoadDataInMem(pData,disk->ulDataSize,file_name,disk->ulDataOffset))
			{
				SND_fn_vDisplayError(E_uwSndErrorReadingFile,"");
				SND_fn_vFreeSnd(pData);
				pData=NULL;
			}
		}
 
	}
	else pData=NULL; /* Sample is streaming*/
	SND_fn_vConvertResDiskToMemMPEG(disk,mem,pData);
	return TRUE;
#else
        return FALSE;
#endif /*DISABLE_MPEG*/
}
 
/*
void SND_CALL SND_fn_vLoadResFromDiskMPEG(tdstBlockResourceDisk* disk,tdstBlockResourceMem* mem)
{
#ifndef DISABLE_MPEG
	void* data;
    char file_name[256];
	unsigned long	ulSize;
 
    if (!disk->uRes.stSample.bStream)
	{
		// for MMX compatibility size should be mod 8
		ulSize = disk->ulDataSize;
		ulSize >>= 3;
		ulSize++;
		ulSize <<=3;
 
		data=SND_fn_pvMallocSnd(ulSize);
        SND_fn_vResolveFileName(disk->uRes.stSample.czFileName,file_name);
		if (!SND_fn_bLoadDataInMem(data,disk->ulDataSize,file_name,0))
		{
			SND_fn_vDisplayError(E_uwSndErrorReadingFile,"");
			SND_fn_vFreeSnd(data);
			data=NULL;
		}
	}
	else
		data=NULL;
 
	SND_fn_vConvertResDiskToMemMPEG(disk,mem,data);
#endif
}
*/
 
void SND_CALL SND_fn_vUnLoadResMPEG(tdstBlockResourceMem* mem)
{
#ifndef DISABLE_MPEG
    if (!mem->uRes.stSample.bStream)
	{
		if ((mem->uRes.stSample.uData.stMem.pvPtrFirst!=NULL)
			&& (mem->eStorage==TYPE_EXTERNAL))
			SND_fn_vFreeSnd(mem->uRes.stSample.uData.stMem.pvPtrFirst);
	}
 
	mem->uRes.stSample.uData.stMem.pvPtrFirst=NULL;
	mem->eType=TYPE_INVALID;
#endif
}
 
SndBool SND_CALL SND_fn_bIsResLoadedMPEG(tdstBlockResourceMem *mem)
{
#ifndef DISABLE_MPEG
	if 	(mem->uRes.stSample.bStream)
		return TRUE;/* Streaming sample is always "loaded"*/
	else  return (mem->uRes.stSample.uData.stMem.pvPtrFirst!=NULL);
#else
        return FALSE;
#endif /*DISABLE_MPEG*/
}
 
/*
void SND_CALL SND_fn_vSetResUnloadedMPEG(tdstBlockResourceMem *pResMem)
{
#ifndef DISABLE_MPEG
	pResMem->uRes.stSample.bStream=FALSE;
	pResMem->uRes.stSample.uData.stMem.pvPtrFirst=NULL;
#endif //DISABLE_MPEG
}
*/
 
/* THEMES*/
long SND_CALL SND_fn_lPlayTransitionMPEG(tduRefRes FirstRes,tduRefRes NextRes,SND_td_pfn_vSoundCallback transition_callback,long param_callback,SampleParam* par)
{
#ifndef DISABLE_MPEG
    short                   wVolume;
    SND_tdstMPEGVoice       *pVoice;
    tdstSampleMemory        *pMemory;
    tdstSampleStreaming		*pStream;
    tdstTypeSampleMem       *pSample = &(FirstRes.pstPtr->uRes.stSample);
 
	snd_assert(FirstRes.pstPtr->uRes.stSample.eZip==SAMPLE_MPEG);
	snd_assert(NextRes.pstPtr->uRes.stSample.eZip==SAMPLE_MPEG);
 
	if (bIsMPEGOk)
	{
        /* STOP CURRENT THEME OR MPEG SOUND*/
        /*SND_fnvStopAllVoicesMPEGTheme();*/
		if (bIsClientPaused) {
			SND_fn_vResumeBufferSxd(ulIdBufferClient);	
			bIsClientPaused = FALSE;
		}
      
        /* START FIRST VOICE...*/
        if (pSample->bStream) {
                pStream = &(pSample->uData.stStream); 
                pVoice = SND_fn_pSimpleAllocateMPEGVoiceFile(pStream->szFileName,pStream->ulOffsetFirst);
                if (pVoice) {
                        if (transition_callback) {
                                pVoice->pfnCallBack = transition_callback;
                                pVoice->ulParam = param_callback;
                        }
						else
                                pVoice->pfnCallBack = NULL;
 
                } else return C_PLAY_FAILED;
        } else {
                pMemory = &(pSample->uData.stMem);
                pVoice = SND_fn_pSimpleAllocateMPEGVoiceMem(pMemory->pvPtrFirst,pMemory->ulNbEch);
                if (pVoice) {
                        if (transition_callback) {
                                pVoice->pfnCallBack = transition_callback;
                                pVoice->ulParam = param_callback;
                        }
						else
                                pVoice->pfnCallBack = NULL;
 
                } else return C_PLAY_FAILED;
        }
 
        /* SET SECOND VOICE...*/
        pSample = &(NextRes.pstPtr->uRes.stSample);
        if (pSample->bStream) {
                pStream = &(pSample->uData.stStream); 
                pVoice = SND_fn_pAllocateMPEGVoiceFile(pStream->szFileName,pStream->ulOffsetFirst);
                if (pVoice) {
                        if (transition_callback) {
                                pVoice->pfnCallBack = transition_callback;
                                pVoice->ulParam = param_callback;
                        }
						else
                                pVoice->pfnCallBack = NULL;
 
                } else return C_PLAY_FAILED;
        } else {
                pMemory = &(pSample->uData.stMem);
                pVoice = SND_fn_pAllocateMPEGVoiceMem(pMemory->pvPtrFirst,pMemory->ulNbEch);
                if (pVoice) {
                        if (transition_callback) {
                                pVoice->pfnCallBack = transition_callback;
                                pVoice->ulParam = param_callback;
                        }
						else
                                pVoice->pfnCallBack = NULL;
 
                } else return C_PLAY_FAILED;
        }

		wVolume = par->ucVol;/*NextRes.pstPtr->ucVolume;*/
		if (wVolume < 0) wVolume =0;
		if (wVolume > 127) wVolume = 127;
 
		pSwapVoice[0]->ucVolume = (unsigned char)wVolume;/*NextRes.pstPtr->ucVolume;*/
		pSwapVoice[0]->ucCurrentVolume = (unsigned char)wVolume;
		pSwapVoice[0]->ucVolumeIndex = ucVolume[wVolume];
		pSwapVoice[1]->ucVolume = (unsigned char)wVolume;/*NextRes.pstPtr->ucVolume;*/
		pSwapVoice[1]->ucCurrentVolume = (unsigned char)wVolume;
		pSwapVoice[1]->ucVolumeIndex = ucVolume[wVolume];
 
		if (pSwapVoice[0]->pAssociatedVoice) {
			pSwapVoice[0]->pAssociatedVoice->ucVolume = (unsigned char)wVolume;/*NextRes.pstPtr->ucVolume;*/
			pSwapVoice[0]->pAssociatedVoice->ucCurrentVolume = (unsigned char)wVolume;/*NextRes.pstPtr->ucVolume;*/
			pSwapVoice[0]->pAssociatedVoice->ucVolumeIndex = ucVolume[wVolume];
		}
		if (pSwapVoice[1]->pAssociatedVoice) {
			pSwapVoice[1]->pAssociatedVoice->ucVolume = (unsigned char)wVolume;/*NextRes.pstPtr->ucVolume;*/
			pSwapVoice[1]->pAssociatedVoice->ucCurrentVolume = (unsigned char)wVolume;/*NextRes.pstPtr->ucVolume;*/
			pSwapVoice[1]->pAssociatedVoice->ucVolumeIndex = ucVolume[wVolume];
		}
 
		return 0;
	}
	else
		return C_PLAY_FAILED;
#else
    return C_PLAY_FAILED;
#endif /*DISABLE_MPEG*/
}
 
SndBool SND_CALL SND_fn_bSetParamTransitionMPEG(long voice,SampleParam* par)
{
#ifndef DISABLE_MPEG
    /*SND_tdstMPEGVoice       *pVoice;*/
    short                   wVolume;
	
    wVolume = par->ucVol;/*NextRes.pstPtr->ucVolume;*/
	if (wVolume < 0) wVolume =0;
	if (wVolume > 127) wVolume = 127;
 
    pSwapVoice[0]->ucVolume = (unsigned char)wVolume;/*NextRes.pstPtr->ucVolume;*/
    pSwapVoice[0]->ucCurrentVolume = (unsigned char)wVolume;
    pSwapVoice[0]->ucVolumeIndex = ucVolume[wVolume];
    pSwapVoice[1]->ucVolume = (unsigned char)wVolume;/*NextRes.pstPtr->ucVolume;*/
    pSwapVoice[1]->ucCurrentVolume = (unsigned char)wVolume;
    pSwapVoice[1]->ucVolumeIndex = ucVolume[wVolume];
 
	if (pSwapVoice[0]->pAssociatedVoice) {
		pSwapVoice[0]->pAssociatedVoice->ucVolume = (unsigned char)wVolume;/*NextRes.pstPtr->ucVolume;*/
		pSwapVoice[0]->pAssociatedVoice->ucCurrentVolume = (unsigned char)wVolume;/*NextRes.pstPtr->ucVolume;*/
		pSwapVoice[0]->pAssociatedVoice->ucVolumeIndex = ucVolume[wVolume];
	}
	if (pSwapVoice[1]->pAssociatedVoice) {
		pSwapVoice[1]->pAssociatedVoice->ucVolume = (unsigned char)wVolume;/*NextRes.pstPtr->ucVolume;*/
		pSwapVoice[1]->pAssociatedVoice->ucCurrentVolume = (unsigned char)wVolume;/*NextRes.pstPtr->ucVolume;*/
		pSwapVoice[1]->pAssociatedVoice->ucVolumeIndex = ucVolume[wVolume];
	}
	return TRUE;
#else
	return FALSE;
#endif
}
 
tduRefRes SND_g_uFadeRes;
 
SndBool SND_CALL SND_fn_bSetNextTransitionMPEG(long voice,tduRefRes new_res)
{
#ifndef DISABLE_MPEG
        /*short                           wVolume;*/
        SND_tdstMPEGVoice       *pVoice;
        tdstSampleMemory        *pMemory;
        tdstSampleStreaming *pStream;
        tdstTypeSampleMem       *pSample = &(new_res.pstPtr->uRes.stSample);
 
		snd_assert(new_res.pstPtr->uRes.stSample.eZip==SAMPLE_MPEG);
 
/*        char szTemp[256];*/
		/* SET THE NEXT MPEG VOICE TO PLAY*/
        if (pSample->bStream) {
			pStream = &(pSample->uData.stStream); 
 
                pVoice = SND_fn_pAllocateMPEGVoiceFile(pStream->szFileName,pStream->ulOffsetFirst);
                if (pVoice) {
						pVoice->bVolable = pSample->bVolable;
                      
                } else return FALSE;
        } else {
                pMemory = &(pSample->uData.stMem);
                pVoice = SND_fn_pAllocateMPEGVoiceMem(pMemory->pvPtrFirst,pMemory->ulNbEch);
                if (pVoice) {
						pVoice->bVolable = pSample->bVolable;
 
                } else return FALSE;
        }

        return TRUE;
#else
    return FALSE;
#endif /*DISABLE_MPEG*/
}
 
SndBool SND_CALL SND_fn_bDoTransitionWithFadeMPEG2( long voice, tduRefRes new_res, SndReal rDuration )
{
#ifndef DISABLE_MPEG
    SND_tdstMPEGVoice       *pCurrentVoice,*pNextVoice;
	unsigned long ulFadeSize,ulCurrentSizeLeft;
	SndBool bFadeInPart;
	int iFadeFrameNumber;
#ifndef M_FRED_DECREAU
	_int64 _iFade;
#endif
 
	if (bIsMPEGOk)
	{
		pCurrentVoice=pSwapVoice[0];
		pNextVoice=pSwapVoice[1];
		bFadeInPart=FALSE;
#ifdef M_FRED_DECREAU
		ulFadeSize=32*2000; /* On voudrait fader sur 1300 miniframes de 32 samples*/
	/*	ulFadeSize=32*3000; // test avec 3 secondes..*/
#else
		/*
		 * Estimate the fade duration in sample unit
		 */
		pCurrentVoice->rDuration = rDuration;
		pNextVoice->rDuration    = rDuration;
		_iFade     = rDuration;
		_iFade     = M_RealToIntSnd( M_MulIntRealSnd( _iFade, M_SND_MPEG_BUFFERFREQ - 32 * 48 ) );
		ulFadeSize = (unsigned long)_iFade;
		/*
		 * The Fade duration in sample must be a modulo of 32. Because in MPEG data are
		 * decompressed Frame after Frame, and a Frame length is 32 sample long
		 */
		ulFadeSize -= ulFadeSize % 32;
#endif
		ulCurrentSizeLeft=pCurrentVoice->ulFinalSize-pCurrentVoice->ulPos;
		
		/* Set bFadeInPart and ulFadeTime:*/
		if (!pNextVoice->bIsPlaying)
		{
			bFadeInPart=TRUE; /* No next part->fade in part!*/
			/* Adjust fade time with remaining time:*/
			if (ulCurrentSizeLeft<ulFadeSize) ulFadeSize=ulCurrentSizeLeft;
		}
		else 
		{
			if (ulCurrentSizeLeft>=ulFadeSize) 
			{ /* enough time left in this part to fade:*/
				bFadeInPart=TRUE;
			}
			else 
			{ /* We'll fade on two parts:*/
				if ((ulCurrentSizeLeft+pNextVoice->ulFinalSize)<ulFadeSize)
					ulFadeSize=ulCurrentSizeLeft+pNextVoice->ulFinalSize;
				bFadeInPart=FALSE;
			}
		}
		/*
		 * Calculate the number of fade frame = iFadeFrameNumber
		 * Volume decrement. Decreament linearly the volume
		 * Set part as fading and fade parameters:
		 */
		iFadeFrameNumber=ulFadeSize/32;
		pCurrentVoice->bIsFading=TRUE;
#if M_FRED_DECREAU
		pCurrentVoice->iFadeIncrement=-((1<<16)/iFadeFrameNumber);
#else
		pCurrentVoice->iFadeIncrement=-(rDuration/iFadeFrameNumber);
#endif
		pCurrentVoice->iFadeVolume=(-pCurrentVoice->iFadeIncrement)*iFadeFrameNumber;
		if( pCurrentVoice->pAssociatedVoice ) {
			pCurrentVoice->pAssociatedVoice->bIsFading      = TRUE;
			pCurrentVoice->pAssociatedVoice->rDuration      = rDuration;
			pCurrentVoice->pAssociatedVoice->iFadeIncrement = pCurrentVoice->iFadeIncrement;
			pCurrentVoice->pAssociatedVoice->iFadeVolume    = pCurrentVoice->iFadeVolume;
		}
		if (bFadeInPart)
		{
	/*		OutputDebugString("start of fade: fade in part\n");*/
			/* Shorten current voice if necessary:*/
			pCurrentVoice->ulFinalSize=pCurrentVoice->ulPos+ulFadeSize;
			/* Set a new transition with the new_res:*/
			SND_fn_bSetNextTransitionMPEG(voice,new_res);
			SND_g_uFadeRes.pstPtr=NULL;
		}
		else
		{ /* Fade in two parts:*/
	/*		OutputDebugString("start of fade: two parts fade\n");*/
			SND_g_uFadeRes=new_res;
			/* Shorten next voice if necessary:*/
			pNextVoice->ulFinalSize=ulFadeSize-ulCurrentSizeLeft;
		}
	}
 
	return FALSE;
#else
	return FALSE;
#endif
}
 
SndBool SND_CALL SND_fn_bDoTransitionWithFadeMPEG( long voice, tduRefRes new_res )
{
#ifndef DISABLE_MPEG
	return SND_fn_bDoTransitionWithFadeMPEG2( voice, new_res, M_FADE_DURATION_MPEG );
#endif /*DISABLE_MPEG*/
}
  
void SND_CALL SND_fn_vStopTransitionMPEG(long voice)
{
#ifndef DISABLE_MPEG
        SND_fnvStopAllVoicesMPEGTheme();
#endif /*DISABLE_MPEG*/
}
 
 
void SND_CALL SND_fn_vPauseTransitionMPEG(long voice)
{
#ifndef DISABLE_MPEG
	/*pSwapVoice[0]->bIsPaused =  TRUE;*/
	if (!bIsClientPaused && bIsMPEGOk) {
	/*	pSwapVoice[0]->bIsPaused =  TRUE;*/
		SND_fn_vPauseBufferSxd(ulIdBufferClient);	
		bIsClientPaused = TRUE;
	}
#endif
}
 
void SND_CALL SND_fn_vResumeTransitionMPEG(long voice)
{
#ifndef DISABLE_MPEG
	/*pSwapVoice[0]->bIsPaused =  FALSE;*/
	if (bIsClientPaused && bIsMPEGOk) {
	/*	pSwapVoice[0]->bIsPaused =  FALSE;*/
		SND_fn_vResumeBufferSxd(ulIdBufferClient);	
		bIsClientPaused = FALSE;
	}
#endif
}
 
 
#ifndef NO_ACP_LDBIN
SndBool SND_CALL SND_fn_bCanFreeDataMPEG(void)
{
	return FALSE;
}
#endif
 
/*--------------------------------------------------
relache-reprise a chaud des drives
---------------------------------------------------------*/
void SND_CALL SND_fn_vReleaseDriverMPEG()
{
#ifndef DISABLE_MPEG
 
	if (!bIsMPEGOk) return;
	if (bIsMPEGReleased) return;
 
	/* FAIRE TOUT CE QU'IL FAUT...*/
 
 
	bIsMPEGReleased = TRUE;
#endif
}
 
void SND_CALL SND_fn_vRestoreDriverMPEG()
{
#ifndef DISABLE_MPEG
	SndReal	rBufferState;
	if (!bIsMPEGOk) return;
	if (!bIsMPEGReleased) return;
 
	/* FAIRE TOUT CE QU'IL FAUT...*/
	rBufferState=SND_fn_rGetPosBufferSxd(ulIdBufferClient);
	if ((rBufferState==SND_C_POS_ENDED) || (rBufferState==SND_C_POS_UNKNOWN))
		/*driver WAV perdu -> MPEG kaput*/
		bIsMPEGOk=FALSE;
 
	bIsMPEGReleased = FALSE;
#endif
}
 
/*---------------------------------------------------------*/
/*	GetPos: retourne la position "théorique" de la ressource*/
/*			exprimé en seconde depuis le début*/
/*			différent du temps absolu (car pitch, dérive..)*/
/*	Entrée: voie concernée*/
/*	Sortie: temps en S (SndReal)*/
/*----------------------------------------------------------*/
SndReal SND_CALL SND_fn_rGetPosMPEG(long voice)
{
#ifndef DISABLE_MPEG
    SND_tdstMPEGVoice *pVoice;
	long temp;
		
	if (bIsMPEGOk && voice!=C_PLAY_FAILED && voice) 
	{
		pVoice = (SND_tdstMPEGVoice*)voice;
        if((pVoice->bIsPlaying) || (pVoice->bIsFinishing))
		{
//		temp=M_DoubleToRealSnd(((double)pVoice->ulPos/*-32.0*kFrameSize*/-480)/44100.);
		temp=M_DoubleToRealSnd(((double)pVoice->ulPos/*-32.0*kFrameSize*/-480)/M_SND_MPEG_BUFFERFREQ.);
		if (temp>0)
			return temp;
		else
			return 0;
		}
	}
#endif
	return SND_C_POS_UNKNOWN;
}
 
/*---------------------------------------------------------*/
/*	GetLength: retourne la durée "théorique" de la ressource*/
/*			exprimé en seconde (constant pour une ressource donnée)*/
/*	Entrée: voie concernée*/
/*	Sortie: durée en S (SndReal)*/
/*----------------------------------------------------------*/
SndReal SND_CALL SND_fn_rGetLengthMPEG(long voice)
{
#ifndef DISABLE_MPEG
    SND_tdstMPEGVoice *pVoice;
		
	if (voice!=C_PLAY_FAILED && voice) 
	{
		pVoice = (SND_tdstMPEGVoice*)voice;
        if(pVoice->bIsPlaying) 
//			return SND_fn_rDivRealRealSnd(pVoice->ulFinalSize,44100);
			return SND_fn_rDivRealRealSnd(pVoice->ulFinalSize,M_SND_MPEG_BUFFERFREQ);
	}
#endif
	return SND_C_LENGTH_UNKNOWN;
}
 
/*-------------------------------------------------*/
/* Fonction de synchro moteur*/
/*	ne sert à rien pour MPEG*/
/*-------------------------------------------------*/
void SND_CALL SND_fn_vSynchroMPEG()
{
}
 
/*nouveau buffers clients*/
long SND_CALL SND_fn_lCreateNewBufferExMPEG(SND_tdstFormat* pformat,SND_tdstCallback* pCallback,SoundParam* par,long user_id)
{
	return C_PLAY_FAILED;
}
 
long SND_CALL SND_fn_lGetPosBufferExMPEG(long id_buffer)
{
	return SND_C_POS_UNKNOWN;
}
 
long SND_CALL SND_fn_lPushBufferExMPEG(long id_buffer,SND_tdstStackBuffer* pStack)
{
	return C_PLAY_FAILED;
}
 
void SND_CALL SND_fn_vSetDefaultRollOffMPEG(RollOffParam* rolloff)
{
	/*nothing to do in, this version*/
}
 
SndBool SND_CALL SND_fn_bCheckVersionResourceMPEG(tdstBlockResourceDisk *disk)
{
	return TRUE;
}

SndBool SND_CALL SND_fn_bSetResourceStaticVolumeMPEG(tdstBlockResourceMem* pstRes,unsigned char ucVolume)
{
#ifndef DISABLE_MPEG
	SND_tdstMPEGVoice *pVoice;
	int	i;

	pstRes->ucVolume=ucVolume;

	for (i=0,pVoice=&MPEGvoices[0];i<(kNumVoice+1)*2;i++,pVoice++)
	{
		if (MPEGCurrentRes[i]!=NULL)
			if (MPEGCurrentRes[i]==pstRes)
			{
				MPEGvoices[i].ucVolume=ucVolume;
			}
	}

#endif /*DISABLE_MPEG*/
	return TRUE;
}

