From 7a95fae1f9e303cc3148ae0d748d6e738481bf43 Mon Sep 17 00:00:00 2001 From: kaetemi Date: Wed, 11 Apr 2012 00:48:47 +0200 Subject: [PATCH] Changed: Improve performance of ryzom client CSoundManager. Strange code, though. --HG-- branch : sound_dev --- code/nel/include/nel/misc/fast_id_map.h | 151 +++++++++++++++++++ code/nel/src/misc/fast_id_map.cpp | 44 ++++++ code/ryzom/client/src/sound_manager.cpp | 189 ++++++++---------------- code/ryzom/client/src/sound_manager.h | 35 +++-- 4 files changed, 276 insertions(+), 143 deletions(-) create mode 100644 code/nel/include/nel/misc/fast_id_map.h create mode 100644 code/nel/src/misc/fast_id_map.cpp diff --git a/code/nel/include/nel/misc/fast_id_map.h b/code/nel/include/nel/misc/fast_id_map.h new file mode 100644 index 000000000..dbd05bc76 --- /dev/null +++ b/code/nel/include/nel/misc/fast_id_map.h @@ -0,0 +1,151 @@ +/** + * \file fast_id_map.h + * \brief CFastIdMap + * \date 2012-04-10 19:28GMT + * \author Jan Boon (Kaetemi) + * CFastIdMap + */ + +/* + * Copyright (C) 2012 by authors + * + * This file is part of RYZOM CORE. + * RYZOM CORE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * RYZOM CORE is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with RYZOM CORE. If not, see + * . + */ + +#ifndef NLMISC_FAST_ID_MAP_H +#define NLMISC_FAST_ID_MAP_H +#include + +// STL includes + +// NeL includes +#include + +// Project includes + +namespace NLMISC { + +/** + * \brief CFastIdMap + * \date 2012-04-10 19:28GMT + * \author Jan Boon (Kaetemi) + * This template allows for assigning unique uint32 identifiers to pointers. + * Useful when externally only exposing an identifier, when pointers may have been deleted. + * The identifier is made from two uint16's, one being the direct index in the identifier vector, + * and the other being a verification value that is increased when the identifier index is re-used. + * TId must be a typedef of uint32. + * TValue should be a pointer. + */ +template +class CFastIdMap +{ +protected: + struct CIdInfo + { + CIdInfo() { } + CIdInfo(uint16 verification, uint16 next, TValue value) : + Verification(verification), Next(next), Value(value) { } + uint16 Verification; + uint16 Next; + TValue Value; + }; + /// ID memory + std::vector m_Ids; + /// Nb of assigned IDs + uint m_Size; + /// Assigned IDs + uint16 m_Next; + +public: + CFastIdMap(TValue defaultValue) : m_Size(0), m_Next(0) + { + // Id 0 will contain the last available unused id, and be 0 if no more unused id's are available + // defaultValue will be returned when the ID is not found + m_Ids.push_back(CIdInfo(0, 0, defaultValue)); + } + + virtual ~CFastIdMap() { } + + void clear() + { + m_Ids.resize(1); + m_Ids[0].Next = 0; + } + + TId insert(TValue value) + { + // get next unused index + uint16 idx = m_Ids[0].Next; + if (idx == 0) + { + // size of used elements must be equal to the vector size minus one, when everything is allocated + nlassert((m_Ids.size() - 1) == m_Size); + + idx = m_Ids.size(); + uint16 verification = rand(); + m_Ids.push_back(CIdInfo(verification, m_Next, value)); + m_Next = idx; + return (TId)(((uint32)verification) << 16) & idx; + } + else + { + m_Ids[0].Next = m_Ids[idx].Next; // restore the last unused id + m_Ids[idx].Value = value; + return (TId)(((uint32)m_Ids[idx].Verification) << 16) & idx; + } + } + + void erase(TId id) + { + uint32 idx = ((uint32)id) & 0xFFFF; + uint16 verification = (uint16)(((uint32)id) >> 16); + if (m_Ids[idx].Verification == verification) + { + m_Ids[idx].Value = m_Ids[0].Value; // clean value for safety + m_Ids[idx].Verification = (uint16)(((uint32)m_Ids[idx].Verification + 1) & 0xFFFF); // change verification value, allow overflow :) + m_Ids[idx].Next = m_Ids[0].Next; // store the last unused id + m_Ids[0].Next = (uint16)idx; // set this as last unused id + } + else + { + nlwarning("Invalid ID"); + } + } + + TValue get(TId id) + { + uint32 idx = ((uint32)id) & 0xFFFF; + uint16 verification = (uint16)(((uint32)id) >> 16); + if (m_Ids[idx].Verification == verification) + { + return m_Ids[idx].Value; + } + else + { + nldebug("Invalid ID"); + return m_Ids[0].Value; + } + } + + inline uint size() { return m_Size; } + +}; /* class CFastIdMap */ + +} /* namespace NLMISC */ + +#endif /* #ifndef NLMISC_FAST_ID_MAP_H */ + +/* end of file */ diff --git a/code/nel/src/misc/fast_id_map.cpp b/code/nel/src/misc/fast_id_map.cpp new file mode 100644 index 000000000..f32d6edd8 --- /dev/null +++ b/code/nel/src/misc/fast_id_map.cpp @@ -0,0 +1,44 @@ +/** + * \file fast_id_map.cpp + * \brief CFastIdMap + * \date 2012-04-10 19:28GMT + * \author Jan Boon (Kaetemi) + * CFastIdMap + */ + +/* + * Copyright (C) 2012 by authors + * + * This file is part of RYZOM CORE. + * RYZOM CORE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * RYZOM CORE is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with RYZOM CORE. If not, see + * . + */ + +#include +#include + +// STL includes + +// NeL includes +// #include + +// Project includes + +namespace NLMISC { + +void dummytoavoidthecompilerwarningfastidmap() { } + +} /* namespace NLMISC */ + +/* end of file */ diff --git a/code/ryzom/client/src/sound_manager.cpp b/code/ryzom/client/src/sound_manager.cpp index fb4b3708f..b15a5269b 100644 --- a/code/ryzom/client/src/sound_manager.cpp +++ b/code/ryzom/client/src/sound_manager.cpp @@ -106,9 +106,10 @@ enum TFilterMapping // constructor //----------------------------------------------- CSoundManager::CSoundManager(IProgressCallback * /* progressCallBack */) -: _AudioMixer(NULL), - _EnvSoundRoot(NULL), - _UserEntitySoundLevel(1.0f) +: _AudioMixer(NULL), + _EnvSoundRoot(NULL), + _UserEntitySoundLevel(1.0f), + _Sources(NULL) { _EnableBackgroundMusicAtTime= 0; _GameMusicVolume= 1.f; @@ -421,7 +422,6 @@ void CSoundManager::reset () //--------------------------------------------------- void CSoundManager::init(IProgressCallback *progressCallBack) { - _NextId = 1; _EnvSoundRoot = NULL; _PlaySound = true; @@ -612,7 +612,7 @@ void CSoundManager::init(IProgressCallback *progressCallBack) // add a new source to the world, attached to the specified entity // return 0 if creation failed, sound id if creation was successful //----------------------------------------------- -uint32 CSoundManager::addSource( const NLMISC::TStringId &soundName, const NLMISC::CVector &position, bool play, bool loop, const CEntityId &id) +CSoundManager::TSourceId CSoundManager::addSource( const NLMISC::TStringId &soundName, const NLMISC::CVector &position, bool play, bool loop, const CEntityId &id) { uint32 retValue = 0; @@ -642,22 +642,16 @@ uint32 CSoundManager::addSource( const NLMISC::TStringId &soundName, const NLMIS pSource->play(); } + TSourceId sourceId = _Sources.insert(pSource); + // attach the source to the entity, if specified if (id != CEntityId::Unknown ) { - _AttachedSources.insert( TMultiMapEntityToSource::value_type( id, pSource ) ); + _AttachedSources.insert( TMultiMapEntityToSource::value_type( id, sourceId ) ); } - // set source id - retValue = _NextId; - - // add the new source - _Sources.insert( TMapIdToSource::value_type( _NextId, pSource ) ); - - ++_NextId; - // return the id of the source - return retValue; + return sourceId; } // addSource // @@ -726,24 +720,20 @@ bool CSoundManager::spawnSource(const NLMISC::TStringId &soundName, const NLMISC // removeSource: // remove a source //--------------------------------------------------- -void CSoundManager::removeSource( uint32 sourceId ) +void CSoundManager::removeSource(CSoundManager::TSourceId sourceId) { nldebug("remove the source : %d", sourceId); /// \todo Malkav : optimize speed nldebug("nb sources = %d", _Sources.size() ); - TMapIdToSource::iterator itS = _Sources.find( sourceId ); - if (itS != _Sources.end() ) + USource *pSource = _Sources.get(sourceId); + if (pSource) { - USource *pSource = (*itS).second; - if ( pSource == NULL ) - return; - TMultiMapEntityToSource::iterator it = _AttachedSources.begin();//, itOld; for ( ; it != _AttachedSources.end() ; ++it) { - if ( (*it).second == pSource ) + if ( (*it).second == sourceId ) { (*it).second = NULL; // itOld = it; @@ -759,8 +749,9 @@ nldebug("nb sources = %d", _Sources.size() ); } // delete the source -// _AudioMixer->removeSource (pSource); delete pSource; + // i think there was something going on here + _Sources.erase(sourceId); } } // removeSource // @@ -789,7 +780,7 @@ void CSoundManager::updateEntityPos( const CEntityId &id, const NLMISC::CVector for ( it = range.first; it != range.second ; ++it) { - (*it).second->setPos( pos ); + _Sources.get((*it).second)->setPos( pos ); } } // updateEntityPos // @@ -805,7 +796,7 @@ void CSoundManager::updateEntityVelocity( const CEntityId &id, const NLMISC::CVe for ( it = range.first; it != range.second ; ++it) { - (*it).second->setVelocity( velocity ); + _Sources.get((*it).second)->setVelocity( velocity ); } } // updateEntityVelocity // @@ -822,7 +813,7 @@ void CSoundManager::updateEntityDirection( const CEntityId &id, const NLMISC::CV for ( it = range.first; it != range.second ; ++it) { - (*it).second->setDirection( dir ); + _Sources.get((*it).second)->setDirection( dir ); } } // updateEntityOrientation // @@ -837,26 +828,15 @@ void CSoundManager::removeEntity( const CEntityId &id) TMultiMapEntityToSource::iterator it; const std::pair range = _AttachedSources.equal_range( id ); - - USource *pSource; + for ( it = range.first; it != range.second ; ++it) { - pSource = (*it).second; - if ( pSource != NULL) + TSourceId sourceId = (*it).second; + if (sourceId) { - TMapIdToSource::iterator itS = _Sources.begin();//, itOld; - - for ( ; itS != _Sources.end() ; ++itS) - { - if ( (*itS).second == pSource ) - { - (*itS).second = NULL; - _Sources.erase( itS ); - break; - } - } - // delete the source - delete (*it).second; + USource *pSource = _Sources.get(sourceId); + delete pSource; + _Sources.erase(sourceId); } } @@ -869,34 +849,24 @@ void CSoundManager::removeEntity( const CEntityId &id) //--------------------------------------------------- // setSoundPosition : //--------------------------------------------------- -void CSoundManager::setSoundPosition( uint32 soundId, const NLMISC::CVector &position) +void CSoundManager::setSoundPosition(TSourceId sourceId, const NLMISC::CVector &position) { if (!_PlaySound) return; - TMapIdToSource::iterator it = _Sources.find( soundId ); - if (it != _Sources.end() ) - { - nlassert( (*it).second ); - - (*it).second->setPos( position ); - } + USource *pSource = _Sources.get(sourceId); + if (pSource) pSource->setPos(position); } // setSoundPosition // //--------------------------------------------------- // loopSound : //--------------------------------------------------- -void CSoundManager::loopSound( uint32 soundId, bool loop) +void CSoundManager::loopSound(TSourceId sourceId, bool loop) { if (!_PlaySound) return; - TMapIdToSource::iterator it = _Sources.find( soundId ); - if (it != _Sources.end() ) - { - nlassert( (*it).second ); - - (*it).second->setLooping( loop ); - } + USource *pSource = _Sources.get(sourceId); + if (pSource) pSource->setLooping(loop); } // loopSound // @@ -904,19 +874,17 @@ void CSoundManager::loopSound( uint32 soundId, bool loop) // playSound : // start or stop playing sound //--------------------------------------------------- -void CSoundManager::playSound( uint32 soundId, bool play) +void CSoundManager::playSound(TSourceId sourceId, bool play) { if (!_PlaySound) return; - TMapIdToSource::iterator it = _Sources.find( soundId ); - if (it != _Sources.end() ) + USource *pSource = _Sources.get(sourceId); + if (pSource) { - nlassert( (*it).second ); - if (play) - (*it).second->play(); + pSource->play(); else - (*it).second->stop(); + pSource->stop(); } } // loopSound // @@ -926,16 +894,10 @@ void CSoundManager::playSound( uint32 soundId, bool play) // isPlaying : // return true if the source is playing //--------------------------------------------------- -bool CSoundManager::isPlaying( uint32 sourceId ) +bool CSoundManager::isPlaying(TSourceId sourceId) { - TMapIdToSource::iterator it = _Sources.find( sourceId ); - if (it != _Sources.end() ) - { - nlassert( (*it).second ); - - return ( (*it).second->isPlaying() ); - } - + USource *pSource = _Sources.get(sourceId); + if (pSource) return pSource->isPlaying(); return false; } // isPlaying // @@ -999,16 +961,10 @@ bool CSoundManager::setSoundForSource( uint32 sourceId, TSound sound, const CVec // setSourceGain : // set the gain of the specified source //--------------------------------------------------- -void CSoundManager::setSourceGain( uint32 sourceId, float gain) +void CSoundManager::setSourceGain(TSourceId sourceId, float gain) { - TMapIdToSource::const_iterator it = _Sources.find( sourceId ); - if (it != _Sources.end() ) - { - USource *pSource = (*it).second; - nlassert( pSource ); - - pSource->setGain( gain ); - } + USource *pSource = _Sources.get(sourceId); + if (pSource) pSource->setGain( gain ); } // setSourceGain // @@ -1016,17 +972,10 @@ void CSoundManager::setSourceGain( uint32 sourceId, float gain) // getSourceGain : // get the gain of the specified source (-1 if source not found) //--------------------------------------------------- -float CSoundManager::getSourceGain( uint32 sourceId ) +float CSoundManager::getSourceGain(TSourceId sourceId) { - TMapIdToSource::const_iterator it = _Sources.find( sourceId ); - if (it != _Sources.end() ) - { - USource *pSource = (*it).second; - nlassert( pSource ); - - return ( pSource->getGain() ); - } - + USource *pSource = _Sources.get(sourceId); + if (pSource) return pSource->getGain(); return -1; } // getSourceGain // @@ -1035,16 +984,10 @@ float CSoundManager::getSourceGain( uint32 sourceId ) // setSourcePitch : // set the Pitch of the specified source //--------------------------------------------------- -void CSoundManager::setSourcePitch( uint32 sourceId, float Pitch) +void CSoundManager::setSourcePitch(TSourceId sourceId, float Pitch) { - TMapIdToSource::const_iterator it = _Sources.find( sourceId ); - if (it != _Sources.end() ) - { - USource *pSource = (*it).second; - nlassert( pSource ); - - pSource->setPitch( Pitch ); - } + USource *pSource = _Sources.get(sourceId); + if (pSource) pSource->setPitch(Pitch); } // setSourcePitch // @@ -1052,17 +995,10 @@ void CSoundManager::setSourcePitch( uint32 sourceId, float Pitch) // getSourcePitch : // get the Pitch of the specified source (-1 if source not found) //--------------------------------------------------- -float CSoundManager::getSourcePitch( uint32 sourceId ) +float CSoundManager::getSourcePitch(TSourceId sourceId) { - TMapIdToSource::const_iterator it = _Sources.find( sourceId ); - if (it != _Sources.end() ) - { - USource *pSource = (*it).second; - nlassert( pSource ); - - return ( pSource->getPitch() ); - } - + USource *pSource = _Sources.get(sourceId); + if (pSource) return pSource->getPitch(); return -1; } // getSourcePitch // @@ -1204,23 +1140,26 @@ void CSoundManager::playPositionedSounds( const CVector& /* pos */ ) list::iterator itPSnd; for( itPSnd = _PositionedSounds.begin(); itPSnd != _PositionedSounds.end(); ++itPSnd ) { - TMapIdToSource::const_iterator itSrc = _Sources.find( *itPSnd ); - if( itSrc == _Sources.end() ) + USource *pSource = _Sources.get(*itPSnd); + if (!pSource) { nlwarning(" : The source %d is unknown",*itPSnd); } - /* - if( (pos - (*itSrc).second.getPos()).norm() < ...) + else { - if( (*itSrc).second.pSource->isPlaying() == false ) + /* + if( (pos - (*itSrc).second.getPos()).norm() < ...) { - (*itSrc).second.pSource->play(); + if( (*itSrc).second.pSource->isPlaying() == false ) + { + (*itSrc).second.pSource->play(); + } + } + */ + if (!pSource->isPlaying()) + { + pSource->play(); } - } - */ - if( (*itSrc).second->isPlaying() == false ) - { - (*itSrc).second->play(); } } diff --git a/code/ryzom/client/src/sound_manager.h b/code/ryzom/client/src/sound_manager.h index 629d9a957..260ab6e81 100644 --- a/code/ryzom/client/src/sound_manager.h +++ b/code/ryzom/client/src/sound_manager.h @@ -26,6 +26,7 @@ #include "nel/misc/types_nl.h" #include "nel/misc/vector.h" #include "nel/misc/config_file.h" +#include "nel/misc/fast_id_map.h" // game_share #include "nel/misc/entity_id.h" // sound @@ -45,8 +46,6 @@ namespace NLMISC class IProgressCallback; } - - /** * class managing all the sounds for the client * \author David Fleury @@ -55,9 +54,12 @@ namespace NLMISC */ class CSoundManager { +public: + typedef uint32 TSourceId; - typedef CHashMultiMap TMultiMapEntityToSource; - typedef std::map TMapIdToSource; +private: + typedef CHashMultiMap TMultiMapEntityToSource; + typedef NLMISC::CFastIdMap TMapIdToSource; /// Load the properties for this sound and aplly them. void loadProperties(const string &soundName, USource *source); @@ -86,7 +88,7 @@ public: /// Return the audio mixer instance pointer. NLSOUND::UAudioMixer *getMixer(); - uint32 addSource( const NLMISC::TStringId &soundName, const NLMISC::CVector &position, bool play = true , bool loop = false, const NLMISC::CEntityId &id = NLMISC::CEntityId::Unknown ); + TSourceId addSource( const NLMISC::TStringId &soundName, const NLMISC::CVector &position, bool play = true , bool loop = false, const NLMISC::CEntityId &id = NLMISC::CEntityId::Unknown ); /// spawn a new source to the world but sound manager don't keep any link and the sound will be automatically deleted when finnished bool spawnSource (const NLMISC::TStringId &soundName, NLSOUND::CSoundContext &context); @@ -98,7 +100,7 @@ public: * remove a source * \param uint32 source id */ - void removeSource( uint32 sourceId ); + void removeSource( TSourceId sourceId ); /** @@ -190,28 +192,28 @@ public: * \param uint32 source id * \param CVector& new position */ - void setSoundPosition( uint32 sourceId, const NLMISC::CVector &position); + void setSoundPosition( TSourceId sourceId, const NLMISC::CVector &position); /** * loop a sound (or stop looping) * \param uint32 source id * \param bool loop (true = loop) */ - void loopSound( uint32 sourceId, bool loop); + void loopSound( TSourceId sourceId, bool loop); /** * play or stop a sound * \param uint32 source id * \param bool play (true = play, false = stop) */ - void playSound( uint32 sourceId, bool play); + void playSound( TSourceId sourceId, bool play); /** * test whether the sepcified source is playing or not * \param uint32 source id * \return bool true if the source is playing */ - bool isPlaying( uint32 sourceId ); + bool isPlaying( TSourceId sourceId ); /** * select the env effect corresponding to tag @@ -236,14 +238,14 @@ public: * \param uint32 sourceId * \param float new gain (0-1) */ - void setSourceGain( uint32 sourceId, float gain); + void setSourceGain( TSourceId sourceId, float gain); /** * get source Gain * \param uint32 sourceId * \return float new gain (0-1) (-1 if source not found) */ - float getSourceGain( uint32 sourceId ); + float getSourceGain( TSourceId sourceId ); /** * set source Pitch @@ -251,14 +253,14 @@ public: * \param uint32 sourceId * \param float new Pitch (0-1) */ - void setSourcePitch( uint32 sourceId, float gain); + void setSourcePitch( TSourceId sourceId, float gain); /** * get source Pitch * \param uint32 sourceId * \return float new Pitch (0-1) (>0) (-1 if source not found) */ - float getSourcePitch( uint32 sourceId ); + float getSourcePitch( TSourceId sourceId ); /** * Play all the positioned sounds which are near the given position @@ -346,10 +348,7 @@ private: //CStepSounds _StepSounds; /// list of positioned sounds - std::list _PositionedSounds; - - /// the next value that will be used as id for the next sound to be created - uint32 _NextId; + std::list _PositionedSounds; /// Gain value for user entity sound. float _UserEntitySoundLevel;