You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ryzom-core/nel/src/sound/context_sound.cpp

295 lines
7.1 KiB
C++

// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This source file has been modified by the following contributors:
// Copyright (C) 2010 Matt RAYKOWSKI (sfb) <matt.raykowski@gmail.com>
// Copyright (C) 2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
//
// This program 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.
//
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdsound.h"
#include "nel/sound/context_sound.h"
#include "nel/sound/sound_bank.h"
using namespace std;
using namespace NLMISC;
namespace NLSOUND {
//CContextSound test;
/// Constructor
CContextSound::CContextSound()
: _ContextSounds(0)
{
}
/// Destructor
CContextSound::~CContextSound()
{
if (_ContextSounds != 0)
delete _ContextSounds;
}
void CContextSound::serial(NLMISC::IStream &s)
{
CSound::serial(s);
s.serial(_PatternName);
if (s.isReading())
{
if (_ContextSounds)
delete _ContextSounds;
}
}
/// Load the sound parameters from georges' form
void CContextSound::importForm(const std::string& filename, NLGEORGES::UFormElm& formRoot)
{
NLGEORGES::UFormElm *psoundType;
std::string dfnName;
// some basic checking.
formRoot.getNodeByName(&psoundType, ".SoundType");
nlassert(psoundType != NULL);
psoundType->getDfnName(dfnName);
nlassert(dfnName == "context_sound.dfn");
// Call the base class
CSound::importForm(filename, formRoot);
// Read the pattern name
formRoot.getValueByName(_PatternName, ".SoundType.PatternName");
}
/// Return true if cone is meaningful
bool CContextSound::isDetailed() const
{
return false;
}
float CContextSound::getMaxDistance() const
{
if (_ContextSounds == 0)
{
const_cast<CContextSound*>(this)->init();
if (_ContextSounds == 0)
{
// invalid state
return 0;
}
}
return _ContextSounds->getMaxDistance();;
}
/// Return the length of the sound in ms
uint32 CContextSound::getDuration()
{
std::vector<std::pair<std::string, CSound*> > sounds;
getSubSoundList(sounds);
uint32 duration = 0;
std::vector<std::pair<std::string, CSound*> >::iterator first(sounds.begin()), last(sounds.end());
for (; first != last; ++first)
{
duration = std::max(duration, first->second->getDuration());
}
return duration;
}
/// Used by the george sound plugin to check sound recursion (ie sound 'toto' use sound 'titi' witch also use sound 'toto' ...).
void CContextSound::getSubSoundList(std::vector<std::pair<std::string, CSound*> > &subsounds) const
{
if (_ContextSounds == 0)
{
const_cast<CContextSound*>(this)->init();
}
if (_ContextSounds)
{
_ContextSounds->getSoundList(subsounds);
}
}
CSound *CContextSound::getContextSound(CSoundContext &context)
{
if (_ContextSounds == 0)
{
// need to init the sound container.
init();
if (_ContextSounds == 0)
return 0;
}
if (_Random > 1)
{
// compute the random value.
uint32 r;
do
{
r = rand()%_Random;
} while (r == context.PreviousRandom);
context.PreviousRandom = r;
return _ContextSounds->getSound(context, r);
}
else
return _ContextSounds->getSound(context, 0);
}
void CContextSound::init()
{
uint nbJoker = 0;
uint contextArgIndex[SoundContextNbArgs];
bool useRandom = false;
bool parseArg = false;
_BaseName.clear();
//nldebug("Init the context sound %s", _PatternName.c_str());
string::iterator first(_PatternName.begin()), last(_PatternName.end());
// 1st loop until the first joker
for(; first != last && *first != '%'; ++first)
_BaseName += *first;
// 2nd loop, now we read the context arg index for each joker.
std::string index;
for (; first != last; ++first)
{
if (parseArg)
{
if (isdigit(int(*first)))
{
index += *first;
}
else if (!index.empty())
{
if (useRandom)
{
fromString(index, _Random);
}
else
{
nlassertex(nbJoker < SoundContextNbArgs, ("Error will trying to play ContextSound '%s'", CStringMapper::unmap(_Name).c_str()));
fromString(index, contextArgIndex[nbJoker++]);
parseArg = false;
index.clear();
}
}
else if (*first == 'r')
{
nlassertex(useRandom == false, ("Error will trying to play ContextSound '%s'", CStringMapper::unmap(_Name).c_str()));
useRandom = true;
}
}
else if (*first == '%')
{
nlassertex(useRandom == false, ("Error will trying to play ContextSound '%s'", CStringMapper::unmap(_Name).c_str()));
parseArg = true;
}
}
// read the last char...
if (!index.empty())
{
if (useRandom)
{
fromString(index, _Random);
}
else
{
nlassertex(nbJoker < SoundContextNbArgs, ("Error will trying to play ContextSound '%s'", CStringMapper::unmap(_Name).c_str()));
fromString(index, contextArgIndex[nbJoker++]);
parseArg = false;
}
}
if (_ContextSounds != 0)
delete _ContextSounds;
// A little macro to make life easier (LM stand for Local Macro)
#define LM_CASE_CONTAINER_CREATOR(size) case (size):\
if (useRandom)\
_ContextSounds = new CContextSoundContainer<(size), true>;\
else\
_ContextSounds = new CContextSoundContainer<(size), false>;\
break;
// ok, now instantiate the correct container
switch (nbJoker)
{
LM_CASE_CONTAINER_CREATOR(0)
LM_CASE_CONTAINER_CREATOR(1)
LM_CASE_CONTAINER_CREATOR(2)
LM_CASE_CONTAINER_CREATOR(3)
LM_CASE_CONTAINER_CREATOR(4)
LM_CASE_CONTAINER_CREATOR(5)
LM_CASE_CONTAINER_CREATOR(6)
LM_CASE_CONTAINER_CREATOR(7)
LM_CASE_CONTAINER_CREATOR(8)
LM_CASE_CONTAINER_CREATOR(9)
LM_CASE_CONTAINER_CREATOR(10)
default:
nlwarning("Unsuported number of context argument in context sound '%s'!", CStringMapper::unmap(_Name).c_str());
return;
}
// cleanup macro
#undef LM_CASE_CONTAINER_CREATOR
_ContextSounds->init(contextArgIndex);
// ok, we have the container, now fill it with the sound
{
std::vector<NLMISC::TStringId> allSounds;
// CSoundBank::getSoundNames(allSounds);
CAudioMixerUser::instance()->getSoundNames(allSounds);
std::vector<NLMISC::TStringId>::iterator first(allSounds.begin()), last(allSounds.end());
for (; first != last; ++first)
{
const std::string &soundName = CStringMapper::unmap(*first);
if (soundName.size() > _BaseName.size())
{
uint i;
for (i=0; i<_BaseName.size(); ++i)
{
if (soundName[i] != _BaseName[i])
break;
}
if (i == _BaseName.size())
{
// The base name is ok, check that the next char is a digit (avoid conflit if some
// sound have a longeur base name with same beginning)
if (soundName[i] >= '0' && soundName[i] <= '9')
_ContextSounds->addSound(CAudioMixerUser::instance()->getSoundId(*first), _BaseName);
}
}
}
}
}
} // NLSOUND