00001 00005 /* Copyright, 2000-2004 Nevrax Ltd. 00006 * 00007 * This file is part of NEVRAX NEL. 00008 * NEVRAX NEL is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2, or (at your option) 00011 * any later version. 00012 00013 * NEVRAX NEL is distributed in the hope that it will be useful, but 00014 * WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * General Public License for more details. 00017 00018 * You should have received a copy of the GNU General Public License 00019 * along with NEVRAX NEL; see the file COPYING. If not, write to the 00020 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, 00021 * MA 02111-1307, USA. 00022 */ 00023 00024 #include "stdsound.h" 00025 00026 #include "audio_mixer_user.h" 00027 #include "music_sound_manager.h" 00028 #include "music_sound.h" 00029 #include "music_source.h" 00030 00031 00032 using namespace NLMISC; 00033 using namespace std; 00034 00035 00036 namespace NLSOUND { 00037 00038 00039 // *************************************************************************** 00040 CMusicSoundManager::CMusicSoundManager() 00041 { 00042 _Enabled= true; 00043 _CurrentMusicPlaying= NULL; 00044 _PlayStartTime= INT_MIN; 00045 _TimeConstraintEnabled= true; 00046 } 00047 00048 // *************************************************************************** 00049 void CMusicSoundManager::addMusicSourcePlaying(CMusicSource *musicSource) 00050 { 00051 if(!musicSource) 00052 return; 00053 _Sources.insert(musicSource); 00054 } 00055 00056 // *************************************************************************** 00057 void CMusicSoundManager::removeMusicSourcePlaying(CMusicSource *musicSource) 00058 { 00059 _Sources.erase(musicSource); 00060 // may remove from the already played source 00061 _AlreadyPlayedSources.erase(musicSource); 00062 } 00063 00064 // *************************************************************************** 00065 void CMusicSoundManager::update() 00066 { 00067 // if disabled, then just quit 00068 if(!_Enabled) 00069 return; 00070 00071 // update playing music each frame 00072 NLMISC::TTime currentTime= CTime::getLocalTime(); 00073 CAudioMixerUser *mixer= CAudioMixerUser::instance(); 00074 00075 // **** First, see if the current music played is cut-able 00076 bool canPlayNewMusic= true; 00077 // if the current played music has not ended his "minimum play time" 00078 if(_TimeConstraintEnabled && _CurrentMusicPlaying && currentTime<=_PlayStartTime+_CurrentMusicPlaying->getMinimumPlayTime()) 00079 canPlayNewMusic= false; 00080 00081 // if cannot play new music, continue the current one 00082 if(!canPlayNewMusic) 00083 return; 00084 00085 // **** Search a music to replace the currently played one 00086 CMusicSound *bestSound= _CurrentMusicPlaying; 00087 CMusicSource *bestSource= NULL; 00088 std::set<CMusicSource*>::iterator it= _Sources.begin(); 00089 // for all possibles music sources 00090 for(;it!=_Sources.end();it++) 00091 { 00092 CMusicSource *src= *it; 00093 CMusicSound *snd= dynamic_cast<CMusicSound*>(src->getSound()); 00094 // error, -> skip 00095 if(!snd) 00096 continue; 00097 // If the source was already played (this is not a loop sound), skip it 00098 // NB: It may be the current one but in this case it doesn't matters.... 00099 if(_AlreadyPlayedSources.find(src)!=_AlreadyPlayedSources.end()) 00100 continue; 00101 // verify that this sound can be played again from the last time it has been played 00102 if(_TimeConstraintEnabled && snd->LastStopTime>INT_MIN && currentTime<=snd->LastStopTime+snd->getTimeBeforeCanReplay()) 00103 continue; 00104 // if no sound yet, take it 00105 if(!bestSound) 00106 { 00107 bestSource= src; 00108 bestSound= snd; 00109 } 00110 // else compare sound 00111 else 00112 { 00113 // take the higher priority (priority value is inversed: 0 is the best priority) 00114 if(snd->getPriority()<bestSound->getPriority()) 00115 { 00116 bestSound= snd; 00117 bestSource= src; 00118 } 00119 // else, other criteria 00120 else if(snd->getPriority()==bestSound->getPriority()) 00121 { 00122 /* if the new sound is not looping and the best is, consider the new sound as an "instant sound" 00123 which is prioritary 00124 */ 00125 if(!snd->getLooping() && bestSound->getLooping()) 00126 { 00127 bestSound= snd; 00128 bestSource= src; 00129 } 00130 else if(snd->getLooping() == bestSound->getLooping()) 00131 { 00132 // if the bestSound is the current sound played, prefer to not change the sound 00133 if(bestSound!=_CurrentMusicPlaying) 00134 { 00135 /* NB: here, bestSound can be != from _CurrentMusicPlaying in the following cases: 00136 - _CurrentMusicPlaying= NULL 00137 - bestSound was assigned to a higher priority sound than _CurrentMusicPlaying 00138 thereFore snd should be different from _CurrentMusicPlaying, since this one is of 00139 lower priority... 00140 */ 00141 // compare name to avoid full random jitter 00142 string snd0= CStringMapper::unmap(bestSound->getFileName()); 00143 string snd1= CStringMapper::unmap(snd->getFileName()); 00144 if(snd1>snd0) 00145 { 00146 bestSound= snd; 00147 bestSource= src; 00148 } 00149 } 00150 } 00151 } 00152 } 00153 } 00154 00155 // if some new music found (different from the currently played one) 00156 if(bestSound && bestSound!= _CurrentMusicPlaying) 00157 { 00158 // then launch the new music 00159 startMusic(bestSound, bestSource); 00160 } 00161 // else, no new music found => if the music is currently playing 00162 else if(_CurrentMusicPlaying) 00163 { 00164 // if the music has ended (and not loop), stop 00165 if(_CurrentMusicPlaying->getLooping()==false && mixer->isMusicEnded()) 00166 { 00167 // without fade (no need since ended) 00168 stopMusic(false); 00169 } 00170 else 00171 { 00172 // verify that a source with this sound still exist. If not, we have to cut this sound too 00173 bool found= false; 00174 std::set<CMusicSource*>::iterator it= _Sources.begin(); 00175 for(;it!=_Sources.end();it++) 00176 { 00177 CMusicSource *src= *it; 00178 CMusicSound *snd= dynamic_cast<CMusicSound*>(src->getSound()); 00179 if(snd && snd==_CurrentMusicPlaying) 00180 { 00181 found= true; 00182 break; 00183 } 00184 } 00185 // if not found, cut the music 00186 if(!found) 00187 { 00188 // with fade 00189 stopMusic(true); 00190 } 00191 } 00192 } 00193 } 00194 00195 // *************************************************************************** 00196 void CMusicSoundManager::enable(bool enable) 00197 { 00198 // if disabled, stop any music (without any fade) 00199 if(!enable) 00200 stopMusic(false); 00201 00202 _Enabled= enable; 00203 } 00204 00205 // *************************************************************************** 00206 void CMusicSoundManager::startMusic(CMusicSound *newMs, CMusicSource *newSrc) 00207 { 00208 nlassert(newMs && newSrc); 00209 // fade with the current. Take the min of new FadeIn and old FadeOut 00210 sint32 xFade= newMs->getFadeInLength(); 00211 if(_CurrentMusicPlaying) 00212 xFade= min(xFade, _CurrentMusicPlaying->getFadeOutLength()); 00213 00214 // start play the new music, xFade with the old 00215 CAudioMixerUser::instance()->playMusic(CStringMapper::unmap(newMs->getFileName()), uint(xFade), true, newMs->getLooping()); 00216 00217 // Mark the old one as stoped 00218 if(_CurrentMusicPlaying) 00219 { 00220 _CurrentMusicPlaying->LastStopTime= CTime::getLocalTime(); 00221 } 00222 00223 // update markers 00224 _CurrentMusicPlaying= newMs; 00225 _PlayStartTime= CTime::getLocalTime(); 00226 00227 // The source is played this time. Avoid replay it for infinite time if the player stay in the zone 00228 if(!newMs->getLooping()) 00229 _AlreadyPlayedSources.insert(newSrc); 00230 } 00231 00232 // *************************************************************************** 00233 void CMusicSoundManager::stopMusic(bool allowFade) 00234 { 00235 if(_CurrentMusicPlaying) 00236 { 00237 // stop with or without fadeout 00238 if(allowFade) 00239 CAudioMixerUser::instance()->stopMusic(_CurrentMusicPlaying->getFadeOutLength()); 00240 else 00241 CAudioMixerUser::instance()->stopMusic(0); 00242 // Mark the last stop time 00243 _CurrentMusicPlaying->LastStopTime= CTime::getLocalTime(); 00244 // no more music playing 00245 _CurrentMusicPlaying= NULL; 00246 } 00247 } 00248 00249 00250 } // NLSOUND
1.6.1