// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This source file has been modified by the following contributors: // Copyright (C) 2010 Matt RAYKOWSKI (sfb) // Copyright (C) 2019 Jan BOON (Kaetemi) // // 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 . #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(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 > sounds; getSubSoundList(sounds); uint32 duration = 0; std::vector >::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 > &subsounds) const { if (_ContextSounds == 0) { const_cast(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 allSounds; // CSoundBank::getSoundNames(allSounds); CAudioMixerUser::instance()->getSoundNames(allSounds); std::vector::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