1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2010 Matt RAYKOWSKI (sfb) <matt.raykowski@gmail.com>
6 // Copyright (C) 2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "nel/sound/context_sound.h"
24 #include "nel/sound/sound_bank.h"
27 using namespace NLMISC
;
38 CContextSound::CContextSound()
43 CContextSound::~CContextSound()
45 if (_ContextSounds
!= 0)
46 delete _ContextSounds
;
49 void CContextSound::serial(NLMISC::IStream
&s
)
52 s
.serial(_PatternName
);
57 delete _ContextSounds
;
62 /// Load the sound parameters from georges' form
63 void CContextSound::importForm(const std::string
& filename
, NLGEORGES::UFormElm
& formRoot
)
65 NLGEORGES::UFormElm
*psoundType
;
68 // some basic checking.
69 formRoot
.getNodeByName(&psoundType
, ".SoundType");
70 nlassert(psoundType
!= NULL
);
71 psoundType
->getDfnName(dfnName
);
72 nlassert(dfnName
== "context_sound.dfn");
74 // Call the base class
75 CSound::importForm(filename
, formRoot
);
77 // Read the pattern name
78 formRoot
.getValueByName(_PatternName
, ".SoundType.PatternName");
81 /// Return true if cone is meaningful
82 bool CContextSound::isDetailed() const
87 float CContextSound::getMaxDistance() const
89 if (_ContextSounds
== 0)
91 const_cast<CContextSound
*>(this)->init();
92 if (_ContextSounds
== 0)
98 return _ContextSounds
->getMaxDistance();;
101 /// Return the length of the sound in ms
102 uint32
CContextSound::getDuration()
104 std::vector
<std::pair
<std::string
, CSound
*> > sounds
;
105 getSubSoundList(sounds
);
109 std::vector
<std::pair
<std::string
, CSound
*> >::iterator
first(sounds
.begin()), last(sounds
.end());
110 for (; first
!= last
; ++first
)
112 duration
= std::max(duration
, first
->second
->getDuration());
117 /// Used by the george sound plugin to check sound recursion (ie sound 'toto' use sound 'titi' witch also use sound 'toto' ...).
118 void CContextSound::getSubSoundList(std::vector
<std::pair
<std::string
, CSound
*> > &subsounds
) const
120 if (_ContextSounds
== 0)
122 const_cast<CContextSound
*>(this)->init();
127 _ContextSounds
->getSoundList(subsounds
);
131 CSound
*CContextSound::getContextSound(CSoundContext
&context
)
133 if (_ContextSounds
== 0)
135 // need to init the sound container.
138 if (_ContextSounds
== 0)
144 // compute the random value.
149 } while (r
== context
.PreviousRandom
);
151 context
.PreviousRandom
= r
;
153 return _ContextSounds
->getSound(context
, r
);
156 return _ContextSounds
->getSound(context
, 0);
161 void CContextSound::init()
164 uint contextArgIndex
[SoundContextNbArgs
];
165 bool useRandom
= false;
166 bool parseArg
= false;
169 //nldebug("Init the context sound %s", _PatternName.c_str());
171 string::iterator
first(_PatternName
.begin()), last(_PatternName
.end());
172 // 1st loop until the first joker
173 for(; first
!= last
&& *first
!= '%'; ++first
)
176 // 2nd loop, now we read the context arg index for each joker.
178 for (; first
!= last
; ++first
)
182 if (isdigit(int(*first
)))
186 else if (!index
.empty())
190 fromString(index
, _Random
);
194 nlassertex(nbJoker
< SoundContextNbArgs
, ("Error will trying to play ContextSound '%s'", CStringMapper::unmap(_Name
).c_str()));
195 fromString(index
, contextArgIndex
[nbJoker
++]);
200 else if (*first
== 'r')
202 nlassertex(useRandom
== false, ("Error will trying to play ContextSound '%s'", CStringMapper::unmap(_Name
).c_str()));
206 else if (*first
== '%')
208 nlassertex(useRandom
== false, ("Error will trying to play ContextSound '%s'", CStringMapper::unmap(_Name
).c_str()));
213 // read the last char...
218 fromString(index
, _Random
);
222 nlassertex(nbJoker
< SoundContextNbArgs
, ("Error will trying to play ContextSound '%s'", CStringMapper::unmap(_Name
).c_str()));
223 fromString(index
, contextArgIndex
[nbJoker
++]);
228 if (_ContextSounds
!= 0)
229 delete _ContextSounds
;
231 // A little macro to make life easier (LM stand for Local Macro)
232 #define LM_CASE_CONTAINER_CREATOR(size) case (size):\
234 _ContextSounds = new CContextSoundContainer<(size), true>;\
236 _ContextSounds = new CContextSoundContainer<(size), false>;\
239 // ok, now instantiate the correct container
242 LM_CASE_CONTAINER_CREATOR(0)
243 LM_CASE_CONTAINER_CREATOR(1)
244 LM_CASE_CONTAINER_CREATOR(2)
245 LM_CASE_CONTAINER_CREATOR(3)
246 LM_CASE_CONTAINER_CREATOR(4)
247 LM_CASE_CONTAINER_CREATOR(5)
248 LM_CASE_CONTAINER_CREATOR(6)
249 LM_CASE_CONTAINER_CREATOR(7)
250 LM_CASE_CONTAINER_CREATOR(8)
251 LM_CASE_CONTAINER_CREATOR(9)
252 LM_CASE_CONTAINER_CREATOR(10)
254 nlwarning("Unsuported number of context argument in context sound '%s'!", CStringMapper::unmap(_Name
).c_str());
258 #undef LM_CASE_CONTAINER_CREATOR
260 _ContextSounds
->init(contextArgIndex
);
262 // ok, we have the container, now fill it with the sound
264 std::vector
<NLMISC::TStringId
> allSounds
;
265 // CSoundBank::getSoundNames(allSounds);
266 CAudioMixerUser::instance()->getSoundNames(allSounds
);
268 std::vector
<NLMISC::TStringId
>::iterator
first(allSounds
.begin()), last(allSounds
.end());
269 for (; first
!= last
; ++first
)
271 const std::string
&soundName
= CStringMapper::unmap(*first
);
272 if (soundName
.size() > _BaseName
.size())
275 for (i
=0; i
<_BaseName
.size(); ++i
)
277 if (soundName
[i
] != _BaseName
[i
])
280 if (i
== _BaseName
.size())
282 // The base name is ok, check that the next char is a digit (avoid conflit if some
283 // sound have a longeur base name with same beginning)
284 if (soundName
[i
] >= '0' && soundName
[i
] <= '9')
285 _ContextSounds
->addSound(CAudioMixerUser::instance()->getSoundId(*first
), _BaseName
);