reman3/Rayman_X/cpa/tempgrp/SND_OLD/src/Win95/Sndstrm2.c

608 lines
17 KiB
C

#include "SNDinc.h"
#include "sndthrd.h"
#if defined(_DLL_COMPILATION_MODE)
#include "snddll.h"
#endif
#include "sndxd.h"
#include "sndres.h"
#include "sndstrm.h"
typedef struct STREAMING_BUFFER_ *pSTREAMING_BUFFER;
typedef struct STREAMING_VOICE_ *pSTREAMING_VOICE;
SNDLST2_M_DynamicUseListOf(pSTREAMING_BUFFER);
SNDLST2_M_DynamicUseListOf(pSTREAMING_VOICE);
typedef struct STREAMING_BUFFER_{
void* ptrData;
unsigned long ulNbSamples;
long lId;
SNDLST2_M_DynamicElementDeclaration(pSTREAMING_BUFFER)
} STREAMING_BUFFER;
typedef struct STREAMING_VOICE_{
long lIdBufferClient;
long lSampleToBytesShift;
tdhSndFile hFile;
long lLastPushed; //id du dernier data-buffer
SndBool bEnding; //TRUE quand il n'y a plus de données à pusher
SndBool bEnded; //TRUE quand la lectre est finie
SndBool bMustLoop; //TRUE si res loopante
unsigned long ulByteLoop; //offset du point de rebouclage dans le fichier
unsigned long ulByteMax; //offset de dernier octet dans le fichier
unsigned long ulNextPtr; //offset du prochain octet à lire dans le fichier
SND_td_pfn_vSoundCallback pfnCallback;
long lParCallback;
SndBool bWaitingCallback;
SndBool bStereo;
SNDLST2_M_DynamicAnchorDeclaration(pSTREAMING_BUFFER) pList;
SNDLST2_M_DynamicElementDeclaration(pSTREAMING_VOICE)
} STREAMING_VOICE;
typedef struct LISTE_STREAMING_VOICE_{
SNDLST2_M_DynamicAnchorDeclaration(pSTREAMING_VOICE) pList;
} LISTE_STREAMING_VOICE;
static LISTE_STREAMING_VOICE ListStreaming;
static SndBool bInitDone=FALSE;
#define SIZE_DATABUFFER 5120
#define NB_BUFFER_AVANCE 4
//------------
void purge_databuffer(pSTREAMING_BUFFER databuffer)
{
SNDLST2_M_DynamicIsolate(databuffer);
SND_fn_vFreeSnd(databuffer->ptrData);
SND_fn_vFreeSndEx(E_ucSndBlockMain,databuffer);
}
void push_databuffer(pSTREAMING_VOICE streaming)
{
pSTREAMING_BUFFER databuffer;
unsigned long nb_lus,nb_to_read,nb_left;
SND_tdstStackBuffer stackbuffer;
if (!streaming->bEnding)
{
databuffer=SND_fn_pvMallocSndEx(E_ucSndBlockMain,sizeof(STREAMING_BUFFER));
SNDLST2_M_DynamicInitElement(databuffer);
databuffer->ulNbSamples=SIZE_DATABUFFER>>streaming->lSampleToBytesShift;
databuffer->ptrData=SND_fn_pvMallocSnd(SIZE_DATABUFFER);
nb_to_read=SIZE_DATABUFFER;
if ((nb_lus=SND_fn_dwReadFileSnd(streaming->hFile
,min(nb_to_read,streaming->ulByteMax-streaming->ulNextPtr)
,databuffer->ptrData)) != nb_to_read)
{//on est arrivé à la fin du fichier
if (streaming->bMustLoop)
{
streaming->ulNextPtr=streaming->ulByteLoop;
SND_fn_dwSeekFileSnd(streaming->hFile,streaming->ulNextPtr,SEEKFILESND_BEGIN);
nb_left=nb_to_read-nb_lus;
while (nb_left>0)
{//reboucler tant que le buffer n'est pas plein
streaming->ulNextPtr=streaming->ulByteLoop;
nb_lus=SND_fn_dwReadFileSnd(streaming->hFile
,min(nb_left,streaming->ulByteMax-streaming->ulNextPtr)
,(char*)databuffer->ptrData+nb_to_read-nb_left);
nb_left-=nb_lus;
if (!nb_lus)
break;
}
streaming->ulNextPtr=streaming->ulByteLoop+nb_lus;
}
else
{
databuffer->ulNbSamples=nb_lus>>streaming->lSampleToBytesShift;
streaming->lLastPushed=databuffer->lId;
SND_fn_vCloseFileSnd(streaming->hFile);
streaming->hFile=OPENFILESND_FAILED;
streaming->bEnding=TRUE;
}
}
else
{//on n'est pas encore à la fin du fichier
streaming->ulNextPtr+=nb_to_read;
}
SNDLST2_M_DynamicAddTail(&streaming->pList,databuffer);
stackbuffer.ulNbSamples=databuffer->ulNbSamples;
stackbuffer.ptrData=databuffer->ptrData;
databuffer->lId=SND_fn_lPushBufferExSxd(streaming->lIdBufferClient,&stackbuffer);
if (streaming->bEnding)
streaming->lLastPushed=databuffer->lId;
//_RPTF1(_CRT_WARN,"Push %d\n",databuffer->lId);
}
else
{
if (streaming->bWaitingCallback)
{
streaming->bWaitingCallback=FALSE;
(*streaming->pfnCallback)(streaming->lParCallback);
}
}
}
void SND_CALL StreamingCallback(long user_id,long poped_id)
{
pSTREAMING_VOICE streaming;
pSTREAMING_BUFFER databuffer;
int i;
SndBool found=FALSE;
//_RPTF1(_CRT_WARN,"Callback %d\n",poped_id);
SND_fn_vEnterCriticalSectionThreadSnd();
streaming=(pSTREAMING_VOICE)user_id;
databuffer=(pSTREAMING_BUFFER)poped_id;
SNDLST2_M_DynamicForEachElementOf(&streaming->pList,databuffer,i)
{
if (databuffer->lId==poped_id)
{
purge_databuffer(databuffer);
found=TRUE;
break;
}
}
snd_assert(found);
if (!streaming->bEnding)
push_databuffer(streaming);
else
{
if (streaming->lLastPushed==poped_id)
streaming->bEnded=TRUE;
}
SND_fn_vQuitCriticalSectionThreadSnd();
}
void purge_streaming(pSTREAMING_VOICE streaming)
{
pSTREAMING_BUFFER pDataBuffer,pDataBufferNext;
int i;
snd_assert(streaming->bEnded);
SND_fn_vDeleteBufferSxd(streaming->lIdBufferClient);
streaming->lIdBufferClient=C_PLAY_FAILED;
if (streaming->hFile!=OPENFILESND_FAILED)
SND_fn_vCloseFileSnd(streaming->hFile);
streaming->hFile=OPENFILESND_FAILED;
SNDLST2_M_DynamicForEachMovingElementOf(&streaming->pList,pDataBuffer,pDataBufferNext,i)
{
purge_databuffer(pDataBuffer);
}
if (streaming->bWaitingCallback)
{
streaming->bWaitingCallback=FALSE;
(*streaming->pfnCallback)(streaming->lParCallback);
}
SNDLST2_M_DynamicIsolate(streaming);
SND_fn_vFreeSndEx(E_ucSndBlockMain,streaming);
}
///
long SND_fn_lPlaySxdStream(tduRefRes res,SoundParam *par,long prio,SND_td_pfn_vSoundCallback fn_callback,long par_callback)
{
pSTREAMING_VOICE streaming;
SND_tdstFormat format;
SND_tdstCallback callback;
char filename[256];
int i;
SoundParam *pstSoundParam;
if (bInitDone)
{
streaming=SND_fn_pvMallocSndEx(E_ucSndBlockMain,sizeof(STREAMING_VOICE));
SNDLST2_M_DynamicInitElement(streaming);
SNDLST2_M_DynamicAddTail(&ListStreaming.pList,streaming);
SNDLST2_M_DynamicInitAnchor(&streaming->pList);
format.eZip=SAMPLE_PCM;
format.uFormat.stPCM.ulNbSamples=0;
format.uFormat.stPCM.uwResolution=res.pstPtr->uRes.stSample.uwResolution;
format.uFormat.stPCM.uwNbChannels=res.pstPtr->uRes.stSample.uwNbChannels;
format.uFormat.stPCM.ulFreq=res.pstPtr->uRes.stSample.ulFreq;
callback.eType=BUFFER_STACK;
callback.uCallback.CallbackStack=StreamingCallback;
callback.uInfo.lNbSampleToPush=0;
streaming->bMustLoop=res.pstPtr->uRes.stSample.bLoop;
streaming->ulByteLoop=res.pstPtr->uRes.stSample.uData.stStream.ulOffsetLoop;
streaming->ulByteMax=res.pstPtr->uRes.stSample.uData.stStream.ulOffsetLast;
streaming->ulNextPtr=res.pstPtr->uRes.stSample.uData.stStream.ulOffsetFirst;
SND_fn_vResolveFileName(res.pstPtr->uRes.stSample.uData.stStream.szFileName,filename);
streaming->hFile=SND_fn_hOpenFileReadSnd(filename);
SND_fn_dwSeekFileSnd(streaming->hFile,streaming->ulNextPtr,SEEKFILESND_BEGIN);
pstSoundParam=SND_fn_pvMallocSnd(SND_M_lGetSizeOfSoundParam(par));
memcpy(pstSoundParam,par,SND_M_lGetSizeOfSoundParam(par));
if (format.uFormat.stPCM.uwNbChannels==2)
{
pstSoundParam->ucVol=par->ucVol/2;
pstSoundParam->iFlags|=C_SOUNDPARAM_COEF_VOL;
}
if (format.uFormat.stPCM.uwNbChannels==2)
streaming->bStereo=TRUE;
else
streaming->bStereo=FALSE;
streaming->lLastPushed=C_PLAY_FAILED;
streaming->bEnded=FALSE;
streaming->bEnding=FALSE;
streaming->lSampleToBytesShift=format.uFormat.stPCM.uwResolution/8+format.uFormat.stPCM.uwNbChannels-2;
streaming->lIdBufferClient=SND_fn_lCreateNewBufferExSxd(&format,&callback,pstSoundParam,(long)streaming);
SND_fn_vFreeSnd(pstSoundParam);
if (fn_callback)
{
streaming->pfnCallback=fn_callback;
streaming->lParCallback=par_callback;
streaming->bWaitingCallback=TRUE;
}
else
streaming->bWaitingCallback=FALSE;
//lancement des 1° push
for (i=0;i<NB_BUFFER_AVANCE;i++)
{
push_databuffer(streaming);
}
return (long)streaming;
/*
if (buffer_dispo_streaming.bClientActive)
fn_vKillStream();
SND_fn_vResolveFileName(res.pstPtr->uRes.stSample.uData.stStream.szFileName,filename);
buffer_dispo_streaming.hFile=SND_fn_hOpenFileReadSnd(filename);
buffer_dispo_streaming.bFileOpened=TRUE;
if (buffer_dispo_streaming.hFile==OPENFILESND_FAILED)
{
SND_fn_vDisplayError(E_uwSndCannotOpenFile,filename);
return C_PLAY_FAILED;
}
SND_fn_dwSeekFileSnd(buffer_dispo_streaming.hFile,res.pstPtr->uRes.stSample.uData.stStream.ulOffsetFirst,SEEKFILESND_BEGIN);
nb_to_read=2*SIZE_FILE_BUFFER;
nb_lus=SND_fn_dwReadFileSnd(buffer_dispo_streaming.hFile,nb_to_read,hFileBuffer[0]);
buffer_dispo_streaming.uRes.pstPtr=res.pstPtr;
buffer_dispo_streaming.bMustLoop=res.pstPtr->uRes.stSample.bLoop;
buffer_dispo_streaming.ulByteLoop=res.pstPtr->uRes.stSample.uData.stStream.ulOffsetLoop;
buffer_dispo_streaming.ulByteMax=res.pstPtr->uRes.stSample.uData.stStream.ulOffsetLast;
buffer_dispo_streaming.bStarting=TRUE;
buffer_dispo_streaming.bStarted=TRUE;
buffer_dispo_streaming.bIsEnding=FALSE;
buffer_dispo_streaming.bIsLooping=FALSE;
buffer_dispo_streaming.lNextPtr=2*SIZE_FILE_BUFFER;
buffer_dispo_streaming.iNextFileBuffer=0;
if (nb_lus!=nb_to_read)
{//fin du sample
if (buffer_dispo_streaming.bMustLoop)
{//on reboucle
nb_to_read-=nb_lus;
while (nb_to_read!=0)
{
SND_fn_dwSeekFileSnd(buffer_dispo_streaming.hFile,buffer_dispo_streaming.ulByteLoop,SEEKFILESND_BEGIN);
nb_lus=SND_fn_dwReadFileSnd(buffer_dispo_streaming.hFile,nb_to_read,hFileBuffer[buffer_dispo_streaming.iNextFileBuffer]);
if (nb_lus!=nb_to_read)
nb_to_read-=nb_lus;
else
nb_to_read=0;
}
buffer_dispo_streaming.bIsLooping=TRUE;
buffer_dispo_streaming.lNextPtr=buffer_dispo_streaming.ulByteLoop+nb_lus;
}
else
{//début de la fin (prématuré)
// buffer_dispo_streaming.bStarting=FALSE;
SND_fn_vCloseFileSnd(buffer_dispo_streaming.hFile);
buffer_dispo_streaming.bFileOpened=FALSE;
memset((char*)(hFileBuffer[buffer_dispo_streaming.iNextFileBuffer])+nb_lus,0,nb_to_read-nb_lus);
buffer_dispo_streaming.bIsEnding=TRUE;
buffer_dispo_streaming.lCmptEnding=2;
if (nb_to_read-nb_lus>SIZE_FILE_BUFFER)
//cas juste où le sample est assez petit (à peine partit, on arrêtre)
buffer_dispo_streaming.lCmptEnding--;
//_RPT0( _CRT_WARN,"bIsEnding mis à TRUE -");
}
}
if (fn_callback)
{
buffer_dispo_streaming.fn_callback=fn_callback;
buffer_dispo_streaming.par_callback=par_callback;
buffer_dispo_streaming.bWaitingCallback=TRUE;
}
if (fn_bCreateStream(res.pstPtr->uRes.stSample.uwResolution,res.pstPtr->uRes.stSample.uwNbChannels,res.pstPtr->uRes.stSample.ulFreq))
return VOICE_STREAMING;
*/
}
return C_PLAY_FAILED;
}
void SND_fn_vRemoveCallbackSxdStream(long voice)
{
}
SndBool SND_fn_bSetParamSxdStream(long voice,SoundParam *par)
{
pSTREAMING_VOICE streaming;
SoundParam *pstSoundParam;
if (voice==C_PLAY_FAILED)
return FALSE;
streaming=(pSTREAMING_VOICE)voice;
if (streaming->bEnded)
{
purge_streaming(streaming);
return FALSE;
}
else
{
pstSoundParam=SND_fn_pvMallocSnd(SND_M_lGetSizeOfSoundParam(par));
memcpy(pstSoundParam,par,SND_M_lGetSizeOfSoundParam(par));
if (streaming->bStereo)
{
pstSoundParam->ucVol=par->ucVol/2;
pstSoundParam->iFlags|=C_SOUNDPARAM_COEF_VOL;
}
SND_fn_vSetParamBufferSxd(streaming->lIdBufferClient,pstSoundParam);
SND_fn_vFreeSnd(pstSoundParam);
return TRUE;
}
}
SndBool SND_fn_bTestIsPlayingSxdStream(long voice)
{
pSTREAMING_VOICE streaming;
if (voice==C_PLAY_FAILED)
return FALSE;
streaming=(pSTREAMING_VOICE)voice;
if (streaming->bEnded)
{
purge_streaming(streaming);
return FALSE;
}
else
{
return TRUE;
}
}
void SND_fn_vStopSxdStream(long voice)
{
pSTREAMING_VOICE streaming;
if (voice!=C_PLAY_FAILED)
{
streaming=(pSTREAMING_VOICE)voice;
streaming->bEnded=TRUE;
if (streaming->bWaitingCallback)
{
streaming->bWaitingCallback=FALSE;
(*streaming->pfnCallback)(streaming->lParCallback);
}
purge_streaming(streaming);
}
}
void SND_fn_vPauseSxdStream(long voice)
{
}
void SND_fn_vResumeSxdStream(long voice)
{
}
int SND_fn_iInitSxdStream(SND_tdstInitStruct *pInitStruct)
{
SNDLST2_M_DynamicInitAnchor(&ListStreaming.pList);
bInitDone=TRUE;
return C_INIT_OK;
}
SndBool SND_fn_bTestInitSxdStream(void)
{
return TRUE;
}
void SND_fn_vDesInitSxdStream(void)
{
pSTREAMING_VOICE pStreaming,pStreamingNext;
int i;
SNDLST2_M_DynamicForEachMovingElementOf(&ListStreaming.pList,pStreaming,pStreamingNext,i)
{
purge_streaming(pStreaming);
}
}
//---------------------------------------------------------
// 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_fn_rGetPosSxdStream(long voie)
{
pSTREAMING_VOICE streaming;
if (voie!=C_PLAY_FAILED)
{
streaming=(pSTREAMING_VOICE)voie;
if (!streaming->bEnded)
return SND_fn_rGetPosBufferSxd(streaming->lIdBufferClient);
else
return SND_C_POS_ENDED;
}
else
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_fn_rGetLengthSxdStream(long voie)
{
return SND_C_LENGTH_UNKNOWN;
}
//-----------------------------------------------------------
// ConvertRsvDiskToMem: convertir in BlockResourceDisk en Mem
// Entrées:ptrBegin=pointeur sur les données UTILES (jamias d'offset)
//------------------------------------------------------------
void SND_fn_vConvertResDiskToMemSxdStream(tdstBlockResourceDisk *disk
,tdstBlockResourceMem *mem
,void* ptrBegin)
{
#ifndef DISABLE_WAVE
snd_assert(disk->eType==TYPE_SAMPLE);
snd_assert(disk->uRes.stSample.eZip==SAMPLE_PCM);
snd_assert(disk->uRes.stSample.bStream);
mem->Id=disk->Id;
mem->eType=disk->eType;
mem->eStorage=disk->eStorage;
mem->ucVolume=disk->ucVolume;
mem->bIsLoaded=TRUE;
//partie spécifique au type de ressource
//
mem->uRes.stSample.eZip=SAMPLE_PCM;
mem->uRes.stSample.bPitchable=disk->uRes.stSample.bPitchable;
mem->uRes.stSample.bVolable=disk->uRes.stSample.bVolable;
mem->uRes.stSample.bPanable=disk->uRes.stSample.bPanable;
mem->uRes.stSample.bSpacable=disk->uRes.stSample.bSpacable;
mem->uRes.stSample.bReverbable=disk->uRes.stSample.bReverbable;
mem->uRes.stSample.bStream=disk->uRes.stSample.bStream;
mem->uRes.stSample.bLoop=disk->uRes.stSample.bLoop;
//mem->uRes.stSample.ulInc0=(disk->uRes.stSample.ulFreq<<OFFSET_BIT_INC)/g_stFormatOutput.nSamplesPerSec;
mem->uRes.stSample.ulFreq=disk->uRes.stSample.ulFreq;
mem->uRes.stSample.uwResolution=disk->uRes.stSample.uwResolution;
mem->uRes.stSample.uwNbChannels=disk->uRes.stSample.uwNbChannels;
strcpy(mem->uRes.stSample.uData.stStream.szFileName,disk->uRes.stSample.czFileName);
mem->uRes.stSample.uData.stStream.ulOffsetFirst=disk->ulDataOffset;
if (!disk->uRes.stSample.bLoop)
{
mem->uRes.stSample.uData.stStream.ulOffsetLoop=0;
mem->uRes.stSample.uData.stStream.ulOffsetLast=disk->ulDataSize+disk->ulDataOffset;
}
else
{
mem->uRes.stSample.uData.stStream.ulOffsetLoop=disk->ulDataOffset+disk->uRes.stSample.ulStartLoop;
mem->uRes.stSample.uData.stStream.ulOffsetLast=disk->ulDataOffset+disk->uRes.stSample.ulStartLoop+disk->uRes.stSample.ulLoopLength;
}
//le sample est prêt à l'emplois
#endif
}
SndBool SND_fn_bLoadResScriptSxdStream(tdstBlockResourceDisk *disk,tdstBlockResourceMem *mem)
{
#ifndef DISABLE_WAVE
snd_assert(disk->uRes.stSample.eZip!=SAMPLE_AIFF);
snd_assert(disk->uRes.stSample.bStream);
//stream sample cannot be AIIF type
SND_fn_vConvertResDiskToMemSxdStream(disk,mem,NULL);
//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
}
SndBool SND_fn_bLoadResBinarySxdStream(tdstBlockResourceDisk *_pBRDisk,tdstBlockResourceMem *_pBRMem,char *pDataBloc)
{
#ifndef DISABLE_WAVE
snd_assert(_pBRDisk->uRes.stSample.eZip!=SAMPLE_AIFF);
snd_assert(_pBRDisk->uRes.stSample.bStream);
//binary load is disabled for AIFF sample
SND_fn_vConvertResDiskToMemSxdStream(_pBRDisk,_pBRMem,NULL);
return TRUE;
#else
return FALSE;
#endif
}
void SND_fn_vUnLoadResSxdStream(tdstBlockResourceMem* mem)
{
#ifndef DISABLE_WAVE
snd_assert(mem->uRes.stSample.bStream);
mem->uRes.stSample.uData.stMem.pvPtrFirst=NULL;
mem->eType=TYPE_INVALID;
#endif
}
SndBool SND_fn_bSetResourceStaticVolumeSxdStream(tdstBlockResourceMem* pstRes,unsigned char ucVolume)
{
#ifndef DISABLE_WAVE
pstRes->ucVolume=ucVolume;
return TRUE;
#else
return FALSE;
#endif
}