Add infos into target window
[ryzomcore.git] / ryzom / client / src / sound_manager.cpp
blob3253aedec9d6a2cb96580d582e6e595c9ba06667
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
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) 2012-2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
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/>.
22 #include "stdpch.h"
25 //////////////
26 // INCLUDES //
27 //////////////
28 // client
29 #include "sound_manager.h"
30 #include "pacs_client.h"
31 #include "light_cycle_manager.h"
32 #include "weather_manager_client.h"
33 #include "user_entity.h"
34 #include "entities.h"
35 #include "time_client.h"
36 #include "weather.h"
37 #include "global.h"
38 // game share
39 #include "game_share/cst_loader.h"
41 // If you compile using the nel distrib and you don't have the source, you must undef this symbol
42 #if !FINAL_VERSION
43 # define DEBUG_SOUND_IN_GAME
44 #endif
46 #if defined(DEBUG_SOUND_IN_GAME)
47 //sound
48 # include "nel/sound/clustered_sound.h"
49 # include "nel/sound/audio_mixer_user.h"
50 // 3d
51 # include "nel/3d/cluster.h"
52 # include "nel/3d/portal.h"
53 # include "nel/3d/dru.h"
54 # include "nel/3d/material.h"
55 # include "nel/3d/driver.h"
56 # include "nel/3d/driver_user.h"
57 # include "view.h"
58 #endif
60 #ifdef DEBUG_NEW
61 #define new DEBUG_NEW
62 #endif
64 extern CLightCycleManager LightCycleManager;
65 extern NL3D::UDriver *Driver;
66 extern NL3D::UCamera MainCam;
67 extern NLLIGO::CLigoConfig LigoConfig;
69 //////////////
70 // USING //
71 //////////////
72 using namespace NLMISC;
73 using namespace NLPACS;
74 using namespace NLSOUND;
75 using namespace std;
76 using namespace NL3D;
79 extern NL3D::UScene *Scene;
81 // The interpolation distance for the portals : 1 m
82 const float PORTAL_INTERPOLATE = 1.0f;
84 // Filter mapping
85 enum TFilterMapping
87 DAY = 0,
88 NIGHT = 1,
89 MORNING = 2,
90 DUSK = 3,
91 SPRING = 4,
92 SUMMER = 5,
93 AUTUMN = 6,
94 WINTER = 7,
95 MIST = 8,
96 FAIR1 = 9,
97 FAIR2 = 10,
98 FAIR3 = 11,
99 CLOUDS = 12,
100 RAIN1 = 13,
101 RAIN2 = 14,
102 SNOW1 = 15,
103 THUNDER1 = 16,
104 THUNDERSEVE1 = 17,
105 THUNDERSAND1 = 18,
106 THUNDERSAND2 = 19,
107 THUNDERSAND3 = 20,
108 BAD = 21,
109 GOOD = 22,
110 QUICK_MUTE = 23
113 //-----------------------------------------------
114 // constructor
115 //-----------------------------------------------
116 CSoundManager::CSoundManager(IProgressCallback * /* progressCallBack */)
117 : _AudioMixer(NULL),
118 _GroupControllerEffects(NULL),
119 _GroupControllerEffectsGame(NULL),
120 _EnvSoundRoot(NULL),
121 _Sources(NULL),
122 _UserEntitySoundLevel(1.0f)
124 _EnableBackgroundMusicAtTime= 0;
125 _GameMusicVolume= 1.f;
126 _UserMusicVolume= 1.f;
127 _FadeGameMusicVolume= 1.f;
128 _FadeSFXVolume= 1.f;
129 _UseGameMusicVolume= true;
130 _EventMusicEnabled= true;
131 _EventMusicLoop= false;
132 _FadeGameMusicVolumeDueToEvent= 1.f;
133 // init(progressCallBack);
134 } // CSoundManager
139 //-----------------------------------------------
140 // Destructor
141 //-----------------------------------------------
142 CSoundManager::~CSoundManager()
144 _Sources.clear();
146 _AttachedSources.clear(); // attached sources already deleted (they are also in the _Sources map)
148 // detach the sound from the particule system
149 NL3D::UParticleSystemSound::setPSSound(NULL);
151 _GroupControllerEffects = NULL;
152 _GroupControllerEffectsGame = NULL;
154 // free the audio mixer (and delete all sources)
155 delete _AudioMixer;
156 _AudioMixer = NULL;
158 // release sound anim properly
159 releaseSoundAnim();
161 } // ~CSoundManager //
164 // ***************************************************************************
165 void CSoundManager::releaseSoundAnim()
167 // Parse all Entities to reset their current sound id
168 EntitiesMngr.resetAllSoundAnimId();
170 // Parse all animation to reset their Id
171 if(EAM)
172 EAM->resetAllSoundAnimId();
174 // Delete the sound anim Singleton
175 CSoundAnimManager::release();
180 // ***************************************************************************
181 void CSoundManager::drawSounds(float camHeight)
183 #if defined(DEBUG_SOUND_IN_GAME)
184 // prepare the cameras for cluster display
185 // draw the cluster bounding box on screen
187 CMatrix newCam;
189 // get the user pos
190 CVector pos(View.viewPos());
191 pos += CVector(0,0,camHeight);
193 // get the view vector ?
194 CVector lookAt(View.view());
195 lookAt.z = 0;
196 lookAt.normalize();
199 if (lookAt.y <0)
200 newCam.rotateZ(float(Pi+/*-Pi/2+*/asin(lookAt.x)));
201 else
202 newCam.rotateZ(float(Pi+/*-Pi/2+*/Pi-asin(lookAt.x)));
204 newCam.rotateX(float(-Pi/2));
207 newCam.setPos(pos);
210 Driver->setMatrixMode3D(MainCam);
211 Driver->setViewMatrix(newCam.inverted());
212 Driver->clearZBuffer();
214 CMatrix model;
215 model.identity();
216 model.translate(-pos);
217 // model.rotateX(mapRX);
218 // model.rotateY(mapRY);
219 model.translate(pos);
222 Driver->setModelMatrix(model);
224 // UAudioMixer *amu = UAudioMixer::instance();
226 IDriver *idriver = static_cast<CDriverUser*>(Driver)->getDriver();
227 CClusteredSound *cs = static_cast<CAudioMixerUser*>(_AudioMixer)->getClusteredSound();
228 // Draw the audible clusters
230 CMaterial mat;
231 CMaterial mat2;
233 CClusteredSound::TClusterStatusMap::const_iterator first(cs->getAudibleClusters().begin()), last(cs->getAudibleClusters().end());
234 for (; first != last; ++first)
236 NL3D::CCluster *cluster = first->first;
238 const CAABBox &box = cluster->getBBox();
239 CVector center(box.getCenter());
240 CVector size(box.getHalfSize());
242 CVector a(center+size), b(center-size);
243 CVector s[8];
244 s[0].set(a.x, a.y, a.z);
245 s[1].set(a.x, b.y, a.z);
246 s[2].set(b.x, b.y, a.z);
247 s[3].set(b.x, a.y, a.z);
248 s[4].set(a.x, a.y, b.z);
249 s[5].set(a.x, b.y, b.z);
250 s[6].set(b.x, b.y, b.z);
251 s[7].set(b.x, a.y, b.z);
253 CLine lines[12] =
255 CLine(s[0], s[1]),
256 CLine(s[1], s[2]),
257 CLine(s[2], s[3]),
258 CLine(s[3], s[0]),
259 CLine(s[4], s[5]),
260 CLine(s[5], s[6]),
261 CLine(s[6], s[7]),
262 CLine(s[7], s[4]),
263 CLine(s[0], s[4]),
264 CLine(s[1], s[5]),
265 CLine(s[2], s[6]),
266 CLine(s[3], s[7]),
269 mat.setColor(CRGBA(255,0,0,255));
270 mat.setZFunc(CMaterial::less);
271 NL3D::CDRU::drawLinesUnlit(lines, 12, mat, *idriver);
272 mat.setColor(CRGBA(80,0,0,255));
273 mat.setZFunc(CMaterial::greater);
274 NL3D::CDRU::drawLinesUnlit(lines, 12, mat, *idriver);
277 mat2.setColor(CRGBA(0,0,255,50));
278 mat2.setZFunc(CMaterial:: always);
279 mat2.setSrcBlend(CMaterial::srcalpha);
280 mat2.setDstBlend(CMaterial::one);
281 mat2.setBlend(true);
282 mat.setColor(CRGBA(0,0,255,255));
283 mat.setZFunc(CMaterial::always);
285 // draw the portals
286 for (uint k = 0; k<cluster->getNbPortals(); ++k)
288 CPortal *portal = cluster->getPortal(k);
289 std::vector<NLMISC::CVector> poly;
290 portal->getPoly(poly);
292 if (poly.size() > 2)
294 for (uint i=1; i<poly.size()-1; ++i)
296 CTriangleUV tri;
297 tri.V0 = poly[0];
298 tri.V1 = poly[i];
299 tri.V2 = poly[i+1];
300 NL3D::CDRU::drawTrianglesUnlit(&tri, 1, mat2, *idriver);
301 tri.V0 = poly[0];
302 tri.V1 = poly[i+1];
303 tri.V2 = poly[i];
304 NL3D::CDRU::drawTrianglesUnlit(&tri, 1, mat2, *idriver);
309 for (uint i=0; i<poly.size(); ++i)
311 CLine line(poly[i], poly[(i+1)%poly.size()]);
313 NL3D::CDRU::drawLinesUnlit(&line, 1, mat, *idriver);
318 } // draw audible clusters
320 CMaterial mat;
321 mat.setColor(CRGBA(255,255,255,255));
323 /* float d = float(Pi/10);
324 for (float j=0; j<float(Pi*2); j+=d)
325 NL3D::CDRU::drawLine(pos+CVector(LISTEN_DISTANCE*float(sin(j)), LISTEN_DISTANCE*float(cos(j)), 0), pos+CVector(LISTEN_DISTANCE*float(sin(j+d)), LISTEN_DISTANCE*float(cos(j+d)),0), CRGBA(255,255,255,255), *idriver);
327 for (j=0; j<float(Pi*2); j+=d)
328 NL3D::CDRU::drawLine(pos+CVector(PORTAL_INTERPOLATE*float(sin(j)), PORTAL_INTERPOLATE*float(cos(j)), 0), pos+CVector(PORTAL_INTERPOLATE*float(sin(j+d)), PORTAL_INTERPOLATE*float(cos(j+d)),0), CRGBA(255,255,255,255), *idriver);
330 mat.setColor(CRGBA(0,255,0,255));
331 mat.setZFunc(CMaterial::always);
332 /* for (uint k=0; k<debugLines.size(); ++k)
334 // CDRU::drawLinesUnlit(debugLines, mat, *idriver);
335 NL3D::CDRU::drawLine(debugLines[k].V0, debugLines[k].V1, CRGBA(0,255,0,255), *idriver);
337 */ // Draw listener pos
338 mat.setColor(CRGBA(0,255,0,255));
340 NL3D::CDRU::drawLine(pos+CVector(2,2,0), pos+CVector(-2,-2,0), CRGBA(255,255,0,255), *idriver);
341 NL3D::CDRU::drawLine(pos+CVector(-2,2,0), pos+CVector(2,-2,0), CRGBA(255,255,0,255), *idriver);
343 // CVector front = Camera->getMatrix().getI();
344 // NL3D::CDRU::drawLine(pos, pos+front*4, CRGBA(255,255,0,255), *idriver);
346 // draw the virtual sound sound
348 CClusteredSound::TClusterStatusMap::const_iterator first(cs->getAudibleClusters().begin()), last(cs->getAudibleClusters().end());
349 for (; first != last; ++first )
351 const CClusteredSound::CClusterSoundStatus &css = first->second;
352 if (css.Direction != CVector::Null)
354 CVector dest = pos+css.Direction*css.Dist;
356 NL3D::CDRU::drawLine(pos, dest, CRGBA(0,255,255,255), *idriver);
357 NL3D::CDRU::drawLine(dest+CVector(0.5f,0.5f,0), dest+CVector(-0.5f,-0.5f,0), CRGBA(0, 255,255,255), *idriver);
358 NL3D::CDRU::drawLine(dest+CVector(-0.5f,0.5f,0), dest+CVector(0.5f,-0.5f,0), CRGBA(0, 255,255,255), *idriver);
362 // draw the audio path
364 idriver->setupMaterial(mat);
365 const std::vector<std::pair<NLMISC::CVector, NLMISC::CVector> > &lines = cs->getAudioPath();
366 std::vector<std::pair<NLMISC::CVector, NLMISC::CVector> >::const_iterator first(lines.begin()), last(lines.end());
367 for (; first != last; ++first)
369 NL3D::CDRU::drawLine(first->first, first->second, CRGBA(0,255,0,255), *idriver);
372 // draw the sound source position
374 std::vector<std::pair<bool, CVector> > soundPos;
375 _AudioMixer->getPlayingSoundsPos(true, soundPos);
377 std::vector<std::pair<bool, CVector> >::iterator first(soundPos.begin()), last(soundPos.end());
378 for (; first != last; ++first)
380 NL3D::CDRU::drawLine(first->second + CVector(0.5f,0.5f,0), first->second + CVector(-0.5f,-0.5f,0), CRGBA(255,0,255,255), *idriver);
381 NL3D::CDRU::drawLine(first->second + CVector(0.5f,-0.5f,0), first->second + CVector(-0.5f,0.5f,0), CRGBA(255,0,255,255), *idriver);
385 #endif // DEBUG_SOUND_IN_GAME
390 UAudioMixer *CSoundManager::getMixer()
392 return _AudioMixer;
396 void CSoundManager::switchSoundState ()
398 _PlaySound = !_PlaySound;
399 _AudioMixer->enable(_PlaySound);
402 void CSoundManager::loadContinent(const string &name, const NLMISC::CVector& pos)
404 if (!_AudioMixer)
405 return;
407 // load already stop all sound and unload them before loading new one
408 _AudioMixer->loadBackgroundSound (name, LigoConfig);
409 _AudioMixer->setListenerPos(pos);
413 void CSoundManager::reset ()
415 if (!_AudioMixer)
416 return;
418 NL3D::UParticleSystemSound::setPSSound(NULL);
420 _GroupControllerEffects = NULL;
421 _GroupControllerEffectsGame = NULL;
423 delete _AudioMixer;
424 _AudioMixer = NULL;
426 // release sound anim properly
427 releaseSoundAnim();
429 init();
431 // _AudioMixer->reset ();
435 //---------------------------------------------------
436 // init :
437 // Initialize the audio mixer, load the sound banks
438 //---------------------------------------------------
439 void CSoundManager::init(IProgressCallback *progressCallBack)
441 _EnvSoundRoot = NULL;
442 _PlaySound = true;
444 _UserEntitySoundLevel = ClientCfg.UserEntitySoundLevel;
446 const std::string &packedSheetPath = ClientCfg.SoundPackedSheetPath;
447 const std::string &samplePath = ClientCfg.SampleBankDir;
448 // try
449 // {
450 // reset particle sound
451 NL3D::UParticleSystemSound::setPSSound(NULL);
453 * Create the audio mixer object and init it.
454 * If the sound driver cannot be loaded, an exception is thrown.
456 _AudioMixer = UAudioMixer::createAudioMixer();
458 if (!_AudioMixer)
459 return;
461 // Set the path to the sample directory
462 _AudioMixer->setSamplePath(samplePath);
463 // Set the path to the packed sheets
465 if (ClientCfg.UpdatePackedSheet)
466 _AudioMixer->setPackedSheetOption(packedSheetPath, true);
467 else
468 _AudioMixer->setPackedSheetOption("", false);
470 UAudioMixer::TDriver driverType= UAudioMixer::DriverAuto;
471 if(ClientCfg.DriverSound==CClientConfig::SoundDrvOpenAL)
472 driverType= UAudioMixer::DriverOpenAl;
473 else if(ClientCfg.DriverSound==CClientConfig::SoundDrvDirectSound)
474 driverType= UAudioMixer::DriverDSound;
475 else if(ClientCfg.DriverSound==CClientConfig::SoundDrvXAudio2)
476 driverType= UAudioMixer::DriverXAudio2;
477 _AudioMixer->init(ClientCfg.MaxTrack, ClientCfg.UseEax, ClientCfg.UseADPCM, progressCallBack, false, driverType, ClientCfg.SoundForceSoftwareBuffer);
478 /* int nbVoice = _AudioMixer->getPolyphony();
479 _AudioMixer->setPriorityReserve(HighPri, max(1, nbVoice /2));
480 nbVoice -= nbVoice /2;
481 _AudioMixer->setPriorityReserve(MidPri, max(1, nbVoice /2));
482 nbVoice -= nbVoice /2;
483 _AudioMixer->setPriorityReserve(LowPri, max(1, nbVoice /2));
485 // when they are only 1 track available, enter in limiting mode.
486 _AudioMixer->setLowWaterMark(1);
489 * Create the CSoundAnimManager. The CSoundAnimManager is a singleton.
490 * Access the singleton with CSoundAnimManager::instance().
492 new CSoundAnimManager(_AudioMixer);
494 // get the controller group for effects
495 _GroupControllerEffects = _AudioMixer->getGroupController("sound:effects");
496 _GroupControllerEffectsGame = _AudioMixer->getGroupController("sound:effects:game");
498 // restore the volume
499 SoundMngr->setSFXVolume(ClientCfg.SoundSFXVolume);
500 SoundMngr->setGameMusicVolume(ClientCfg.SoundGameMusicVolume);
502 // Init clustered sound system
503 _AudioMixer->initClusteredSound(Scene, 0.01f, 100.0f, PORTAL_INTERPOLATE);
505 // Init the background flags;
506 for (uint i=0; i<NLSOUND::UAudioMixer::TBackgroundFlags::NB_BACKGROUND_FLAGS; ++i)
507 _BackgroundFlags.Flags[i] = false;
508 _AudioMixer->setBackgroundFlags(_BackgroundFlags);
511 * Initialize listener's position
513 CVector initpos ( 0.0f, 0.0f, 0.0f );
514 //_AudioMixer->getListener()->setPos( initpos );
515 _AudioMixer->setListenerPos(initpos);
518 * Init the particule sound system
520 // attach the sound from the particule system
521 NL3D::UParticleSystemSound::setPSSound(_AudioMixer);
523 //loadPositionedSounds();
525 // reload Sound Animation (if EAM already init)
526 if(EAM)
527 EAM->reloadAllSoundAnim();
529 // Special option for DEV (easier to test when disabled)
530 _AudioMixer->enableBackgroundMusicTimeConstraint(ClientCfg.EnableBackgroundMusicTimeConstraint);
532 /* }
533 catch(const Exception &e)
535 nlwarning( "Error: %s", e.what() );
538 } // init //
540 //---------------------------------------------------
541 // getSoundName:
542 //---------------------------------------------------
543 /*bool CSoundManager::getSoundName( TSound sound, std::string &name, const CVector& pos ) const
545 /// \todo Malkav: take ground type into account, and all the different sounds
546 switch (sound)
548 case WALK:
550 //name = "walk";
551 UGlobalPosition globalPos = GR->retrievePosition( pos );
552 uint32 material = GR->getMaterial( globalPos );
555 break;
557 case RUN:
558 name = "run";
559 break;
561 case USER_WALK:
562 name = "user_walk";
563 break;
565 case USER_RUN:
566 name = "user_run";
567 break;
569 default:
570 return false;
573 return true;
575 } // getSoundName //
580 //---------------------------------------------------
581 // addSource :
582 // add a new source to the world, attached to the specified entity
583 // return 0 if creation failed, sound id if creation was successful
584 //---------------------------------------------------
585 /*uint32 CSoundManager::addSource( TSound sound, const NLMISC::CVector &position, bool play, bool loop, const CEntityId &parentId )
587 static std::string name;
588 static TSource source;
590 uint32 retValue = 0;
592 if ( ! getSoundName ( sound, name, position ) )
593 return 0;
595 USource *pSource = _AudioMixer->createSource( name );
597 if ( pSource != NULL )
599 pSource ->setPos( position );
601 pSource ->setLooping( loop );
603 if (play)
604 pSource ->play();
606 //create the TSource object
607 source.sound = sound;
608 source.pSource = pSource;
610 // attach the source to the entity, if specified
611 if (parentId != CEntityId::Unknown)
612 _AttachedSources.insert( TMultiMapEntityToSource::value_type( parentId, source ) );
614 // set source id
615 retValue = _NextId;
616 _Sources.insert( TMapIdToSource::value_type( _NextId, source ) );
617 ++_NextId;
619 else
621 nlwarning( "Sound '%s' not found", name );
624 return retValue;
625 } // addSource //
628 //-----------------------------------------------
629 // addSource :
630 // add a new source to the world, attached to the specified entity
631 // return 0 if creation failed, sound id if creation was successful
632 //-----------------------------------------------
633 CSoundManager::TSourceId CSoundManager::addSource(const NLMISC::TStringId &soundName, const NLMISC::CVector &position, bool play, bool loop, const CEntityId &id)
635 uint32 retValue = 0;
637 // Create a source
638 USource *pSource = _AudioMixer->createSource(soundName);
640 // If the source is valid.
641 if(pSource == 0)
643 nlwarning("Sound '%s' not found !", CStringMapper::unmap(soundName).c_str());
644 return retValue;
647 // Load the properties for this sound.
648 // REMOVED because the pitch and the gain are now in the .nss (don't need .sdf anymore)
649 // loadProperties(soundName, pSource);
651 // Set the source position.
652 pSource->setPos( position );
654 // Is the source looping ?
655 pSource->setLooping( loop );
657 // Play the sound immedialty if asked.
658 if(play)
660 pSource->play();
663 TSourceId sourceId = _Sources.insert(pSource);
665 // attach the source to the entity, if specified
666 if (id != CEntityId::Unknown )
668 _AttachedSources.insert( TMultiMapEntityToSource::value_type( id, sourceId ) );
671 // return the id of the source
672 return sourceId;
674 } // addSource //
677 //-----------------------------------------------
678 // spawn a new source to the world
679 // return false if creation failed, true if creation was successful
680 //-----------------------------------------------
681 bool CSoundManager::spawnSource(const NLMISC::TStringId &soundName, CSoundContext &context)
683 if (!_PlaySound) return false;
685 // Create a source
686 // TODO : find the correct cluster
687 USource *pSource = _AudioMixer->createSource( soundName, true, NULL, NULL, NULL, &context);
689 // If the source is valid.
690 if(pSource == 0)
692 nlwarning("Sound '%s' not found !", soundName);
693 return false;
696 // Set the source position.
697 pSource->setPos (context.Position);
698 pSource->play();
700 ////nlinfo ("%.3f spawn source %p", (float)ryzomGetLocalTime ()/1000.0f, pSource);
702 return true;
704 } // addSource //
707 //-----------------------------------------------
708 // spawn a new source to the world
709 // return false if creation failed, true if creation was successful
710 //-----------------------------------------------
711 bool CSoundManager::spawnSource(const NLMISC::TStringId &soundName, const NLMISC::CVector &position)
713 if (!_PlaySound) return false;
715 // Create a source
716 USource *pSource = _AudioMixer->createSource( soundName, true);
718 // If the source is valid.
719 if(pSource == 0)
721 nlwarning("Sound '%s' not found !", CStringMapper::unmap(soundName).c_str ());
722 return false;
725 // Set the source position.
726 pSource->setPos (position);
727 pSource->play();
729 ////nlinfo ("%.3f spawn source %p", (float)ryzomGetLocalTime ()/1000.0f, pSource);
731 return true;
733 } // addSource //
737 //---------------------------------------------------
738 // removeSource:
739 // remove a source
740 //---------------------------------------------------
741 void CSoundManager::removeSource(CSoundManager::TSourceId sourceId)
743 nldebug("remove the source : %d", sourceId);
745 /// \todo Malkav : optimize speed
746 nldebug("nb sources = %d", _Sources.size() );
747 USource *pSource = _Sources.get(sourceId);
748 if (pSource)
750 TMultiMapEntityToSource::iterator it = _AttachedSources.begin();//, itOld;
752 for ( ; it != _AttachedSources.end() ; ++it)
754 if ( (*it).second == sourceId )
756 (*it).second = 0;
757 // itOld = it;
758 // ++it;
760 _AttachedSources.erase( it/*Old*/ );
762 break;
764 // if (it == _AttachedSources.end() )
765 // break;
769 // delete the source
770 delete pSource;
771 // i think there was something going on here
772 _Sources.erase(sourceId);
774 } // removeSource //
778 //---------------------------------------------------
779 // getSounds :
781 //---------------------------------------------------
782 /*bool CSoundManager::getSounds( uint32 material, TMoveType moveType, bool soft, std::vector<string>& sounds )
784 return _StepSounds.getSounds( material, moveType, soft, sounds );
786 } // getSounds //*/
790 //---------------------------------------------------
791 // updateEntityPos :
792 // update the pos of all the sounds attached to that entity
793 //---------------------------------------------------
794 void CSoundManager::updateEntityPos( const CEntityId &id, const NLMISC::CVector &pos)
796 TMultiMapEntityToSource::iterator it;
797 const std::pair<TMultiMapEntityToSource::iterator, TMultiMapEntityToSource::iterator> range = _AttachedSources.equal_range( id );
799 for ( it = range.first; it != range.second ; ++it)
801 _Sources.get((*it).second)->setPos( pos );
803 } // updateEntityPos //
806 //---------------------------------------------------
807 // updateEntityVelocity :
808 // update the velocity of all the sounds attached to that entity
809 //---------------------------------------------------
810 void CSoundManager::updateEntityVelocity( const CEntityId &id, const NLMISC::CVector &velocity)
812 TMultiMapEntityToSource::iterator it;
813 const std::pair<TMultiMapEntityToSource::iterator, TMultiMapEntityToSource::iterator> range = _AttachedSources.equal_range( id );
815 for ( it = range.first; it != range.second ; ++it)
817 _Sources.get((*it).second)->setVelocity( velocity );
820 } // updateEntityVelocity //
823 //---------------------------------------------------
824 // updateEntityDirection :
825 // update the direction of all the sounds attached to that entity
826 //---------------------------------------------------
827 void CSoundManager::updateEntityDirection( const CEntityId &id, const NLMISC::CVector &dir )
829 TMultiMapEntityToSource::iterator it;
830 const std::pair<TMultiMapEntityToSource::iterator, TMultiMapEntityToSource::iterator> range = _AttachedSources.equal_range( id );
832 for ( it = range.first; it != range.second ; ++it)
834 _Sources.get((*it).second)->setDirection( dir );
836 } // updateEntityOrientation //
839 //---------------------------------------------------
840 // removeEntity :
841 // remove an entity from the view : delete all the sources attached to that entity
842 //---------------------------------------------------
843 void CSoundManager::removeEntity( const CEntityId &id)
845 /// \todo Malkav : optimize speed
847 TMultiMapEntityToSource::iterator it;
848 const std::pair<TMultiMapEntityToSource::iterator, TMultiMapEntityToSource::iterator> range = _AttachedSources.equal_range( id );
850 for ( it = range.first; it != range.second ; ++it)
852 TSourceId sourceId = (*it).second;
853 if (sourceId)
855 USource *pSource = _Sources.get(sourceId);
856 delete pSource;
857 _Sources.erase(sourceId);
861 _AttachedSources.erase( range.first, range.second );
862 } // removeEntity //
867 //---------------------------------------------------
868 // setSoundPosition :
869 //---------------------------------------------------
870 void CSoundManager::setSoundPosition(TSourceId sourceId, const NLMISC::CVector &position)
872 if (!_PlaySound) return;
874 USource *pSource = _Sources.get(sourceId);
875 if (pSource) pSource->setPos(position);
876 } // setSoundPosition //
879 //---------------------------------------------------
880 // loopSound :
881 //---------------------------------------------------
882 void CSoundManager::loopSound(TSourceId sourceId, bool loop)
884 if (!_PlaySound) return;
886 USource *pSource = _Sources.get(sourceId);
887 if (pSource) pSource->setLooping(loop);
888 } // loopSound //
891 //---------------------------------------------------
892 // playSound :
893 // start or stop playing sound
894 //---------------------------------------------------
895 void CSoundManager::playSound(TSourceId sourceId, bool play)
897 if (!_PlaySound) return;
899 USource *pSource = _Sources.get(sourceId);
900 if (pSource)
902 if (play)
903 pSource->play();
904 else
905 pSource->stop();
907 } // loopSound //
911 //---------------------------------------------------
912 // isPlaying :
913 // return true if the source is playing
914 //---------------------------------------------------
915 bool CSoundManager::isPlaying(TSourceId sourceId)
917 USource *pSource = _Sources.get(sourceId);
918 if (pSource) return pSource->isPlaying();
919 return false;
920 } // isPlaying //
924 //---------------------------------------------------
925 // setSoundForSource :
926 // set the sound associated to the specified source
927 //---------------------------------------------------
929 bool CSoundManager::setSoundForSource( uint32 sourceId, TSound sound, const CVector& pos )
931 // find the sound name
932 static std::string soundName;
933 soundName.clear();
934 if ( ! getSoundName( sound , soundName, pos) )
935 return false;
937 TMapIdToSource::iterator it = _Sources.find( sourceId );
938 if (it != _Sources.end() )
940 nlassert( (*it).second.pSource );
942 // get the sound
943 TSoundId soundId = _AudioMixer->getSoundId( soundName.c_str() );
945 if (soundId != NULL)
947 (*it).second.pSource->setSound( soundId );
948 (*it).second.sound = sound;
949 nlinfo("sound has been set to %d",sound);
950 return true;
953 return false;
954 } // setSoundForSource //
959 //---------------------------------------------------
960 // getSoundFromSource :
961 // get the sound type currently associated to a source
962 //---------------------------------------------------
963 /*CSoundManager::TSound CSoundManager::getSoundFromSource( uint32 sourceId ) const
965 TMapIdToSource::const_iterator it = _Sources.find( sourceId );
966 if (it != _Sources.end() )
968 nlassert( (*it).second.pSource );
970 return ( (*it).second.sound );
973 return NONE;
974 } // getSoundFromSource //
978 //---------------------------------------------------
979 // setSourceGain :
980 // set the gain of the specified source
981 //---------------------------------------------------
982 void CSoundManager::setSourceGain(TSourceId sourceId, float gain)
984 USource *pSource = _Sources.get(sourceId);
985 if (pSource) pSource->setGain( gain );
986 } // setSourceGain //
989 //---------------------------------------------------
990 // getSourceGain :
991 // get the gain of the specified source (-1 if source not found)
992 //---------------------------------------------------
993 float CSoundManager::getSourceGain(TSourceId sourceId)
995 USource *pSource = _Sources.get(sourceId);
996 if (pSource) return pSource->getGain();
997 return -1;
998 } // getSourceGain //
1001 //---------------------------------------------------
1002 // setSourcePitch :
1003 // set the Pitch of the specified source
1004 //---------------------------------------------------
1005 void CSoundManager::setSourcePitch(TSourceId sourceId, float Pitch)
1007 USource *pSource = _Sources.get(sourceId);
1008 if (pSource) pSource->setPitch(Pitch);
1009 } // setSourcePitch //
1012 //---------------------------------------------------
1013 // getSourcePitch :
1014 // get the Pitch of the specified source (-1 if source not found)
1015 //---------------------------------------------------
1016 float CSoundManager::getSourcePitch(TSourceId sourceId)
1018 USource *pSource = _Sources.get(sourceId);
1019 if (pSource) return pSource->getPitch();
1020 return -1;
1021 } // getSourcePitch //
1025 //---------------------------------------------------
1026 // loadProperties :
1027 // Load the properties for this sound and apply them.
1028 //---------------------------------------------------
1029 void CSoundManager::loadProperties(const string &soundName, USource *source)
1031 // If the source does not exist -> return nothing to do.
1032 if(!source)
1033 return;
1035 // Search for the file.
1036 string filePath = CPath::lookup(soundName+".sdf");
1038 CIFile file;
1040 // Try to open the file.
1041 if (file.open(filePath))
1043 char tmpBuff[260];
1044 char delimiterBox[] = "\t ";
1045 // While the end of the file is not reached.
1046 while(!file.eof())
1048 // Get a line (the line should not be more than _MAX_LINE_SIZE).
1049 file.getline(tmpBuff, 260);
1050 char *token = strtok(tmpBuff, delimiterBox);
1051 while(token != NULL)
1053 // Get the pitch.
1054 if(strcmp(token, "Pitch:") == 0)
1056 token = strtok(NULL, delimiterBox);
1057 if(token)
1059 float pitch;
1060 fromString(token, pitch);
1061 nlinfo("Pitch: %f", pitch);
1062 source->setPitch(pitch);
1065 // Get the Gain.
1066 else if(strcmp(token, "Gain:") == 0)
1068 token = strtok(NULL, delimiterBox);
1069 if(token)
1071 float gain;
1072 fromString(token, gain);
1073 nlinfo("Gain: %f", gain);
1074 source->setGain(gain);
1078 // Next property.
1079 token = strtok(NULL, delimiterBox);
1082 // Close the file.
1083 file.close();
1085 }// loadProperties //
1090 //---------------------------------------------------
1091 // loadPositionedSounds :
1093 //---------------------------------------------------
1094 /*void CSoundManager::loadPositionedSounds()
1096 nlstopex(("class CStepSounds is not used anymore"));
1097 // cst loader
1098 CSTLoader cstl;
1100 // build file format
1101 map<string,CSTLoader::TDataType> fileFormat;
1102 fileFormat.insert( make_pair( string( "sound name" ) , CSTLoader::STRING ));
1103 fileFormat.insert( make_pair( string( "x" ) , CSTLoader::FLOAT ));
1104 fileFormat.insert( make_pair( string( "y" ) , CSTLoader::FLOAT ));
1105 fileFormat.insert( make_pair( string( "z" ) , CSTLoader::FLOAT ));
1106 fileFormat.insert( make_pair( string( "loop" ) , CSTLoader::BOOL ));
1109 string str = CPath::lookup("positioned_sounds.txt", false);
1110 if(str.empty())
1112 nlwarning ("cant load positioned_sounds");
1113 return;
1116 // init loader
1117 cstl.init( str, fileFormat );
1119 // read the file
1120 while( cstl.readLine() )
1122 string soundName;
1123 cstl.getStringValue( "sound name", soundName );
1125 CVector sourcePos;
1126 cstl.getValue( "x", sourcePos.x );
1127 cstl.getValue( "y", sourcePos.y );
1128 cstl.getValue( "z", sourcePos.z );
1130 bool loop;
1131 cstl.getBoolValue( "loop", loop );
1133 uint32 sourceId = addSource( soundName, sourcePos, false , loop );
1135 if(sourceId != 0)
1137 _PositionedSounds.push_back( sourceId );
1139 else
1141 nlwarning ("positioned sound: can't find sound: '%s'", soundName.c_str());
1145 cstl.close();
1147 } // chooseSoundOnMaterial //
1151 //---------------------------------------------------
1152 // playPositionedSounds :
1154 //---------------------------------------------------
1155 void CSoundManager::playPositionedSounds( const CVector& /* pos */ )
1157 if (!_PlaySound) return;
1159 list<uint32>::iterator itPSnd;
1160 for( itPSnd = _PositionedSounds.begin(); itPSnd != _PositionedSounds.end(); ++itPSnd )
1162 USource *pSource = _Sources.get(*itPSnd);
1163 if (!pSource)
1165 nlwarning("<CSoundManager::playPositionedSounds> : The source %d is unknown",*itPSnd);
1167 else
1170 if( (pos - (*itSrc).second.getPos()).norm() < ...)
1172 if( (*itSrc).second.pSource->isPlaying() == false )
1174 (*itSrc).second.pSource->play();
1178 if (!pSource->isPlaying())
1180 pSource->play();
1185 } // playPositionedSounds //
1188 void CSoundManager::selectEnv( const std::string &/* tag */)
1190 // TODO : boris : temporarily removed.
1191 /* if (_EnvSoundRoot==NULL)
1192 return;
1194 _EnvSoundRoot->selectEnv (tag.c_str(), true);
1198 void CSoundManager::setFilterState(uint filterId, bool state)
1200 nlassert(filterId < NLSOUND::UAudioMixer::TBackgroundFlags::NB_BACKGROUND_FLAGS);
1201 _BackgroundFlags.Flags[filterId] = state;
1203 _AudioMixer->setBackgroundFlags(_BackgroundFlags);
1208 // ***************************************************************************
1209 void CSoundManager::update ()
1211 // Filters : day = 0, night = 1, morning = 2, Dusk = 3
1212 // update the filter state for day/night management.
1213 switch(LightCycleManager.getState())
1215 case CLightCycleManager::Day:
1216 _BackgroundFlags.Flags[DAY] = true;
1217 _BackgroundFlags.Flags[NIGHT] = false;
1218 _BackgroundFlags.Flags[MORNING] = false;
1219 _BackgroundFlags.Flags[DUSK] = false;
1220 break;
1221 case CLightCycleManager::Night:
1222 _BackgroundFlags.Flags[DAY] = false;
1223 _BackgroundFlags.Flags[NIGHT] = true;
1224 _BackgroundFlags.Flags[MORNING] = false;
1225 _BackgroundFlags.Flags[DUSK] = false;
1226 break;
1227 case CLightCycleManager::DayToNight:
1228 _BackgroundFlags.Flags[DAY] = true;
1229 _BackgroundFlags.Flags[NIGHT] = false;
1230 _BackgroundFlags.Flags[MORNING] = true;
1231 _BackgroundFlags.Flags[DUSK] = false;
1232 break;
1233 case CLightCycleManager::NightToDay:
1234 _BackgroundFlags.Flags[DAY] = false;
1235 _BackgroundFlags.Flags[NIGHT] = false;
1236 _BackgroundFlags.Flags[MORNING] = false;
1237 _BackgroundFlags.Flags[DUSK] = true;
1238 break;
1239 case CLightCycleManager::StateUnknown:
1240 //nlwarning("Unknown light cycle state reached.");
1241 break;
1244 // update the filter for season.
1245 EGSPD::CSeason::TSeason season = CurrSeason;
1246 switch(season)
1248 case EGSPD::CSeason::Spring:
1249 _BackgroundFlags.Flags[SPRING] = true;
1250 _BackgroundFlags.Flags[SUMMER] = false;
1251 _BackgroundFlags.Flags[AUTUMN] = false;
1252 _BackgroundFlags.Flags[WINTER] = false;
1253 break;
1254 case EGSPD::CSeason::Summer:
1255 _BackgroundFlags.Flags[SPRING] = false;
1256 _BackgroundFlags.Flags[SUMMER] = true;
1257 _BackgroundFlags.Flags[AUTUMN] = false;
1258 _BackgroundFlags.Flags[WINTER] = false;
1259 break;
1260 case EGSPD::CSeason::Autumn:
1261 _BackgroundFlags.Flags[SPRING] = false;
1262 _BackgroundFlags.Flags[SUMMER] = false;
1263 _BackgroundFlags.Flags[AUTUMN] = true;
1264 _BackgroundFlags.Flags[WINTER] = false;
1265 break;
1266 case EGSPD::CSeason::Winter:
1267 _BackgroundFlags.Flags[SPRING] = false;
1268 _BackgroundFlags.Flags[SUMMER] = false;
1269 _BackgroundFlags.Flags[AUTUMN] = false;
1270 _BackgroundFlags.Flags[WINTER] = true;
1271 break;
1272 default:
1273 //nlwarning("Updating unknown season.");
1274 break;
1276 // TODO : update the filter state for weather effet
1277 CWeatherState weatherState = WeatherManager.getCurrWeatherState();
1281 enum TWeatherSoundEnv
1283 WSEMist = 0, // not used
1284 WSEFair1,
1285 WSEFair2,
1286 WSEFair3,
1287 WSEClouds,
1288 WSERain1,
1289 WSERain2,
1290 WSESnow1,
1291 WSEThunder1,
1292 WSEThunderSeve,
1293 WSEThunderSand1, // not used
1294 WSEThunderSand2, // not used
1295 WSEThunderSand3, // not used
1296 WSECount
1299 // For each weather setup, gives the matching weather sound env to used, when there are precipitation or not
1300 class CWeatherSetupSoundEnv
1302 public:
1303 NLMISC::TStringId SetupName; // setup nem as found is the .weather_setup sheets
1304 TWeatherSoundEnv Sound;
1305 CWeatherSetupSoundEnv(const char *setupName, TWeatherSoundEnv sound)
1307 SetupName = NLMISC::CStringMapper::map(setupName);
1308 Sound = sound;
1312 // association between weather setup names & sound env
1313 static const CWeatherSetupSoundEnv weatherSoundLUT[] =
1315 CWeatherSetupSoundEnv("fair1", WSEFair1),
1316 CWeatherSetupSoundEnv("fair2", WSEFair2),
1317 CWeatherSetupSoundEnv("fair3", WSEFair3),
1318 CWeatherSetupSoundEnv("wind1", WSEClouds),
1319 CWeatherSetupSoundEnv("humidity1", WSERain1),
1320 CWeatherSetupSoundEnv("humidity2", WSERain2),
1321 CWeatherSetupSoundEnv("clouds1", WSERain1),
1322 CWeatherSetupSoundEnv("clouds2", WSERain2),
1323 CWeatherSetupSoundEnv("thunderseve", WSEThunderSeve),
1324 CWeatherSetupSoundEnv("storm", WSEThunder1),
1325 CWeatherSetupSoundEnv("snow", WSESnow1),
1328 const CWeatherSetupSoundEnv *weatherSetupSoundEnv = NULL;
1329 for(uint k = 0; k < sizeof(weatherSoundLUT) / sizeof(weatherSoundLUT[0]); ++k)
1331 if (weatherSoundLUT[k].SetupName == weatherState.BestSetupName)
1333 weatherSetupSoundEnv = &weatherSoundLUT[k];
1334 break;
1338 // disable all weather setup sound flags except the current one
1339 for(uint k = 0; k < WSECount; ++k)
1341 _BackgroundFlags.Flags[MIST+k] = false;
1343 if (weatherSetupSoundEnv)
1345 _BackgroundFlags.Flags[MIST + weatherSetupSoundEnv->Sound] = true;
1347 else
1349 static bool bDisplayOnce = false;
1350 if (!bDisplayOnce)
1352 nlinfo("The current weather setup '%s' is unknown !", CStringMapper::unmap(weatherState.BestSetupName).c_str());
1353 bDisplayOnce = true;
1357 // update the background flags in the mixer.
1358 _AudioMixer->setBackgroundFlags(_BackgroundFlags);
1360 // update background music enabling
1361 if(_EnableBackgroundMusicAtTime && CTime::getLocalTime()>_EnableBackgroundMusicAtTime)
1363 setGameMusicMode(true, true);
1366 // Special option for DEV (easier to test when disabled)
1367 _AudioMixer->enableBackgroundMusicTimeConstraint(ClientCfg.EnableBackgroundMusicTimeConstraint);
1369 // update game music volume because of event played or not
1370 updateEventAndGameMusicVolume();
1372 // update audio mixer
1373 _AudioMixer->update ();
1376 // ***************************************************************************
1377 void CSoundManager::updateAudioMixerOnly()
1379 if(!_AudioMixer)
1380 return;
1381 _AudioMixer->update ();
1384 // ***************************************************************************
1385 void CSoundManager::playBackgroundSound()
1387 _AudioMixer->playBackgroundSound();
1390 // ***************************************************************************
1391 void CSoundManager::stopBackgroundSound()
1393 _AudioMixer->stopBackgroundSound();
1396 // ***************************************************************************
1397 void CSoundManager::playMusic(const string &fileName, uint xFadeTime, bool async, bool loop, bool forceGameMusicVolume)
1399 if(fileName.empty())
1401 stopMusic(xFadeTime);
1403 else
1405 if(_AudioMixer)
1407 // disable before the background music (before is important else may have bug)
1408 setGameMusicMode(false, forceGameMusicVolume);
1409 // play
1410 _AudioMixer->playMusic(fileName, xFadeTime, async, loop);
1415 // ***************************************************************************
1416 void CSoundManager::stopMusic(uint xFadeTime)
1418 if(_AudioMixer)
1420 // stop the music
1421 _AudioMixer->stopMusic(xFadeTime);
1422 // and reenable the background music system. after a delay if xFadeTime
1423 if(xFadeTime>0)
1425 // enable background music later
1426 _EnableBackgroundMusicAtTime= CTime::getLocalTime()+xFadeTime;
1428 else
1430 // else enable now
1431 setGameMusicMode(true, true);
1436 // ***************************************************************************
1437 void CSoundManager::playEventMusic(const string &fileName, uint xFadeTime, bool loop)
1439 // if event music not enabled (mp3 player), abort
1440 if(!_EventMusicEnabled)
1441 return;
1443 if(fileName.empty())
1445 stopEventMusic("", xFadeTime);
1447 else
1449 if(_AudioMixer)
1451 // if the music is not already currently playing (with same loop state)
1452 if(_EventMusicPlayed.empty() || nlstricmp(fileName, _EventMusicPlayed)!=0 || loop!=_EventMusicLoop)
1454 // play
1455 _AudioMixer->playEventMusic(fileName, xFadeTime, true, loop);
1456 _EventMusicPlayed= fileName;
1457 _EventMusicLoop= loop;
1463 // ***************************************************************************
1464 void CSoundManager::stopEventMusic(const string &fileName, uint xFadeTime)
1466 if(_AudioMixer)
1468 // if the event music is the one currently played, or if empty fileName
1469 if(fileName.empty() || nlstricmp(_EventMusicPlayed,fileName)==0)
1471 // stop the music
1472 _AudioMixer->stopEventMusic(xFadeTime);
1473 // music no more played
1474 _EventMusicPlayed.clear();
1479 // ***************************************************************************
1480 void CSoundManager::pauseMusic()
1482 if(_AudioMixer)
1483 _AudioMixer->pauseMusic();
1486 // ***************************************************************************
1487 void CSoundManager::resumeMusic()
1489 if(_AudioMixer)
1490 _AudioMixer->resumeMusic();
1493 // ***************************************************************************
1494 bool CSoundManager::isMusicEnded()
1496 if(_AudioMixer)
1497 return _AudioMixer->isMusicEnded();
1498 return false;
1501 // ***************************************************************************
1502 void CSoundManager::setGameMusicVolume(float val)
1504 clamp(val,0.f,1.f);
1505 _GameMusicVolume= val;
1506 updateVolume();
1509 // ***************************************************************************
1510 void CSoundManager::setUserMusicVolume(float val)
1512 clamp(val,0.f,1.f);
1513 _UserMusicVolume= val;
1514 updateVolume();
1517 // ***************************************************************************
1518 void CSoundManager::setSFXVolume(float val)
1520 clamp(val,0.f,1.f);
1521 _SFXVolume= val;
1522 updateVolume();
1525 // ***************************************************************************
1526 void CSoundManager::setGameMusicMode(bool enableBackground, bool useGameMusicVolume)
1528 // update background music state
1529 _EnableBackgroundMusicAtTime= 0;
1530 _AudioMixer->enableBackgroundMusic(enableBackground);
1531 _UseGameMusicVolume= useGameMusicVolume;
1532 // event music enabled if the background music is also enabled
1533 _EventMusicEnabled= enableBackground;
1534 // stop any event music if disabled
1535 if(!_EventMusicEnabled)
1536 stopEventMusic("", 500);
1537 // update music volume state
1538 updateVolume();
1541 // ***************************************************************************
1542 void CSoundManager::updateVolume()
1544 if(_AudioMixer)
1546 // update music volume
1547 if(_UseGameMusicVolume)
1548 // Game music (background music system)
1549 _AudioMixer->setMusicVolume(_GameMusicVolume*_FadeGameMusicVolume*_FadeGameMusicVolumeDueToEvent);
1550 else
1551 // User music volume (mp3 player) is not affected by fadein/fadeout
1552 _AudioMixer->setMusicVolume(_UserMusicVolume);
1554 // The event music volume get the game music volume, but is not faded (want music during teleport)
1555 _AudioMixer->setEventMusicVolume(_GameMusicVolume);
1557 // update sfx volume
1558 _GroupControllerEffects->setGain(_SFXVolume);
1559 _GroupControllerEffectsGame->setGain(_FadeSFXVolume);
1563 // ***************************************************************************
1564 void CSoundManager::fadeInGameSound(sint32 timeFadeMs)
1566 // if already at max, noop
1567 if(_FadeGameMusicVolume==1.f && _FadeSFXVolume==1.f)
1568 return;
1570 fadeGameSound(true, timeFadeMs);
1573 // ***************************************************************************
1574 void CSoundManager::fadeOutGameSound(sint32 timeFadeMs)
1576 // if already at 0, noop
1577 if(_FadeGameMusicVolume==0.f && _FadeSFXVolume==0.f)
1578 return;
1580 fadeGameSound(false, timeFadeMs);
1583 // ***************************************************************************
1584 void CSoundManager::fadeGameSound(bool fadeIn, sint32 timeFadeMs)
1586 // fade in
1587 clamp(_FadeGameMusicVolume, 0.f, 1.f);
1588 clamp(_FadeSFXVolume, 0.f, 1.f);
1589 TTime t0= CTime::getLocalTime();
1590 float dVolumeOverDt= 1.f / (timeFadeMs*0.001f);
1591 if(!fadeIn)
1592 dVolumeOverDt*= -1;
1593 while(fadeIn?(_FadeGameMusicVolume<1.f || _FadeSFXVolume<1.f):(_FadeGameMusicVolume>0.f || _FadeSFXVolume>0.f))
1595 // update volume vars
1596 TTime t1= CTime::getLocalTime();
1597 float dt= (t1-t0)*0.001f;
1598 t0= t1;
1599 _FadeGameMusicVolume+= dVolumeOverDt*dt;
1600 _FadeSFXVolume+= dVolumeOverDt*dt;
1601 clamp(_FadeGameMusicVolume, 0.f, 1.f);
1602 clamp(_FadeSFXVolume, 0.f, 1.f);
1603 // update volume and sound
1604 updateVolume();
1605 update();
1609 // ***************************************************************************
1610 void CSoundManager::setupFadeSound(float sfxFade, float musicFade)
1612 clamp(sfxFade, 0.f, 1.f);
1613 clamp(musicFade, 0.f, 1.f);
1614 _FadeGameMusicVolume= musicFade;
1615 _FadeSFXVolume= sfxFade;
1616 updateVolume();
1619 // ***************************************************************************
1620 void CSoundManager::updateEventAndGameMusicVolume()
1622 // update event music played state if not looping
1623 if(!_EventMusicPlayed.empty() && !_EventMusicLoop)
1625 if(!_AudioMixer)
1626 _EventMusicPlayed.clear();
1627 else
1629 if(_AudioMixer->isEventMusicEnded())
1630 _EventMusicPlayed.clear();
1634 // Fade
1635 const sint32 timeFadeMs= 500;
1636 static TTime t0= CTime::getLocalTime();
1637 TTime t1= CTime::getLocalTime();
1638 float dVolume= (t1-t0) / (float)timeFadeMs;
1639 t0= t1;
1641 // if event music is played, music lower the music
1642 if(!_EventMusicPlayed.empty())
1643 dVolume*= -1;
1644 float f= _FadeGameMusicVolumeDueToEvent + dVolume;
1645 clamp(f, 0.f, 1.f);
1647 // if faded, update the volume
1648 if(f!=_FadeGameMusicVolumeDueToEvent)
1650 _FadeGameMusicVolumeDueToEvent= f;
1651 updateVolume();
1656 //---------------------------------------------------
1657 // CStepSounds :
1659 //---------------------------------------------------
1660 /*CStepSounds::CStepSounds()
1662 nlstopex(("class CStepSounds is not used anymore"));
1663 //init( CPath::lookup("materials_for_step_sounds.txt", false).c_str() );
1665 } // CStepSounds //
1668 //---------------------------------------------------
1669 // init :
1671 //---------------------------------------------------
1672 /*void CStepSounds::init( const char * fileName )
1674 nlstopex(("class CStepSounds is not used anymore"));
1675 if(fileName==NULL || strlen(fileName)==0 || fileName[0]=='\0')
1677 nlwarning ("can't load step sound because no material step file");
1678 return;
1681 // get all the materials used for step sounds
1682 list<uint32> materials;
1685 CConfigFile cf;
1686 cf.load( fileName );
1688 CConfigFile::CVar &cvMaterials = cf.getVar("Materials");
1689 for(sint i = 0; i < cvMaterials.size(); i++)
1691 materials.push_back( cvMaterials.asInt(i) );
1694 catch (const EConfigFile &e)
1696 nlerror("Problem in the file %s : %s", fileName,e.what ());
1699 // load all sounds for each of these material
1700 list<uint32>::const_iterator itMaterials;
1701 for( itMaterials = materials.begin(); itMaterials != materials.end(); ++itMaterials )
1703 CMaterialStepSounds materialStepSounds;
1704 materialStepSounds.load( CPath::lookup(string("sndmat_") + toString(*itMaterials) + string(".txt")) );
1705 _StepSoundsByMaterial.insert( make_pair(*itMaterials,materialStepSounds) );
1708 } // init //*/
1712 //---------------------------------------------------
1713 // getSounds :
1715 //---------------------------------------------------
1716 /*bool CStepSounds::getSounds( uint32 material, TMoveType moveType, bool soft, std::vector<string>& sounds )
1718 nlstopex(("class CStepSounds is not used anymore"));
1719 map<uint32,CMaterialStepSounds>::iterator itMatSounds = _StepSoundsByMaterial.find( material );
1720 if( itMatSounds == _StepSoundsByMaterial.end() )
1722 return false;
1724 else
1726 return (*itMatSounds).second.getSounds( moveType, soft, sounds );
1729 } // getSounds //*/
1732 //---------------------------------------------------
1733 // readVar :
1735 //---------------------------------------------------
1736 /*void CMaterialStepSounds::readVar( CConfigFile& cf, TMoveType moveType, bool soft, char * varName )
1740 vector<string> sounds;
1741 CConfigFile::CVar &cvSounds = cf.getVar( varName );
1742 for(sint i = 0; i < cvSounds.size(); i++)
1744 sounds.push_back( cvSounds.asString(i) );
1746 _Sounds.insert( make_pair( make_pair(moveType,soft), sounds) );
1748 catch (const EConfigFile &e)
1750 nlwarning("Problem in the sounds by material config file : %s", e.what ());
1753 } // readVar //
1757 //---------------------------------------------------
1758 // load :
1760 //---------------------------------------------------
1761 /*void CMaterialStepSounds::load( string fileName )
1763 CConfigFile cf;
1764 cf.load(CPath::lookup(fileName.c_str()));
1766 // walk soft sounds
1767 readVar(cf,WALK,true,"walk_sounds_soft");
1768 // walk hard sounds
1769 readVar(cf,WALK,false,"walk_sounds_hard");
1770 // run soft sounds
1771 readVar(cf,RUN,true,"run_sounds_soft");
1772 // run hard sounds
1773 readVar(cf,RUN,false,"run_sounds_hard");
1776 // user walk soft sounds
1777 readVar(cf,USER_WALK,true,"user_walk_sounds_soft");
1778 // user walk hard sounds
1779 readVar(cf,USER_WALK,false,"user_walk_sounds_hard");
1780 // user run soft sounds
1781 readVar(cf,USER_RUN,true,"user_run_sounds_soft");
1782 // user run hard sounds
1783 readVar(cf,USER_RUN,false,"user_run_sounds_hard");
1785 } // load //
1788 /*//---------------------------------------------------
1789 // getSounds :
1791 //---------------------------------------------------
1792 bool CMaterialStepSounds::getSounds( TMoveType moveType, bool soft, vector<string>& sounds )
1794 map<pair<TMoveType,bool>,vector<string> >::iterator itSounds = _Sounds.find( make_pair(moveType,soft) );
1795 if( itSounds == _Sounds.end() )
1797 return false;
1800 uint i;
1801 uint sz = (*itSounds).second.size();
1802 sounds.clear();
1803 sounds.resize( sz );
1804 for( i=0; i < sz; i++ )
1806 sounds[i] = (*itSounds).second[i];
1809 return true;
1811 } // getSounds //*/