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

1259 lines
32 KiB
C++

//////////////////////////////////////////////////////////////////////
//
// Crytek (C) 2001
//
// CrySound Source Code
//
// File: Sound.cpp
// Description: ISound interface implementation.
//
// History:
// -June 06,2001:Implemented by Marco Corbetta
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#ifndef _XBOX
#include "Sound.h"
#include <CrySizer.h>
#include <Cry_Camera.h>
#include "SoundSystem.h"
#include <ICOnsole.h>
#include <ISystem.h>
#include <ITimer.h>
#include <I3dEngine.h> //needed to check if the listener is in indoor or outdoor
#pragma warning(disable:4003) // warning C4003: not enough actual parameters for macro 'CHECK_LOADED'
#define CRYSOUND_MAXDIST 10000.0f
//////////////////////////////////////////////////////////////////////////
#define CHECK_LOADED(_func, _retval) if (!m_pSound->Loaded()) { TRACE("%s(%d) Warning: %s called without a sound (%s) being fully loaded !", __FILE__, __LINE__, #_func, GetName()); return _retval; }
int CSound::m_PlayingChannels = 0;
//////////////////////////////////////////////////////////////////////
CSound::CSound(CSoundSystem *pSSys,const char *szFile)
{
ASSERT(pSSys);
ASSERT(pSSys->m_pISystem);
m_pSSys = pSSys;
m_pTimer=pSSys->m_pISystem->GetITimer();
// m_refCount = 0;
//SetName( "Sound not loaded" );
// m_nId = soundId;
m_nChannel=0;
m_bPlaying=false;
m_position(0,0,0);
m_speed(0,0,0);
m_orient(0,0,0);
m_State=eSoundState_None;
m_fLastPlayTime=0.0f;
m_nChannel=CS_FREE;
m_nSoundScaleGroups=SETSCALEBIT(SOUNDSCALE_MASTER) | SETSCALEBIT(SOUNDSCALE_SCALEABLE) | SETSCALEBIT(SOUNDSCALE_DEAFNESS) | SETSCALEBIT(SOUNDSCALE_MISSIONHINT);
m_nStartOffset=0;
m_nVolume=-1;
m_nPlayingVolume=-1;
m_nPan=127;
m_fPitching=-1;
m_nCurrPitch=0;
//m_nBaseFreq=44100;
m_nRelativeFreq=1000;
m_nFxChannel=-1;
m_bLoop=false;
m_fRatio=1.0f;
//m_nLastId=0;
//m_nFadeType=0;
m_fMaxRadius2=m_fMinRadius2=m_fDiffRadius2=0;
m_fPreloadRadius2=0;
m_nMaxVolume=255;
m_fMinDist=m_fMaxDist=1;
m_fSoundLengthSec = 0;
// m_fMaxSoundDistance2=500*500;
m_refCount=0;
m_pArea=NULL;
m_fFadingValue=1.0f; ///5.0f; // by default
//m_fCurrentFade=1.0f;
m_fCurrentFade=1.0f;
m_nSoundPriority=0;
m_bPlayAfterLoad=false;
m_fPostLoadRatio=0;
m_bPostLoadForceActiveState=false;
m_bPostLoadSetRatio=false;
m_bAutoStop = false;
m_bAlreadyLoaded = false;
SetAttrib(255, 1.0f, 127);
//Timur: Never addref on creation.
//AddRef();
//SetName(szFile);
}
//////////////////////////////////////////////////////////////////////
CSound::~CSound()
{
if (m_pSound)
m_pSound->RemoveFromLoadReqList(this);
//stop the sound
if (m_nChannel>=0)
Stop();
if (m_pSSys->m_pCVarDebugSound->GetIVal()==1)
{
m_pSSys->m_pILog->Log("<Sound> Destroying sound %s \n",GetName());
}
m_pSSys->RemoveReference(this);
}
//////////////////////////////////////////////////////////////////////
int CSound::Release()
{
//reset the reference
int ref=0;
if((ref=--m_refCount)<=0)
{
#if defined(WIN64)// && defined(_DEBUG)
// Win64 has a special variable to disable deleting all the sounds
ICVar* pVar = m_pSSys->GetSystem()->GetIConsole()->GetCVar("s_EnableRelease");
if (!pVar || pVar->GetIVal())
#endif
delete this;
}
return (ref);
};
//load the sound for real
//////////////////////////////////////////////////////////////////////
bool CSound::Preload()
{
if (!m_pSSys->IsEnabled())
{
OnEvent( SOUND_EVENT_ON_LOADED );
return true;
}
return m_pSound->Load(m_bLoop, this);
}
//////////////////////////////////////////////////////////////////////////
void CSound::SetSoundPriority(unsigned char nSoundPriority)
{
m_nSoundPriority=nSoundPriority;
if (nSoundPriority==255)
{
// keep in memory all sounds with highest priority
// Not needed.
//m_nFlags|=FLAG_SOUND_LOAD_SYNCHRONOUSLY;
//Preload();
}
}
/*
//////////////////////////////////////////////////////////////////////
void CSound::SetMaxSoundDistance(float fMaxSoundDistance)
{
//keep it squared
m_fMaxSoundDistance2=fMaxSoundDistance*fMaxSoundDistance;
}*/
//calc the sound volume takiing into account gaem sound attenuation,
//reduction ratio, sound system sfx volume, master volume (concentration feature)
//////////////////////////////////////////////////////////////////////
int CSound::CalcSoundVolume(int nSoundValue,float fRatio)
{
//FRAME_PROFILER( "CSound:CalcSoundVolume",m_pSSys->GetSystem(),PROFILE_SOUND );
int nVolume;
for (int i=0;i<MAX_SOUNDSCALE_GROUPS;i++)
{
if (m_nSoundScaleGroups & SETSCALEBIT(i))
fRatio*=m_pSSys->m_fSoundScale[i];
}
/* if (m_pSound->m_btType==SoundBuffer::btSTREAM)
{
//straming sounds use music volume
nVolume=(int)((float)nSoundValue*fRatio*m_pSSys->m_fMusicVolume);
}
else
{*/
//if (m_nFlags & FLAG_SOUND_MUSIC)
// nVolume=(int)((((float)nSoundValue*m_pSSys->m_fMusicVolume)*fRatio));
//else
nVolume=(int)((((float)nSoundValue*m_pSSys->m_fSFXVolume)*fRatio));
// }
return (nVolume);
}
//////////////////////////////////////////////////////////////////////
bool CSound::IsPlaying()
{
//if (m_bPlaying && m_bLoop)
if (m_bPlaying)
return true;
return false;
//return IsPlayingOnChannel();
}
//////////////////////////////////////////////////////////////////////
bool CSound::IsPlayingOnChannel()
{
if (m_nChannel == CS_FREE)
return false;
GUARD_HEAP;
signed char bRes=CS_IsPlaying(m_nChannel);
if (bRes==TRUE)
{
//m_pSSys->m_pILog->LogToConsole("channel %d IS playing!!",m_nChannel);
return (true);
}
//m_pSSys->m_pILog->LogToConsole("channel %d,not playing!!",m_nChannel);
return (false);
}
//////////////////////////////////////////////////////////////////////////
bool CSound::IsPlayingVirtual()
{
return m_bPlaying && m_bLoop;
}
//////////////////////////////////////////////////////////////////////
void CSound::PlayFadeUnderwater(float fRatio, bool bForceActiveState, bool bSetRatio)
{
m_pSSys->m_lstFadeUnderwaterSounds.insert(this);
Play(fRatio,bForceActiveState,bSetRatio);
m_nFlags|=FLAG_SOUND_FADE_OUT_UNDERWATER;
}
//////////////////////////////////////////////////////////////////////
void CSound::Play(float fRatio, bool bForceActiveState, bool bSetRatio)
{
GUARD_HEAP;
FUNCTION_PROFILER( m_pSSys->GetSystem(),PROFILE_SOUND );
if (!m_pSSys->IsEnabled())
{
// Simulate that sound is played for disabled sound system.
OnEvent( SOUND_EVENT_ON_LOADED );
OnEvent( SOUND_EVENT_ON_PLAY );
OnEvent( SOUND_EVENT_ON_STOP );
return;
}
float currTime = m_pTimer->GetCurrTime();
float timeSinceLastPlay = currTime - m_fLastPlayTime;
if (bSetRatio)
m_fRatio = fRatio;
//////////////////////////////////////////////////////////////////////////
// If sound is already playing, skip until it stops.
// overwise it creates alot of overhead and channel leaks.
//////////////////////////////////////////////////////////////////////////
if (IsPlayingOnChannel())
{
if (!m_bLoop)
{
// For not looping sounds stop previous if after minimal repeat timeout.
if (m_pSSys->m_pCVarMinRepeatSoundTimeout->GetIVal() > timeSinceLastPlay*1000.0f)
{
return;
}
}
else {
// For looping sounds ignore, repeated play.
return;
}
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// If sound is already allocated fmod channel (may not even play it), it must free it before.
if (IsUsingChannel())
{
FreeChannel();
}
//////////////////////////////////////////////////////////////////////////
// Sounds with lower priority then current minimum set by sound system are ignored.
if (m_nSoundPriority < m_pSSys->GetMinSoundPriority())
return;
//////////////////////////////////////////////////////////////////////////
bool bStartSound=true;
if (m_nFlags & FLAG_SOUND_OUTDOOR)
{
if (m_pSSys->m_bInside)
bStartSound=false;
}
if (m_nFlags & FLAG_SOUND_INDOOR)
{
if (!m_pSSys->m_bInside)
bStartSound=false;
}
// if there are already too many sounds playing, this one
// should not be started
bool bCanPlay = ((int)(m_pSSys->m_lstSoundSpotsActive.size())<m_pSSys->m_pCVarMaxSoundSpots->GetIVal());
//////////////////////////////////////////////////////////////////////////
// For Not looping sounds too far away, stop immidiatly not even preload sound if too far.
//////////////////////////////////////////////////////////////////////////
if (!m_bLoop)
{
if (!bStartSound || !bCanPlay)
{
// Dont try to start non looping sounds at all.
return;
}
if (m_nFlags & (FLAG_SOUND_3D|FLAG_SOUND_RADIUS))
{
if (!m_pSSys->m_bValidPos)
{
return; //too far
}
//check the distance from the listener
float fDist2 = GetSquaredDistance(m_pSSys->m_cCam.GetPos(),m_RealPos);//position);
if (fDist2 > m_fMaxRadius2)
{
return; //too far
}
}
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//load the sound for real the first time is played
if (!Preload())
return; //the sound buffer cannot be loaded
// Preloading is also playing.
m_bPlaying = true;
bool bAllocatedChannel = false;
if (m_pSound->Loading())
{
if (m_pSSys->m_pCVarDebugSound->GetIVal()==3)
m_pSSys->m_pILog->Log("<Sound> Warning: %s, Play() called before loading was finished", GetName());
// save the state, will be played later
m_bPlayAfterLoad=true;
m_fPostLoadRatio=fRatio;
m_bPostLoadForceActiveState=bForceActiveState;
m_bPostLoadSetRatio=bSetRatio;
return;
/*
float fTime;
if (m_pSSys->m_pCVarDebugSound->GetIVal())
fTime=m_pTimer->GetAsyncCurTime();
TRACE("INFO: Synchroneous reading of %s due to Play() call before loading was finished.", GetName());
if (!m_pSound->WaitForLoad())
return;
if (m_pSSys->m_pCVarDebugSound->GetIVal())
m_pSSys->m_pILog->Log("Warning: Synchroneous reading of %s due to Play() call before loading was finished stalled for %1.3f milliseconds !", GetName(), (m_pTimer->GetAsyncCurTime()-fTime)*1000.0f);
*/
}
//CHECK_LOADED(Play);
//UpdatePosition();
bool bStarted=false;
int nVolume=CalcSoundVolume(m_nVolume,fRatio);
if (bStartSound)
{
switch (m_pSound->GetType())
{
case btSTREAM:
if ((!m_bLoop) || (!IsPlayingOnChannel()))
{
if (bCanPlay)
{
m_nChannel=CS_Stream_PlayEx(CS_FREE, m_pSound->GetStream(), NULL, true);
m_PlayingChannels++;
m_fChannelPlayTime = currTime;
m_fSoundLengthSec = GetLengthMs()/1000.0f;
bAllocatedChannel = true;
}
bStarted=true;
}
SetLoopMode(m_bLoop);
break;
case btSAMPLE:
{
if (m_nFlags & FLAG_SOUND_3D)
{
if (!m_pSSys->m_bValidPos)
{
if (m_bLoop)
bCanPlay = false;
else
return;
}
//check the distance from the listener
float fDist=GetSquaredDistance(m_pSSys->m_cCam.GetPos(),m_RealPos);//position);
if (fDist>m_fMaxRadius2)
{
if (!m_bLoop)
{
FreeChannel(); //free a channel
return; //too far
}
bCanPlay = false;
}
//min max distance and loop mode must be set before 'cos it operates
//on a per-sound basis
SetMinMaxDistance(m_fMinDist,m_fMaxDist);
SetLoopMode(m_bLoop);
FRAME_PROFILER( "CSound:CS_PlaySoundEX",m_pSSys->GetSystem(),PROFILE_SOUND );
if ((!m_bLoop) || (!IsPlayingOnChannel()))
{
if (bCanPlay)
{
m_nChannel=CS_PlaySoundEx(CS_FREE, m_pSound->GetSample(), NULL, true);//,m_pSSys->GetDSPUnitFilter(),FALSE);
m_PlayingChannels++;
m_fChannelPlayTime = currTime;
m_fSoundLengthSec = GetLengthMs()/1000.0f;
bAllocatedChannel = true;
}
bStarted=true;
}
SetPosition(m_position);
//SetFrequency(m_nBaseFreq);
}
else
{
//loop mode must be set before 'cos it operates
//on a per-sound basis
SetLoopMode(m_bLoop);
if ((!m_bLoop) || (!IsPlayingOnChannel()))
{
if (bCanPlay)
{
m_nChannel=CS_PlaySoundEx(CS_FREE, m_pSound->GetSample(), NULL, true);//,m_pSSys->GetDSPUnitFilter(),FALSE);
m_PlayingChannels++;
m_fChannelPlayTime = currTime;
m_fSoundLengthSec = GetLengthMs()/1000.0f;
bAllocatedChannel = true;
}
bStarted=true;
}
//SetFrequency(m_nRelativeFreq);
}
}
if (bStarted)
{
if (m_fPitching>0.0f)
{
float fRand=(float)rand()/(float)RAND_MAX;
fRand=fRand*2.0f-1.0f;
m_nCurrPitch=(int)(fRand*m_fPitching);
}
else
m_nCurrPitch=0;
SetFrequency(m_nRelativeFreq);
if (m_nStartOffset)
CS_SetCurrentPosition(m_nChannel, m_nStartOffset);
m_nStartOffset=0;
}
break;
}
}
//set volume (after we got the channel)
ChangeVolume(nVolume);
//set panning as well (after we got the channel)
if (bCanPlay && m_nChannel!=-1)
{
CS_SetPan(m_nChannel, m_nPan);
CS_SetPriority(m_nChannel, m_nSoundPriority);
if (bStarted)
CS_SetPaused(m_nChannel,false);
}
bool bAddedToList = false;
if (m_bLoop && bForceActiveState && (!m_pSound->LoadFailure()))
{
if (m_nFlags & FLAG_SOUND_ACTIVELIST)
{
if (bCanPlay)
{
m_pSSys->SetSoundActiveState(this, eSoundState_Active);
bAddedToList = true;
}
else
{
// let's put it in the inactive list if can't be played
// right now
m_pSSys->SetSoundActiveState(this, eSoundState_Inactive);
bAddedToList = true;
}
}
}
// If not looping sound it should be added to temporary auto stop sound list,
// to be stoped and free channel after it have been played.
if (IsUsingChannel() && !m_bLoop)
{
m_bAutoStop = true;
m_pSSys->RegisterAutoStopSound( this );
}
m_fLastPlayTime = currTime;
if (bAllocatedChannel && m_pSSys->m_pCVarDebugSound->GetIVal()==1)
{
m_pSSys->m_pILog->Log("<Sound> Playing sound: %s,channel %d,volume=%d,pan=%d, priority=%d Snd:%X, TimeDiff:%.2f",GetName(),m_nChannel,m_nPlayingVolume,m_nPan,m_nSoundPriority,this,timeSinceLastPlay);
}
if (bAllocatedChannel)
{
OnEvent( SOUND_EVENT_ON_PLAY );
}
}
//////////////////////////////////////////////////////////////////////////
void CSound::FreeChannel()
{
if (!m_bPlaying || m_nChannel <= 0)
return;
m_nPlayingVolume = -1;
if (m_pSound->Loaded())
{
switch (m_pSound->GetType())
{
case btSTREAM:
CS_Stream_Stop(m_pSound->GetStream());
m_PlayingChannels--;
break;
case btSAMPLE:
CS_StopSound(m_nChannel);
m_PlayingChannels--;
break;
}
}
m_fChannelPlayTime = -1;
m_nChannel = CS_FREE;
}
//////////////////////////////////////////////////////////////////////
void CSound::Stop()
{
FUNCTION_PROFILER( m_pSSys->GetSystem(),PROFILE_SOUND );
GUARD_HEAP;
// don't play after finishing with loading - if still loading yet...
m_bPlayAfterLoad=false;
if (!m_bPlaying)
return;
bool bUsedChannel = IsUsingChannel();
FreeChannel();
m_bPlaying = false;
m_nPlayingVolume = -1;
if (bUsedChannel && (m_pSSys->m_pCVarDebugSound->GetIVal()==1))
m_pSSys->m_pILog->Log("<Sound> Stop sound: %s",GetName());
if (m_nFlags & FLAG_SOUND_FADE_OUT_UNDERWATER)
{
SoundListItor It=m_pSSys->m_lstFadeUnderwaterSounds.find(this);
if (It!=m_pSSys->m_lstFadeUnderwaterSounds.end())
m_pSSys->m_lstFadeUnderwaterSounds.erase(It);
}
if (bUsedChannel)
OnEvent( SOUND_EVENT_ON_STOP );
// Must be last.
if (m_bAutoStop)
{
m_bAutoStop = false;
// This can deallocate the sound.
m_pSSys->UnregisterAutoStopSound( this );
}
}
/*
//////////////////////////////////////////////////////////////////////
void CSound::SetName(const char *szName)
{
if (szName)
{
m_strName = szName;
}
else
m_strName = "";
}
*/
//////////////////////////////////////////////////////////////////////
const char *CSound::GetName()
{
//return (m_strName.c_str());
if (m_pSound!=NULL)
return (m_pSound->GetName());
return (m_pSSys->m_szEmptyName);
}
//////////////////////////////////////////////////////////////////////
const int CSound::GetId()
{
return 0;//(m_nId);
}
//////////////////////////////////////////////////////////////////////
void CSound::SetLoopMode(bool bLoop)
{
GUARD_HEAP;
//FRAME_PROFILER( "CSound:SetLoopMode",m_pSSys->GetSystem(),PROFILE_SOUND );
if (m_pSound->Loaded()) // && m_pSound->m_btType==SoundBuffer::btSAMPLE && m_pSound->m_data.m_sfx)
{
switch (m_pSound->GetType())
{
//case btSAMPLE: CS_Sample_SetMode(m_pSound->GetSample(), bLoop ? CS_LOOP_NORMAL : CS_LOOP_OFF); break;
case btSAMPLE: CS_Sample_SetMode(m_pSound->GetSample(), m_pSound->GetFModFlags(bLoop)); break;
//case btSTREAM: if (m_nChannel>=0) CS_SetLoopMode(m_nChannel, bLoop ? CS_LOOP_NORMAL : CS_LOOP_OFF); break; // [Lennert] this call screws up ! Always set loopmode before playing the stream-sound !
}
}
if (bLoop)
m_nFlags|=FLAG_SOUND_LOOP;
else
m_nFlags&=~FLAG_SOUND_LOOP;
if ((m_nFlags & FLAG_SOUND_STREAM) && (m_bLoop!=bLoop))
{ // this is kinda unfortunate, but we have to reload the stream when we the change loop-mode because changing it runtime doesnt seem to work...
if (!m_pSound->NotLoaded())
{
m_pSound->AbortLoading();
m_pSound->DestroyData();
m_pSound->Load(bLoop, NULL);
}
}
m_bLoop=bLoop;
}
//////////////////////////////////////////////////////////////////////
void CSound::SetPitching(float fPitching)
{
m_fPitching = fPitching;
}
//////////////////////////////////////////////////////////////////////
void CSound::SetBaseFrequency(int nFreq)
{
//m_nBaseFreq = nFreq;
}
//////////////////////////////////////////////////////////////////////
int CSound::GetBaseFrequency(int nFreq)
{
if (m_pSound)
return (m_pSound->GetBaseFreq());
return (0);
}
//////////////////////////////////////////////////////////////////////
void CSound::SetPan(int nPan)
{
if (m_nChannel>=0)
{
if (nPan != m_nPan)
{
CS_SetPan(m_nChannel,nPan);
}
}
m_nPan=nPan;
}
//////////////////////////////////////////////////////////////////////
void CSound::SetFrequency(int nFreq)
{
//FRAME_PROFILER( "CSound:SetFrequency",m_pSSys->GetSystem(),PROFILE_SOUND );
m_nRelativeFreq = nFreq;
if ((m_nChannel>=0) && (m_pSound->GetType()==btSAMPLE))
{
float fFreq=(float)m_pSound->GetBaseFreq()*((float)(m_nRelativeFreq+m_nCurrPitch)/1000.0f);
CS_SetFrequency(m_nChannel, (int)fFreq);
}
}
//////////////////////////////////////////////////////////////////////
void CSound::SetMinMaxDistance(float fMinDist, float fMaxDist)
{
//FRAME_PROFILER( "CSound:SetMinMaxDistance",m_pSSys->GetSystem(),PROFILE_SOUND );
// increasing mindistnace makes it louder in 3d space
m_fMinDist=fMinDist;
m_fMaxDist=fMaxDist;
m_fMaxRadius2=fMaxDist*fMaxDist;
m_fMinRadius2=fMinDist*fMinDist;
float fPreloadRadius=fMaxDist+SOUND_PRELOAD_DISTANCE;
m_fPreloadRadius2=fPreloadRadius*fPreloadRadius;
#ifdef _DEBUG
if(fMinDist<0.1f)
{
m_pSSys->m_pILog->LogToConsole("SOUND[%s] min out of range %f",GetName(),fMinDist);
}
if(fMaxDist>1000000000.0f)
{
m_pSSys->m_pILog->LogToConsole("SOUND[%s] max out of range %f",GetName(),fMaxDist);
}
#endif
if (m_pSound->GetSample())
{
GUARD_HEAP;
CS_Sample_SetMinMaxDistance(m_pSound->GetSample(), fMinDist, CRYSOUND_MAXDIST);//fMaxDist);
}
}
//////////////////////////////////////////////////////////////////////
void CSound::SetAttrib(int nVolume, float fRatio, int nPan, int nFreq, bool bSetRatio)
{
ASSERT(nFreq==1000);
if (bSetRatio)
m_fRatio=fRatio;
m_nVolume=nVolume;
if (m_nChannel>=0)
{
ChangeVolume( CalcSoundVolume(m_nVolume,fRatio) );
if (m_nPan != nPan)
{
CS_SetPan(m_nChannel,nPan);
}
}
m_nPan=nPan;
}
//////////////////////////////////////////////////////////////////////
void CSound::SetAttrib(const Vec3d &pos, const Vec3d &speed)
{
m_position=pos;
m_speed=speed;
}
//////////////////////////////////////////////////////////////////////////
void CSound::SetRatio(float fRatio)
{
m_fRatio=fRatio;
ChangeVolume(CalcSoundVolume(m_nVolume,m_fRatio));
}
//////////////////////////////////////////////////////////////////////////
void CSound::UpdatePosition()
{
SetPosition(m_position);
}
//////////////////////////////////////////////////////////////////////
void CSound::SetPosition(const Vec3d &pos)
{
m_position=pos;
m_RealPos=m_position;
if (!(m_nFlags & FLAG_SOUND_3D))
return;
/*
if (m_pSSys->m_pCVarDebugSound->GetIVal()==1)
{
m_pSSys->m_pILog->Log("Sound %s, pos+%f,%f,%f",m_strName.c_str(),m_position.x,m_position.y,m_position.z);
}
*/
float fPos[3];
fPos[0]=m_position.x;
fPos[1]=m_position.z;
fPos[2]=m_position.y;
if ((m_pSSys->m_fDirAttCone>0.0f) && (m_pSSys->m_fDirAttCone<1.0f))
{
Vec3d DirToPlayer=m_position-m_pSSys->m_DirAttPos;
DirToPlayer.Normalize();
float fScale=((1.0f-(DirToPlayer*m_pSSys->m_DirAttDir))/(1.0f-m_pSSys->m_fDirAttCone));
if ((fScale>0.0f) && (fScale<=1.0f)) // inside cone
{
if ((1.0f-fScale)>m_pSSys->m_fDirAttMaxScale)
m_pSSys->m_fDirAttMaxScale=1.0f-fScale;
m_RealPos=m_position*fScale+(m_pSSys->m_DirAttPos+(m_pSSys->m_DirAttDir*0.1f))*(1.0f-fScale);
fPos[0]=m_RealPos.x;
fPos[1]=m_RealPos.z;
fPos[2]=m_RealPos.y;
//TRACE("Sound-Proj: %s, %1.3f, %1.3f, %1.3f, (%5.3f, %5.3f, %5.3f)", m_strName.c_str(), fScale, DirToPlayer*m_pSSys->m_DirAttDir, m_pSSys->m_fDirAttCone, m_RealPos.x, m_RealPos.y, m_RealPos.z);
}
}
if (m_pSSys->m_pCVarDopplerEnable->GetIVal() && (m_nFlags & FLAG_SOUND_DOPPLER))
{
Vec3d vVel=(pos-m_position);
float fTimeDelta=m_pSSys->m_pISystem->GetITimer()->GetFrameTime();
vVel=vVel*(m_pSSys->m_pCVarDopplerEnable->GetFVal()/fTimeDelta);
float fVel[3];
fVel[0]=vVel.x;
fVel[1]=vVel.z;
fVel[2]=vVel.y;
GUARD_HEAP;
CS_3D_SetAttributes(m_nChannel, fPos, fVel);
}
else
{
GUARD_HEAP;
//m_pSSys->m_pILog->LogToConsole("Setting sound pos for channel %d",m_nChannel);
CS_3D_SetAttributes(m_nChannel, fPos, NULL);
}
// check if the sound must be considered
// for sound occlusion
if (m_nFlags & FLAG_SOUND_OCCLUSION)
{
//check where the position is
I3DEngine *p3dEngine=m_pSSys->m_pISystem->GetI3DEngine();
if (p3dEngine)
m_pArea=p3dEngine->GetVisAreaFromPos(pos);
}
}
//////////////////////////////////////////////////////////////////////
const bool CSound::GetPosition(Vec3d &vPos)
{
if (m_nFlags & FLAG_SOUND_3D)
{
vPos=m_position;
return (true);
}
return (false);
}
//////////////////////////////////////////////////////////////////////
void CSound::SetVelocity(const Vec3d &speed)
{
m_speed=speed;
}
//////////////////////////////////////////////////////////////////////
void CSound::SetDirection(const Vec3d &vDir)
{
m_orient=vDir;
}
//////////////////////////////////////////////////////////////////////
void CSound::ChangeVolume(int nVolume)
{
if (m_nChannel>=0 && nVolume != m_nPlayingVolume)
// if (m_nChannel>=0)
{
CS_SetVolume(m_nChannel, nVolume);
m_nPlayingVolume = nVolume;
}
}
//////////////////////////////////////////////////////////////////////
void CSound::SetVolume(int nVolume)
{
if (nVolume>255)
nVolume=255;
m_nVolume=m_nMaxVolume=nVolume;
nVolume=CalcSoundVolume(m_nVolume,1.0f);
//if (m_pSSys->m_pCVarDebugSound->GetIVal()==5)
// m_pSSys->m_pILog->LogToConsole("VOL:%s,ch=%d,Set vol=%d",GetName(),m_nChannel,nVolume);
ChangeVolume(nVolume);
}
//////////////////////////////////////////////////////////////////////
void CSound::SetConeAngles(float fInnerAngle,float fOuterAngle)
{
}
//////////////////////////////////////////////////////////////////////
void CSound::SetPitch(int nValue)
{
int iReScaledValue;
// Scale from 0 - 1000 to FMOD range
iReScaledValue = (int)((float)nValue / 1000.0f * (float)m_pSound->GetBaseFreq());
iReScaledValue = __max(iReScaledValue, 100);
// channel = The channel number/handle to change the frequency for. CS_ALL can also be used (see remarks).
// freq = The frequency to set. Valid ranges are from 100 to 705600.
if ((m_nChannel>=0) && (m_pSound->GetType()==btSAMPLE))
{
GUARD_HEAP;
CS_SetFrequency(m_nChannel, iReScaledValue);
}
}
//////////////////////////////////////////////////////////////////////
void CSound::SetLoopPoints(const int iLoopStart, const int iLoopEnd)
{
CHECK_LOADED(SetLoopPoints);
if (m_pSound->GetSample())
{
GUARD_HEAP;
CS_Sample_SetLoopPoints(m_pSound->GetSample(), iLoopStart, iLoopEnd);
}
}
//////////////////////////////////////////////////////////////////////
void CSound::FXEnable(int nFxNumber)
{
if (!m_pSSys->m_pCVarEnableSoundFX->GetIVal())
return;
if ((m_pSound->GetType()==btSAMPLE) && (m_nChannel!=-1))
{
GUARD_HEAP;
m_nFxChannel=CS_FX_Enable(m_nChannel, nFxNumber);
}
}
//////////////////////////////////////////////////////////////////////
void CSound::FXSetParamEQ(float fCenter,float fBandwidth,float fGain)
{
if (!m_pSSys->m_pCVarEnableSoundFX->GetIVal())
return;
if ((m_pSound->GetType()==btSAMPLE) && (m_nFxChannel>=0))
{
GUARD_HEAP;
CS_FX_SetParamEQ(m_nFxChannel, fCenter, fBandwidth, fGain);
}
}
//////////////////////////////////////////////////////////////////////
//! returns the size of the stream in ms
int CSound::GetLengthMs()
{
GUARD_HEAP;
if (m_pSound->NotLoaded())
{
m_nFlags|=FLAG_SOUND_LOAD_SYNCHRONOUSLY; // force to load the sound
if (!Preload())
{
//the sound buffer cannot be loaded
if (!m_pSound->WaitForLoad())
return (0);
}
}
//CHECK_LOADED(GetLengthMs, 0);
switch (m_pSound->GetType())
{
case btSTREAM: return CS_Stream_GetLengthMs(m_pSound->GetStream());
case btSAMPLE: return (int)((float)CS_Sample_GetLength(m_pSound->GetSample())/(float)m_pSound->GetBaseFreq()*1000.0f);
}
return 0;
}
//////////////////////////////////////////////////////////////////////
//! returns the size of the stream in bytes
int CSound::GetLength()
{
GUARD_HEAP;
if (m_pSound->NotLoaded())
{
if (!Preload())
return (0); //the sound buffer cannot be loaded
}
CHECK_LOADED(GetLengt, 0);
if (m_pSound->GetStream())
return CS_Stream_GetLength(m_pSound->GetStream());
return 0;
// return (GetLengthMs()*1000.0f);
}
//////////////////////////////////////////////////////////////////////
//! retrieves the currently played sample-pos, in milliseconds or bytes
unsigned int CSound::GetCurrentSamplePos(bool bMilliSeconds)
{
GUARD_HEAP;
if (m_pSound->NotLoaded())
{
if (!Preload())
return (0); //the sound buffer cannot be loaded
}
//CHECK_LOADED(GetCurrentSamplePos, 0);
switch (m_pSound->GetType())
{
case btSAMPLE:
if (bMilliSeconds)
{
int nFreq;
CS_Sample_GetDefaults(m_pSound->GetSample(), &nFreq, NULL, NULL, NULL);
return (unsigned int)((float)CS_GetCurrentPosition(m_nChannel)/(float)nFreq*1000.0f);
}else
{
return ((unsigned int)CS_GetCurrentPosition(m_nChannel));
}
case btSTREAM:
if (bMilliSeconds)
return ((unsigned int)CS_Stream_GetTime(m_pSound->GetStream()));
else
return ((unsigned int)CS_Stream_GetPosition(m_pSound->GetStream()));
}
return (0);
}
//! set the currently played sample-pos in bytes or milliseconds
//////////////////////////////////////////////////////////////////////
void CSound::SetCurrentSamplePos(unsigned int nPos,bool bMilliSeconds)
{
GUARD_HEAP;
if (m_pSound->NotLoaded())
{
if (!Preload())
return; //the sound buffer cannot be loaded
}
//CHECK_LOADED(SetCurrentSamplePos);
switch (m_pSound->GetType())
{
case btSAMPLE:
if (bMilliSeconds)
{
unsigned int nSample=(unsigned int)(((float)nPos/1000.0f)*(float)m_pSound->GetBaseFreq());
if (IsPlayingOnChannel())
CS_SetCurrentPosition(m_nChannel, nSample);
else
m_nStartOffset=nSample;
}else
{
if (IsPlayingOnChannel())
CS_SetCurrentPosition(m_nChannel,nPos);
else
m_nStartOffset=nPos;
}
break;
case btSTREAM:
if (bMilliSeconds)
CS_Stream_SetTime(m_pSound->GetStream(),nPos);
else
CS_Stream_SetPosition(m_pSound->GetStream(),nPos);
break;
}
}
//////////////////////////////////////////////////////////////////////////
void CSound::SetSoundProperties(float fFadingValue)
{
m_fFadingValue = fFadingValue;
}
//////////////////////////////////////////////////////////////////////////
bool CSound::FadeIn()
{
if (m_fCurrentFade >= 1)
{
m_fCurrentFade = 1;
return true;
}
// this type of fading is purely framerate dependent
m_fCurrentFade += m_fFadingValue*m_pSSys->m_pISystem->GetITimer()->GetFrameTime();
//m_pSSys->m_pILog->LogToConsole("Fade IN, current fade=%f",m_fCurrentFade);
if (m_fCurrentFade<0)
m_fCurrentFade=0;
else
{
if (m_fCurrentFade>1.0f)
{
m_fCurrentFade=1.0f;
//m_nFadeType=0;
return (true);
}
}
return (false);
}
//////////////////////////////////////////////////////////////////////////
bool CSound::FadeOut()
{
// this type of fading is purely framerate dependent
m_fCurrentFade-=m_fFadingValue*m_pSSys->m_pISystem->GetITimer()->GetFrameTime();
//m_pSSys->m_pILog->LogToConsole("Fade OUT, current fade=%f",m_fCurrentFade);
if (m_fCurrentFade<0)
{
m_fCurrentFade=0;
if (IsUsingChannel())
FreeChannel();
return (true);
}
else
if (m_fCurrentFade>1.0f)
m_fCurrentFade=1.0f;
return (false);
}
//////////////////////////////////////////////////////////////////////////
void CSound::OnBufferLoaded()
{
if (!m_bAlreadyLoaded)
{
OnEvent( SOUND_EVENT_ON_LOADED );
if (m_bPlayAfterLoad)
{
m_bPlayAfterLoad=false;
Play(m_fPostLoadRatio,m_bPostLoadForceActiveState,m_bPostLoadSetRatio);
}
}
m_bAlreadyLoaded = true;
}
//////////////////////////////////////////////////////////////////////////
void CSound::OnBufferLoadFailed()
{
OnEvent( SOUND_EVENT_ON_LOAD_FAILED );
}
//////////////////////////////////////////////////////////////////////////
void CSound::GetMemoryUsage(class ICrySizer* pSizer)
{
if (!pSizer->Add(*this))
return;
CSoundBuffer *pBuffer=m_pSound;
pSizer->Add(*pBuffer);
}
//////////////////////////////////////////////////////////////////////////
bool CSound::IsLoading()
{
if (m_pSound)
return m_pSound->Loading();
return false;
}
//////////////////////////////////////////////////////////////////////////
bool CSound::IsLoaded()
{
if (m_pSound)
return m_pSound->Loaded();
return false;
}
bool CSound::IsUsingChannel()
{
if (m_nChannel >=0)
return true;
return false;
}
//////////////////////////////////////////////////////////////////////////
void CSound::AddEventListener( ISoundEventListener *pListener )
{
m_listeners.insert(pListener );
}
//////////////////////////////////////////////////////////////////////////
void CSound::RemoveEventListener( ISoundEventListener *pListener )
{
m_listeners.erase(pListener );
}
//////////////////////////////////////////////////////////////////////////
void CSound::OnEvent( ESoundCallbackEvent event )
{
enum {THRESHOLD = 8};
if (!m_listeners.empty())
{
size_t numListeners = m_listeners.size(); // set size is cached both in MS STL and STLPORT
if (numListeners == 1)
(*m_listeners.begin())->OnSoundEvent (event, this); // single listener
else
if (numListeners < THRESHOLD)
{
// a small number of listeners
ISoundEventListener* arrListeners[THRESHOLD];
unsigned i = 0;
for (Listeners::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it, ++i)
arrListeners[i] = *it;
// iterate through all callbacks
for (i = 0; i < numListeners;++i)
{
ISoundEventListener* pListener = arrListeners[i];
if (m_listeners.find(pListener) != m_listeners.end()) // this listener is still alive
pListener->OnSoundEvent( event, this );
}
}
else
{
// copy the current array of listeners and iterate through it
// during each OnSoundEvent, the listener set may change, so validate
// if the next listener is still in the set before calling upon it
std::vector<ISoundEventListener*> arrListeners;
arrListeners.reserve (numListeners);
{
// copy the array
for (Listeners::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
arrListeners.push_back(*it);
}
// iterate through all callbacks
for (std::vector<ISoundEventListener*>::iterator it = arrListeners.begin(); it != arrListeners.end(); ++it)
{
ISoundEventListener* pListener = *it;
if (m_listeners.find(pListener) != m_listeners.end()) // this listener is still alive
pListener->OnSoundEvent( event, this );
}
}
}
}
//////////////////////////////////////////////////////////////////////////
bool CSound::IsPlayLengthExpired( float fCurrTime )
{
if (m_fChannelPlayTime < 0 || m_bLoop || m_pSSys->m_bPause)
return false;
// Take few additional seconds precaution, (10 secs).
if (fCurrTime > m_fChannelPlayTime+m_fSoundLengthSec + 10)
{
return true;
}
return false;
}
#pragma warning(default:4003)
#endif //_XBOX