# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

complex_source.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #include "stdsound.h"
00027 
00028 #include "complex_source.h"
00029 #include "complex_sound.h"
00030 
00031 using namespace std;
00032 using namespace NLMISC;
00033 
00034 namespace NLSOUND 
00035 {
00036 
00037 CComplexSource::CComplexSource  (CComplexSound *soundPattern, bool spawn, TSpawnEndCallback cb, void *cbUserParam)
00038 :       CSourceCommon(soundPattern, spawn, cb, cbUserParam),
00039         _Source1(NULL),
00040         _Source2(NULL)
00041 {
00042         nlassert(soundPattern->getSoundType() == CSound::SOUND_COMPLEX);
00043         _PatternSound = static_cast<CComplexSound*>(soundPattern);
00044 
00045         // read original parameters
00046         _Gain = soundPattern->getGain();
00047         _Pitch = soundPattern->getPitch();
00048         _Looping = soundPattern->getLooping();
00049         _Priority = soundPattern->getPriority();
00050         _TickPerSecond = soundPattern->getTicksPerSecond();
00051 }
00052 
00053 CComplexSource::~CComplexSource()
00054 {
00055         CAudioMixerUser *mixer = CAudioMixerUser::instance();
00056         // security
00057         CAudioMixerUser::instance()->unregisterUpdate(this);
00058         CAudioMixerUser::instance()->removeEvents(this);
00059 
00060         std::vector<USource     *>::iterator first(_AllSources.begin()), last(_AllSources.end());
00061         for (; first != last; ++first)
00062         {
00063                 //mixer->removeSource(*first);
00064                 delete *first;
00065         }
00066 }
00067 
00068 
00069 void CComplexSource::setSound( TSoundId id, CSoundContext *context)
00070 {
00071 }
00072 
00073 TSoundId CComplexSource::getSound()
00074 {
00075         return _PatternSound;
00076 }
00077 /*
00078 void CComplexSource::setPriority( TSoundPriority pr, bool redispatch)
00079 {
00080 }
00081 
00082 void CComplexSource::   setLooping( bool l )
00083 {
00084 }
00085 bool CComplexSource::getLooping() const
00086 {
00087         return false;
00088 }
00089 */
00090 
00091 bool CComplexSource::isPlaying()
00092 {
00093         return _Playing;
00094 }
00095 
00096 void CComplexSource::play()
00097 {
00098         CAudioMixerUser *mixer = CAudioMixerUser::instance();
00099         NLMISC::TTime now = NLMISC::CTime::getLocalTime();
00100 
00101         switch (_PatternSound->getPatternMode())
00102         {
00103         case CComplexSound::MODE_CHAINED:
00104                 {
00105                         _SoundSeqIndex = 0;
00106                         const vector<uint32>    &soundSeq = _PatternSound->getSoundSeq();
00107                         if (!soundSeq.empty())
00108                         {
00109                                 CSound *sound = mixer->getSoundId(_PatternSound->getSound(soundSeq[_SoundSeqIndex++]));
00110 
00111                                 if (sound == 0)
00112                                         return;
00113                                 
00114                                 if (_PatternSound->doFadeIn())
00115                                         _FadeLength = min(uint32(_PatternSound->getFadeLenght()/_TickPerSecond), sound->getDuration() /2);
00116                                 else
00117                                         _FadeLength = 0;
00118 
00119                                 _Source2 = mixer->createSource(sound, false);
00120                                 if (_Source2 == NULL)
00121                                         return;
00122                                 _Source2->setRelativeGain(0);
00123                                 _Source2->setPos(_Position);
00124                                 _Source2->play();
00125                                 _StartTime2 = now;
00126 
00127                                 // register for fade in.
00128                                 mixer->registerUpdate(this);
00129                         }
00130                 }
00131                 break;
00132         case CComplexSound::MODE_SPARSE:
00133                 {
00134                         // use Source1, sound sequence, delay sequence and event.
00135                         _SoundSeqIndex = 0;
00136                         _DelaySeqIndex = 0;
00137                         const vector<uint32>    &soundSeq = _PatternSound->getSoundSeq();
00138                         if (!soundSeq.empty())
00139                         {
00140                                 CSound *sound = mixer->getSoundId(_PatternSound->getSound(soundSeq[_SoundSeqIndex++]));
00141 
00142                                 _Source1 = mixer->createSource(sound, false);
00143                                 if (_Source1 == NULL)
00144                                         return;
00145                                 _Source1->setRelativeGain(_Gain);
00146                                 _Source1->setPos(_Position);
00147                                 _Source1->play();
00148                                 _StartTime1 = now;
00149 
00150                                 // register event for next sound.
00151                                 const std::vector<uint32> &delaySeq = _PatternSound->getDelaySeq();
00152                                 if (!delaySeq.empty() && _DelaySeqIndex < delaySeq.size())
00153                                 {
00154                                         _LastSparseEvent = false;
00155                                         // event for next sound.
00156                                         mixer->addEvent(this, uint64(now + sound->getDuration() + delaySeq[_DelaySeqIndex++]/_TickPerSecond));
00157                                 }
00158                                 else
00159                                 {
00160                                         _LastSparseEvent = true;
00161                                         // event for stop
00162                                         mixer->addEvent(this, now + sound->getDuration());
00163                                 }
00164                         }
00165                 }
00166                 break;
00167         case CComplexSound::MODE_ALL_IN_ONE:
00168                 {
00169                         // just spanw all the listed source.
00170                         const std::vector<std::string> &sounds = _PatternSound->getSounds();
00171 
00172                         std::vector<std::string>::const_iterator first(sounds.begin()), last(sounds.end());
00173 
00174                         if (_AllSources.empty())
00175                         {
00176                                 // create the sources
00177                                 for (; first != last; ++first)
00178                                 {
00179                                         CSound *sound = mixer->getSoundId(*first);
00180                                         if (sound != NULL)
00181                                         {
00182                                                 USource *source = mixer->createSource(sound, false);
00183                                                 source->setRelativeGain(_Gain);
00184                                                 source->setPos(_Position);
00185                                                 source->play();
00186                                                 
00187                                                 _AllSources.push_back(source);
00188                                         }
00189                                 }
00190                         }
00191                         else
00192                         {
00193                                 // just replay the existing source.
00194                                 std::vector<USource     *>::iterator first(_AllSources.begin()), last(_AllSources.end());
00195 
00196                                 for (; first != last; ++first)
00197                                 {
00198                                         (*first)->setRelativeGain(_Gain);
00199                                         (*first)->setPos(_Position);
00200                                         (*first)->play();
00201                                 }
00202                         }
00203 
00204                         mixer->addEvent(this, NLMISC::CTime::getLocalTime() + _PatternSound->getDuration());
00205                 }
00206                 break;
00207         default:
00208                 nldebug("Unknow pattern mode. Can't play.");
00209         }
00210 
00211         CSourceCommon::play();
00212 }
00213 void CComplexSource::stop()
00214 {
00215         CAudioMixerUser *mixer = CAudioMixerUser::instance();
00216         if (_Source1)
00217         {
00218 //              _Source1->stop();
00219 //              mixer->removeSource(_Source1);
00220                 delete _Source1;
00221 
00222                 _Source1 = NULL;
00223         }
00224         if (_Source2)
00225         {
00226 //              _Source2->stop();
00227 //              mixer->removeSource(_Source2);
00228                 delete _Source2;
00229 
00230                 _Source2 = NULL;
00231         }
00232 
00233         std::vector<USource     *>::iterator first(_AllSources.begin()), last(_AllSources.end());
00234         for (; first != last; ++first)
00235         {
00236                 if ((*first)->isPlaying())
00237                         (*first)->stop();
00238         }
00239 
00240         switch (_PatternSound->getPatternMode())
00241         {
00242         case CComplexSound::MODE_CHAINED:
00243                 mixer->unregisterUpdate(this);
00244                 mixer->removeEvents(this);
00245                 break;
00246         case CComplexSound::MODE_SPARSE:
00247         case CComplexSound::MODE_ALL_IN_ONE:
00248                 mixer->removeEvents(this);
00249                 break;
00250         }
00251 
00252         CSourceCommon::stop();
00253 }
00254 
00255 /*void CComplexSource::unregisterSpawnCallBack()
00256 {
00257 }
00258 */
00259 void CComplexSource::setPos( const NLMISC::CVector& pos )
00260 {
00261         CSourceCommon::setPos(pos);
00262         
00263         if (_Source1 != NULL)
00264                 _Source1->setPos(pos);
00265         if (_Source2 != NULL)
00266                 _Source2->setPos(pos);
00267 
00268         std::vector<USource     *>::iterator first(_AllSources.begin()), last(_AllSources.end());
00269         for (; first != last; ++first)
00270         {
00271                 (*first)->setPos(pos);
00272         }
00273 }
00274 
00275 void CComplexSource::setVelocity( const NLMISC::CVector& vel )
00276 {
00277         CSourceCommon::setVelocity(vel);
00278         
00279         if (_Source1 != NULL)
00280                 _Source1->setVelocity(vel);
00281         if (_Source2 != NULL)
00282                 _Source2->setVelocity(vel);
00283 
00284         std::vector<USource     *>::iterator first(_AllSources.begin()), last(_AllSources.end());
00285         for (; first != last; ++first)
00286         {
00287                 (*first)->setVelocity(vel);
00288         }
00289 }
00290 /*void CComplexSource::getVelocity( NLMISC::CVector& vel ) const
00291 {
00292 }
00293 */
00294 void CComplexSource::setDirection( const NLMISC::CVector& dir )
00295 {
00296         CSourceCommon::setDirection(dir);
00297         
00298         if (_Source1 != NULL)
00299                 _Source1->setDirection(dir);
00300         if (_Source2 != NULL)
00301                 _Source2->setDirection(dir);
00302 
00303         std::vector<USource     *>::iterator first(_AllSources.begin()), last(_AllSources.end());
00304         for (; first != last; ++first)
00305         {
00306                 (*first)->setDirection(dir);
00307         }
00308 }
00309 /*
00310 void CComplexSource::getDirection( NLMISC::CVector& dir ) const
00311 {
00312 }
00313 */
00314 void CComplexSource::setGain( float gain )
00315 {
00316         CSourceCommon::setGain(gain);
00317         // update the gain of the played source.
00318         if (_Source1 != NULL)
00319                 _Source1->setGain(gain);
00320         if (_Source2 != NULL)
00321                 _Source2->setGain(gain);
00322 
00323         std::vector<USource     *>::iterator first(_AllSources.begin()), last(_AllSources.end());
00324         for (; first != last; ++first)
00325         {
00326                 (*first)->setGain(_Gain);
00327         }
00328 }
00329 
00330 void CComplexSource::setRelativeGain( float gain )
00331 {
00332         CSourceCommon::setRelativeGain(gain);
00333 
00334         if (_Source1 != NULL)
00335                 _Source1->setRelativeGain(gain);
00336         if (_Source2 != NULL)
00337                 _Source2->setRelativeGain(gain);
00338 
00339         std::vector<USource     *>::iterator first(_AllSources.begin()), last(_AllSources.end());
00340         for (; first != last; ++first)
00341         {
00342                 (*first)->setRelativeGain(_Gain);
00343         }
00344 }
00345 
00346 /*
00347 void CComplexSource::setPitch( float pitch )
00348 {
00349 }
00350 float CComplexSource::getPitch() const
00351 {
00352         return 0;
00353 }
00354 */
00355 /*
00356 void CComplexSource::setSourceRelativeMode( bool mode )
00357 {
00358 }
00359 bool CComplexSource::getSourceRelativeMode() const
00360 {
00361         return false;
00362 }
00363 */
00364 
00365 uint32 CComplexSource::getTime()
00366 {
00367         // evaluate the elapsed time.
00368         if (!_Playing || _PlayStart == 0)       // not started ?
00369                 return 0;
00370 
00371         TTime now = NLMISC::CTime::getLocalTime();
00372 
00373         TTime delta = now - _PlayStart;
00374 
00375         return uint32(delta);
00376 }
00377 
00378 
00380 void CComplexSource::onUpdate()
00381 {
00382         // do the cross fade : 
00383         //      - lower sound1, louder sound2, 
00384         //      - when max reach, stop the update, swap the sound, delete sound1 and set event for next fade.
00385 
00386         // can only occur for chained mode.
00387         nlassert(_PatternSound->getPatternMode() == CComplexSound::MODE_CHAINED);
00388 
00389         CAudioMixerUser *mixer = CAudioMixerUser::instance();
00390         
00391         // compute xfade factor.
00392         TTime now = NLMISC::CTime::getLocalTime();
00393         if (_FadeLength > 0)
00394         {
00395                 _FadeFactor = float((double(now) - double(_StartTime2)) / double(_FadeLength)) ;
00396 //              _FadeFactor = (_FadeFactor*_FadeFactor);
00397         }
00398         else
00399                 _FadeFactor = 1.0f;
00400 
00401         nldebug("Fade factor = %f", _FadeFactor);
00402         if (_FadeFactor >= 1.0)
00403         {
00404                 // fade end !
00405                 if (_Source1)
00406                 {
00407 //                      _Source1->stop();
00408 //                      mixer->removeSource(_Source1);
00409                         delete _Source1;
00410                         _Source1 = NULL;
00411                 }
00412                 if (_Source2)
00413                 {
00414                         // set max volume
00415                         _Source2->setRelativeGain(1.0f * _Gain);
00416                         // 'swap' the source
00417                         _Source1 = _Source2;
00418                         _StartTime1 = _StartTime2;
00419                         _Source2 = NULL;
00420                         // if there is a next sound available, program an event for the next xfade.
00421                         CSound  *sound2 = NULL;
00422 //                      _SoundSeqIndex++;
00423                         const vector<uint32>    &soundSeq = _PatternSound->getSoundSeq();
00424                         if (_SoundSeqIndex < soundSeq.size())
00425                         {
00426                                 sound2 = mixer->getSoundId(_PatternSound->getSound(soundSeq[_SoundSeqIndex++]));
00427                         }
00428                         else if (_Looping)
00429                         {
00430                                 // restart the sound sequence
00431                                 _SoundSeqIndex = 0;
00432                                 sound2 = mixer->getSoundId(_PatternSound->getSound(soundSeq[_SoundSeqIndex++]));
00433                         }
00434                                 
00435 
00436                         if (sound2 != NULL)
00437                         {
00438                                 nldebug("CS : Chaining to sound %s", sound2->getName().c_str());
00439                                 CAudioMixerUser *mixer = CAudioMixerUser::instance();
00440 
00441                                 // determine the XFade lenght (if next sound is too short.
00442                                 _FadeLength = minof<uint32>(uint32(_PatternSound->getFadeLenght()/_TickPerSecond), sound2->getDuration() / 2, _Source1->getSound()->getDuration()/2);
00443                                 _Source2 = mixer->createSource(sound2, false);
00444                                 // there is a next sound, add event for xfade.
00445                                 nldebug("Seting event for sound %s in %u millisec (XFade = %u).", _Source1->getSound()->getName().c_str(), _Source1->getSound()->getDuration(), _FadeLength);
00446                                 mixer->addEvent(this, _StartTime1 + _Source1->getSound()->getDuration() - _FadeLength);
00447                         }
00448                         else
00449                         {
00450                                 // no sound after, just set an event at end of current sound to stop the complex sound.
00451                                 nldebug("Setting last event for sound %s in %u millisec.", _Source1->getSound()->getName().c_str(), _Source1->getSound()->getDuration());
00452                                 if (_PatternSound->doFadeOut())
00453                                 {
00454                                         // set the event to begin fade out.
00455                                         mixer->addEvent(this, _StartTime1 + _Source1->getSound()->getDuration() - _PatternSound->getFadeLenght());
00456                                 }
00457                                 else
00458                                 {
00459                                         // set the event at end of sound.
00460                                         mixer->addEvent(this, _StartTime1 + _Source1->getSound()->getDuration());
00461                                 }
00462                         }
00463                 }
00464                 else
00465                 {
00466                         if (_PatternSound->doFadeOut())
00467                         {
00468                                 // update is responsible for stoping the sound.
00469                                 _Playing = false;
00470                         }
00471                 }
00472                 // remove from the update list
00473                 mixer->unregisterUpdate(this);
00474         }
00475         else
00476         {
00477                 // do the xfade
00478                 if (_Source1)
00479                 {
00480                         // lower the sound 1.
00481                         _Source1->setRelativeGain(float(1.0 - _FadeFactor) * _Gain);
00482 
00483                 }
00484                 if (_Source2)
00485                 {
00486                         // lower the sound 1.
00487 //                      _Source2->setRelativeGain(float(sqrt(_FadeFactor)) * _Gain);
00488                         _Source2->setRelativeGain(float(_FadeFactor) * _Gain);
00489                 }
00490         }
00491 }
00493 void CComplexSource::onEvent()
00494 {
00495         CAudioMixerUser *mixer = CAudioMixerUser::instance();
00496         NLMISC::TTime now = NLMISC::CTime::getLocalTime();
00497 
00498         switch (_PatternSound->getPatternMode())
00499         {
00500         case CComplexSound::MODE_CHAINED:
00501                 {
00502                         // either it's time to begin a new xfade, or to end this sound.
00503                         if (_Source2 != NULL)
00504                         {
00505                                 // start new cross fade.?
00506                                 _StartTime2 = now;
00507                                 // mute the source2
00508                                 _Source2->setRelativeGain(0);
00509                                 // start the source 2
00510                                 _Source2->play();
00511                                 // register for update.
00512                                 mixer->registerUpdate(this);
00513                         }
00514                         else
00515                         {
00516                                 if (_PatternSound->doFadeOut())
00517                                 {
00518                                         // set in update list for fade out.
00519                                         _StartTime2 = now;
00520                                         mixer->registerUpdate(this);
00521                                 }
00522                                 else
00523                                 {
00524                                         // end the sound.
00525 //                                      _Source1->stop();
00526 //                                      mixer->removeSource(_Source1);
00527                                         delete _Source1;
00528                                         _Source1 = NULL;
00529                                         _Playing = false;
00530                                 }
00531                         }
00532                 }
00533                 break;
00534         case CComplexSound::MODE_SPARSE:
00535                 {
00536                         if (_Source1 != NULL)
00537                         {
00538 //                              _Source1->stop();
00539 //                              mixer->removeSource(_Source1);
00540                                 delete _Source1;
00541                                 _Source1 = NULL;
00542                         }
00543 
00544                         const std::vector<uint32> &delaySeq = _PatternSound->getDelaySeq();
00545                         const vector<uint32>    &soundSeq = _PatternSound->getSoundSeq();
00546 
00547                         if (_Looping && _DelaySeqIndex >= delaySeq.size())
00548                         {
00549                                 _DelaySeqIndex = 0;
00550                         }
00551 
00552                         if (!soundSeq.empty() && !_LastSparseEvent)
00553                         {
00554                                 // wrap around sound sequence until there are delays...
00555                                 if (_SoundSeqIndex >= soundSeq.size())
00556                                         _SoundSeqIndex = 0;
00557 
00558                                 CSound *sound = mixer->getSoundId(_PatternSound->getSound(soundSeq[_SoundSeqIndex++]));
00559 
00560                                 _Source1 = mixer->createSource(sound, false);
00561                                 if (_Source1 == NULL)
00562                                 {
00563                                         stop();
00564                                         return;
00565                                 }
00566                                 _Source1->setRelativeGain(_Gain);
00567                                 _Source1->setPos(_Position);
00568                                 _Source1->play();
00569                                 _StartTime1 = now;
00570 
00571                                 // register event for next sound.
00572                                 if (!delaySeq.empty() && _DelaySeqIndex < delaySeq.size())
00573                                 {
00574                                         // event for next sound.
00575                                         mixer->addEvent(this, uint64(now + sound->getDuration() + delaySeq[_DelaySeqIndex++]/_TickPerSecond));
00576                                 }
00577                                 else
00578                                 {
00579                                         // event for stop
00580                                         _LastSparseEvent = true;
00581                                         mixer->addEvent(this, now + sound->getDuration());
00582                                 }
00583                         }
00584                         else
00585                         {
00586                                 // this is the event for stop !
00587                                 stop();
00588                         }
00589                 }
00590                 break;
00591         case CComplexSound::MODE_ALL_IN_ONE:
00592                 // just call the stop method.
00593                 stop();
00594                 break;
00595         default:
00596                 nlassert(false);
00597         }
00598 }
00599 
00600 
00601 
00602 } // NLSOUND