988 lines
30 KiB
C
988 lines
30 KiB
C
/*==============================================================================================
|
|
* FILE "SNDADPCM.C"
|
|
*
|
|
* Created : 31 / 10 / 97
|
|
* Author : Stephane Ronse & Nicolas Meyer
|
|
* Description: Code source file which manage ADPCM conversion
|
|
* and play. Works with Dx3D, Dx2D, WinMM DLL.
|
|
* Formalism : Public functions are prefixed with "SND_"
|
|
* Ubi guidelines
|
|
*
|
|
* Copyright (C) 1997 by Ubi Sound Studio Entertainment
|
|
* All rights Reserved
|
|
*==============================================================================================*/
|
|
|
|
/* Super Public*/
|
|
#if 0
|
|
#include <crtdbg.h>
|
|
#endif
|
|
#include "SNDinc.h"
|
|
#include "sndres.h"
|
|
#include "sndxd.h"
|
|
|
|
#if defined(_DLL_COMPILATION_MODE)
|
|
#include "snddll.h"
|
|
#endif
|
|
|
|
|
|
#ifndef DISABLE_ADPCM
|
|
|
|
#ifndef NO_ACP_SOUND
|
|
|
|
/* Moyen public*/
|
|
#include "Sndadpcm.h"
|
|
#include "Sndthrd.h"
|
|
#include "ApmThrd.h"/*En-tete contenant du code multi tâche*/
|
|
/* Prive*/
|
|
#include "Adpcm.h"
|
|
#include "Adpcm.hxx"
|
|
#include "Adpcm.cxx"
|
|
/* DECLARATION DES FONCTIONS*/
|
|
/*==================================================*/
|
|
void SND_CALL fn_vRefreshSynchroneADPCM( long lIdBuffer, unsigned long ulStart, unsigned long ulSizeByte, void* pvBuffer );
|
|
void SND_CALL fn_vRefreshASynchroneADPCM( long lIdBuffer, unsigned long ulStart, unsigned long ulSizeByte, void* pvBuffer );
|
|
SndBool fn_bConvertBlockResDiskADPCMtoWAV(tdstBlockResourceDisk* pstDiskADPCM,void* ptrDataADPCM,tdstBlockResourceDisk* pstDiskWAV);
|
|
SndBool fn_bConvertDataADPCMtoWAV(tdstBlockResourceDisk* pstDiskADPCM,void* ptrDataADPCM,void* ptrDataWAV);
|
|
/*==================================================*/
|
|
|
|
/*
|
|
* STRUCTURE DEFINITIONS
|
|
*/
|
|
typedef struct {
|
|
long lBufferId;
|
|
unsigned long ulSizeLast;
|
|
unsigned long ulSizePos;
|
|
} tdstBufferDescriptor;
|
|
/*
|
|
* GLOBALES VARIABLES
|
|
*/
|
|
static tdstBufferDescriptor gstASynch;
|
|
static tdstBufferDescriptor gstSynch;
|
|
static long gbDecompress; /* Mutex qui gere le multi-tâche*/
|
|
static SndBool gbClientPause; /* Flag qui indique que le buffer client est dejà en pause*/
|
|
static SndBool gbInitDone = FALSE; /* Flag qui indique l'init du module "ADPCM" c'est faite sans encombre*/
|
|
static SND_tdstADPCMCriticalSection gstSection;
|
|
/*
|
|
* Current file name & error information
|
|
*/
|
|
static char gchFileName[] = "SndAdpcm.c";
|
|
static char gchBuffer[256];
|
|
/*
|
|
* DEFINITION DES FONCTIONS
|
|
*/
|
|
void SND_fn_vConvertResDiskToMemSampleADPCM( tdstBlockResourceDisk *disk, tdstBlockResourceMem *mem, void* ptrBegin )
|
|
{
|
|
snd_assert(disk->eType==TYPE_SAMPLE);
|
|
snd_assert( disk->uRes.stSample.eZip == SAMPLE_ADPCM );
|
|
|
|
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.stSample.eZip = SAMPLE_ADPCM;
|
|
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.ulFreq = disk->uRes.stSample.ulFreq;
|
|
mem->uRes.stSample.uwResolution = disk->uRes.stSample.uwResolution;
|
|
mem->uRes.stSample.uwNbChannels = disk->uRes.stSample.uwNbChannels;
|
|
|
|
if( disk->uRes.stSample.bStream ) {
|
|
/*sample streame*/
|
|
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; /* Indice de sample*/
|
|
mem->uRes.stSample.uData.stStream.ulOffsetLast = disk->ulDataOffset+disk->ulDataSize; /* Nombre de samples*/
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
else {/*sample non streame*/
|
|
mem->uRes.stSample.uData.stMem.ulNbEchLoop = disk->uRes.stSample.ulStartLoop;
|
|
mem->uRes.stSample.uData.stMem.ulNbEch = disk->uRes.stSample.ulLoopLength;
|
|
mem->uRes.stSample.uData.stMem.pvPtrFirst = ptrBegin;
|
|
snd_assert( ! ( (unsigned long)mem->uRes.stSample.uData.stMem.pvPtrFirst % 4 ) );
|
|
}
|
|
/*le sample est pret à l'emplois*/
|
|
}
|
|
|
|
char gchNoVoice[] = "No active voice.";
|
|
char gchInvalPa[] = "Address non affected.";
|
|
char gchNoTheme[] = "None possibility to play theme.";
|
|
char gchNotAdpm[] = "Is not ADPCM datas.";
|
|
char gchBadForm[] = "Bad format.";
|
|
long SND_fn_lPlaySampleADPCM( tduRefRes res, SampleParam *par, long prio, SND_td_pfn_vSoundCallback fn_callback, long par_callback )
|
|
{
|
|
long lId;
|
|
char* pchString;
|
|
|
|
if( gbInitDone ) {
|
|
SND_fn_vEnterCriticalSection( & gstSection );
|
|
|
|
switch( fn_ulAddVoiceADPCM( res.pstPtr
|
|
, par
|
|
, fn_callback
|
|
, par_callback
|
|
, NULL
|
|
, & lId
|
|
, gstSynch.ulSizePos ) ) {
|
|
/* L'allocation de la voie a ete faite*/
|
|
case ADPCM_NOERROR:
|
|
break;
|
|
case ADPCM_NOVOICELEFT:
|
|
pchString = gchNoVoice;
|
|
lId = C_PLAY_FAILED;
|
|
break;
|
|
case ADPCM_INVALIDPARAM:
|
|
pchString = gchInvalPa;
|
|
lId = C_PLAY_FAILED;
|
|
break;
|
|
case ADPCM_NOTHEMELEFT:
|
|
pchString = gchNoTheme;
|
|
lId = C_PLAY_FAILED;
|
|
break;
|
|
case ADPCM_NOTADPCMDATAS:
|
|
pchString = gchNotAdpm;
|
|
lId = C_PLAY_FAILED;
|
|
break;
|
|
default:
|
|
pchString = gchBadForm;
|
|
lId = C_PLAY_FAILED;
|
|
}
|
|
SND_fn_vLeaveCriticalSection( & gstSection );
|
|
if( lId == C_PLAY_FAILED )
|
|
SND_fn_vDisplayError( E_uwSndSystemError, pchString );
|
|
}
|
|
return lId;
|
|
}
|
|
|
|
void SND_fn_vRemoveCallbackSampleADPCM( long voice )
|
|
{
|
|
if( gbInitDone ) {
|
|
SND_fn_vEnterCriticalSection( & gstSection );/* Entree en section critique*/
|
|
fn_ulRemoveVoiceCallbackADPCM( voice );
|
|
SND_fn_vLeaveCriticalSection( & gstSection );/* Sortie de section critique*/
|
|
}
|
|
}
|
|
|
|
SndBool SND_fn_bSetParamSampleADPCM( long voice, SampleParam *par )
|
|
{
|
|
SndBool bRet = FALSE;
|
|
|
|
if( gbInitDone ) {
|
|
SND_fn_vEnterCriticalSection( & gstSection );/* Entree en section critique*/
|
|
if( fn_ulSetParams( voice, par ) == ADPCM_NOERROR ) {
|
|
bRet = TRUE;
|
|
}
|
|
SND_fn_vLeaveCriticalSection( & gstSection );/* Sortie de section critique*/
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
SndBool SND_fn_bTestIsPlayingSampleADPCM( long voice )
|
|
{
|
|
if( gbInitDone ) {
|
|
if( fn_bVoiceIsPlayingADPCM( voice ) )
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void SND_fn_vStopSampleADPCM( long voice )
|
|
{
|
|
if( gbInitDone ) {
|
|
if( voice ) {
|
|
SND_fn_vEnterCriticalSection( & gstSection );
|
|
fn_ulRemoveVoiceADPCM( voice );
|
|
SND_fn_vLeaveCriticalSection( & gstSection );
|
|
}
|
|
}
|
|
}
|
|
|
|
void SND_fn_vPauseSampleADPCM( long voice )
|
|
{
|
|
if( gbInitDone ) {
|
|
SND_fn_vEnterCriticalSection( & gstSection );
|
|
fn_ulPauseVoiceADPCM( voice );
|
|
SND_fn_vLeaveCriticalSection( & gstSection );
|
|
}
|
|
}
|
|
|
|
void SND_fn_vResumeSampleADPCM(long voice)
|
|
{
|
|
if( gbInitDone ) {
|
|
SND_fn_vEnterCriticalSection( & gstSection );
|
|
fn_ulResumeVoiceADPCM( voice );
|
|
SND_fn_vLeaveCriticalSection( & gstSection );
|
|
}
|
|
}
|
|
|
|
SndBool SND_fn_bIsResourceLoopingSampleADPCM(tduRefRes res)
|
|
{
|
|
return res.pstPtr->uRes.stSample.bLoop;
|
|
}
|
|
|
|
SndReal SND_fn_rGetPosSampleADPCM( long voice )
|
|
{
|
|
SndReal rAnswer;
|
|
|
|
rAnswer = SND_C_LENGTH_UNKNOWN;
|
|
if( gbInitDone ) {
|
|
double dTime;
|
|
|
|
switch( fn_ulGetPosVoiceADPCM( voice, &dTime, gstASynch.ulSizePos ) ) {
|
|
case ADPCM_NOERROR:
|
|
rAnswer = M_DoubleToRealSnd( dTime ); /* Retourne un reel 16 16*/
|
|
break;
|
|
case ADPCM_ENDREACH:
|
|
rAnswer = SND_C_POS_ENDED;
|
|
break;
|
|
}
|
|
}
|
|
return rAnswer;
|
|
}
|
|
|
|
SndReal SND_fn_rGetLengthSampleADPCM(long voice)
|
|
{
|
|
SndReal rAnswer;
|
|
|
|
rAnswer = SND_C_LENGTH_UNKNOWN;
|
|
if( gbInitDone ) {
|
|
unsigned long ulLength;
|
|
|
|
if( fn_ulGetLengthVoiceADPCM( voice, & ulLength ) == ADPCM_NOERROR ) {
|
|
double dTemp;
|
|
|
|
/* La valeur à retourner est en seconde. ( SND_ADPCM_BUFFERFREQ samples font 1s )*/
|
|
dTemp = (double)ulLength / (double)SND_ADPCM_BUFFERFREQ;
|
|
rAnswer = M_DoubleToRealSnd( dTemp ); /* Retourne un reel 16 16*/
|
|
/* return ulLength << 16; // Retourne un reel 16 16*/
|
|
}
|
|
}
|
|
return rAnswer;
|
|
}
|
|
/*************************************************************************/
|
|
/* FONCTIONS INUTILES*/
|
|
void SND_fn_vSetSoundVolumeSampleADPCM(unsigned char vol)
|
|
{
|
|
}
|
|
|
|
unsigned char SND_fn_ucGetSoundVolumeSampleADPCM()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void SND_fn_vSetStereoSampleADPCM(SndBool active)
|
|
{
|
|
}
|
|
|
|
SndBool SND_fn_bGetStereoSampleADPCM(void)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
void SND_fn_vSetReverseStereoSampleADPCM(SndBool active)
|
|
{
|
|
fn_vSetReverseStereoSampleADPCM(active);
|
|
}
|
|
|
|
SndBool SND_fn_bGetReverseStereoSampleADPCM(void)
|
|
{
|
|
return fn_bGetReverseStereoSampleADPCM();
|
|
}
|
|
/* fin FONCTIONS INUTILES*/
|
|
/****************************************************************************/
|
|
int SND_fn_iInitSampleADPCM( SND_tdstInitStruct *pInitStruct )
|
|
{
|
|
unsigned long ulAnswer;
|
|
SND_tdstFormat stFormatClient;
|
|
SND_tdstCallback stCallback;
|
|
|
|
ulAnswer = C_INIT_FAILED;
|
|
if( fn_ulInitModuleADPCM( ) == ADPCM_NOERROR ) {
|
|
/*
|
|
* Client buffer for "One Shot Voices"
|
|
*/
|
|
stFormatClient.eZip = SAMPLE_PCM;
|
|
stFormatClient.uFormat.stPCM.ulNbSamples = 0;
|
|
stFormatClient.uFormat.stPCM.uwResolution = 16;
|
|
stFormatClient.uFormat.stPCM.uwNbChannels = 2;
|
|
stFormatClient.uFormat.stPCM.ulFreq = SND_ADPCM_BUFFERFREQ;
|
|
memset( & stCallback, 0, sizeof(SND_tdstCallback) );
|
|
stCallback.eType = BUFFER_SYNCHRONE;
|
|
stCallback.uCallback.CallbackASynchrone = fn_vRefreshSynchroneADPCM;
|
|
|
|
gstSynch.lBufferId = SND_fn_lCreateNewBufferExSxd( & stFormatClient, &stCallback, NULL, 0 );
|
|
if( gstSynch.lBufferId != C_PLAY_FAILED ) {
|
|
/*
|
|
* Client buffer for "Streaming Voices"
|
|
*/
|
|
stFormatClient.uFormat.stPCM.ulNbSamples = M_SIZE_ASSYNCHRONE;
|
|
stCallback.eType = BUFFER_ASYNCHRONE;
|
|
stCallback.uCallback.CallbackASynchrone = fn_vRefreshASynchroneADPCM;
|
|
stCallback.uInfo.rCallbackPeriod = 0;
|
|
|
|
gstASynch.lBufferId = SND_fn_lCreateNewBufferExSxd( & stFormatClient, &stCallback, NULL, 0 );
|
|
if( gstASynch.lBufferId != C_PLAY_FAILED ) {
|
|
SND_fn_vInitializeCriticalSection( & gstSection );/* Creation d'une section critique */
|
|
gbClientPause = FALSE;
|
|
gbInitDone = TRUE;
|
|
ulAnswer = C_INIT_OK;
|
|
}
|
|
else
|
|
SND_fn_vDeleteBufferSxd( gstSynch.lBufferId );
|
|
}
|
|
/* Client Buffer cannot be created when SoundDriver is busy -> no assert please
|
|
snd_assert( gstSynch.lBufferId != C_PLAY_FAILED );
|
|
snd_assert( gstASynch.lBufferId != C_PLAY_FAILED );
|
|
*/
|
|
}
|
|
return ulAnswer;
|
|
}
|
|
|
|
SndBool SND_fn_bTestInitSampleADPCM( void )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
void SND_fn_vDesInitSampleADPCM( void )
|
|
{
|
|
if( gbInitDone ) {
|
|
SND_fn_vDeleteBufferSxd( gstSynch.lBufferId );
|
|
SND_fn_vDeleteBufferSxd( gstASynch.lBufferId );
|
|
SND_fn_vDeleteCriticalSection( & gstSection );/* Destruction d'une section critique */
|
|
}
|
|
}
|
|
|
|
void SND_fn_vSetEffectSampleADPCM(long num)
|
|
{
|
|
}
|
|
|
|
void SND_fn_vCreateMicroSampleADPCM(MicroParam* par,long id)
|
|
{
|
|
}
|
|
|
|
void SND_fn_vSetMicroParamSampleADPCM(long sxdId,MicroParam* par)
|
|
{
|
|
}
|
|
|
|
void SND_fn_vDestroyMicroSampleADPCM(long sxdId)
|
|
{
|
|
}
|
|
|
|
/*gestion de buffers A VOIR*/
|
|
long SND_fn_lCreateNewBufferSampleADPCM(unsigned long nb_samples,unsigned short uwResolution,unsigned short uwNbChannels,unsigned long ulFreq,SampleParam* par,td_pfn_vRefreshBufferClient callback,long user_id)
|
|
{
|
|
return C_PLAY_FAILED;
|
|
}
|
|
|
|
void SND_fn_vSetParamBufferSampleADPCM(long id_buffer,SampleParam *par)
|
|
{
|
|
}
|
|
|
|
void SND_fn_vDeleteBufferSampleADPCM(long id_buffer)
|
|
{
|
|
}
|
|
|
|
void SND_fn_vPauseBufferSampleADPCM( long id_buffer )
|
|
{
|
|
if( gbInitDone ) {
|
|
if( ! gbClientPause ) {
|
|
SND_fn_vPauseBufferSxd( gstSynch.lBufferId );
|
|
SND_fn_vPauseBufferSxd( gstASynch.lBufferId );
|
|
gbClientPause = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SND_fn_vResumeBufferSampleADPCM( long id_buffer )
|
|
{
|
|
if( gbInitDone ) {
|
|
if( gbClientPause ) {
|
|
SND_fn_vResumeBufferSxd( gstSynch.lBufferId );
|
|
SND_fn_vResumeBufferSxd( gstASynch.lBufferId );
|
|
gbClientPause = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* OBSOLETE*/
|
|
void* SND_fn_pvGetPtrBufferSampleADPCM(long id_buffer)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
SndReal SND_fn_rGetPosBufferSampleADPCM(long id_buffer)
|
|
{
|
|
return SND_C_POS_UNKNOWN;
|
|
}
|
|
|
|
#if !defined(NO_ACP_SCRIPT) || defined(_DLL_COMPILATION_MODE)
|
|
/*this function must be defined in Script/Hybrid or DLL mode*/
|
|
SndBool SND_fn_bLoadResScriptSampleADPCM( tdstBlockResourceDisk *disk, tdstBlockResourceMem *mem )
|
|
{
|
|
SndBool bAnswer;
|
|
void* pvData;
|
|
char file_name[ 256 ];
|
|
|
|
bAnswer = FALSE;
|
|
if( gbInitDone ) {
|
|
|
|
if( !disk->uRes.stSample.bStream ) {
|
|
pvData = SND_fn_pvMallocSnd( disk->ulDataSize );
|
|
if( pvData ) {
|
|
/* Le "ResolveFileName" est tres important ici*/
|
|
SND_fn_vResolveFileName( disk->uRes.stSample.czFileName, file_name );
|
|
if ( !SND_fn_bLoadDataInMem( pvData, disk->ulDataSize, file_name, disk->ulDataOffset ) ) {
|
|
sprintf( gchBuffer, "Src %s\nData %s\nDisk %x", gchFileName, disk->uRes.stSample.czFileName, disk );
|
|
SND_fn_vDisplayError( E_uwSndErrorReadingFile, gchBuffer );
|
|
SND_fn_vFreeSnd( pvData );
|
|
pvData = NULL;
|
|
}
|
|
else
|
|
bAnswer = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
bAnswer = TRUE;
|
|
pvData = NULL;
|
|
}
|
|
if( bAnswer ) {
|
|
/*
|
|
* en script, chaque ressources charge ces propres data (on ne tient pas compte de eStorage)
|
|
*/
|
|
SND_fn_vConvertResDiskToMemSampleADPCM( disk, mem, pvData );
|
|
mem->eStorage=TYPE_EXTERNAL;
|
|
}
|
|
}
|
|
return bAnswer;
|
|
}
|
|
#endif
|
|
|
|
SndBool SND_fn_bLoadResBinarySampleADPCM(tdstBlockResourceDisk *disk,tdstBlockResourceMem *mem,char *pDataBloc)
|
|
{
|
|
void* pData;
|
|
char file_name[ 256 ];
|
|
|
|
if (!gbInitDone)
|
|
return FALSE;
|
|
|
|
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 pDataBloc:*/
|
|
pData=(void *)(pDataBloc +disk->ulDataOffset);
|
|
}
|
|
else
|
|
{ /* Sample is external: it must be loaded from a file:*/
|
|
pData=SND_fn_pvMallocSnd(disk->ulDataSize);
|
|
SND_fn_vResolveFileName(disk->uRes.stSample.czFileName,file_name);
|
|
if (!SND_fn_bLoadDataInMem(pData,disk->ulDataSize,file_name,disk->ulDataOffset))
|
|
{
|
|
sprintf( gchBuffer, "Src %s\nData %s\nDisk %x", gchFileName, disk->uRes.stSample.czFileName, disk );
|
|
SND_fn_vDisplayError( E_uwSndErrorReadingFile, gchBuffer );
|
|
SND_fn_vFreeSnd(pData);
|
|
pData=NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
pData=NULL; /* Sample is streaming*/
|
|
|
|
SND_fn_vConvertResDiskToMemSampleADPCM( disk, mem, pData );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#if !defined(NO_ACP_SCRIPT) || defined(_DLL_COMPILATION_MODE)
|
|
/*this function must be defined in Script/Hybrid or DLL mode*/
|
|
/*conversion d'un BlockResDisk ADPCM en BlockResMem WAV pour les non streames*/
|
|
SndBool SND_fn_bLoadResScriptAndConvertToWAVSampleADPCM( tdstBlockResourceDisk *disk, tdstBlockResourceMem *mem )
|
|
{
|
|
void *pDataWAV,*pDataADPCM;
|
|
tdstBlockResourceDisk stPseudoRes;
|
|
char file_name[ 256 ];
|
|
|
|
if (!gbInitDone)
|
|
return FALSE;
|
|
|
|
if( ! disk->uRes.stSample.bStream ) {
|
|
/*chargement de l'ADPCM*/
|
|
pDataADPCM = SND_fn_pvMallocSnd( disk->ulDataSize );
|
|
if( pDataADPCM == NULL )
|
|
return FALSE;
|
|
/* Le "ResolveFileName" est tres important ici*/
|
|
SND_fn_vResolveFileName( disk->uRes.stSample.czFileName, file_name );
|
|
if ( ! SND_fn_bLoadDataInMem( pDataADPCM, disk->ulDataSize, file_name, disk->ulDataOffset ) ) {
|
|
sprintf( gchBuffer, "Src %s\nData %s\nDisk %x", gchFileName, disk->uRes.stSample.czFileName, disk );
|
|
SND_fn_vDisplayError( E_uwSndErrorReadingFile, gchBuffer );
|
|
SND_fn_vFreeSnd( pDataADPCM );
|
|
return FALSE;
|
|
}
|
|
|
|
memcpy(&stPseudoRes,disk,sizeof(stPseudoRes));
|
|
|
|
/*conversion du BlockResDisk*/
|
|
if (!fn_bConvertBlockResDiskADPCMtoWAV(disk,pDataADPCM,&stPseudoRes))
|
|
{
|
|
sprintf( gchBuffer, "Src %s\nData %s\nDisk %x\nConvertion block res failed", gchFileName, disk->uRes.stSample.czFileName, disk );
|
|
SND_fn_vDisplayError( E_uwSndErrorReadingFile, gchBuffer );
|
|
SND_fn_vFreeSnd( pDataADPCM );
|
|
return FALSE;
|
|
}
|
|
|
|
/*malloc pour les data WAV*/
|
|
pDataWAV=SND_fn_pvMallocSnd(stPseudoRes.ulDataSize);
|
|
|
|
/*conversion des data*/
|
|
if (!fn_bConvertDataADPCMtoWAV(disk,pDataADPCM,pDataWAV))
|
|
{
|
|
sprintf( gchBuffer, "Src %s\nData %s\nDisk %x\nConvertion data failed", gchFileName, disk->uRes.stSample.czFileName, disk );
|
|
SND_fn_vDisplayError( E_uwSndErrorReadingFile, gchBuffer );
|
|
SND_fn_vFreeSnd( pDataADPCM );
|
|
SND_fn_vFreeSnd( pDataWAV );
|
|
return FALSE;
|
|
}
|
|
if (disk->eStorage==TYPE_EXTERNAL)
|
|
SND_fn_vFreeSnd( pDataADPCM );
|
|
|
|
/*generation du BlockResMem*/
|
|
SND_fn_vConvertResDiskToMemSxd( &stPseudoRes, mem, pDataWAV );
|
|
|
|
/*en script, chaque ressources charge ces propres data (on ne tient pas compte de eStorage)*/
|
|
mem->eStorage=TYPE_EXTERNAL;
|
|
|
|
return TRUE;
|
|
}
|
|
else {
|
|
/*stream sample are not converted to WAV, but played in APDMC*/
|
|
return SND_fn_bLoadResScriptSampleADPCM(disk,mem);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*conversion d'un BlockResDisk ADPCM en BlockResMem WAV pour les non streames*/
|
|
SndBool SND_fn_bLoadResBinaryAndConvertToWAVSampleADPCM(tdstBlockResourceDisk *disk,tdstBlockResourceMem *mem,char *pDataBloc)
|
|
{
|
|
void *pDataWAV,*pDataADPCM;
|
|
tdstBlockResourceDisk stPseudoRes;
|
|
char file_name[ 256 ];
|
|
|
|
if (!gbInitDone)
|
|
return FALSE;
|
|
|
|
/*
|
|
* Sample is not streaming: must be really loaded in memory
|
|
*/
|
|
if( !disk->uRes.stSample.bStream ) {
|
|
if (disk->eStorage!=TYPE_EXTERNAL)
|
|
{ /* Sample is in the bank: its position is known relatively to pDataBloc:*/
|
|
pDataADPCM=(void *)(pDataBloc +disk->ulDataOffset);
|
|
}
|
|
else
|
|
{ /* Sample is external: it must be loaded from a file:*/
|
|
pDataADPCM=SND_fn_pvMallocSnd(disk->ulDataSize);
|
|
SND_fn_vResolveFileName(disk->uRes.stSample.czFileName,file_name);
|
|
if (!SND_fn_bLoadDataInMem(pDataADPCM,disk->ulDataSize,file_name,disk->ulDataOffset))
|
|
{
|
|
sprintf( gchBuffer, "Src %s\nData %s\nDisk %x\nConvertion data failed", gchFileName, disk->uRes.stSample.czFileName, disk );
|
|
SND_fn_vDisplayError( E_uwSndErrorReadingFile, gchBuffer );
|
|
SND_fn_vFreeSnd(pDataADPCM);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
memcpy(&stPseudoRes,disk,sizeof(stPseudoRes));
|
|
/*conversion du BlockResDisk*/
|
|
if( !fn_bConvertBlockResDiskADPCMtoWAV(disk,pDataADPCM,&stPseudoRes))
|
|
{
|
|
// snd_assert( 0 );
|
|
sprintf( gchBuffer, "Src %s\nData %s\nDisk %x\nConvertion block failed", gchFileName, disk->uRes.stSample.czFileName, disk );
|
|
SND_fn_vDisplayError( E_uwSndErrorReadingFile, gchBuffer );
|
|
SND_fn_vFreeSnd( pDataADPCM );
|
|
return FALSE;
|
|
}
|
|
|
|
/*malloc pour les data WAV*/
|
|
pDataWAV=SND_fn_pvMallocSnd(stPseudoRes.ulDataSize);
|
|
|
|
/*conversion des data*/
|
|
if (!fn_bConvertDataADPCMtoWAV(disk,pDataADPCM,pDataWAV))
|
|
{
|
|
snd_assert( 0 );
|
|
SND_fn_vDisplayError( E_uwSndInvalidTypeOfResource, "Cannot convert ADPCM resource");
|
|
SND_fn_vFreeSnd( pDataADPCM );
|
|
SND_fn_vFreeSnd( pDataWAV );
|
|
return FALSE;
|
|
}
|
|
if (disk->eStorage==TYPE_EXTERNAL)
|
|
SND_fn_vFreeSnd( pDataADPCM );
|
|
|
|
/*generation du BlockResMem*/
|
|
SND_fn_vConvertResDiskToMemSxd( &stPseudoRes, mem, pDataWAV );
|
|
|
|
/*en script, chaque ressources charge ces propres data (on ne tient pas compte de eStorage)*/
|
|
mem->eStorage=TYPE_EXTERNAL;
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return SND_fn_bLoadResBinarySampleADPCM(disk,mem,pDataBloc);
|
|
}
|
|
}
|
|
|
|
void SND_fn_vUnLoadResSampleADPCM( tdstBlockResourceMem* mem )
|
|
{
|
|
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;
|
|
}
|
|
|
|
SndBool SND_fn_bIsResLoadedSampleADPCM( tdstBlockResourceMem *mem )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
/*---themes*/
|
|
long SND_fn_lPlayTransitionSampleADPCM( tduRefRes FirstRes, tduRefRes NextRes, SND_td_pfn_vSoundCallback transition_callback, long param_callback, SampleParam* par )
|
|
{
|
|
long lId = C_PLAY_FAILED;
|
|
|
|
snd_assert(FirstRes.pstPtr->uRes.stSample.eZip==SAMPLE_ADPCM);snd_assert(NextRes.pstPtr->uRes.stSample.eZip==SAMPLE_ADPCM);
|
|
|
|
if( gbInitDone ) {
|
|
SND_fn_vEnterCriticalSection( & gstSection );/* Entree en section critique*/
|
|
if( fn_ulAddVoiceADPCM( FirstRes.pstPtr
|
|
, par
|
|
, transition_callback
|
|
, param_callback
|
|
, NextRes.pstPtr
|
|
, & lId
|
|
, gstSynch.ulSizePos ) != ADPCM_NOERROR )
|
|
lId = C_PLAY_FAILED;
|
|
SND_fn_vLeaveCriticalSection( & gstSection );/* Sortie de section critique*/
|
|
}
|
|
return lId;
|
|
}
|
|
|
|
SndBool SND_fn_bSetParamTransitionSampleADPCM( long voice, SampleParam *par )
|
|
{
|
|
SndBool bRet=FALSE;
|
|
|
|
if( gbInitDone ) {
|
|
if( voice ) {
|
|
SND_fn_vEnterCriticalSection( & gstSection );
|
|
if( fn_ulSetParams( voice, par ) == ADPCM_NOERROR )
|
|
bRet=TRUE;
|
|
else
|
|
bRet=FALSE;
|
|
SND_fn_vLeaveCriticalSection( & gstSection );
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
SndBool SND_fn_bSetNextTransitionSampleADPCM( long voice, tduRefRes new_res )
|
|
{
|
|
SndBool bRet = FALSE;
|
|
|
|
if( gbInitDone ) {
|
|
SND_fn_vEnterCriticalSection( & gstSection );/* Entree en section critique*/
|
|
if( fn_ulSetNextThemeADPCM( voice, new_res.pstPtr ) == ADPCM_NOERROR )
|
|
bRet = TRUE;
|
|
SND_fn_vLeaveCriticalSection( & gstSection );/* Sortie de section critique*/
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
/* SEUL CAS OU ARRETE UNE PART EN COURS*/
|
|
SndBool SND_fn_bDoTransitionWithFadeSampleADPCM( long voice, tduRefRes new_res, SndReal rDuration )
|
|
{
|
|
SndBool bRet = FALSE;
|
|
if( gbInitDone ) {
|
|
SND_fn_vEnterCriticalSection( & gstSection );/* Entree en section critique*/
|
|
bRet = fn_bFadeThemeADPCM( voice, new_res.pstPtr, rDuration );
|
|
SND_fn_vLeaveCriticalSection( & gstSection );/* Sortie de section critique*/
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
void SND_fn_vStopTransitionSampleADPCM( long voice )
|
|
{
|
|
if( gbInitDone ) {
|
|
SND_fn_vEnterCriticalSection( & gstSection );
|
|
fn_vStopThemeADPCM( voice );
|
|
SND_fn_vLeaveCriticalSection( & gstSection );
|
|
}
|
|
}
|
|
|
|
void SND_fn_vPauseTransitionSampleADPCM( long voice )
|
|
{
|
|
if( gbInitDone ) {
|
|
SND_fn_vEnterCriticalSection( & gstSection );
|
|
fn_ulPauseVoiceADPCM( voice );
|
|
SND_fn_vLeaveCriticalSection( & gstSection );
|
|
}
|
|
}
|
|
|
|
void SND_fn_vResumeTransitionSampleADPCM( long voice )
|
|
{
|
|
if( gbInitDone ) {
|
|
SND_fn_vEnterCriticalSection( & gstSection );
|
|
fn_ulResumeVoiceADPCM( voice );
|
|
SND_fn_vLeaveCriticalSection( & gstSection );
|
|
}
|
|
}
|
|
|
|
#ifndef NO_ACP_LDBIN
|
|
SndBool SND_fn_bCanFreeDataSampleADPCM(void)
|
|
{
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
/*--relache-reprise a chaud des drives*/
|
|
void SND_fn_vReleaseDriverSampleADPCM(void)
|
|
{
|
|
}
|
|
|
|
void SND_fn_vRestoreDriverSampleADPCM(void)
|
|
{
|
|
}
|
|
|
|
void SND_fn_vGetTargetLabelSampleADPCM(char* name,int nb_char)
|
|
{
|
|
}
|
|
|
|
void SND_fn_vSetupTargetSampleADPCM()
|
|
{
|
|
}
|
|
|
|
SndBool SND_fn_bCanSetupTargetSampleADPCM()
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
void SND_fn_vSynchroSampleADPCM()
|
|
{
|
|
}
|
|
|
|
long SND_fn_lCreateNewBufferExSampleADPCM(SND_tdstFormat* pformat,SND_tdstCallback* pCallback,SoundParam* par,long user_id)
|
|
{
|
|
return C_PLAY_FAILED;
|
|
}
|
|
|
|
long SND_fn_lGetPosBufferExSampleADPCM(long id_buffer)
|
|
{
|
|
return SND_C_POS_UNKNOWN;
|
|
}
|
|
|
|
long SND_fn_lPushBufferExSampleADPCM( long id_buffer, SND_tdstStackBuffer* pStack )
|
|
{
|
|
return C_PLAY_FAILED;
|
|
}
|
|
|
|
#endif /*NO_ACP_SOUND*/
|
|
|
|
//#define M_SAVE_MIX_APM
|
|
|
|
void SND_CALL fn_vRefreshSynchroneADPCM( long lIdBuffer, unsigned long ulStart, unsigned long ulSizeByte, void* pvBuffer )
|
|
{
|
|
/* Play only memory resource */
|
|
static SndBool bRun = FALSE;
|
|
unsigned long uMixerState;
|
|
#ifdef M_SAVE_MIX_APM
|
|
HANDLE hBinFile;
|
|
DWORD dwWrite;
|
|
#endif
|
|
|
|
/* Protege reentrance*/
|
|
if( gbInitDone ) {
|
|
if( ! bRun ) {
|
|
bRun = TRUE;
|
|
SND_fn_vEnterCriticalSection( & gstSection );
|
|
gbDecompress = TRUE;
|
|
uMixerState = fn_ulMixerStereoADPCM( FALSE, ulSizeByte, (short*)pvBuffer, gstSynch.ulSizePos );
|
|
gstSynch.ulSizeLast = ulSizeByte;
|
|
gstSynch.ulSizePos += ulSizeByte;
|
|
#ifdef M_SAVE_MIX_APM
|
|
hBinFile = CreateFile( "c:\\binapm.raw", GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_ALWAYS, 0, NULL );
|
|
SetFilePointer( hBinFile, 0, NULL, FILE_END );
|
|
WriteFile( hBinFile, pvBuffer, ulSizeByte << 2, &dwWrite, NULL );
|
|
CloseHandle( hBinFile );
|
|
#endif
|
|
if( ( uMixerState == ADPCM_NOVOICELEFT ) || ( uMixerState == ADPCM_NOVOICEACTIVE ) )
|
|
memset( pvBuffer, 0, ulSizeByte << 2 );
|
|
gbDecompress = FALSE;
|
|
SND_fn_vLeaveCriticalSection( & gstSection );
|
|
bRun = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//#define M_SAVE_MIX_STRM_APM
|
|
void SND_CALL fn_vRefreshASynchroneADPCM( long lIdBuffer, unsigned long ulStart, unsigned long ulSizeByte, void* pvBuffer )
|
|
{
|
|
if( gbInitDone ) {
|
|
static SndBool bRun;
|
|
/* Play only streamed resource */
|
|
unsigned long uMixerState;
|
|
#ifdef M_SAVE_MIX_STRM_APM
|
|
HANDLE hBinFile;
|
|
DWORD dwWrite;
|
|
#endif
|
|
|
|
/*
|
|
* Protege reentrance
|
|
*/
|
|
bRun = FALSE;
|
|
if( ! bRun ) {
|
|
bRun = TRUE;
|
|
SND_fn_vEnterCriticalSection( &gstSection );
|
|
/*
|
|
* Actualize Asynchronous buffer envirronement
|
|
*/
|
|
gbDecompress = TRUE;
|
|
uMixerState = fn_ulMixerStereoADPCM( TRUE, ulSizeByte, (short*)pvBuffer, gstASynch.ulSizePos );
|
|
/*
|
|
* Store addition of all bytes refresh size
|
|
*/
|
|
gstASynch.ulSizeLast = ulSizeByte;
|
|
gstASynch.ulSizePos += ulSizeByte;
|
|
#ifdef M_SAVE_MIX_STRM_APM
|
|
hBinFile = CreateFile( "c:\\binapmstr.raw", GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_ALWAYS, 0, NULL );
|
|
SetFilePointer( hBinFile, 0, NULL, FILE_END );
|
|
WriteFile( hBinFile, pvBuffer, ulSizeByte << 2, &dwWrite, NULL );
|
|
CloseHandle( hBinFile );
|
|
#endif
|
|
if( ( uMixerState == ADPCM_NOVOICELEFT ) || ( uMixerState == ADPCM_NOVOICEACTIVE ) )
|
|
memset( pvBuffer, 0, ulSizeByte << 2 );
|
|
gbDecompress = FALSE;
|
|
SND_fn_vLeaveCriticalSection( & gstSection );
|
|
bRun = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
SndBool SND_fn_bCheckVersionResourceSampleADPCM( tdstBlockResourceDisk* disk )
|
|
{
|
|
SndBool bResult = FALSE;
|
|
void* data;
|
|
char file_name[ 256 ];
|
|
|
|
|
|
data = SND_fn_pvMallocSnd( disk->ulDataSize );
|
|
/* Le "ResolveFileName" est tres important ici*/
|
|
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, gchFileName );
|
|
SND_fn_vFreeSnd( data );
|
|
data = NULL;
|
|
}
|
|
else {
|
|
if( fn_ulResolveVersion( ( (lpSND_tdstWAVEFORMATEX)data )->ulCompressId ) == ADPCM_NOERROR )
|
|
bResult = TRUE;
|
|
SND_fn_vFreeSnd( data );
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
/*------------------------------------------------------*/
|
|
/* SND_fn_lGetNbVoiceWishedSampleADPCM: returns the maximum number of voices to be played in the same time*/
|
|
/*------------------------------------------------------*/
|
|
long SND_fn_lGetNbVoiceWishedSampleADPCM()
|
|
{
|
|
return 0x10;
|
|
}
|
|
|
|
/*!!!!!!!!!!!!!!!!!!fonctions de conversion ADPCM->WAV au chargement!!!!!!!!!!!!!!!!!!!!!!*/
|
|
|
|
/*---------------------------------------------------------*/
|
|
/* fn_bConvertBlockResDiskADPCMtoWAV: */
|
|
/* generation du BlockResDisk de la ressources WAV equivalente à une ressources ADPCM*/
|
|
/*Entrees:*/
|
|
/* pstDiskADPCM:descripteur de la ressources ADPCM (ne pas exploiter le FileName)*/
|
|
/* ptrDataADPCM:pointeur sur les data ADPMC dejà chargees*/
|
|
/* pstDiskWAV:descripteur de la ressources WAV à generer (un memcpy a dejà eu lieu)*/
|
|
/*Sortie:TRUE si OK, FALSE si echec (annulation de la conversion)*/
|
|
/*------------------------------------------------------------*/
|
|
SndBool fn_bConvertBlockResDiskADPCMtoWAV( tdstBlockResourceDisk* pstDiskADPCM, void* ptrDataADPCM, tdstBlockResourceDisk* pstDiskWAV )
|
|
{
|
|
SndBool bAnswer;
|
|
|
|
bAnswer = FALSE;
|
|
memcpy( pstDiskWAV, pstDiskADPCM, sizeof(tdstBlockResourceDisk) );
|
|
/*
|
|
* Modification de quelques champs
|
|
*/
|
|
pstDiskWAV->eType = TYPE_SAMPLE;
|
|
pstDiskWAV->eStorage = 0;
|
|
pstDiskWAV->ulDataOffset = 0;
|
|
pstDiskWAV->uRes.stSample.eZip = SAMPLE_PCM;
|
|
pstDiskWAV->uRes.stSample.czFileName[ 0 ] = 0;
|
|
pstDiskWAV->uRes.stSample.bStream = FALSE;
|
|
if( fn_ulFillSizeAndLoopADPCM( pstDiskWAV, ptrDataADPCM ) == ADPCM_NOERROR )
|
|
bAnswer = TRUE;
|
|
return bAnswer;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* fn_bConvertDataADPCMtoWAV:*/
|
|
/* generation en memoire des data WAV correspondantes à une ressource ADPCM*/
|
|
/*Entrees:*/
|
|
/* pstDiskWAV:descripteur de la ressource WAV à conevrtir*/
|
|
/* ptrDataADPCM:pointeur sur les data ADPCM dejà chargees en memoire*/
|
|
/* ptrDataWAV:pointeur cible des donnees à generer*/
|
|
/*Retour:TRUE si OK, FALSE si echec (annulation de la conversion)*/
|
|
/*------------------------------------------------------------*/
|
|
SndBool fn_bConvertDataADPCMtoWAV( tdstBlockResourceDisk* pstDiskADPCM, void* ptrDataADPCM, void* ptrDataWAV )
|
|
{
|
|
SndBool bAnswer;
|
|
|
|
bAnswer = FALSE;
|
|
if( fn_ulConvertDataADPCM( ptrDataADPCM, ptrDataWAV ) == ADPCM_NOERROR )
|
|
bAnswer = TRUE;
|
|
return bAnswer;
|
|
}
|
|
|
|
SndBool SND_fn_bSetResourceStaticVolumeSampleADPCM(tdstBlockResourceMem* pstRes,unsigned char ucVolume)
|
|
{
|
|
int i;
|
|
|
|
pstRes->ucVolume=ucVolume;
|
|
|
|
for (i=0;i<NB_MAX_ADPCM_VOICE;i++)
|
|
if (gstVoice[i].uRefRes.pstPtr!=NULL)
|
|
if (gstVoice[i].uRefRes.pstPtr==pstRes)
|
|
gstVoice[i].ulStaticVolume=ucVolume;
|
|
|
|
for (i=0;i<NB_MAX_ADPCM_THEME;i++)
|
|
if (gstTheme[i].uRefRes.pstPtr!=NULL)
|
|
if (gstTheme[i].uRefRes.pstPtr==pstRes)
|
|
gstTheme[i].ulStaticVolume=ucVolume;
|
|
|
|
if (gstVoiceFade.uRefRes.pstPtr!=NULL)
|
|
if (gstVoiceFade.uRefRes.pstPtr==pstRes)
|
|
gstVoiceFade.ulStaticVolume=ucVolume;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#endif
|
|
/*
|
|
* DISABLE_ADPCM
|
|
*/ |