Fix "no remove aqua speed" bug when player leaves the water
[ryzomcore.git] / nel / src / sound / music_sound_manager.cpp
blobff0ad72aadb14573ef087b9aabd9a2884a5bc90d
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
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 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stdsound.h"
22 #include "nel/sound/audio_mixer_user.h"
23 #include "nel/sound/music_sound_manager.h"
24 #include "nel/sound/music_sound.h"
25 #include "nel/sound/music_source.h"
28 using namespace NLMISC;
29 using namespace std;
32 namespace NLSOUND {
35 // ***************************************************************************
36 CMusicSoundManager::CMusicSoundManager()
38 _Enabled= true;
39 _CurrentMusicPlaying= NULL;
40 _PlayStartTime= INT_MIN;
41 _TimeConstraintEnabled= true;
44 // ***************************************************************************
45 void CMusicSoundManager::addMusicSourcePlaying(CMusicSource *musicSource)
47 if(!musicSource)
48 return;
49 _Sources.insert(musicSource);
52 // ***************************************************************************
53 void CMusicSoundManager::removeMusicSourcePlaying(CMusicSource *musicSource)
55 _Sources.erase(musicSource);
56 // may remove from the already played source
57 _AlreadyPlayedSources.erase(musicSource);
60 // ***************************************************************************
61 void CMusicSoundManager::update()
63 // if disabled, then just quit
64 if(!_Enabled)
65 return;
67 // update playing music each frame
68 NLMISC::TTime currentTime= CTime::getLocalTime();
69 CAudioMixerUser *mixer= CAudioMixerUser::instance();
71 // **** First, see if the current music played is cut-able
72 bool canPlayNewMusic= true;
73 // if the current played music has not ended his "minimum play time"
74 if(_TimeConstraintEnabled && _CurrentMusicPlaying && currentTime<=_PlayStartTime+_CurrentMusicPlaying->getMinimumPlayTime())
75 canPlayNewMusic= false;
77 // if cannot play new music, continue the current one
78 if(!canPlayNewMusic)
79 return;
81 // **** Search a music to replace the currently played one
82 CMusicSound *bestSound= _CurrentMusicPlaying;
83 CMusicSource *bestSource= NULL;
84 std::set<CMusicSource*>::iterator it= _Sources.begin();
85 // for all possibles music sources
86 for(;it!=_Sources.end();it++)
88 CMusicSource *src= *it;
89 CMusicSound *snd= dynamic_cast<CMusicSound*>(src->getSound());
90 // error, -> skip
91 if(!snd)
92 continue;
93 // If the source was already played (this is not a loop sound), skip it
94 // NB: It may be the current one but in this case it doesn't matters....
95 if(_AlreadyPlayedSources.find(src)!=_AlreadyPlayedSources.end())
96 continue;
97 // verify that this sound can be played again from the last time it has been played
98 if(_TimeConstraintEnabled && snd->LastStopTime>INT_MIN && currentTime<=snd->LastStopTime+snd->getTimeBeforeCanReplay())
99 continue;
100 // if no sound yet, take it
101 if(!bestSound)
103 bestSource= src;
104 bestSound= snd;
106 // else compare sound
107 else
109 // take the higher priority (priority value is inversed: 0 is the best priority)
110 if(snd->getPriority()<bestSound->getPriority())
112 bestSound= snd;
113 bestSource= src;
115 // else, other criteria
116 else if(snd->getPriority()==bestSound->getPriority())
118 /* if the new sound is not looping and the best is, consider the new sound as an "instant sound"
119 which is prioritary
121 if(!snd->getLooping() && bestSound->getLooping())
123 bestSound= snd;
124 bestSource= src;
126 else if(snd->getLooping() == bestSound->getLooping())
128 // if the bestSound is the current sound played, prefer to not change the sound
129 if(bestSound!=_CurrentMusicPlaying)
131 /* NB: here, bestSound can be != from _CurrentMusicPlaying in the following cases:
132 - _CurrentMusicPlaying= NULL
133 - bestSound was assigned to a higher priority sound than _CurrentMusicPlaying
134 thereFore snd should be different from _CurrentMusicPlaying, since this one is of
135 lower priority...
137 // compare name to avoid full random jitter
138 string snd0= CStringMapper::unmap(bestSound->getFileName());
139 string snd1= CStringMapper::unmap(snd->getFileName());
140 if(snd1>snd0)
142 bestSound= snd;
143 bestSource= src;
151 // if some new music found (different from the currently played one)
152 if(bestSound && bestSound!= _CurrentMusicPlaying)
154 // then launch the new music
155 startMusic(bestSound, bestSource);
157 // else, no new music found => if the music is currently playing
158 else if(_CurrentMusicPlaying)
160 // if the music has ended (and not loop), stop
161 if(_CurrentMusicPlaying->getLooping()==false && mixer->isMusicEnded())
163 // without fade (no need since ended)
164 stopMusic(false);
166 else
168 // verify that a source with this sound still exist. If not, we have to cut this sound too
169 bool found= false;
170 std::set<CMusicSource*>::iterator it= _Sources.begin();
171 for(;it!=_Sources.end();it++)
173 CMusicSource *src= *it;
174 CMusicSound *snd= dynamic_cast<CMusicSound*>(src->getSound());
175 if(snd && snd==_CurrentMusicPlaying)
177 found= true;
178 break;
181 // if not found, cut the music
182 if(!found)
184 // with fade
185 stopMusic(true);
191 // ***************************************************************************
192 void CMusicSoundManager::enable(bool enable)
194 // if disabled, stop any music (without any fade)
195 if(!enable)
196 stopMusic(false);
198 _Enabled= enable;
201 // ***************************************************************************
202 void CMusicSoundManager::startMusic(CMusicSound *newMs, CMusicSource *newSrc)
204 nlassert(newMs && newSrc);
205 // fade with the current. Take the min of new FadeIn and old FadeOut
206 sint32 xFade= newMs->getFadeInLength();
207 if(_CurrentMusicPlaying)
208 xFade= min(xFade, _CurrentMusicPlaying->getFadeOutLength());
210 // start play the new music, xFade with the old
211 CAudioMixerUser::instance()->playMusic(CStringMapper::unmap(newMs->getFileName()), uint(xFade), true, newMs->getLooping());
213 // Mark the old one as stopped
214 if(_CurrentMusicPlaying)
216 _CurrentMusicPlaying->LastStopTime= CTime::getLocalTime();
219 // update markers
220 _CurrentMusicPlaying= newMs;
221 _PlayStartTime= CTime::getLocalTime();
223 // The source is played this time. Avoid replay it for infinite time if the player stay in the zone
224 if(!newMs->getLooping())
225 _AlreadyPlayedSources.insert(newSrc);
228 // ***************************************************************************
229 void CMusicSoundManager::stopMusic(bool allowFade)
231 if(_CurrentMusicPlaying)
233 // stop with or without fadeout
234 if(allowFade)
235 CAudioMixerUser::instance()->stopMusic(_CurrentMusicPlaying->getFadeOutLength());
236 else
237 CAudioMixerUser::instance()->stopMusic(0);
238 // Mark the last stop time
239 _CurrentMusicPlaying->LastStopTime= CTime::getLocalTime();
240 // no more music playing
241 _CurrentMusicPlaying= NULL;
246 } // NLSOUND