Files
FC1/CrySoundSystem/SoundSystem.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

2003 lines
53 KiB
C++

//////////////////////////////////////////////////////////////////////
//
// Crytek (C) 2001
//
// CrySound Source Code
//
// File: SoundSystem.cpp
// Description: ISoundSystem interface implementation.
//
// History:
// -June 06,2001:Implemented by Marco Corbetta
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#ifndef _XBOX
#include <ISystem.h>
#include <CrySizer.h>
#include <algorithm>
#include <IConsole.h>
#include <ITimer.h>
#include <Cry_Math.h>
#include <Cry_Camera.h>
#include <IRenderer.h>
#include "SoundSystem.h"
#include "MusicSystem.h"
#include "Sound.h"
#include <I3dEngine.h> //needed to check if the listener is in indoor or outdoor
#include <ICryPak.h> //needed to check if the listener is in indoor or outdoor
//#define CS_BUFFERSIZE 10 /* millisecond value for FMOD buffersize. */
#ifdef WIN64
//#define CS_SAFEBORDER 16
#endif
//////////////////////////////////////////////////////////////////////////
void* _DSPUnit_SFXFilter_Callback(void *pOriginalBuffer, void *pNewBuffer, int nLength, INT_PTR nParam)
{
if (!nParam)
return pNewBuffer;
CSoundSystem *pOwner=(CSoundSystem*)nParam;
return pOwner->DSPUnit_SFXFilter_Callback(pOriginalBuffer, pNewBuffer, nLength);
}
extern "C"
{
#if CS_SAFEBORDER
enum {g_cFillConst = 0xCE};
void CheckSafeBorder (char* p)
{
for (unsigned i = 0; i < CS_SAFEBORDER; ++i)
if (p[i] != (char)(g_cFillConst+i))
__debugbreak();
}
void FillSafeBofder (char* p)
{
for (unsigned i = 0; i < CS_SAFEBORDER; ++i)
p[i] = (char)(g_cFillConst+i);
}
#endif
static void * F_CALLBACKAPI CrySound_Alloc (unsigned int size)
{
#if CS_SAFEBORDER
unsigned* pN = (unsigned*)malloc (size + 2 * CS_SAFEBORDER + sizeof(unsigned));
*pN = size;
char* p = (char*)(pN+1);
FillSafeBofder(p);
FillSafeBofder(p + size + CS_SAFEBORDER);
return p + CS_SAFEBORDER;
#else
return malloc (size);
#endif
}
static void F_CALLBACKAPI CrySound_Free (void* ptr)
{
#if CS_SAFEBORDER
char* pOld = ((char*)ptr) - CS_SAFEBORDER;
unsigned* pNOld = ((unsigned*)pOld) - 1;
CheckSafeBorder(pOld);
CheckSafeBorder(pOld + *pNOld + CS_SAFEBORDER);
free (pNOld);
#else
free (ptr);
#endif
}
static void * F_CALLBACKAPI CrySound_Realloc (void *ptr, unsigned int size)
{
#if CS_SAFEBORDER
char* pOld = ((char*)ptr) - CS_SAFEBORDER;
unsigned* pNOld = ((unsigned*)pOld) - 1;
char* pRet = (char*)CrySound_Alloc(size);
memcpy (pRet, ptr, min(*pNOld,size));
CrySound_Free (ptr);
return pRet;
#else
return realloc (ptr, size);
#endif
}
}
//////////////////////////////////////////////////////////////////////////
// File callbacks for fmod.
//////////////////////////////////////////////////////////////////////////
#ifdef CS_VERSION_372
static void * F_CALLBACKAPI CrySound_fopen( const char *name )
{
// File is opened for streaming.
FILE *file = GetISystem()->GetIPak()->FOpen( name,"rb",ICryPak::FOPEN_HINT_DIRECT_OPERATION );
//FILE *file = GetISystem()->GetIPak()->FOpen( name,"rb" );
if (!file)
{
GetISystem()->Warning( VALIDATOR_MODULE_SOUNDSYSTEM,VALIDATOR_WARNING,VALIDATOR_FLAG_SOUND,"Sound %s failed to load", name );
}
return (void *)file;
}
static void F_CALLBACKAPI CrySound_fclose( void * nFile )
{
FILE *file = (FILE*)nFile;
GetISystem()->GetIPak()->FClose( file );
}
static int F_CALLBACKAPI CrySound_fread( void *buffer, int size, void * nFile )
{
FILE *file = (FILE*)nFile;
return GetISystem()->GetIPak()->FRead( buffer,1,size,file );
}
static int F_CALLBACKAPI CrySound_fseek( void * nFile, int pos, signed char mode)
{
FILE *file = (FILE*)nFile;
return GetISystem()->GetIPak()->FSeek( file,pos,mode );
}
static int F_CALLBACKAPI CrySound_ftell( void * nFile )
{
FILE *file = (FILE*)nFile;
return GetISystem()->GetIPak()->FTell( file );
}
#else
#ifdef CS_VERSION_361
static unsigned int F_CALLBACKAPI CrySound_fopen( const char *name )
{
// File is opened for streaming.
FILE *file = GetISystem()->GetIPak()->FOpen( name,"rb",ICryPak::FOPEN_HINT_DIRECT_OPERATION );
//FILE *file = GetISystem()->GetIPak()->FOpen( name,"rb" );
if (!file)
{
GetISystem()->Warning( VALIDATOR_MODULE_SOUNDSYSTEM,VALIDATOR_WARNING,VALIDATOR_FLAG_SOUND,"Sound %s failed to load", name );
}
return (unsigned int)file;
}
static void F_CALLBACKAPI CrySound_fclose( unsigned int nFile )
{
FILE *file = (FILE*)nFile;
GetISystem()->GetIPak()->FClose( file );
}
static int F_CALLBACKAPI CrySound_fread( void *buffer, int size, unsigned int nFile )
{
FILE *file = (FILE*)nFile;
return GetISystem()->GetIPak()->FRead( buffer,1,size,file );
}
static int F_CALLBACKAPI CrySound_fseek( unsigned int nFile, int pos, signed char mode)
{
FILE *file = (FILE*)nFile;
return GetISystem()->GetIPak()->FSeek( file,pos,mode );
}
static int F_CALLBACKAPI CrySound_ftell( unsigned int nFile )
{
FILE *file = (FILE*)nFile;
return GetISystem()->GetIPak()->FTell( file );
}
#else
static UINT_PTR F_CALLBACKAPI CrySound_fopen( const char *name )
{
// File is opened for streaming.
FILE *file = GetISystem()->GetIPak()->FOpen( name,"rb",ICryPak::FOPEN_HINT_DIRECT_OPERATION );
//FILE *file = GetISystem()->GetIPak()->FOpen( name,"rb" );
if (!file)
{
GetISystem()->Warning( VALIDATOR_MODULE_SOUNDSYSTEM,VALIDATOR_WARNING,VALIDATOR_FLAG_SOUND,"Sound %s failed to load", name );
}
return (UINT_PTR)file;
}
static void F_CALLBACKAPI CrySound_fclose( UINT_PTR nFile )
{
FILE *file = (FILE*)nFile;
GetISystem()->GetIPak()->FClose( file );
}
static int F_CALLBACKAPI CrySound_fread( void *buffer, int size, UINT_PTR nFile )
{
FILE *file = (FILE*)nFile;
return GetISystem()->GetIPak()->FRead( buffer,1,size,file );
}
static int F_CALLBACKAPI CrySound_fseek( UINT_PTR nFile, int pos, signed char mode)
{
FILE *file = (FILE*)nFile;
return GetISystem()->GetIPak()->FSeek( file,pos,mode );
}
static int F_CALLBACKAPI CrySound_ftell( UINT_PTR nFile )
{
FILE *file = (FILE*)nFile;
return GetISystem()->GetIPak()->FTell( file );
}
#endif
#endif
//////////////////////////////////////////////////////////////////////
CSoundSystem::CSoundSystem(ISystem* pSystem, HWND hWnd) : CSoundSystemCommon(pSystem)
{
GUARD_HEAP;
m_bOK=m_bInside=false;
if (!pSystem)
return;
m_fSFXVolume=1.0f;
m_fMusicVolume=1.0f;
m_pVisArea=NULL;
m_nSpeakerConfig=-1; //force to set
m_bPause=false;
m_pISystem = pSystem;
m_pILog=pSystem->GetILog();
m_pTimer=pSystem->GetITimer();
m_pStreamEngine=pSystem->GetStreamEngine();
m_itLastInactivePos=m_lstSoundSpotsInactive.end();
m_nInactiveSoundSpotsSize=0;
m_nBuffersLoaded=0;
m_nMinSoundPriority = 0;
m_pDSPUnitSFXFilter=NULL;
m_fDirAttCone=0.0f;
for (int i=0;i<MAX_SOUNDSCALE_GROUPS;i++) m_fSoundScale[i]=1.0f;
memset(m_VisAreas,0,MAX_VIS_AREAS*sizeof(int));
m_nMuteRefCnt=0;
m_nSampleRate=m_pCVarSampleRate->GetIVal();
//if (!m_pCVARSoundEnable->GetIVal())
// return;
if (m_pCVARDummySound->GetIVal())
return; // creates dummy sound system
if (CS_GetVersion() != CS_VERSION)
{
m_pILog->Log("Music:Init:Incorrect DLL version for CRYSOUND: Need %.2f\n",CS_VERSION);
return;
}
#if !defined(_DEBUG)// || defined(WIN64)
CS_SetMemorySystem(NULL,NULL,CrySound_Alloc,CrySound_Realloc,CrySound_Free);
#endif
m_pILog->Log("------------------------------------------CRYSOUND VERSION=%f\n",CS_GetVersion());
//configure CS's stability under windows
//CS_SetBufferSize(CS_BUFFERSIZE);
//init CS
//CS_SetOutput(CS_OUTPUT_DSOUND);
//CS_SetDriver(0);
//CS_SetMixer(CS_MIXER_QUALITY_AUTODETECT);
#if 0//defined(WIN64) || defined(CS_VERSION_3_63)
//CS_DSP_SetActive(CS_DSP_GetClearUnit(), FALSE);
//CS_DSP_SetActive(CS_DSP_GetSFXUnit(), FALSE);
//CS_DSP_SetActive(CS_DSP_GetMusicUnit(), FALSE);
//CS_DSP_SetActive(CS_DSP_GetClipAndCopyUnit(), FALSE);
CS_SetOutput(CS_OUTPUT_WINMM);
CS_SetMaxHardwareChannels(0);
#else
// Defines the minimum number of hardware channels.
// if less than that, the sound engine will switch to software mixing.
CS_SetMinHardwareChannels(m_pCVarMinHWChannels->GetIVal());
CS_SetMaxHardwareChannels(m_pCVarMaxHWChannels->GetIVal());
#endif
CS_SetHWND(hWnd);
// Assign file access callbacks to fmod to our pak file system.
CS_File_SetCallbacks( CrySound_fopen,CrySound_fclose,CrySound_fread,CrySound_fseek,CrySound_ftell );
for (int i=0; i < CS_GetNumDrivers(); i++)
{
m_pILog->Log("%d - %s\n", i+1, CS_GetDriverName(i)); // print driver names
if (m_pCVarCapsCheck->GetIVal()>0) //caps checking is slow
{
unsigned int caps =0;
CS_GetDriverCaps(i,&caps);
if (caps & CS_CAPS_HARDWARE)
m_pILog->Log(" Driver supports hardware 3D sound");
if (caps & CS_CAPS_EAX2)
m_pILog->Log(" Driver supports EAX 2.0 reverb");
if (caps & CS_CAPS_EAX3)
m_pILog->Log(" Driver supports EAX 3.0 reverb");
//if (caps & CS_CAPS_GEOMETRY_OCCLUSIONS)
// m_pILog->Log(" Driver supports hardware 3d geometry processing with occlusions");
//if (caps & CS_CAPS_GEOMETRY_REFLECTIONS)
// m_pILog->Log(" Driver supports hardware 3d geometry processing with reflections");
//if (caps & CS_CAPS_EAX2)
// m_pILog->Log(" Driver supports EAX 2.0 reverb!");
}
}
//CS_SetMixer(CS_MIXER_QUALITY_FPU);
if (m_pCVarCompatibleMode->GetIVal()!=0)
{
CS_SetBufferSize(200);
}
if (!CS_Init(m_nSampleRate, 256, 0))
{
m_pILog->Log("Cannot init CRYSOUND\n");
CS_Close();
return;
}
//CS_3D_SetRolloffFactor(0.0);
m_pILog->Log("CRYSOUND Driver: %s", CS_GetDriverName(CS_GetDriver()));
m_pILog->Log("Total number of channels available: %d\n",CS_GetMaxChannels());
// WARNING!!! Wat
//m_pILog->Log("Total number of hardware channels available: %d\n",CS_GetNumHardwareChannels());
SetSpeakerConfig();
// lets create a dsp unit for the sfx-filter
//m_pDSPUnitSFXFilter=CS_DSP_Create(_DSPUnit_SFXFilter_Callback, SFXFILTER_PRIORITY, (INT_PTR)this);
if (m_pDSPUnitSFXFilter)
{
m_fDSPUnitSFXFilterCutoff=500.0f;
m_fDSPUnitSFXFilterResonance=0.5f;
m_fDSPUnitSFXFilterLowLVal=0.0f;
m_fDSPUnitSFXFilterBandLVal=0.0f;
m_fDSPUnitSFXFilterLowRVal=0.0f;
m_fDSPUnitSFXFilterBandRVal=0.0f;
//CS_DSP_SetActive(m_pDSPUnitSFXFilter, TRUE);
}
Mute(false);
m_bOK = true;
m_bValidPos=false;
m_nLastEax=EAX_PRESET_OFF;
m_EAXIndoor.nPreset=EAX_PRESET_OFF;
m_EAXOutdoor.nPreset=EAX_PRESET_OFF;
strcpy(m_szEmptyName,"NONAME");
m_bResetVolume=false;
m_fSFXResetVolume=1.0f;
m_pLastEAXProps=NULL;
}
//////////////////////////////////////////////////////////////////////////
void* CSoundSystem::DSPUnit_SFXFilter_Callback(void *pOriginalBuffer, void *pNewBuffer, int nLength)
{
GUARD_HEAP;
// originalbuffer = crysounds original mixbuffer.
// newbuffer = the buffer passed from the previous DSP unit.
// length = length in samples at this mix time.
// param = user parameter passed through in CS_DSP_Create.
//
// modify the buffer in some fashion
int nMixer=CS_GetMixer();
if (nMixer!=CS_MIXER_QUALITY_FPU)
return pNewBuffer;
float f, q, h;
f=2.0f*(float)sin(3.1415962*m_fDSPUnitSFXFilterCutoff/(float)CS_GetOutputRate());
q=m_fDSPUnitSFXFilterResonance;
float fInput;
nLength<<=1;
for (int i=0;i<nLength;)
{
// left channel
fInput=((float*)pNewBuffer)[i];
m_fDSPUnitSFXFilterLowLVal+=f*m_fDSPUnitSFXFilterBandLVal;
h=fInput-m_fDSPUnitSFXFilterLowLVal-(m_fDSPUnitSFXFilterBandLVal*q);
m_fDSPUnitSFXFilterBandLVal+=f*h;
// writing output
((float*)pNewBuffer)[i]=m_fDSPUnitSFXFilterLowLVal;
// right channel
i++;
fInput=((float*)pNewBuffer)[i];
m_fDSPUnitSFXFilterLowRVal+=f*m_fDSPUnitSFXFilterBandRVal;
h=fInput-m_fDSPUnitSFXFilterLowRVal-(m_fDSPUnitSFXFilterBandRVal*q);
m_fDSPUnitSFXFilterBandRVal+=f*h;
// writing output
((float*)pNewBuffer)[i]=m_fDSPUnitSFXFilterLowRVal;
i++;
}
return pNewBuffer;
}
//////////////////////////////////////////////////////////////////////
void CSoundSystem::SetSpeakerConfig()
{
GUARD_HEAP;
int nCurrSpeakerConfig=m_pCVarSpeakerConfig->GetIVal();
if (nCurrSpeakerConfig!=m_nSpeakerConfig)
{
switch (nCurrSpeakerConfig)
{
case CSSPEAKERCONFIG_5POINT1:
CS_SetSpeakerMode(CS_SPEAKERMODE_DOLBYDIGITAL);
m_pILog->Log("Set speaker mode 5.1\n");
break;
case CSSPEAKERCONFIG_HEADPHONE:
CS_SetSpeakerMode(CS_SPEAKERMODE_HEADPHONES);
m_pILog->Log("Set speaker mode head phone\n");
break;
case CSSPEAKERCONFIG_MONO:
CS_SetSpeakerMode(CS_SPEAKERMODE_MONO);
m_pILog->Log("Set speaker mode mono\n");
break;
case CSSPEAKERCONFIG_QUAD:
CS_SetSpeakerMode(CS_SPEAKERMODE_QUAD);
m_pILog->Log("Set speaker mode quad\n");
break;
case CSSPEAKERCONFIG_STEREO:
CS_SetSpeakerMode(CS_SPEAKERMODE_STEREO);
m_pILog->Log("Set speaker mode stereo\n");
break;
case CSSPEAKERCONFIG_SURROUND:
m_pILog->Log("Set speaker mode surround\n");
CS_SetSpeakerMode(CS_SPEAKERMODE_SURROUND);
break;
}
m_nSpeakerConfig=nCurrSpeakerConfig;
//Set the pan scalar to full pan separation 'cos cs_setspeakermode will reset it.
CS_SetPanSeperation(1.0f);
}
}
//////////////////////////////////////////////////////////////////////
void CSoundSystem::Reset()
{
GUARD_HEAP;
Silence();
// for the sake of clarity...
m_vecSounds.clear();
m_lstSoundSpotsActive.clear();
m_lstSoundSpotsInactive.clear();m_nInactiveSoundSpotsSize=0;
//m_nLastInactiveListPos=0;
m_itLastInactivePos=m_lstSoundSpotsInactive.end();
m_lstFadeUnderwaterSounds.clear();
m_autoStopSounds.clear();
m_stoppedSoundToBeDeleted.clear();
}
//////////////////////////////////////////////////////////////////////
CSoundSystem::~CSoundSystem()
{
GUARD_HEAP;
Reset();
if (m_pDSPUnitSFXFilter)
CS_DSP_Free(m_pDSPUnitSFXFilter);
m_pDSPUnitSFXFilter=NULL;
if (m_bOK)
CS_Close();
m_bOK = false;
SetEaxListenerEnvironment(EAX_PRESET_OFF);
}
//////////////////////////////////////////////////////////////////////
void CSoundSystem::Release()
{
delete this;
}
//////////////////////////////////////////////////////////////////////////
void CSoundSystem::DeactivateSound( CSound *pSound )
{
if (pSound->m_bPlaying)
pSound->Stop();
if (pSound->m_State == eSoundState_Active)
{
m_lstSoundSpotsActive.erase(pSound);
pSound->m_State = eSoundState_Inactive;
m_lstSoundSpotsInactive.insert(pSound);
}
}
//////////////////////////////////////////////////////////////////////////
bool CSoundSystem::ProcessActiveSound( CSound *cs )
{
FUNCTION_PROFILER( GetSystem(),PROFILE_SOUND );
bool bFadeoutFinished = false;
bool bIsSoundPotentiallyHearable = IsSoundPH(cs);
if (!bIsSoundPotentiallyHearable)
{
// decrease it as the player is leaving the room or moving from outdoor to indoor or viceversa.
bFadeoutFinished = cs->FadeOut();
}
float fRatio = 1.0f;
if (cs->m_nFlags & FLAG_SOUND_RADIUS)
{
float fDist2=GetSquaredDistance(cs->m_RealPos,m_vPos);
if (fDist2 > cs->m_fMaxRadius2)
{
// Too far.
return false;
}
if (bFadeoutFinished)
{
return false;
}
if (fDist2 > cs->m_fMinRadius2)
{
//calc attenuation, cal sound ratio between min & max radius
if (!(cs->m_nFlags & FLAG_SOUND_NO_SW_ATTENUATION))
{
fRatio=1.0f-((fDist2-cs->m_fMinRadius2)/cs->m_fMaxRadius2);
}
else
fRatio=1.0f;
}
}
if (bIsSoundPotentiallyHearable)
{
// check if the sound became hearable because of sound occlusion
cs->FadeIn();
}
// if Steve doesnt want to change frequency and pan, this can be replaced just with set volume
cs->SetAttrib(cs->m_nMaxVolume,fRatio*cs->m_fCurrentFade*cs->m_fRatio,cs->m_nPan,1000,false);
return true;
}
//////////////////////////////////////////////////////////////////////
void CSoundSystem::Update()
{
GUARD_HEAP;
FUNCTION_PROFILER( GetSystem(),PROFILE_SOUND );
// check if volume has changed
if (Ffabs(m_pCVarMusicVolume->GetFVal()-m_fMusicVolume)>0.2f)
{
if (m_pCVarMusicVolume->GetFVal()<0)
m_pCVarMusicVolume->Set(0.0f);
m_fMusicVolume=m_pCVarMusicVolume->GetFVal();
}
if (m_pCVarSFXVolume->GetFVal()<0)
m_pCVarSFXVolume->Set(0.0f);
if (m_pCVarSFXVolume->GetFVal()>1.0f)
m_pCVarSFXVolume->Set(1.0f);
if ((Ffabs(m_pCVarSFXVolume->GetFVal()-m_fSFXVolume)>0.2f))
{
m_fSFXVolume=m_pCVarSFXVolume->GetFVal();
// call set volume for each sound so it can rescale itself
for (SoundListItor It=m_vecSounds.begin();It!=m_vecSounds.end();It++)
{
CSound *cs=(*It);
if (cs->m_nFlags & FLAG_SOUND_MUSIC)
continue;
cs->SetVolume(cs->GetVolume());
} // It
}
if (m_pISystem && m_pCVarSoundInfo->GetIVal())
{
IRenderer *pRenderer=m_pISystem->GetIRenderer();
if (pRenderer)
{
int nChannels = CSound::m_PlayingChannels;
float x = 40;
float fColor[4]={1.0f, 1.0f, 1.0f, 0.7f};
float fColorRed[4]={1.0f, 0.0f, 0.0f, 0.7f};
float fColorYellow[4]={1.0f, 1.0f, 0.0f, 0.7f};
float fColorGreen[4]={0.0f, 1.0f, 0.0f, 0.7f};
pRenderer->Draw2dLabel(x, 1, 1, fColor, false, "SoundSystem[Debug]");
pRenderer->Draw2dLabel(x, 10, 1, fColor, false, " Current Voices: %d (Channels: %d), CPU-Mixing-Overhead: %3.1f", GetUsedVoices(),nChannels, GetCPUUsage());
pRenderer->Draw2dLabel(x, 20, 1, fColor, false, " Loaded SoundBuffers: %d (%d)", m_nBuffersLoaded,m_soundBuffers.size());
pRenderer->Draw2dLabel(x, 30, 1, fColor, false, " SoundSpots-Active: %d, Inactive: %d", (int)m_lstSoundSpotsActive.size(), (int)m_lstSoundSpotsInactive.size());
if (!m_bValidPos)
{
pRenderer->Draw2dLabel(x, 40, 1, fColor, false, "Listener invalid!");
}
else
{
if (m_bInside)
pRenderer->Draw2dLabel(x, 40, 1, fColor, false, "Listener INSIDE: Vis area=: %s",m_pVisArea->GetName());
else
pRenderer->Draw2dLabel(x, 40, 1, fColor, false, "Listener OUTSIDE ");
}
float ypos=50;
if (m_pCVarSoundInfo->GetIVal()==1)
{
for (SoundListItor It=m_lstSoundSpotsActive.begin();It!=m_lstSoundSpotsActive.end();It++)
{
CSound *cs=(*It);
if (cs->IsPlayingOnChannel())
pRenderer->Draw2dLabel(1, ypos, 1, fColorRed, false, "<Playing>");
else if (cs->IsUsingChannel())
pRenderer->Draw2dLabel(1, ypos, 1, fColorYellow, false, "[%d]",cs->m_nChannel );
float *pCurColor = fColor;
if (!cs->m_bLoop)
pCurColor = fColorGreen;
if (cs->m_nFlags & FLAG_SOUND_3D)
pRenderer->Draw2dLabel(x, ypos, 1, pCurColor, false, "%s,3d,pos=%d,%d,%d,minR=%d,maxR=%d,vol=%d",cs->GetName(),(int)(cs->m_position.x),(int)(cs->m_position.y),(int)(cs->m_position.z),(int)(cs->m_fMinDist),(int)(cs->m_fMaxDist),cs->m_nPlayingVolume );
else
pRenderer->Draw2dLabel(x, ypos, 1, pCurColor, false, "%s,2d,volume=%d",cs->GetName(),cs->m_nPlayingVolume );
ypos+=10;
} //it
}
else
{
for (SoundBufferPropsMapItor It=m_soundBuffers.begin();It!=m_soundBuffers.end();It++)
{
CSoundBuffer *pBuf=It->second;
if (pBuf->GetSample())
{
pRenderer->Draw2dLabel(x, ypos, 1, fColor, false, "%s",pBuf->GetName());
ypos+=10;
}
} //it
}
// All playing sounds...
{
ypos = 10;
x = 400;
pRenderer->Draw2dLabel(x, ypos, 1, fColor, false, "----- Playing Sounds -----" );
ypos += 10;
for (SoundListItor It=m_vecSounds.begin();It!=m_vecSounds.end();It++)
{
CSound *cs=(*It);
if (!cs->IsUsingChannel())
continue;
float *pCurColor = fColorYellow;
if (cs->IsPlayingOnChannel())
pCurColor = fColorRed;
if (cs->m_nFlags & FLAG_SOUND_3D)
pRenderer->Draw2dLabel(x, ypos, 1, pCurColor, false, "%s,3d,pos=%d,%d,%d,minR=%d,maxR=%d,vol=%d,channel=%d",cs->GetName(),(int)(cs->m_position.x),(int)(cs->m_position.y),(int)(cs->m_position.z),(int)(cs->m_fMinDist),(int)(cs->m_fMaxDist),cs->m_nPlayingVolume,cs->m_nChannel );
else
pRenderer->Draw2dLabel(x, ypos, 1, pCurColor, false, "%s,2d,volume=%d,channel=%d",cs->GetName(),cs->m_nPlayingVolume,cs->m_nChannel );
ypos+=10;
} //it
}
}
}
Vec3_tpl<float> vPos=m_cCam.GetPos();
if (GetLengthSquared(vPos)<1)
{
m_bValidPos=false;
return; // hasnt been set yet, but the update3d function has been called
}
m_bValidPos=true;
if (m_pCVARSoundEnable->GetIVal()==0)
{
Silence();
return;
}
SetSpeakerConfig();
bool bWasInside=m_bInside;
m_bInside=false;
RecomputeSoundOcclusion(true,false);
m_bInside=(m_pVisArea!=NULL);
/*
if (bWasInside!=m_bInside)
{
if (m_bInside)
SetEaxListenerEnvironment(m_EAXIndoor.nPreset, (m_EAXIndoor.nPreset==-1) ? &m_EAXIndoor.EAX : NULL, FLAG_SOUND_INDOOR);
else
SetEaxListenerEnvironment(m_EAXOutdoor.nPreset, (m_EAXOutdoor.nPreset==-1) ? &m_EAXOutdoor.EAX : NULL, FLAG_SOUND_OUTDOOR);
}
*/
// check if sr has changed
if (m_pCVarSampleRate->GetFVal()!=m_nSampleRate)
{
m_nSampleRate=(int)m_pCVarSampleRate->GetFVal();
}
std::pair< SoundListItor, bool > pr;
int nActiveSize=m_lstSoundSpotsActive.size();
if ((nActiveSize<m_pCVarMaxSoundSpots->GetIVal()) && (!m_lstSoundSpotsInactive.empty()))
{
FRAME_PROFILER( "CSoundSystem::Update:Inactive",GetSystem(),PROFILE_SOUND );
// iterate through a couple of inactive sounds to see if they became active...
//int nInactiveSoundSpots=(int)m_vecSoundSpotsInactive.size();
//if (m_nLastInactiveListPos>=nInactiveSoundSpots)
//m_nLastInactiveListPos=0;
if (m_itLastInactivePos==m_lstSoundSpotsInactive.end())
m_itLastInactivePos=m_lstSoundSpotsInactive.begin();
// lets choose the iteration-count, so it iterates through all sounds every m_pCVarInactiveSoundIterationTimeout seconds
int nInactiveSoundItCount=(int)cry_ceilf((m_pTimer->GetFrameTime()/m_pCVarInactiveSoundIterationTimeout->GetFVal())*(float)m_nInactiveSoundSpotsSize);
if (!nInactiveSoundItCount)
nInactiveSoundItCount=1;
if (nInactiveSoundItCount>m_nInactiveSoundSpotsSize)
nInactiveSoundItCount=m_nInactiveSoundSpotsSize;
/*
if (m_pISystem && m_pCVarSoundInfo->GetIVal())
{
float fColor[4]={1.0f, 1.0f, 1.0f, 1.0f};
IRenderer *pRenderer=m_pISystem->GetIRenderer();
if (pRenderer)
pRenderer->Draw2dLabel(10, 110, 1, fColor, false, " SoundSpots-InActive size: %d, iter count=%d ", m_nInactiveSoundSpotsSize,nInactiveSoundItCount);
}
*/
SoundListItor It=m_itLastInactivePos; //m_vecSoundSpotsInactive.begin()+m_nLastInactiveListPos;
int nSoundSpotAdded=0;
for (int i=0;i<nInactiveSoundItCount;i++)
{
CSound *cs=(*It);
if (cs->m_bPlaying)
{
float fDist2=GetSquaredDistance(cs->m_RealPos,m_vPos);
if (fDist2<=cs->m_fPreloadRadius2)
{
//////////////////////////////////////////////////////////////////////////
// are we getting too many soundspots?
if ((nActiveSize+nSoundSpotAdded)>m_pCVarMaxSoundSpots->GetIVal())
{
break; // resume next frame
}
//////////////////////////////////////////////////////////////////////////
// move sound to active list...
//m_vecSoundSpotsActive.push_back(cs);
m_lstSoundSpotsActive.insert(cs);
nSoundSpotAdded++;
It=m_lstSoundSpotsInactive.erase(It);m_nInactiveSoundSpotsSize--;
m_itLastInactivePos=It;
cs->m_State=eSoundState_Active;
cs->Preload();
}
else
{
++It;
//m_nLastInactiveListPos++;
++m_itLastInactivePos;
}
}
else
{
++It;
//m_nLastInactiveListPos++;
++m_itLastInactivePos;
}
if (It==m_lstSoundSpotsInactive.end())
{
It=m_lstSoundSpotsInactive.begin();
//m_nLastInactiveListPos=0;
m_itLastInactivePos=It;
}
} //i
}
float fCurrTime = m_pTimer->GetCurrTime();
// process the sound spheres for fading and occlusion
//for (SoundVecItor It=m_vecSoundSpotsActive.begin();It!=m_vecSoundSpotsActive.end();)
SoundListItor It,nextIt;
for (It=m_lstSoundSpotsActive.begin();It!=m_lstSoundSpotsActive.end();)
{
FRAME_PROFILER( "CSoundSystem::Update:Active",GetSystem(),PROFILE_SOUND );
nextIt = It; nextIt++;
CSound *cs=(*It);
if (cs->m_pSound->LoadFailure())
{
cs->m_State=eSoundState_None;
It = m_lstSoundSpotsActive.erase(It);
continue;
}
// make sure that one-shot samples reset its playing flag when they exceed their play-time and are clipped...
if ((!cs->m_bPlaying) || (cs->IsUsingChannel() && !cs->m_bLoop && !cs->IsPlayingOnChannel()) || cs->IsPlayLengthExpired(fCurrTime))
{
FRAME_PROFILER( "CSoundSystem::Update:Active-Deactivate",GetSystem(),PROFILE_SOUND );
//++It;
// move sound to inactive list...
//m_vecSoundSpotsInactive.push_back(cs);
pr=m_lstSoundSpotsInactive.insert(cs);
m_itLastInactivePos=pr.first;
m_nInactiveSoundSpotsSize++;
cs->m_State=eSoundState_Inactive;
It=m_lstSoundSpotsActive.erase(It);
if (cs->m_bPlaying)
{
// Stop can release sound for autostop onces.
cs->Stop();
}
continue;
}
// check if the sound became occluded
bool bZeroFadeCheckDist=false;
bool bIsSoundPotentiallyHearable = IsSoundPH(cs);
if (!bIsSoundPotentiallyHearable)
{
FRAME_PROFILER( "CSoundSystem::Update:Active-FadeOut",GetSystem(),PROFILE_SOUND );
// decrease it as the player is leaving the room
// or moving from outdoor to indoor or viceversa
bZeroFadeCheckDist=cs->FadeOut();
/*{
++It;
continue;
}*/
}
//const char *szTest=cs->GetName(); //debug
float fRatio=1.0f;
if (cs->m_nFlags & FLAG_SOUND_RADIUS)
{
float fDist2=GetSquaredDistance(cs->m_RealPos,m_vPos);
if (fDist2>cs->m_fMaxRadius2)
{
cs->FreeChannel();
// do not change the fading here because
// there is a different reason why we stopped this sound
if (fDist2>cs->m_fPreloadRadius2)
{
// move sound to inactive list...
//m_vecSoundSpotsInactive.push_back(cs);
pr=m_lstSoundSpotsInactive.insert(cs);
m_itLastInactivePos=pr.first;
m_nInactiveSoundSpotsSize++;
It=m_lstSoundSpotsActive.erase(It);
cs->m_State=eSoundState_Inactive;
}
else
{
++It;
}
continue; //too far
}
if (bZeroFadeCheckDist)
{
++It;
continue; // the sound is faded out to 0, we just do this check here because it might also be too far away in which case it will be moved to the inactive list again...
}
if (fDist2>cs->m_fMinRadius2)
{
//calc attenuation
//calculate sound ratio between min & max radius
if (cs->m_nFlags & FLAG_SOUND_NO_SW_ATTENUATION)
{
//fRatio=0.5f-((fDist2-cs->m_fMinRadius2)/cs->m_fMaxRadius2);//cs->m_fMaxSoundDistance2);
//if (fRatio<0)
//fRatio=0;
fRatio=1.0f;
//m_pILog->LogToConsole("fratio=%f",fRatio);
}
else
fRatio=1.0f-((fDist2-cs->m_fMinRadius2)/cs->m_fMaxRadius2);//cs->m_fMaxSoundDistance2);
//else
}
}
if (bIsSoundPotentiallyHearable)
{
// check if the sound became hearable because of sound occlusion
cs->FadeIn();
}
if (!cs->IsPlayingOnChannel() && cs->IsPlayingVirtual()) //loop check
{
cs->Play(fRatio*cs->m_fCurrentFade, false, false);
}
{
FRAME_PROFILER( "CSoundSystem::Update:Active-SetAttrib",GetSystem(),PROFILE_SOUND );
// if Steve doesnt want to change frequency and pan, this
// can be replaced just with set volume
cs->SetAttrib(cs->m_nMaxVolume,fRatio*cs->m_fCurrentFade*cs->m_fRatio,cs->m_nPan,1000,false);
}
++It;
}
//////////////////////////////////////////////////////////////////////////
// Stop expired auto stop sounds.
//////////////////////////////////////////////////////////////////////////
if (!m_autoStopSounds.empty())
{
AutoStopSounds::iterator it,next;
for (it = m_autoStopSounds.begin(); it != m_autoStopSounds.end(); it = next)
{
next = it; next++;
CSound *pSound = *it;
if (pSound->IsPlayingOnChannel())
{
bool bContinueSound = ProcessActiveSound(pSound);
if (!bContinueSound || pSound->IsPlayLengthExpired(fCurrTime))
{
UnregisterAutoStopSound( pSound );
pSound->m_bAutoStop = false;
pSound->Stop();
continue;
}
}
else if (pSound->IsUsingChannel())
{
UnregisterAutoStopSound( pSound );
pSound->m_bAutoStop = false;
pSound->Stop();
}
}
}
/////////////////////////////////////////////////////////////////////////
if (m_nLastEax!=EAX_PRESET_UNDERWATER)
{
// if not underwater, check if we now went to outside
if (bWasInside!=m_bInside)
{
if (!m_bInside)
{
// if outside,set the global EAX outdoor environment
SetEaxListenerEnvironment(m_EAXOutdoor.nPreset, (m_EAXOutdoor.nPreset==-1) ? &m_EAXOutdoor.EAX : NULL);
}
}
}
/*
if (m_nLastEax==EAX_PRESET_UNDERWATER)
{
for (It=m_lstFadeUnderwaterSounds.begin();It!=m_lstFadeUnderwaterSounds.end();)
{
CSound *cs=(*It);
SoundListItor ItNext=It;ItNext++;
if (!cs->IsPlayingOnChannel() || cs->FadeOut())
{
// in case the sound has been removed already by calling stop from
// script
It=m_lstFadeUnderwaterSounds.find(cs);
if (It!=m_lstFadeUnderwaterSounds.end())
m_lstFadeUnderwaterSounds.erase(It);
It=ItNext;
continue;
}
cs->SetAttrib(cs->m_nVolume,cs->m_fCurrentFade);
It=ItNext;
} //it
}
*/
// Here actually delete all auto stop sounds.
m_stoppedSoundToBeDeleted.resize(0);
{
FRAME_PROFILER( "CSoundSystem::CS_Update",GetSystem(),PROFILE_SOUND );
CS_Update();
}
}
//////////////////////////////////////////////////////////////////////////
bool CSoundSystem::IsSoundPH(CSound *pSound)
{
GUARD_HEAP;
// check if indoor only or outdoor only
if (pSound->m_nFlags & FLAG_SOUND_OUTDOOR)
{
return (!m_bInside); // fade out or fade in
}
if (pSound->m_nFlags & FLAG_SOUND_INDOOR)
{
return(m_bInside); // fade out or fade in
}
// at this point check if should use sound occlusion at all
if (!(pSound->m_nFlags & FLAG_SOUND_OCCLUSION))
return (true); // always hearable, no occlusion - proceed with fade in
if (!m_pVisArea)
{
// if the listener is not inside a vis area but the sound is,
// then the sound is not hearable
if (pSound->m_pArea)
return (false); // fade out
return (true); // both listener and sound in outdoor - fade in
}
// if the listener is inside a vis area but the sound is not,
// then the sound is not hearable
if (!pSound->m_pArea)
return (false); // fade out
// now check that the area where the sound is in, isn't occluded by doors,
// objects or buildings
int numToCheck = m_pCVarVisAreaProp->GetIVal();
for (int k=0; k < numToCheck; k++)
{
IVisArea *pArea=m_VisAreas[k];
if (!pArea)
break;
if (pArea==pSound->m_pArea)
return (true); // both listener and sound in indoor, and in a not-occluded area - fade in
} //k
return (false); //fade out
}
//////////////////////////////////////////////////////////////////////////
IMusicSystem* CSoundSystem::CreateMusicSystem()
{
CMusicSystem *pMusicSystem=new CMusicSystem(m_pISystem);
return pMusicSystem;
}
//////////////////////////////////////////////////////////////////////////
void CSoundSystem::AddToSoundSystem(CSound *pSound,int dwFlags)
{
GUARD_HEAP;
pSound->m_nFlags=dwFlags;
bool bLoop;
if (dwFlags & FLAG_SOUND_LOOP)
{
pSound->SetLoopMode(true);
bLoop = true;
}
else
{
bLoop = false;
pSound->SetLoopMode(false);
}
if (dwFlags & FLAG_SOUND_UNSCALABLE)
{
pSound->RemoveFromScaleGroup(SOUNDSCALE_SCALEABLE);
pSound->RemoveFromScaleGroup(SOUNDSCALE_MISSIONHINT);
}
//m_vecSounds.push_back(pSound);
m_vecSounds.insert(pSound);
std::pair<SoundListItor,bool> pr;
// check if the sound has a radius, and add it to a separate list
// to speed up the checks, occlusions and sound system update
//if (dwFlags & (FLAG_SOUND_RADIUS | FLAG_SOUND_OCCLUSION | FLAG_SOUND_INDOOR | FLAG_SOUND_OUTDOOR))
if (dwFlags & (FLAG_SOUND_ACTIVELIST) && bLoop)
{
if (m_bValidPos && (dwFlags & FLAG_SOUND_RADIUS))
{
float fDist2=GetSquaredDistance(pSound->m_RealPos, m_vPos);
if (fDist2>pSound->m_fPreloadRadius2)
{
//m_vecSoundSpotsInactive.push_back(pSound); // move sound to inactive list...
pr=m_lstSoundSpotsInactive.insert(pSound);
m_itLastInactivePos=pr.first;
m_nInactiveSoundSpotsSize++;
pSound->m_State=eSoundState_Inactive;
}
}
if (pSound->m_State!=eSoundState_Inactive)
{
//m_vecSoundSpotsActive.push_back(pSound); // move sound to active list...
m_lstSoundSpotsActive.insert(pSound);
pSound->m_State=eSoundState_Active;
}
}
}
//////////////////////////////////////////////////////////////////////////
void CSoundSystem::RegisterAutoStopSound( CSound *pSound )
{
m_autoStopSounds.insert( pSound );
}
//////////////////////////////////////////////////////////////////////////
void CSoundSystem::UnregisterAutoStopSound( CSound *pSound )
{
m_stoppedSoundToBeDeleted.push_back( pSound );
m_autoStopSounds.erase( pSound );
}
//////////////////////////////////////////////////////////////////////////
void CSoundSystem::SetSoundActiveState(CSound *pSound, ESoundActiveState State) // take care from where you call this function, because it may cause crashes if you change the state while the system is iterating through the lists (Update())
{
GUARD_HEAP;
if (pSound->m_State==State)
return;
switch (pSound->m_State)
{
case eSoundState_Active:
{
//SoundVecItor It=std::find(m_vecSoundSpotsActive.begin(), m_vecSoundSpotsActive.end(), pSound);
SoundListItor It=m_lstSoundSpotsActive.find(pSound);
ASSERT(It!=m_lstSoundSpotsActive.end());
m_lstSoundSpotsActive.erase(It);
break;
}
case eSoundState_Inactive:
{
//SoundVecItor It=std::find(m_vecSoundSpotsInactive.begin(), m_vecSoundSpotsInactive.end(), pSound);
SoundListItor It=m_lstSoundSpotsInactive.find(pSound);
ASSERT(It!=m_lstSoundSpotsInactive.end());
m_itLastInactivePos=m_lstSoundSpotsInactive.erase(It);
m_nInactiveSoundSpotsSize--;
break;
}
}
pSound->m_State=State;
switch (pSound->m_State)
{
case eSoundState_Active:
{
//m_vecSoundSpotsActive.push_back(pSound);
m_lstSoundSpotsActive.insert(pSound);
break;
}
case eSoundState_Inactive:
{
//m_vecSoundSpotsInactive.push_back(pSound);
std::pair<SoundListItor,bool> pr;
pr=m_lstSoundSpotsInactive.insert(pSound);
m_itLastInactivePos=pr.first;
m_nInactiveSoundSpotsSize++;
break;
}
}
}
//////////////////////////////////////////////////////////////////////
ISound* CSoundSystem::LoadSound(const char *szFile, int flags)
{
GUARD_HEAP;
FUNCTION_PROFILER( GetSystem(),PROFILE_SOUND );
CSound* pSound = NULL;
if (!szFile || (!szFile[0]))
return (NULL);
//if (!strlen(szFile))
// return (NULL);
if (flags & FLAG_SOUND_3D) // make all 3d sounds use the sw-attenuation
flags|=FLAG_SOUND_RADIUS;
CSoundBuffer *pSB;
SSoundBufferProps name=SSoundBufferProps(szFile, flags);
SoundBufferPropsMapItor nit = m_soundBuffers.find(name);
if ((!(flags & FLAG_SOUND_STREAM)) && (nit!=m_soundBuffers.end())) // we cannot share streams !
{
//sound is already present
pSB= nit->second;
if (flags & FLAG_SOUND_3D)
{
if (pSB->GetProps().nFlags & FLAG_SOUND_2D)
{
m_pILog->Log("\001 [ERROR] trying to load the same sound buffer file as 2d and 3d sound (%s)",szFile);
return (NULL);
}
}
else
if (flags & FLAG_SOUND_2D)
{
if (pSB->GetProps().nFlags & FLAG_SOUND_3D)
{
m_pILog->Log("\001 [ERROR] trying to load the same sound buffer file as 2d and 3d sound (%s)",szFile);
return (NULL);
}
}
//create a new instance
pSound=new CSound(this,szFile);
pSound->m_pSound=pSB;
AddToSoundSystem(pSound,flags);
return (pSound);
}
// check if this is an ogg...to avoid people calling
// loadsound and decompressing the entire ogg into memory (several megabytes)
// but if the load sync is specified, load the sound anyway doesnt matter what
if (!(flags & FLAG_SOUND_LOAD_SYNCHRONOUSLY))
{
size_t len = strlen(szFile)-1;
const char *szExt=NULL;
while (len)
{
if (szFile[len]=='.')
{
szExt=&szFile[len];
break;
}
len--;
}
if (szExt && (stricmp(szExt,".ogg")==0) && (!(flags & FLAG_SOUND_STREAM)))
{
m_pILog->Log("\001 WARNING - THE FILE %s is a streaming sound but there is an attempt to decompress it into memory-it will not be loaded",szFile);
return (NULL);
}
}
//create a new instance and a new sound buffer
pSound=new CSound(this,szFile);
//m_pILog->LogToFile("sound %s loaded, sound size=%d",szFile,m_setSounds.size());
//create a new sound buffer
pSB=new CSoundBuffer(this, name);
pSound->m_pSound=pSB;
pSound->SetAttrib(255,1.0f,pSound->m_nPan);
m_soundBuffers[name] = pSB;
nit = m_soundBuffers.find(name);
if (nit==m_soundBuffers.end())
{
int t=0;
}
AddToSoundSystem(pSound,flags);
return (pSound);
}
//////////////////////////////////////////////////////////////////////////
void CSoundSystem::RecomputeSoundOcclusion(bool bRecomputeListener,bool bForceRecompute,bool bReset)
{
GUARD_HEAP;
if (bReset)
{
m_pVisArea=NULL;
return;
}
if (m_nMuteRefCnt>0)
return; // don't do this during mute (usually during loading)
FUNCTION_PROFILER( GetSystem(),PROFILE_SOUND );
I3DEngine *p3dEngine=m_pISystem->GetI3DEngine();
if (p3dEngine)
{
//check where the listener is
IVisArea *pCurrArea=NULL;
if (bRecomputeListener)
{
Vec3_tpl<float> vPos=m_cCam.GetPos();
pCurrArea=p3dEngine->GetVisAreaFromPos(vPos);
}
else
pCurrArea=m_pVisArea;
// avoid silly people to mess around with too many visareas
int nMaxVis=(m_pCVarVisAreaProp->GetIVal() & (MAX_VIS_AREAS-1));
if ((pCurrArea!=m_pVisArea) || (bForceRecompute))
{
// listener has changed sector or has moved from indoor to outdoor or viceversa
m_pVisArea=pCurrArea;
memset(m_VisAreas,0,sizeof(m_VisAreas));
if (m_pVisArea)
{
// if inside let's get a list of visible areas to use for sound occlusion
int nAreas=m_pVisArea->GetVisAreaConnections(m_VisAreas,nMaxVis,true);
// engine doesn't return the current area - be sure to add it or
// all the sounds currently playing in the listener area will fade out
if (nAreas<nMaxVis)
m_VisAreas[nAreas]=m_pVisArea;
else
// override the first one - this one is more important
m_VisAreas[0]=m_pVisArea;
}
}
}
}
//////////////////////////////////////////////////////////////////////
void CSoundSystem::RemoveReference(CSound *cs)
{
GUARD_HEAP;
if (m_vecSounds.empty())
return;
SoundListItor It;
//It=std::find(m_vecSounds.begin(), m_vecSounds.end(), cs);
It=m_vecSounds.find(cs);
//if (It==m_vecSounds.end()) // double release
// return;
ASSERT(It!=m_vecSounds.end());
m_vecSounds.erase(It);
switch (cs->m_State)
{
case eSoundState_Active:
{
//It=std::find(m_vecSoundSpotsActive.begin(), m_vecSoundSpotsActive.end(), cs);
It=m_lstSoundSpotsActive.find(cs);
if (It!=m_lstSoundSpotsActive.end())
m_lstSoundSpotsActive.erase(It);
break;
}
case eSoundState_Inactive:
{
//It=std::find(m_vecSoundSpotsInactive.begin(), m_vecSoundSpotsInactive.end(), cs);
It=m_lstSoundSpotsInactive.find(cs);
if (It!=m_lstSoundSpotsInactive.end())
{
//if (((It-m_SoundSpotsInactive.begin())>=m_nLastInactiveListPos) && (m_nLastInactiveListPos>0))
// m_nLastInactiveListPos--;
m_itLastInactivePos=m_lstSoundSpotsInactive.erase(It);
m_nInactiveSoundSpotsSize--;
}
break;
}
}
cs->m_State=eSoundState_None;
It=m_lstFadeUnderwaterSounds.find(cs);
if (It!=m_lstFadeUnderwaterSounds.end())
m_lstFadeUnderwaterSounds.erase(It);
}
//////////////////////////////////////////////////////////////////////
ISound* CSoundSystem::GetSound(int soundId)
{
return (NULL);
}
//////////////////////////////////////////////////////////////////////
void CSoundSystem::PlaySound(int soundId)
{
GUARD_HEAP;
CSound *sound = (CSound *)GetSound(soundId);
if (sound)
sound->Play();
}
//////////////////////////////////////////////////////////////////////
void CSoundSystem::SetListener(const CCamera &cCam,const Vec3d &vVel)
{
GUARD_HEAP;
FUNCTION_PROFILER( GetSystem(),PROFILE_SOUND );
m_cCam=cCam;
Vec3d vPos=m_cCam.GetPos();
if (GetLengthSquared(vPos)<1)
return; // hasnt been set yet, but the update3d function has been called
Vec3d vAngles=m_cCam.GetAngles();
//position,left handed
float pos[3];
pos[0]=vPos.x;
pos[1]=vPos.z;
pos[2]=vPos.y;
//listener orientation
Vec3d FVec1=vAngles;
//flip up/down
Vec3d TVec1=FVec1;
TVec1.x+=270;
if (TVec1.x>360)
TVec1.x-=360;
//calculate forward and top vector
FVec1=ConvertToRadAngles(FVec1);
TVec1=ConvertToRadAngles(TVec1);
//already normalized after conversion to radians
FVec1.Normalize();
TVec1.Normalize();
if (m_pCVarDopplerEnable->GetIVal())
{
Vec3d vTempVel=(vPos-m_vPos);
float fTimeDelta=m_pISystem->GetITimer()->GetFrameTime();
vTempVel=vTempVel*(m_pCVarDopplerValue->GetFVal()/fTimeDelta);
float fVel[3];
fVel[0]=vTempVel.x;
fVel[1]=vTempVel.z;
fVel[2]=vTempVel.y;
//CS_3D_Listener_SetAttributes(pos, NULL, 0, 0, 1.0f, 0, 1.0f, 0);
CS_3D_Listener_SetAttributes(pos, fVel,FVec1.x,FVec1.z,FVec1.y,TVec1.x,TVec1.z,TVec1.y);
}
else
{
CS_3D_Listener_SetAttributes(pos, NULL,FVec1.x,FVec1.z,FVec1.y,TVec1.x,TVec1.z,TVec1.y);
};
m_vPos=vPos;
m_vForward=FVec1;
m_vTop=TVec1;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
void CSoundSystem::Silence()
{
GUARD_HEAP;
SetEaxListenerEnvironment(EAX_PRESET_OFF);
// reset last listener vis area - just to be 100% sure we dont use an invalid vis area
RecomputeSoundOcclusion(false,false,true);
m_bValidPos=false;
// reset sound-scaling
for (int i=0;i<MAX_SOUNDSCALE_GROUPS;i++)
{
m_fSoundScale[i]=1.0f;
}
CS_StopSound(CS_FREE);
//if (m_vecSounds.empty())
// return;
SoundListItor It=m_vecSounds.begin();
while(It!=m_vecSounds.end())
{
CSound *pSound=*It;
pSound->FreeChannel();
//if (pSound->m_nFlags & FLAG_SOUND_ACTIVELIST)
//SetSoundActiveState(pSound,eSoundState_Inactive);
++It;
}
//Update();
}
//////////////////////////////////////////////////////////////////////////
void CSoundSystem::Pause(bool bPause,bool bResetVolume)
{
m_bPause=bPause;
SoundListItor It=m_vecSounds.begin();
while (It!=m_vecSounds.end())
{
CSound *pSound=*It;
if (pSound->m_nChannel>=0)
{
if (bPause)
CS_SetPaused(pSound->m_nChannel,1);
else
{
pSound->m_fChannelPlayTime=GetISystem()->GetITimer()->GetCurrTime();
CS_SetPaused(pSound->m_nChannel,0);
}
}
++It;
} //It
if (bResetVolume)
{
// this is needed for instance when going back to menu
// after setting the sound volume to 0. The sound volume
// calculation takes the general volume into account,
// so if it was set to 0, when going to menu the sliders
// and buttons won't produce any sound, because the sound system
// is not updated anymore so it doesn't have a chance to
// update the general volume. Hence we reset the volume to 1,
// and the individual volume of sound and music sliders is set
// by the menu scripts calling setvolume
//m_fSFXResetVolume=m_pCVarSFXVolume->GetFVal();
//m_pCVarSFXVolume->Set(1.0f);
m_bResetVolume=true;
m_fSFXVolume=1.0f; //m_pCVarSFXVolume->GetFVal();
}
if (!bPause && m_bResetVolume)
{
// restore normal volume back
//m_pCVarSFXVolume->Set(m_fSFXResetVolume);
m_bResetVolume=false;
m_fSFXVolume=m_pCVarSFXVolume->GetFVal();
//SetGroupScale(SOUNDSCALE_MISSIONHINT,m_fSFXVolume*0.65f);
}
}
//////////////////////////////////////////////////////////////////////////
void CSoundSystem::Mute(bool bMute)
{
GUARD_HEAP;
if (bMute)
m_nMuteRefCnt++;
else
m_nMuteRefCnt--;
if (m_nMuteRefCnt<0)
m_nMuteRefCnt=0;
bool bSetMute=m_nMuteRefCnt!=0;
CS_SetSFXMasterVolume(bSetMute ? 0 : 255);
// CS_SetMute(CS_ALL, bSetMute);
}
//////////////////////////////////////////////////////////////////////
bool CSoundSystem::IsEAX(int version)
{
return (true);
}
//////////////////////////////////////////////////////////////////////////
bool CSoundSystem::GetCurrentEaxEnvironment(int &nPreset, CS_REVERB_PROPERTIES &Props)
{
nPreset=m_nLastEax;
if (m_pLastEAXProps)
memcpy(&Props,m_pLastEAXProps,sizeof(CS_REVERB_PROPERTIES));
else
memset(&Props,0,sizeof(CS_REVERB_PROPERTIES));
return (true);
}
//////////////////////////////////////////////////////////////////////
bool CSoundSystem::SetEaxListenerEnvironment(int nPreset, CS_REVERB_PROPERTIES *tpProps, int nFlags)
{
GUARD_HEAP;
FUNCTION_PROFILER( GetSystem(),PROFILE_SOUND );
if (!m_pCVarEnableSoundFX->GetIVal())
{
return (false);
}
if (nFlags==FLAG_SOUND_OUTDOOR)
{
m_EAXOutdoor.nPreset=nPreset;
m_EAXOutdoor.EAX=*tpProps;
m_pILog->Log("Setting global EAX outdoor");
if (m_bInside)
return (false); // set only when outside
}
//if (!nFlags)
// nFlags=FLAG_SOUND_INDOOR | FLAG_SOUND_OUTDOOR;
/*
bool bIndoor=(m_pVisArea!=NULL);
bool bIndoor=false;
I3DEngine *p3dEngine=m_pISystem->GetI3DEngine();
if (p3dEngine)
bIndoor=p3dEngine->GetVisAreaFromPos(m_cCam.GetPos())!=NULL;
*/
bool bSet=false;
/*
if (nFlags & FLAG_SOUND_INDOOR)
{
if (tpProps)
{
m_EAXIndoor.nPreset=-1;
m_EAXIndoor.EAX=*tpProps;
}else
{
m_EAXIndoor.nPreset=nPreset;
}
if (m_bInside)
bSet=true;
}
if (nFlags & FLAG_SOUND_OUTDOOR)
{
if (tpProps)
{
m_EAXOutdoor.nPreset=-1;
m_EAXOutdoor.EAX=*tpProps;
}else
{
m_EAXOutdoor.nPreset=nPreset;
}
if (!m_bInside)
bSet=true;
}
if (!bSet)
return true;
*/
if (tpProps)
{
CS_Reverb_SetProperties(tpProps);
m_nLastEax=-1;
m_pLastEAXProps=tpProps;
}
else
{
if (m_nLastEax==nPreset)
return (true); // already set
switch (nPreset)
{
case EAX_PRESET_GENERIC:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_GENERIC;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_PADDEDCELL:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_PADDEDCELL;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_ROOM:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_ROOM;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_BATHROOM:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_BATHROOM;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_LIVINGROOM:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_LIVINGROOM;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_STONEROOM:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_STONEROOM;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_AUDITORIUM:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_AUDITORIUM;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_CONCERTHALL:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_CONCERTHALL;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_CAVE:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_CAVE;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_ARENA:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_ARENA;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_HANGAR:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_HANGAR;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_CARPETTEDHALLWAY:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_CARPETTEDHALLWAY;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_HALLWAY:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_HALLWAY;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_STONECORRIDOR:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_STONECORRIDOR;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_ALLEY:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_ALLEY;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_FOREST:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_FOREST;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_CITY:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_CITY;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_MOUNTAINS:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_MOUNTAINS;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_QUARRY:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_QUARRY;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_PLAIN:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_PLAIN;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_PARKINGLOT:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_PARKINGLOT;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_SEWERPIPE:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_SEWERPIPE;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_UNDERWATER:
{
CS_REVERB_PROPERTIES pProps=CS_PRESET_UNDERWATER;
CS_Reverb_SetProperties(&pProps);
break;
}
case EAX_PRESET_OFF:
default:
{
CS_REVERB_PROPERTIES pProps=MY_CS_PRESET_OFF;
CS_Reverb_SetProperties(&pProps);
break;
}
}
m_nLastEax=nPreset;
m_pLastEAXProps=NULL; // using one of pre-defined presets
}
return (true);
}
//////////////////////////////////////////////////////////////////////////
bool CSoundSystem::SetGroupScale(int nGroup, float fScale)
{
GUARD_HEAP;
if ((nGroup<0) || (nGroup>=MAX_SOUNDSCALE_GROUPS))
return false;
if (fabs(m_fSoundScale[nGroup]-fScale)<0.001f)
return true;
m_fSoundScale[nGroup]=fScale;
//change volume of all looping/playing sounds
//m_pILog->LogToConsole("scaling group for %s",cs->GetName());
for (SoundListItor It=m_vecSounds.begin();It!=m_vecSounds.end();++It)
{
CSound *cs=(*It);
if (cs->IsPlayingOnChannel())
{
int nVolume=cs->CalcSoundVolume(cs->m_nVolume,cs->m_fRatio);
cs->ChangeVolume(nVolume);
}
} //It
return true;
}
//////////////////////////////////////////////////////////////////////
void CSoundSystem::SetMasterVolumeScale(float fScale, bool bForceRecalc)
{
GUARD_HEAP;
if ((!bForceRecalc) && ((fabs(fScale-m_fSoundScale[0]))<0.01f))
return;
SetGroupScale(0, fScale);
}
//////////////////////////////////////////////////////////////////////
void CSoundSystem::RemoveBuffer(SSoundBufferProps &sn)
{
GUARD_HEAP;
SoundBufferPropsMapItor itor=m_soundBuffers.find(sn);
if(itor!=m_soundBuffers.end())
{
m_pILog->LogToFile("Removing sound [%s]",itor->first.sName.c_str());
m_soundBuffers.erase(itor);
}
else
{
m_pILog->LogToFile("Warning Trying to remove sound [%s] NOT FOUND!!!",sn.sName.c_str());
}
}
//////////////////////////////////////////////////////////////////////
void CSoundSystem::GetSoundMemoryUsageInfo(size_t &nCurrentMemory,size_t &nMaxMemory)
{
GUARD_HEAP;
#if (defined CS_VERSION_372) || (defined CS_VERSION_361)
unsigned int tmpnCurrentMemory = nCurrentMemory;
unsigned int tmpnMaxMemory = nMaxMemory;
CS_GetMemoryStats(&tmpnCurrentMemory,&tmpnMaxMemory);
nCurrentMemory = tmpnCurrentMemory;
nMaxMemory = tmpnMaxMemory;
#else
CS_GetMemoryStats(&nCurrentMemory,&nMaxMemory);
#endif
}
//////////////////////////////////////////////////////////////////////////
int CSoundSystem::GetUsedVoices()
{
GUARD_HEAP;
return CS_GetChannelsPlaying();
}
/////////////////////////////////// ///////////////////////////////////////
float CSoundSystem::GetCPUUsage()
{
GUARD_HEAP;
return CS_GetCPUUsage();
}
//////////////////////////////////////////////////////////////////////////
float CSoundSystem::GetMusicVolume()
{
return (m_fMusicVolume*m_fSoundScale[SOUNDSCALE_MISSIONHINT]*m_fSoundScale[SOUNDSCALE_DEAFNESS]);
}
//////////////////////////////////////////////////////////////////////////
void CSoundSystem::CalcDirectionalAttenuation(Vec3d &Pos, Vec3d &Dir, float fConeInRadians)
{
GUARD_HEAP;
float fCosCone=(float)cry_cosf(fConeInRadians);
if (IsEquivalent(Pos, m_DirAttPos, VEC_EPSILON) &&
IsEquivalent(Dir, m_DirAttDir, VEC_EPSILON) &&
(fCosCone==m_fDirAttCone))
return;
m_DirAttPos=Pos;
m_DirAttDir=Dir;
m_fDirAttCone=fCosCone;
m_fDirAttMaxScale=0.0f;
//update position of all looping/playing sounds
for (SoundListItor It=m_vecSounds.begin();It!=m_vecSounds.end();++It)
{
CSound *cs=(*It);
if (cs->m_bPlaying || cs->IsPlayingVirtual())
cs->UpdatePosition();
}
}
//////////////////////////////////////////////////////////////////////////
void CSoundSystem::GetMemoryUsage(class ICrySizer* pSizer)
{
GUARD_HEAP;
size_t nSize = sizeof(*this);
//if (!pSizer->AddObject(this, sizeof(*this)+nCurrentAlloced))
// return;
for (SoundListItor SoundIt=m_vecSounds.begin();SoundIt!=m_vecSounds.end();++SoundIt)
{
CSound *pSound=(*SoundIt);
pSound->GetMemoryUsage(pSizer);
}
for (SoundBufferPropsMap::iterator it = m_soundBuffers.begin(); it != m_soundBuffers.end(); ++it)
nSize += sizeof (*it) + sizeof(it->first) + it->first.sName.size() + 1;
pSizer->AddObject(this, nSize);
{
SIZER_COMPONENT_NAME(pSizer, "FMOD");
size_t nCurrentAlloced;
size_t nMaxAlloced;
#if (defined CS_VERSION_372) || (defined CS_VERSION_361)
unsigned int tmpnCurrentMemory;
unsigned int tmpnMaxMemory;
CS_GetMemoryStats(&tmpnCurrentMemory,&tmpnMaxMemory);
nCurrentAlloced = tmpnCurrentMemory;
nMaxAlloced = tmpnMaxMemory;
#else
CS_GetMemoryStats(&nCurrentAlloced, &nMaxAlloced);
#endif
//CS_GetMemoryStats(&nCurrentAlloced, &nMaxAlloced);
if (!pSizer->AddObject(&CS_Init, nCurrentAlloced))
return;
}
}
//////////////////////////////////////////////////////////////////////////
int CSoundSystem::SetMinSoundPriority( int nPriority )
{
int nPrev = m_nMinSoundPriority;
m_nMinSoundPriority = nPriority;
return nPrev;
}
//////////////////////////////////////////////////////////////////////////
void CSoundSystem::LockResources()
{
for (SoundBufferPropsMapItor It=m_soundBuffers.begin();It!=m_soundBuffers.end();It++)
{
CSoundBuffer *pBuf = It->second;
m_lockedResources.push_back( pBuf );
}
}
//////////////////////////////////////////////////////////////////////////
void CSoundSystem::UnlockResources()
{
m_lockedResources.clear();
}
//////////////////////////////////////////////////////////////////////////
bool CSoundSystem::IsEnabled()
{
return m_pCVARSoundEnable->GetIVal() != 0;
}
#endif
extern "C"
{
void CheckMem(void* pData, size_t nSize)
{
assert (0 == IsBadReadPtr(pData, nSize));
}
}