ps_sound.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2000, 2001 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
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 // we batch computation of Gains and frequencies. Here is the buffer size:
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     //if (!_SoundStopped) return;
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     // delete all sounds, and rebuild them all
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             // delete all sounds, and rebuild them all
00134             removeAllSources();
00135             for (k = 0; k < (sint32) size; ++k)
00136             {
00137                 CPSEmitterInfo ei;
00138                 ei.setDefaults();
00139                 newElement(ei);
00140             }
00141         }
00142         // don't need to reupdate sound
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         // compute Gain
00165         currVol = _GainScheme ? (float *) _GainScheme->make(getOwner(), size - leftToDo, Gains, sizeof(float), toProcess, true)
00166                               : &_Gain;
00167         if (!_UseOriginalPitch)
00168         {
00169             // compute pitch
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) // was this sound instanciated?
00177                 {
00178                     (*it)->setSoundParams(*currVol,
00179                                           localToWorld * *posIt,
00180                                           localToWorld.mulVector(*speedIt),
00181                                           *currPitch);
00182                     if ((*it)->isLooping() && !(*it)->isPlaying())
00183                     {
00184                         // looping sources do not play when they are clipped, so "reminds" the source to play when possible.
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             // keep original pitch
00199             endIt = it + toProcess;
00200             const CMatrix &localToWorld = _Owner->getLocalToWorldMatrix();
00201             do
00202             {
00203                 if (*it) // was this sound instanciated?
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     // version 3 : added option to keep original pitch from the .sound
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); // we are very unlikely to save a system with sounds being played in it,
00288                             // but we need to keep datas coherency.
00289         if (_Owner)
00290         {
00291             _Sounds.resize(_Owner->getMaxSize());
00292         }
00293     }
00294     else
00295     {
00296         nbSounds = _Sounds.getSize(); // number of used sound
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     // save Gain infos
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     // serial pitch infos
00320     if (ver >= 3)
00321     {
00322         bool useOriginalPitch = _UseOriginalPitch;
00323         f.serial(useOriginalPitch);
00324         _UseOriginalPitch = useOriginalPitch;
00325         if (!_UseOriginalPitch)
00326         {
00327             // serialize pitch infos (no needed otherwise)
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         // insert blank sources
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     // if there's a sound server, we generate a new sound instance
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         // if vector size has been shrunk, must delete sounds instances
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 } // NL3D

Generated on Thu Jan 7 08:26:30 2010 for NeL by  doxygen 1.6.1