1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2010 Matt RAYKOWSKI (sfb) <matt.raykowski@gmail.com>
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/>.
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
;
35 // ***************************************************************************
36 CMusicSoundManager::CMusicSoundManager()
39 _CurrentMusicPlaying
= NULL
;
40 _PlayStartTime
= INT_MIN
;
41 _TimeConstraintEnabled
= true;
44 // ***************************************************************************
45 void CMusicSoundManager::addMusicSourcePlaying(CMusicSource
*musicSource
)
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
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
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());
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())
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())
100 // if no sound yet, take it
106 // else compare sound
109 // take the higher priority (priority value is inversed: 0 is the best priority)
110 if(snd
->getPriority()<bestSound
->getPriority())
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"
121 if(!snd
->getLooping() && bestSound
->getLooping())
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
137 // compare name to avoid full random jitter
138 string snd0
= CStringMapper::unmap(bestSound
->getFileName());
139 string snd1
= CStringMapper::unmap(snd
->getFileName());
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)
168 // verify that a source with this sound still exist. If not, we have to cut this sound too
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
)
181 // if not found, cut the music
191 // ***************************************************************************
192 void CMusicSoundManager::enable(bool enable
)
194 // if disabled, stop any music (without any fade)
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();
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
235 CAudioMixerUser::instance()->stopMusic(_CurrentMusicPlaying
->getFadeOutLength());
237 CAudioMixerUser::instance()->stopMusic(0);
238 // Mark the last stop time
239 _CurrentMusicPlaying
->LastStopTime
= CTime::getLocalTime();
240 // no more music playing
241 _CurrentMusicPlaying
= NULL
;