ps_sound.cpp
Go to the documentation of this file.00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "std3d.h"
00025 #include "nel/misc/string_mapper.h"
00026 #include "nel/3d/ps_sound.h"
00027 #include "nel/3d/particle_system.h"
00028 #include "nel/3d/u_ps_sound_interface.h"
00029 #include "nel/3d/ps_attrib_maker.h"
00030
00031 namespace NL3D
00032 {
00033
00034
00035
00036 static const uint SoundBufSize = 1024;
00037
00038
00039
00040 CPSSound::CPSSound() : _Gain(1.f),
00041 _GainScheme(NULL),
00042 _Pitch(1.f),
00043 _PitchScheme(NULL),
00044 _EmissionPercent(1),
00045 _SpawnSounds(false),
00046 _Mute(false),
00047 _SoundStopped(false),
00048 _SoundReactivated(false),
00049 _UseOriginalPitch(false)
00050 {
00051 NL_PS_FUNC(CPSSound_CPSSound)
00052 if (CParticleSystem::getSerializeIdentifierFlag()) _Name = std::string("sound");
00053 _SoundName = NLMISC::CStringMapper::emptyId();
00054 }
00055
00056
00057 void CPSSound::stopSound()
00058 {
00059 NL_PS_FUNC(CPSSound_stopSound)
00060 _SoundReactivated = false;
00061 if (_SoundStopped) return;
00062 CPSAttrib<UPSSoundInstance *>::iterator it = _Sounds.begin()
00063 , endIt = _Sounds.end();
00064 while (it != endIt)
00065 {
00066 if (*it)
00067 {
00068 (*it)->setLooping(false);
00069 (*it)->release();
00070 (*it) = NULL;
00071 }
00072 ++it;
00073 }
00074 _SoundStopped = true;
00075 }
00076
00077
00078 void CPSSound::reactivateSound()
00079 {
00080 NL_PS_FUNC(CPSSound_reactivateSound)
00081
00082 _SoundReactivated = true;
00083 }
00084
00085
00086 void CPSSound::removeAllSources(void)
00087 {
00088 NL_PS_FUNC(CPSSound_removeAllSources)
00089 const sint32 size = _Sounds.getSize();
00090
00091 for (sint32 k = size - 1; k >= 0; --k)
00092 {
00093 deleteElement(k);
00094 }
00095 }
00096
00097
00098 CPSSound::~CPSSound()
00099 {
00100 NL_PS_FUNC(CPSSound_CPSSound)
00101 removeAllSources();
00102 delete _GainScheme;
00103 delete _PitchScheme;
00104 }
00105
00106
00107 uint32 CPSSound::getType(void) const
00108 {
00109 NL_PS_FUNC(CPSSound_getType)
00110 return PSSound;
00111 }
00112
00113
00114
00115
00116 void CPSSound::step(TPSProcessPass pass)
00117 {
00118 NL_PS_FUNC(CPSSound_step)
00119 if (pass != PSMotion) return;
00120 const uint32 size = _Owner->getSize();
00121 if (!size) return;
00122 if (_SoundStopped && !_SoundReactivated)
00123 {
00124 return;
00125 }
00126 if (_SoundReactivated)
00127 {
00128 _SoundStopped = false;
00129 _SoundReactivated = false;
00130 if (!_Mute)
00131 {
00132 sint32 k;
00133
00134 removeAllSources();
00135 for (k = 0; k < (sint32) size; ++k)
00136 {
00137 CPSEmitterInfo ei;
00138 ei.setDefaults();
00139 newElement(ei);
00140 }
00141 }
00142
00143 return;
00144 }
00145 nlassert(_Owner);
00146 uint32 toProcess, leftToDo = size;
00147
00148 float Gains[SoundBufSize];
00149 float frequencies[SoundBufSize];
00150
00151 uint GainPtInc = _GainScheme ? 1 : 0;
00152 uint pitchPtInc = _PitchScheme ? 1 : 0;
00153 float *currVol, *currPitch;
00154
00155
00156 CPSAttrib<UPSSoundInstance *>::iterator it = _Sounds.begin(),
00157 endIt;
00158 CPSAttrib<NLMISC::CVector>::const_iterator posIt = _Owner->getPos().begin();
00159 CPSAttrib<NLMISC::CVector>::const_iterator speedIt = _Owner->getSpeed().begin();
00160
00161 do
00162 {
00163 toProcess = leftToDo > SoundBufSize ? SoundBufSize : leftToDo;
00164
00165 currVol = _GainScheme ? (float *) _GainScheme->make(getOwner(), size - leftToDo, Gains, sizeof(float), toProcess, true)
00166 : &_Gain;
00167 if (!_UseOriginalPitch)
00168 {
00169
00170 currPitch = _PitchScheme ? (float *) _PitchScheme->make(getOwner(), size - leftToDo, frequencies, sizeof(float), toProcess, true)
00171 : &_Pitch;
00172 endIt = it + toProcess;
00173 const CMatrix &localToWorld = _Owner->getLocalToWorldMatrix();
00174 do
00175 {
00176 if (*it)
00177 {
00178 (*it)->setSoundParams(*currVol,
00179 localToWorld * *posIt,
00180 localToWorld.mulVector(*speedIt),
00181 *currPitch);
00182 if ((*it)->isLooping() && !(*it)->isPlaying())
00183 {
00184
00185 (*it)->play();
00186 }
00187 }
00188 currVol += GainPtInc;
00189 currPitch += pitchPtInc;
00190 ++posIt;
00191 ++speedIt;
00192 ++it;
00193 }
00194 while (it != endIt);
00195 }
00196 else
00197 {
00198
00199 endIt = it + toProcess;
00200 const CMatrix &localToWorld = _Owner->getLocalToWorldMatrix();
00201 do
00202 {
00203 if (*it)
00204 {
00205 (*it)->setSoundParams(*currVol,
00206 localToWorld * *posIt,
00207 localToWorld.mulVector(*speedIt),
00208 (*it)->getPitch());
00209 }
00210 currVol += GainPtInc;
00211 ++posIt;
00212 ++speedIt;
00213 ++it;
00214 }
00215 while (it != endIt);
00216 }
00217 leftToDo -= toProcess;
00218 }
00219 while (leftToDo);
00220 }
00221
00222
00223 void CPSSound::setGain(float Gain)
00224 {
00225 NL_PS_FUNC(CPSSound_setGain)
00226 delete _GainScheme;
00227 _GainScheme = NULL;
00228 _Gain = Gain;
00229 }
00230
00231
00232 void CPSSound::setGainScheme(CPSAttribMaker<float> *Gain)
00233 {
00234 NL_PS_FUNC(CPSSound_setGainScheme)
00235 delete _GainScheme;
00236 _GainScheme = Gain;
00237 if (_Owner)
00238 {
00239 if (_GainScheme && _GainScheme->hasMemory()) _GainScheme->resize(_Owner->getMaxSize(), _Owner->getSize());
00240 }
00241 }
00242
00243
00244 void CPSSound::setPitch(float pitch)
00245 {
00246 NL_PS_FUNC(CPSSound_setPitch)
00247 delete _PitchScheme;
00248 _PitchScheme = NULL;
00249 _Pitch = pitch;
00250 }
00251
00252
00253 void CPSSound::setPitchScheme(CPSAttribMaker<float> *pitch)
00254 {
00255 NL_PS_FUNC(CPSSound_setPitchScheme)
00256 delete _PitchScheme;
00257 _PitchScheme = pitch;
00258 if (_Owner)
00259 {
00260 if (_PitchScheme && _PitchScheme->hasMemory()) _PitchScheme->resize(_Owner->getMaxSize(), _Owner->getSize());
00261 }
00262 }
00263
00264
00265 void CPSSound::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00266 {
00267 NL_PS_FUNC(CPSSound_serial)
00268 CPSLocatedBindable::serial(f);
00269
00270 sint ver = f.serialVersion(3);
00271 if (f.isReading())
00272 {
00273 std::string soundName;
00274 f.serial(soundName);
00275 _SoundName = NLMISC::CStringMapper::map(soundName);
00276 }
00277 else
00278 {
00279 std::string soundName = NLMISC::CStringMapper::unmap(_SoundName);
00280 f.serial(soundName);
00281 }
00282
00283 sint32 nbSounds;
00284 bool hasScheme;
00285 if (f.isReading())
00286 {
00287 f.serial(nbSounds);
00288
00289 if (_Owner)
00290 {
00291 _Sounds.resize(_Owner->getMaxSize());
00292 }
00293 }
00294 else
00295 {
00296 nbSounds = _Sounds.getSize();
00297 f.serial(nbSounds);
00298 }
00299
00300
00301 if (f.isReading())
00302 {
00303 delete _GainScheme;
00304 _GainScheme = NULL;
00305 delete _PitchScheme;
00306 _PitchScheme = NULL;
00307 }
00308
00309 hasScheme = _GainScheme != NULL;
00310 f.serial(hasScheme);
00311 if (hasScheme)
00312 {
00313 f.serialPolyPtr(_GainScheme);
00314 }
00315 else
00316 {
00317 f.serial(_Gain);
00318 }
00319
00320 if (ver >= 3)
00321 {
00322 bool useOriginalPitch = _UseOriginalPitch;
00323 f.serial(useOriginalPitch);
00324 _UseOriginalPitch = useOriginalPitch;
00325 if (!_UseOriginalPitch)
00326 {
00327
00328 hasScheme = _PitchScheme != NULL;
00329 f.serial(hasScheme);
00330 if (hasScheme)
00331 {
00332 f.serialPolyPtr(_PitchScheme);
00333 }
00334 else
00335 {
00336 f.serial(_Pitch);
00337 }
00338 }
00339 }
00340 else
00341 {
00342 hasScheme = _PitchScheme != NULL;
00343 f.serial(hasScheme);
00344 if (hasScheme)
00345 {
00346 f.serialPolyPtr(_PitchScheme);
00347 }
00348 else
00349 {
00350 f.serial(_Pitch);
00351 }
00352 }
00353
00354 if (ver > 1)
00355 {
00356 f.serial(_EmissionPercent);
00357 f.serial(_SpawnSounds);
00358 }
00359
00360 if (f.isReading())
00361 {
00362 _SoundStopped = true;
00363
00364 for (sint k = 0; k < nbSounds; ++k)
00365 {
00366 CPSEmitterInfo ei;
00367 ei.setDefaults();
00368 newElement(ei);
00369 }
00370 _SoundStopped = false;
00371 _SoundReactivated = true;
00372 }
00373 }
00374
00375
00376
00377 void CPSSound::newElement(const CPSEmitterInfo &info)
00378 {
00379 NL_PS_FUNC(CPSSound_newElement)
00380 nlassert(_Owner);
00381 if (_GainScheme && _GainScheme->hasMemory()) _GainScheme->newElement(info);
00382 if (_PitchScheme && _PitchScheme->hasMemory()) _PitchScheme->newElement(info);
00383
00384 if (!_Mute && !_SoundStopped && CParticleSystem::getSoundServer())
00385 {
00386 if ((rand() % 99) * 0.01f < _EmissionPercent)
00387 {
00388 uint32 index = _Sounds.insert(CParticleSystem::getSoundServer()->createSound(_SoundName, _SpawnSounds));
00389
00390
00391
00393 if (_Sounds[index])
00394 {
00395 const NLMISC::CMatrix &mat = getLocalToWorldMatrix();
00396 float pitch;
00397 if (_UseOriginalPitch)
00398 {
00399 pitch = _Sounds[index]->getPitch();
00400 }
00401 else
00402 {
00403 pitch = _PitchScheme ? _PitchScheme->get(getOwner(), 0) : _Pitch;
00404 }
00405 _Sounds[index]->setSoundParams(_GainScheme ? _GainScheme->get(getOwner(), 0) : _Gain,
00406 mat * _Owner->getPos()[index],
00407 _Owner->getSpeed()[index],
00408 pitch
00409 );
00410 _Sounds[index]->play();
00411 }
00412 }
00413 else
00414 {
00415 _Sounds.insert(NULL);
00416 }
00417 }
00418 else
00419 {
00420 _Sounds.insert(NULL);
00421 }
00422 }
00423
00424
00425 void CPSSound::deleteElement(uint32 index)
00426 {
00427 NL_PS_FUNC(CPSSound_deleteElement)
00428 if (_GainScheme && _GainScheme->hasMemory()) _GainScheme->deleteElement(index);
00429 if (_PitchScheme && _PitchScheme->hasMemory()) _PitchScheme->deleteElement(index);
00430 if (_Sounds[index])
00431 {
00432 _Sounds[index]->setLooping(false);
00433 _Sounds[index]->release();
00434 }
00435 _Sounds.remove(index);
00436 }
00437
00438
00439 void CPSSound::resize(uint32 size)
00440 {
00441 NL_PS_FUNC(CPSSound_resize)
00442 nlassert(size < (1 << 16));
00443 if (_GainScheme && _GainScheme->hasMemory()) _GainScheme->resize(size, getOwner()->getSize());
00444 if (_PitchScheme && _PitchScheme->hasMemory()) _PitchScheme->resize(size, getOwner()->getSize());
00445 if (size < _Sounds.getSize())
00446 {
00447
00448 for(uint k = size; k < _Sounds.getSize(); ++k)
00449 {
00450 if (_Sounds[k])
00451 {
00452 _Sounds[k]->setLooping(false);
00453 _Sounds[k]->release();
00454 }
00455 }
00456 }
00457 _Sounds.resize(size);
00458 }
00459
00460
00461 void CPSSound::setUseOriginalPitchFlag(bool useOriginalPitch)
00462 {
00463 NL_PS_FUNC(CPSSound_setUseOriginalPitchFlag)
00464 if (_PitchScheme)
00465 {
00466 delete _PitchScheme;
00467 _PitchScheme = NULL;
00468 }
00469 _UseOriginalPitch = useOriginalPitch;
00470 }
00471
00472
00473 }