Linux multi-monitor fullscreen support
[ryzomcore.git] / ryzom / client / src / sound_manager.cpp
blob572bf2c07fc15805848fab59984d02f12f5b795f
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::SoundDrvFMod)
472 driverType= UAudioMixer::DriverFMod;
473 else if(ClientCfg.DriverSound==CClientConfig::SoundDrvOpenAL)
474 driverType= UAudioMixer::DriverOpenAl;
475 else if(ClientCfg.DriverSound==CClientConfig::SoundDrvDirectSound)
476 driverType= UAudioMixer::DriverDSound;
477 else if(ClientCfg.DriverSound==CClientConfig::SoundDrvXAudio2)
478 driverType= UAudioMixer::DriverXAudio2;
479 _AudioMixer->init(ClientCfg.MaxTrack, ClientCfg.UseEax, ClientCfg.UseADPCM, progressCallBack, false, driverType, ClientCfg.SoundForceSoftwareBuffer);
480 /* int nbVoice = _AudioMixer->getPolyphony();
481 _AudioMixer->setPriorityReserve(HighPri, max(1, nbVoice /2));
482 nbVoice -= nbVoice /2;
483 _AudioMixer->setPriorityReserve(MidPri, max(1, nbVoice /2));
484 nbVoice -= nbVoice /2;
485 _AudioMixer->setPriorityReserve(LowPri, max(1, nbVoice /2));
487 // when they are only 1 track available, enter in limiting mode.
488 _AudioMixer->setLowWaterMark(1);
491 * Create the CSoundAnimManager. The CSoundAnimManager is a singleton.
492 * Access the singleton with CSoundAnimManager::instance().
494 new CSoundAnimManager(_AudioMixer);
496 // get the controller group for effects
497 _GroupControllerEffects = _AudioMixer->getGroupController("sound:effects");
498 _GroupControllerEffectsGame = _AudioMixer->getGroupController("sound:effects:game");
500 // restore the volume
501 SoundMngr->setSFXVolume(ClientCfg.SoundSFXVolume);
502 SoundMngr->setGameMusicVolume(ClientCfg.SoundGameMusicVolume);
504 // Init clustered sound system
505 _AudioMixer->initClusteredSound(Scene, 0.01f, 100.0f, PORTAL_INTERPOLATE);
507 // Init the background flags;
508 for (uint i=0; i<NLSOUND::UAudioMixer::TBackgroundFlags::NB_BACKGROUND_FLAGS; ++i)
509 _BackgroundFlags.Flags[i] = false;
510 _AudioMixer->setBackgroundFlags(_BackgroundFlags);
513 * Initialize listener's position
515 CVector initpos ( 0.0f, 0.0f, 0.0f );
516 //_AudioMixer->getListener()->setPos( initpos );
517 _AudioMixer->setListenerPos(initpos);
520 * Init the particule sound system
522 // attach the sound from the particule system
523 NL3D::UParticleSystemSound::setPSSound(_AudioMixer);
525 //loadPositionedSounds();
527 // reload Sound Animation (if EAM already init)
528 if(EAM)
529 EAM->reloadAllSoundAnim();
531 // Special option for DEV (easier to test when disabled)
532 _AudioMixer->enableBackgroundMusicTimeConstraint(ClientCfg.EnableBackgroundMusicTimeConstraint);
534 /* }
535 catch(const Exception &e)
537 nlwarning( "Error: %s", e.what() );
540 } // init //
542 //---------------------------------------------------
543 // getSoundName:
544 //---------------------------------------------------
545 /*bool CSoundManager::getSoundName( TSound sound, std::string &name, const CVector& pos ) const
547 /// \todo Malkav: take ground type into account, and all the different sounds
548 switch (sound)
550 case WALK:
552 //name = "walk";
553 UGlobalPosition globalPos = GR->retrievePosition( pos );
554 uint32 material = GR->getMaterial( globalPos );
557 break;
559 case RUN:
560 name = "run";
561 break;
563 case USER_WALK:
564 name = "user_walk";
565 break;
567 case USER_RUN:
568 name = "user_run";
569 break;
571 default:
572 return false;
575 return true;
577 } // getSoundName //
582 //---------------------------------------------------
583 // addSource :
584 // add a new source to the world, attached to the specified entity
585 // return 0 if creation failed, sound id if creation was successful
586 //---------------------------------------------------
587 /*uint32 CSoundManager::addSource( TSound sound, const NLMISC::CVector &position, bool play, bool loop, const CEntityId &parentId )
589 static std::string name;
590 static TSource source;
592 uint32 retValue = 0;
594 if ( ! getSoundName ( sound, name, position ) )
595 return 0;
597 USource *pSource = _AudioMixer->createSource( name );
599 if ( pSource != NULL )
601 pSource ->setPos( position );
603 pSource ->setLooping( loop );
605 if (play)
606 pSource ->play();
608 //create the TSource object
609 source.sound = sound;
610 source.pSource = pSource;
612 // attach the source to the entity, if specified
613 if (parentId != CEntityId::Unknown)
614 _AttachedSources.insert( TMultiMapEntityToSource::value_type( parentId, source ) );
616 // set source id
617 retValue = _NextId;
618 _Sources.insert( TMapIdToSource::value_type( _NextId, source ) );
619 ++_NextId;
621 else
623 nlwarning( "Sound '%s' not found", name );
626 return retValue;
627 } // addSource //
630 //-----------------------------------------------
631 // addSource :
632 // add a new source to the world, attached to the specified entity
633 // return 0 if creation failed, sound id if creation was successful
634 //-----------------------------------------------
635 CSoundManager::TSourceId CSoundManager::addSource(const NLMISC::TStringId &soundName, const NLMISC::CVector &position, bool play, bool loop, const CEntityId &id)
637 uint32 retValue = 0;
639 // Create a source
640 USource *pSource = _AudioMixer->createSource(soundName);
642 // If the source is valid.
643 if(pSource == 0)
645 nlwarning("Sound '%s' not found !", CStringMapper::unmap(soundName).c_str());
646 return retValue;
649 // Load the properties for this sound.
650 // REMOVED because the pitch and the gain are now in the .nss (don't need .sdf anymore)
651 // loadProperties(soundName, pSource);
653 // Set the source position.
654 pSource->setPos( position );
656 // Is the source looping ?
657 pSource->setLooping( loop );
659 // Play the sound immedialty if asked.
660 if(play)
662 pSource->play();
665 TSourceId sourceId = _Sources.insert(pSource);
667 // attach the source to the entity, if specified
668 if (id != CEntityId::Unknown )
670 _AttachedSources.insert( TMultiMapEntityToSource::value_type( id, sourceId ) );
673 // return the id of the source
674 return sourceId;
676 } // addSource //
679 //-----------------------------------------------
680 // spawn a new source to the world
681 // return false if creation failed, true if creation was successful
682 //-----------------------------------------------
683 bool CSoundManager::spawnSource(const NLMISC::TStringId &soundName, CSoundContext &context)
685 if (!_PlaySound) return false;
687 // Create a source
688 // TODO : find the correct cluster
689 USource *pSource = _AudioMixer->createSource( soundName, true, NULL, NULL, NULL, &context);
691 // If the source is valid.
692 if(pSource == 0)
694 nlwarning("Sound '%s' not found !", soundName);
695 return false;
698 // Set the source position.
699 pSource->setPos (context.Position);
700 pSource->play();
702 ////nlinfo ("%.3f spawn source %p", (float)ryzomGetLocalTime ()/1000.0f, pSource);
704 return true;
706 } // addSource //
709 //-----------------------------------------------
710 // spawn a new source to the world
711 // return false if creation failed, true if creation was successful
712 //-----------------------------------------------
713 bool CSoundManager::spawnSource(const NLMISC::TStringId &soundName, const NLMISC::CVector &position)
715 if (!_PlaySound) return false;
717 // Create a source
718 USource *pSource = _AudioMixer->createSource( soundName, true);
720 // If the source is valid.
721 if(pSource == 0)
723 nlwarning("Sound '%s' not found !", CStringMapper::unmap(soundName).c_str ());
724 return false;
727 // Set the source position.
728 pSource->setPos (position);
729 pSource->play();
731 ////nlinfo ("%.3f spawn source %p", (float)ryzomGetLocalTime ()/1000.0f, pSource);
733 return true;
735 } // addSource //
739 //---------------------------------------------------
740 // removeSource:
741 // remove a source
742 //---------------------------------------------------
743 void CSoundManager::removeSource(CSoundManager::TSourceId sourceId)
745 nldebug("remove the source : %d", sourceId);
747 /// \todo Malkav : optimize speed
748 nldebug("nb sources = %d", _Sources.size() );
749 USource *pSource = _Sources.get(sourceId);
750 if (pSource)
752 TMultiMapEntityToSource::iterator it = _AttachedSources.begin();//, itOld;
754 for ( ; it != _AttachedSources.end() ; ++it)
756 if ( (*it).second == sourceId )
758 (*it).second = 0;
759 // itOld = it;
760 // ++it;
762 _AttachedSources.erase( it/*Old*/ );
764 break;
766 // if (it == _AttachedSources.end() )
767 // break;
771 // delete the source
772 delete pSource;
773 // i think there was something going on here
774 _Sources.erase(sourceId);
776 } // removeSource //
780 //---------------------------------------------------
781 // getSounds :
783 //---------------------------------------------------
784 /*bool CSoundManager::getSounds( uint32 material, TMoveType moveType, bool soft, std::vector<string>& sounds )
786 return _StepSounds.getSounds( material, moveType, soft, sounds );
788 } // getSounds //*/
792 //---------------------------------------------------
793 // updateEntityPos :
794 // update the pos of all the sounds attached to that entity
795 //---------------------------------------------------
796 void CSoundManager::updateEntityPos( const CEntityId &id, const NLMISC::CVector &pos)
798 TMultiMapEntityToSource::iterator it;
799 const std::pair<TMultiMapEntityToSource::iterator, TMultiMapEntityToSource::iterator> range = _AttachedSources.equal_range( id );
801 for ( it = range.first; it != range.second ; ++it)
803 _Sources.get((*it).second)->setPos( pos );
805 } // updateEntityPos //
808 //---------------------------------------------------
809 // updateEntityVelocity :
810 // update the velocity of all the sounds attached to that entity
811 //---------------------------------------------------
812 void CSoundManager::updateEntityVelocity( const CEntityId &id, const NLMISC::CVector &velocity)
814 TMultiMapEntityToSource::iterator it;
815 const std::pair<TMultiMapEntityToSource::iterator, TMultiMapEntityToSource::iterator> range = _AttachedSources.equal_range( id );
817 for ( it = range.first; it != range.second ; ++it)
819 _Sources.get((*it).second)->setVelocity( velocity );
822 } // updateEntityVelocity //
825 //---------------------------------------------------
826 // updateEntityDirection :
827 // update the direction of all the sounds attached to that entity
828 //---------------------------------------------------
829 void CSoundManager::updateEntityDirection( const CEntityId &id, const NLMISC::CVector &dir )
831 TMultiMapEntityToSource::iterator it;
832 const std::pair<TMultiMapEntityToSource::iterator, TMultiMapEntityToSource::iterator> range = _AttachedSources.equal_range( id );
834 for ( it = range.first; it != range.second ; ++it)
836 _Sources.get((*it).second)->setDirection( dir );
838 } // updateEntityOrientation //
841 //---------------------------------------------------
842 // removeEntity :
843 // remove an entity from the view : delete all the sources attached to that entity
844 //---------------------------------------------------
845 void CSoundManager::removeEntity( const CEntityId &id)
847 /// \todo Malkav : optimize speed
849 TMultiMapEntityToSource::iterator it;
850 const std::pair<TMultiMapEntityToSource::iterator, TMultiMapEntityToSource::iterator> range = _AttachedSources.equal_range( id );
852 for ( it = range.first; it != range.second ; ++it)
854 TSourceId sourceId = (*it).second;
855 if (sourceId)
857 USource *pSource = _Sources.get(sourceId);
858 delete pSource;
859 _Sources.erase(sourceId);
863 _AttachedSources.erase( range.first, range.second );
864 } // removeEntity //
869 //---------------------------------------------------
870 // setSoundPosition :
871 //---------------------------------------------------
872 void CSoundManager::setSoundPosition(TSourceId sourceId, const NLMISC::CVector &position)
874 if (!_PlaySound) return;
876 USource *pSource = _Sources.get(sourceId);
877 if (pSource) pSource->setPos(position);
878 } // setSoundPosition //
881 //---------------------------------------------------
882 // loopSound :
883 //---------------------------------------------------
884 void CSoundManager::loopSound(TSourceId sourceId, bool loop)
886 if (!_PlaySound) return;
888 USource *pSource = _Sources.get(sourceId);
889 if (pSource) pSource->setLooping(loop);
890 } // loopSound //
893 //---------------------------------------------------
894 // playSound :
895 // start or stop playing sound
896 //---------------------------------------------------
897 void CSoundManager::playSound(TSourceId sourceId, bool play)
899 if (!_PlaySound) return;
901 USource *pSource = _Sources.get(sourceId);
902 if (pSource)
904 if (play)
905 pSource->play();
906 else
907 pSource->stop();
909 } // loopSound //
913 //---------------------------------------------------
914 // isPlaying :
915 // return true if the source is playing
916 //---------------------------------------------------
917 bool CSoundManager::isPlaying(TSourceId sourceId)
919 USource *pSource = _Sources.get(sourceId);
920 if (pSource) return pSource->isPlaying();
921 return false;
922 } // isPlaying //
926 //---------------------------------------------------
927 // setSoundForSource :
928 // set the sound associated to the specified source
929 //---------------------------------------------------
931 bool CSoundManager::setSoundForSource( uint32 sourceId, TSound sound, const CVector& pos )
933 // find the sound name
934 static std::string soundName;
935 soundName.clear();
936 if ( ! getSoundName( sound , soundName, pos) )
937 return false;
939 TMapIdToSource::iterator it = _Sources.find( sourceId );
940 if (it != _Sources.end() )
942 nlassert( (*it).second.pSource );
944 // get the sound
945 TSoundId soundId = _AudioMixer->getSoundId( soundName.c_str() );
947 if (soundId != NULL)
949 (*it).second.pSource->setSound( soundId );
950 (*it).second.sound = sound;
951 nlinfo("sound has been set to %d",sound);
952 return true;
955 return false;
956 } // setSoundForSource //
961 //---------------------------------------------------
962 // getSoundFromSource :
963 // get the sound type currently associated to a source
964 //---------------------------------------------------
965 /*CSoundManager::TSound CSoundManager::getSoundFromSource( uint32 sourceId ) const
967 TMapIdToSource::const_iterator it = _Sources.find( sourceId );
968 if (it != _Sources.end() )
970 nlassert( (*it).second.pSource );
972 return ( (*it).second.sound );
975 return NONE;
976 } // getSoundFromSource //
980 //---------------------------------------------------
981 // setSourceGain :
982 // set the gain of the specified source
983 //---------------------------------------------------
984 void CSoundManager::setSourceGain(TSourceId sourceId, float gain)
986 USource *pSource = _Sources.get(sourceId);
987 if (pSource) pSource->setGain( gain );
988 } // setSourceGain //
991 //---------------------------------------------------
992 // getSourceGain :
993 // get the gain of the specified source (-1 if source not found)
994 //---------------------------------------------------
995 float CSoundManager::getSourceGain(TSourceId sourceId)
997 USource *pSource = _Sources.get(sourceId);
998 if (pSource) return pSource->getGain();
999 return -1;
1000 } // getSourceGain //
1003 //---------------------------------------------------
1004 // setSourcePitch :
1005 // set the Pitch of the specified source
1006 //---------------------------------------------------
1007 void CSoundManager::setSourcePitch(TSourceId sourceId, float Pitch)
1009 USource *pSource = _Sources.get(sourceId);
1010 if (pSource) pSource->setPitch(Pitch);
1011 } // setSourcePitch //
1014 //---------------------------------------------------
1015 // getSourcePitch :
1016 // get the Pitch of the specified source (-1 if source not found)
1017 //---------------------------------------------------
1018 float CSoundManager::getSourcePitch(TSourceId sourceId)
1020 USource *pSource = _Sources.get(sourceId);
1021 if (pSource) return pSource->getPitch();
1022 return -1;
1023 } // getSourcePitch //
1027 //---------------------------------------------------
1028 // loadProperties :
1029 // Load the properties for this sound and apply them.
1030 //---------------------------------------------------
1031 void CSoundManager::loadProperties(const string &soundName, USource *source)
1033 // If the source does not exist -> return nothing to do.
1034 if(!source)
1035 return;
1037 // Search for the file.
1038 string filePath = CPath::lookup(soundName+".sdf");
1040 CIFile file;
1042 // Try to open the file.
1043 if (file.open(filePath))
1045 char tmpBuff[260];
1046 char delimiterBox[] = "\t ";
1047 // While the end of the file is not reached.
1048 while(!file.eof())
1050 // Get a line (the line should not be more than _MAX_LINE_SIZE).
1051 file.getline(tmpBuff, 260);
1052 char *token = strtok(tmpBuff, delimiterBox);
1053 while(token != NULL)
1055 // Get the pitch.
1056 if(strcmp(token, "Pitch:") == 0)
1058 token = strtok(NULL, delimiterBox);
1059 if(token)
1061 float pitch;
1062 fromString(token, pitch);
1063 nlinfo("Pitch: %f", pitch);
1064 source->setPitch(pitch);
1067 // Get the Gain.
1068 else if(strcmp(token, "Gain:") == 0)
1070 token = strtok(NULL, delimiterBox);
1071 if(token)
1073 float gain;
1074 fromString(token, gain);
1075 nlinfo("Gain: %f", gain);
1076 source->setGain(gain);
1080 // Next property.
1081 token = strtok(NULL, delimiterBox);
1084 // Close the file.
1085 file.close();
1087 }// loadProperties //
1092 //---------------------------------------------------
1093 // loadPositionedSounds :
1095 //---------------------------------------------------
1096 /*void CSoundManager::loadPositionedSounds()
1098 nlstopex(("class CStepSounds is not used anymore"));
1099 // cst loader
1100 CSTLoader cstl;
1102 // build file format
1103 map<string,CSTLoader::TDataType> fileFormat;
1104 fileFormat.insert( make_pair( string( "sound name" ) , CSTLoader::STRING ));
1105 fileFormat.insert( make_pair( string( "x" ) , CSTLoader::FLOAT ));
1106 fileFormat.insert( make_pair( string( "y" ) , CSTLoader::FLOAT ));
1107 fileFormat.insert( make_pair( string( "z" ) , CSTLoader::FLOAT ));
1108 fileFormat.insert( make_pair( string( "loop" ) , CSTLoader::BOOL ));
1111 string str = CPath::lookup("positioned_sounds.txt", false);
1112 if(str.empty())
1114 nlwarning ("cant load positioned_sounds");
1115 return;
1118 // init loader
1119 cstl.init( str, fileFormat );
1121 // read the file
1122 while( cstl.readLine() )
1124 string soundName;
1125 cstl.getStringValue( "sound name", soundName );
1127 CVector sourcePos;
1128 cstl.getValue( "x", sourcePos.x );
1129 cstl.getValue( "y", sourcePos.y );
1130 cstl.getValue( "z", sourcePos.z );
1132 bool loop;
1133 cstl.getBoolValue( "loop", loop );
1135 uint32 sourceId = addSource( soundName, sourcePos, false , loop );
1137 if(sourceId != 0)
1139 _PositionedSounds.push_back( sourceId );
1141 else
1143 nlwarning ("positioned sound: can't find sound: '%s'", soundName.c_str());
1147 cstl.close();
1149 } // chooseSoundOnMaterial //
1153 //---------------------------------------------------
1154 // playPositionedSounds :
1156 //---------------------------------------------------
1157 void CSoundManager::playPositionedSounds( const CVector& /* pos */ )
1159 if (!_PlaySound) return;
1161 list<uint32>::iterator itPSnd;
1162 for( itPSnd = _PositionedSounds.begin(); itPSnd != _PositionedSounds.end(); ++itPSnd )
1164 USource *pSource = _Sources.get(*itPSnd);
1165 if (!pSource)
1167 nlwarning("<CSoundManager::playPositionedSounds> : The source %d is unknown",*itPSnd);
1169 else
1172 if( (pos - (*itSrc).second.getPos()).norm() < ...)
1174 if( (*itSrc).second.pSource->isPlaying() == false )
1176 (*itSrc).second.pSource->play();
1180 if (!pSource->isPlaying())
1182 pSource->play();
1187 } // playPositionedSounds //
1190 void CSoundManager::selectEnv( const std::string &/* tag */)
1192 // TODO : boris : temporarily removed.
1193 /* if (_EnvSoundRoot==NULL)
1194 return;
1196 _EnvSoundRoot->selectEnv (tag.c_str(), true);
1200 void CSoundManager::setFilterState(uint filterId, bool state)
1202 nlassert(filterId < NLSOUND::UAudioMixer::TBackgroundFlags::NB_BACKGROUND_FLAGS);
1203 _BackgroundFlags.Flags[filterId] = state;
1205 _AudioMixer->setBackgroundFlags(_BackgroundFlags);
1210 // ***************************************************************************
1211 void CSoundManager::update ()
1213 // Filters : day = 0, night = 1, morning = 2, Dusk = 3
1214 // update the filter state for day/night management.
1215 switch(LightCycleManager.getState())
1217 case CLightCycleManager::Day:
1218 _BackgroundFlags.Flags[DAY] = true;
1219 _BackgroundFlags.Flags[NIGHT] = false;
1220 _BackgroundFlags.Flags[MORNING] = false;
1221 _BackgroundFlags.Flags[DUSK] = false;
1222 break;
1223 case CLightCycleManager::Night:
1224 _BackgroundFlags.Flags[DAY] = false;
1225 _BackgroundFlags.Flags[NIGHT] = true;
1226 _BackgroundFlags.Flags[MORNING] = false;
1227 _BackgroundFlags.Flags[DUSK] = false;
1228 break;
1229 case CLightCycleManager::DayToNight:
1230 _BackgroundFlags.Flags[DAY] = true;
1231 _BackgroundFlags.Flags[NIGHT] = false;
1232 _BackgroundFlags.Flags[MORNING] = true;
1233 _BackgroundFlags.Flags[DUSK] = false;
1234 break;
1235 case CLightCycleManager::NightToDay:
1236 _BackgroundFlags.Flags[DAY] = false;
1237 _BackgroundFlags.Flags[NIGHT] = false;
1238 _BackgroundFlags.Flags[MORNING] = false;
1239 _BackgroundFlags.Flags[DUSK] = true;
1240 break;
1241 case CLightCycleManager::StateUnknown:
1242 //nlwarning("Unknown light cycle state reached.");
1243 break;
1246 // update the filter for season.
1247 EGSPD::CSeason::TSeason season = CurrSeason;
1248 switch(season)
1250 case EGSPD::CSeason::Spring:
1251 _BackgroundFlags.Flags[SPRING] = true;
1252 _BackgroundFlags.Flags[SUMMER] = false;
1253 _BackgroundFlags.Flags[AUTUMN] = false;
1254 _BackgroundFlags.Flags[WINTER] = false;
1255 break;
1256 case EGSPD::CSeason::Summer:
1257 _BackgroundFlags.Flags[SPRING] = false;
1258 _BackgroundFlags.Flags[SUMMER] = true;
1259 _BackgroundFlags.Flags[AUTUMN] = false;
1260 _BackgroundFlags.Flags[WINTER] = false;
1261 break;
1262 case EGSPD::CSeason::Autumn:
1263 _BackgroundFlags.Flags[SPRING] = false;
1264 _BackgroundFlags.Flags[SUMMER] = false;
1265 _BackgroundFlags.Flags[AUTUMN] = true;
1266 _BackgroundFlags.Flags[WINTER] = false;
1267 break;
1268 case EGSPD::CSeason::Winter:
1269 _BackgroundFlags.Flags[SPRING] = false;
1270 _BackgroundFlags.Flags[SUMMER] = false;
1271 _BackgroundFlags.Flags[AUTUMN] = false;
1272 _BackgroundFlags.Flags[WINTER] = true;
1273 break;
1274 default:
1275 //nlwarning("Updating unknown season.");
1276 break;
1278 // TODO : update the filter state for weather effet
1279 CWeatherState weatherState = WeatherManager.getCurrWeatherState();
1283 enum TWeatherSoundEnv
1285 WSEMist = 0, // not used
1286 WSEFair1,
1287 WSEFair2,
1288 WSEFair3,
1289 WSEClouds,
1290 WSERain1,
1291 WSERain2,
1292 WSESnow1,
1293 WSEThunder1,
1294 WSEThunderSeve,
1295 WSEThunderSand1, // not used
1296 WSEThunderSand2, // not used
1297 WSEThunderSand3, // not used
1298 WSECount
1301 // For each weather setup, gives the matching weather sound env to used, when there are precipitation or not
1302 class CWeatherSetupSoundEnv
1304 public:
1305 NLMISC::TStringId SetupName; // setup nem as found is the .weather_setup sheets
1306 TWeatherSoundEnv Sound;
1307 CWeatherSetupSoundEnv(const char *setupName, TWeatherSoundEnv sound)
1309 SetupName = NLMISC::CStringMapper::map(setupName);
1310 Sound = sound;
1314 // association between weather setup names & sound env
1315 static const CWeatherSetupSoundEnv weatherSoundLUT[] =
1317 CWeatherSetupSoundEnv("fair1", WSEFair1),
1318 CWeatherSetupSoundEnv("fair2", WSEFair2),
1319 CWeatherSetupSoundEnv("fair3", WSEFair3),
1320 CWeatherSetupSoundEnv("wind1", WSEClouds),
1321 CWeatherSetupSoundEnv("humidity1", WSERain1),
1322 CWeatherSetupSoundEnv("humidity2", WSERain2),
1323 CWeatherSetupSoundEnv("clouds1", WSERain1),
1324 CWeatherSetupSoundEnv("clouds2", WSERain2),
1325 CWeatherSetupSoundEnv("thunderseve", WSEThunderSeve),
1326 CWeatherSetupSoundEnv("storm", WSEThunder1),
1327 CWeatherSetupSoundEnv("snow", WSESnow1),
1330 const CWeatherSetupSoundEnv *weatherSetupSoundEnv = NULL;
1331 for(uint k = 0; k < sizeof(weatherSoundLUT) / sizeof(weatherSoundLUT[0]); ++k)
1333 if (weatherSoundLUT[k].SetupName == weatherState.BestSetupName)
1335 weatherSetupSoundEnv = &weatherSoundLUT[k];
1336 break;
1340 // disable all weather setup sound flags except the current one
1341 for(uint k = 0; k < WSECount; ++k)
1343 _BackgroundFlags.Flags[MIST+k] = false;
1345 if (weatherSetupSoundEnv)
1347 _BackgroundFlags.Flags[MIST + weatherSetupSoundEnv->Sound] = true;
1349 else
1351 static bool bDisplayOnce = false;
1352 if (!bDisplayOnce)
1354 nlinfo("The current weather setup '%s' is unknown !", CStringMapper::unmap(weatherState.BestSetupName).c_str());
1355 bDisplayOnce = true;
1359 // update the background flags in the mixer.
1360 _AudioMixer->setBackgroundFlags(_BackgroundFlags);
1362 // update background music enabling
1363 if(_EnableBackgroundMusicAtTime && CTime::getLocalTime()>_EnableBackgroundMusicAtTime)
1365 setGameMusicMode(true, true);
1368 // Special option for DEV (easier to test when disabled)
1369 _AudioMixer->enableBackgroundMusicTimeConstraint(ClientCfg.EnableBackgroundMusicTimeConstraint);
1371 // update game music volume because of event played or not
1372 updateEventAndGameMusicVolume();
1374 // update audio mixer
1375 _AudioMixer->update ();
1378 // ***************************************************************************
1379 void CSoundManager::updateAudioMixerOnly()
1381 if(!_AudioMixer)
1382 return;
1383 _AudioMixer->update ();
1386 // ***************************************************************************
1387 void CSoundManager::playBackgroundSound()
1389 _AudioMixer->playBackgroundSound();
1392 // ***************************************************************************
1393 void CSoundManager::stopBackgroundSound()
1395 _AudioMixer->stopBackgroundSound();
1398 // ***************************************************************************
1399 void CSoundManager::playMusic(const string &fileName, uint xFadeTime, bool async, bool loop, bool forceGameMusicVolume)
1401 if(fileName.empty())
1403 stopMusic(xFadeTime);
1405 else
1407 if(_AudioMixer)
1409 // disable before the background music (before is important else may have bug)
1410 setGameMusicMode(false, forceGameMusicVolume);
1411 // play
1412 _AudioMixer->playMusic(fileName, xFadeTime, async, loop);
1417 // ***************************************************************************
1418 void CSoundManager::stopMusic(uint xFadeTime)
1420 if(_AudioMixer)
1422 // stop the music
1423 _AudioMixer->stopMusic(xFadeTime);
1424 // and reenable the background music system. after a delay if xFadeTime
1425 if(xFadeTime>0)
1427 // enable background music later
1428 _EnableBackgroundMusicAtTime= CTime::getLocalTime()+xFadeTime;
1430 else
1432 // else enable now
1433 setGameMusicMode(true, true);
1438 // ***************************************************************************
1439 void CSoundManager::playEventMusic(const string &fileName, uint xFadeTime, bool loop)
1441 // if event music not enabled (mp3 player), abort
1442 if(!_EventMusicEnabled)
1443 return;
1445 if(fileName.empty())
1447 stopEventMusic("", xFadeTime);
1449 else
1451 if(_AudioMixer)
1453 // if the music is not already currently playing (with same loop state)
1454 if(_EventMusicPlayed.empty() || nlstricmp(fileName, _EventMusicPlayed)!=0 || loop!=_EventMusicLoop)
1456 // play
1457 _AudioMixer->playEventMusic(fileName, xFadeTime, true, loop);
1458 _EventMusicPlayed= fileName;
1459 _EventMusicLoop= loop;
1465 // ***************************************************************************
1466 void CSoundManager::stopEventMusic(const string &fileName, uint xFadeTime)
1468 if(_AudioMixer)
1470 // if the event music is the one currently played, or if empty fileName
1471 if(fileName.empty() || nlstricmp(_EventMusicPlayed,fileName)==0)
1473 // stop the music
1474 _AudioMixer->stopEventMusic(xFadeTime);
1475 // music no more played
1476 _EventMusicPlayed.clear();
1481 // ***************************************************************************
1482 void CSoundManager::pauseMusic()
1484 if(_AudioMixer)
1485 _AudioMixer->pauseMusic();
1488 // ***************************************************************************
1489 void CSoundManager::resumeMusic()
1491 if(_AudioMixer)
1492 _AudioMixer->resumeMusic();
1495 // ***************************************************************************
1496 bool CSoundManager::isMusicEnded()
1498 if(_AudioMixer)
1499 return _AudioMixer->isMusicEnded();
1500 return false;
1503 // ***************************************************************************
1504 void CSoundManager::setGameMusicVolume(float val)
1506 clamp(val,0.f,1.f);
1507 _GameMusicVolume= val;
1508 updateVolume();
1511 // ***************************************************************************
1512 void CSoundManager::setUserMusicVolume(float val)
1514 clamp(val,0.f,1.f);
1515 _UserMusicVolume= val;
1516 updateVolume();
1519 // ***************************************************************************
1520 void CSoundManager::setSFXVolume(float val)
1522 clamp(val,0.f,1.f);
1523 _SFXVolume= val;
1524 updateVolume();
1527 // ***************************************************************************
1528 void CSoundManager::setGameMusicMode(bool enableBackground, bool useGameMusicVolume)
1530 // update background music state
1531 _EnableBackgroundMusicAtTime= 0;
1532 _AudioMixer->enableBackgroundMusic(enableBackground);
1533 _UseGameMusicVolume= useGameMusicVolume;
1534 // event music enabled if the background music is also enabled
1535 _EventMusicEnabled= enableBackground;
1536 // stop any event music if disabled
1537 if(!_EventMusicEnabled)
1538 stopEventMusic("", 500);
1539 // update music volume state
1540 updateVolume();
1543 // ***************************************************************************
1544 void CSoundManager::updateVolume()
1546 if(_AudioMixer)
1548 // update music volume
1549 if(_UseGameMusicVolume)
1550 // Game music (background music system)
1551 _AudioMixer->setMusicVolume(_GameMusicVolume*_FadeGameMusicVolume*_FadeGameMusicVolumeDueToEvent);
1552 else
1553 // User music volume (mp3 player) is not affected by fadein/fadeout
1554 _AudioMixer->setMusicVolume(_UserMusicVolume);
1556 // The event music volume get the game music volume, but is not faded (want music during teleport)
1557 _AudioMixer->setEventMusicVolume(_GameMusicVolume);
1559 // update sfx volume
1560 _GroupControllerEffects->setGain(_SFXVolume);
1561 _GroupControllerEffectsGame->setGain(_FadeSFXVolume);
1565 // ***************************************************************************
1566 void CSoundManager::fadeInGameSound(sint32 timeFadeMs)
1568 // if already at max, noop
1569 if(_FadeGameMusicVolume==1.f && _FadeSFXVolume==1.f)
1570 return;
1572 fadeGameSound(true, timeFadeMs);
1575 // ***************************************************************************
1576 void CSoundManager::fadeOutGameSound(sint32 timeFadeMs)
1578 // if already at 0, noop
1579 if(_FadeGameMusicVolume==0.f && _FadeSFXVolume==0.f)
1580 return;
1582 fadeGameSound(false, timeFadeMs);
1585 // ***************************************************************************
1586 void CSoundManager::fadeGameSound(bool fadeIn, sint32 timeFadeMs)
1588 // fade in
1589 clamp(_FadeGameMusicVolume, 0.f, 1.f);
1590 clamp(_FadeSFXVolume, 0.f, 1.f);
1591 TTime t0= CTime::getLocalTime();
1592 float dVolumeOverDt= 1.f / (timeFadeMs*0.001f);
1593 if(!fadeIn)
1594 dVolumeOverDt*= -1;
1595 while(fadeIn?(_FadeGameMusicVolume<1.f || _FadeSFXVolume<1.f):(_FadeGameMusicVolume>0.f || _FadeSFXVolume>0.f))
1597 // update volume vars
1598 TTime t1= CTime::getLocalTime();
1599 float dt= (t1-t0)*0.001f;
1600 t0= t1;
1601 _FadeGameMusicVolume+= dVolumeOverDt*dt;
1602 _FadeSFXVolume+= dVolumeOverDt*dt;
1603 clamp(_FadeGameMusicVolume, 0.f, 1.f);
1604 clamp(_FadeSFXVolume, 0.f, 1.f);
1605 // update volume and sound
1606 updateVolume();
1607 update();
1611 // ***************************************************************************
1612 void CSoundManager::setupFadeSound(float sfxFade, float musicFade)
1614 clamp(sfxFade, 0.f, 1.f);
1615 clamp(musicFade, 0.f, 1.f);
1616 _FadeGameMusicVolume= musicFade;
1617 _FadeSFXVolume= sfxFade;
1618 updateVolume();
1621 // ***************************************************************************
1622 void CSoundManager::updateEventAndGameMusicVolume()
1624 // update event music played state if not looping
1625 if(!_EventMusicPlayed.empty() && !_EventMusicLoop)
1627 if(!_AudioMixer)
1628 _EventMusicPlayed.clear();
1629 else
1631 if(_AudioMixer->isEventMusicEnded())
1632 _EventMusicPlayed.clear();
1636 // Fade
1637 const sint32 timeFadeMs= 500;
1638 static TTime t0= CTime::getLocalTime();
1639 TTime t1= CTime::getLocalTime();
1640 float dVolume= (t1-t0) / (float)timeFadeMs;
1641 t0= t1;
1643 // if event music is played, music lower the music
1644 if(!_EventMusicPlayed.empty())
1645 dVolume*= -1;
1646 float f= _FadeGameMusicVolumeDueToEvent + dVolume;
1647 clamp(f, 0.f, 1.f);
1649 // if faded, update the volume
1650 if(f!=_FadeGameMusicVolumeDueToEvent)
1652 _FadeGameMusicVolumeDueToEvent= f;
1653 updateVolume();
1658 //---------------------------------------------------
1659 // CStepSounds :
1661 //---------------------------------------------------
1662 /*CStepSounds::CStepSounds()
1664 nlstopex(("class CStepSounds is not used anymore"));
1665 //init( CPath::lookup("materials_for_step_sounds.txt", false).c_str() );
1667 } // CStepSounds //
1670 //---------------------------------------------------
1671 // init :
1673 //---------------------------------------------------
1674 /*void CStepSounds::init( const char * fileName )
1676 nlstopex(("class CStepSounds is not used anymore"));
1677 if(fileName==NULL || strlen(fileName)==0 || fileName[0]=='\0')
1679 nlwarning ("can't load step sound because no material step file");
1680 return;
1683 // get all the materials used for step sounds
1684 list<uint32> materials;
1687 CConfigFile cf;
1688 cf.load( fileName );
1690 CConfigFile::CVar &cvMaterials = cf.getVar("Materials");
1691 for(sint i = 0; i < cvMaterials.size(); i++)
1693 materials.push_back( cvMaterials.asInt(i) );
1696 catch (const EConfigFile &e)
1698 nlerror("Problem in the file %s : %s", fileName,e.what ());
1701 // load all sounds for each of these material
1702 list<uint32>::const_iterator itMaterials;
1703 for( itMaterials = materials.begin(); itMaterials != materials.end(); ++itMaterials )
1705 CMaterialStepSounds materialStepSounds;
1706 materialStepSounds.load( CPath::lookup(string("sndmat_") + toString(*itMaterials) + string(".txt")) );
1707 _StepSoundsByMaterial.insert( make_pair(*itMaterials,materialStepSounds) );
1710 } // init //*/
1714 //---------------------------------------------------
1715 // getSounds :
1717 //---------------------------------------------------
1718 /*bool CStepSounds::getSounds( uint32 material, TMoveType moveType, bool soft, std::vector<string>& sounds )
1720 nlstopex(("class CStepSounds is not used anymore"));
1721 map<uint32,CMaterialStepSounds>::iterator itMatSounds = _StepSoundsByMaterial.find( material );
1722 if( itMatSounds == _StepSoundsByMaterial.end() )
1724 return false;
1726 else
1728 return (*itMatSounds).second.getSounds( moveType, soft, sounds );
1731 } // getSounds //*/
1734 //---------------------------------------------------
1735 // readVar :
1737 //---------------------------------------------------
1738 /*void CMaterialStepSounds::readVar( CConfigFile& cf, TMoveType moveType, bool soft, char * varName )
1742 vector<string> sounds;
1743 CConfigFile::CVar &cvSounds = cf.getVar( varName );
1744 for(sint i = 0; i < cvSounds.size(); i++)
1746 sounds.push_back( cvSounds.asString(i) );
1748 _Sounds.insert( make_pair( make_pair(moveType,soft), sounds) );
1750 catch (const EConfigFile &e)
1752 nlwarning("Problem in the sounds by material config file : %s", e.what ());
1755 } // readVar //
1759 //---------------------------------------------------
1760 // load :
1762 //---------------------------------------------------
1763 /*void CMaterialStepSounds::load( string fileName )
1765 CConfigFile cf;
1766 cf.load(CPath::lookup(fileName.c_str()));
1768 // walk soft sounds
1769 readVar(cf,WALK,true,"walk_sounds_soft");
1770 // walk hard sounds
1771 readVar(cf,WALK,false,"walk_sounds_hard");
1772 // run soft sounds
1773 readVar(cf,RUN,true,"run_sounds_soft");
1774 // run hard sounds
1775 readVar(cf,RUN,false,"run_sounds_hard");
1778 // user walk soft sounds
1779 readVar(cf,USER_WALK,true,"user_walk_sounds_soft");
1780 // user walk hard sounds
1781 readVar(cf,USER_WALK,false,"user_walk_sounds_hard");
1782 // user run soft sounds
1783 readVar(cf,USER_RUN,true,"user_run_sounds_soft");
1784 // user run hard sounds
1785 readVar(cf,USER_RUN,false,"user_run_sounds_hard");
1787 } // load //
1790 /*//---------------------------------------------------
1791 // getSounds :
1793 //---------------------------------------------------
1794 bool CMaterialStepSounds::getSounds( TMoveType moveType, bool soft, vector<string>& sounds )
1796 map<pair<TMoveType,bool>,vector<string> >::iterator itSounds = _Sounds.find( make_pair(moveType,soft) );
1797 if( itSounds == _Sounds.end() )
1799 return false;
1802 uint i;
1803 uint sz = (*itSounds).second.size();
1804 sounds.clear();
1805 sounds.resize( sz );
1806 for( i=0; i < sz; i++ )
1808 sounds[i] = (*itSounds).second[i];
1811 return true;
1813 } // getSounds //*/