simple_source.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2001 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 "simple_source.h"
00027 #include "driver/buffer.h"
00028 #include "driver/source.h"
00029 #include "mixing_track.h"
00030 #include "simple_sound.h"
00031 #include "clustered_sound.h"
00032 
00033 using namespace NLMISC;
00034 
00035 
00036 namespace NLSOUND
00037 {
00038 
00039 
00040 /*
00041  * Constructor
00042  */
00043 CSimpleSource::CSimpleSource( CSimpleSound *simpleSound, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster)
00044 :   CSourceCommon(simpleSound, spawn, cb, cbUserParam, cluster),
00045     _Track(NULL), _PlayMuted(false)
00046 {
00047     nlassert(simpleSound != 0);
00048     _Sound = simpleSound;
00049 
00050     // get a local copy of the simple sound parameter
00051     _Alpha = _Sound->getAlpha();
00052 }
00053 
00054 
00055 /*
00056  * Destructor
00057  */
00058 CSimpleSource::~CSimpleSource()
00059 {
00060     if (_Playing)
00061         stop();
00062     // Yoyo: security. with prec stop(), should not be needed, but a crash still raise
00063     // in "currentEvent->onEvent();" in audio_mixer_user.cpp
00064     CAudioMixerUser::instance()->removeEvents(this);
00065 }
00066 
00067 CSimpleSound    *CSimpleSource::getSimpleSound()
00068 {
00069     return _Sound;
00070 }
00071 
00072 uint32  CSimpleSource::getTime()
00073 {
00074     if (_Track && _Track->DrvSource)
00075     {
00076         return _Track->DrvSource->getTime();
00077     }
00078     else
00079         return 0;
00080 }
00081 
00082 
00083 IBuffer                 *CSimpleSource::getBuffer()
00084 {
00085     return _Sound->getBuffer();
00086 }
00087 
00088 
00089 
00090 
00091 /*
00092  * Set looping on/off for future playbacks (default: off)
00093  */
00094 void                    CSimpleSource::setLooping( bool l )
00095 {
00096     CSourceCommon::setLooping(l);
00097     if ( _Track != NULL )
00098     {
00099         _Track->DrvSource->setLooping( l );
00100     }
00101 }
00102 
00103 
00104 CVector     CSimpleSource::getVirtualPos() const
00105 {
00106     if (getCluster() != 0)
00107     {
00108         // need to check the cluster status
00109         const CClusteredSound::CClusterSoundStatus *css = CAudioMixerUser::instance()->getClusteredSound()->getClusterSoundStatus(getCluster());
00110         if (css != 0)
00111         {
00112             // there is some data here, update the virtual position of the sound.
00113             float dist = (css->Position - getPos()).norm();
00114             CVector vpos(CAudioMixerUser::instance()->getListenPosVector() + css->Direction * (css->Dist + dist));
00115             vpos = _Position * (1-css->PosAlpha) + vpos*(css->PosAlpha);
00116             return vpos;
00117         }
00118     }
00119 
00120     return _Position;
00121 }
00122 
00123 
00124 /*
00125  * Play
00126  */
00127 void                    CSimpleSource::play()
00128 {
00129 //  nldebug("CSimpleSource %p : play", this);
00130 
00131     CAudioMixerUser *mixer = CAudioMixerUser::instance();
00132 
00133     // -- Some test to scheck if we can play the source
00134 
00135     // Check if sample buffer is available and if the sound source is not too far
00136     if (_Sound->getBuffer() == 0
00137         || !_Sound->getBuffer()->isBufferLoaded()
00138         || (mixer->getListenPosVector() - _Position).sqrnorm() > _Sound->getMaxDistance()*_Sound->getMaxDistance())
00139     {
00140         // The sample buffer is not available, don't play (we don't know the lenght)
00141         if (_Spawn)
00142         {
00143             if (_SpawnEndCb != 0)
00144                 _SpawnEndCb(this, _CbUserParam);
00145 
00146             delete this;
00147         }
00148 //      nldebug("CSimpleSource %p : play FAILED !", (CAudioMixerUser::IMixerEvent*)this);
00149         return;
00150     }
00151 
00152     // -- Here we can play the source, either in a real track or as a muted source.
00153 
00154     // Try to obtain a track
00155     if (_Track == 0)
00156         _Track = mixer->getFreeTrack(this);
00157     if (_Track != 0)
00158     {
00159         // ok, we have a track to realy play, fill the data into the track
00160         _Track->DrvSource->setStaticBuffer(_Sound->getBuffer());
00161 
00162 //      _Track->DrvSource->setPos( _Position, false);
00163         _Track->DrvSource->setPos( getVirtualPos(), false);
00164         if ( ! _Sound->getBuffer()->isStereo() )
00165         {
00166             _Track->DrvSource->setMinMaxDistances( _Sound->getMinDistance(), _Sound->getMaxDistance(), false );
00167             setDirection( _Direction ); // because there is a workaround inside
00168             _Track->DrvSource->setVelocity( _Velocity );
00169         }
00170         _Track->DrvSource->setGain( _Gain );
00171         _Track->DrvSource->setSourceRelativeMode( _RelativeMode );
00172         _Track->DrvSource->setLooping( _Looping );
00173         _Track->DrvSource->setPitch( _Pitch );
00174         _Track->DrvSource->setAlpha( _Alpha );
00175 
00176         // and play the sound
00177         bool play = _Track->DrvSource->play();
00178 
00179         nlassert(play);
00180 //      nldebug("CSimpleSource %p : REAL play done", (CAudioMixerUser::IMixerEvent*)this);
00181     }
00182     else
00183     {
00184         if (_Priority == HighestPri)
00185         {
00186             // This sound is not discardable, add it in waiting playlist
00187             mixer->addSourceWaitingForPlay(this);
00188             return;
00189         }
00190         // there is no available track, just do a 'muted' play
00191         mixer->addEvent(this, CTime::getLocalTime()+_Sound->getDuration());
00192         _PlayMuted = true;
00193         mixer->incPlayingSourceMuted();
00194 //      nldebug("CSimpleSource %p : MUTED play done", (CAudioMixerUser::IMixerEvent*)this);
00195     }
00196 
00197     CSourceCommon::play();
00198 
00199 }
00200 
00201 void CSimpleSource::onEvent()
00202 {
00203 //  nldebug("CSimpleSource %p : stop EVENT", (CAudioMixerUser::IMixerEvent*)this);
00204     // A muted play is terminated.
00205     if (!_Playing)
00206         return;
00207 //  nlassert(_Playing);
00208 //  nlassert(_Track == 0);
00209     _PlayMuted = false;
00210     CAudioMixerUser::instance()->decPlayingSourceMuted();
00211 
00212     stop();
00213 }
00214 
00215 /*
00216  * Stop playing
00217  */
00218 void                    CSimpleSource::stop()
00219 {
00220 //  nldebug("CSimpleSource %p : stop", (CAudioMixerUser::IMixerEvent*)this);
00221 //  nlassert(_Playing);
00222     if (!_Playing)
00223         return;
00224 
00225     if (_Track != 0)
00226     {
00227         // free the track
00228         _Track->DrvSource->stop();
00229         _Track->DrvSource->setStaticBuffer(0);
00230         CAudioMixerUser::instance()->freeTrack(_Track);
00231         _Track = 0;
00232     }
00233     else if (_PlayMuted)
00234     {
00235         // clear the registered event because of a stop before normal end of play
00236         CAudioMixerUser::instance()->decPlayingSourceMuted();
00237         CAudioMixerUser::instance()->removeEvents(this);
00238     }
00239 
00240 //  CAudioMixerUser::instance()->decPlayingSource();
00241     CSourceCommon::stop();
00242 
00243     if (_Spawn)
00244     {
00245         if ( _SpawnEndCb != 0 )
00246         {
00247             _SpawnEndCb( this, _CbUserParam);
00248         }
00249 
00250         delete this;
00251     }
00252 }
00253 
00254 
00255 /* Set the position vector (default: (0,0,0)).
00256  * 3D mode -> 3D position
00257  * st mode -> x is the pan value (from left (-1) to right (1)), set y and z to 0
00258  */
00259 void                    CSimpleSource::setPos( const NLMISC::CVector& pos )
00260 {
00261     CSourceCommon::setPos(pos);
00262 
00263     // Set the position
00264     if ( _Track != NULL )
00265     {
00266 //      _Track->DrvSource->setPos( pos );
00267         _Track->DrvSource->setPos( getVirtualPos() );
00268     }
00269 }
00270 
00271 
00272 /*
00273  * Set the velocity vector (3D mode only, ignored in stereo mode) (default: (0,0,0))
00274  */
00275 void                    CSimpleSource::setVelocity( const NLMISC::CVector& vel )
00276 {
00277     CSourceCommon::setVelocity(vel);
00278 
00279     // Set the velocity
00280     if ( _Track != NULL )
00281     {
00282         // TODO : uncomment, test only
00283         _Track->DrvSource->setVelocity( vel );
00284     }
00285 }
00286 
00287 
00288 /*
00289  * Set the direction vector (3D mode only, ignored in stereo mode) (default: (0,0,0) as non-directional)
00290  */
00291 void                    CSimpleSource::setDirection( const NLMISC::CVector& dir )
00292 {
00293     CSourceCommon::setDirection(dir);
00294 
00295     // Set the direction
00296     if ( _Track != NULL )
00297     {
00298         if ( ! _Sound->getBuffer()->isStereo() )
00299         {
00300             static bool coneset = false;
00301             if ( dir.isNull() ) // workaround
00302             {
00303                 _Track->DrvSource->setCone( float(Pi*2), float(Pi*2), 1.0f ); // because the direction with 0 is not enough for a non-directional source!
00304                 _Track->DrvSource->setDirection( CVector::I );  // Don't send a 0 vector, DSound will complain. Send (1,0,0), it's omnidirectional anyway.
00305                 coneset = false;
00306             }
00307             else
00308             {
00309 //              if ( ! coneset )
00310                 {
00311                     _Track->DrvSource->setCone( _Sound->getConeInnerAngle(), _Sound->getConeOuterAngle(), _Sound->getConeOuterGain() );
00312                     coneset = true;
00313                 }
00314                 _Track->DrvSource->setDirection( dir );
00315             }
00316         }
00317     }
00318 }
00319 
00320 
00321 /* Set the gain (volume value inside [0 , 1]). (default: 1)
00322  * 0.0 -> silence
00323  * 0.5 -> -6dB
00324  * 1.0 -> no attenuation
00325  * values > 1 (amplification) not supported by most drivers
00326  */
00327 void                    CSimpleSource::setGain( float gain )
00328 {
00329     CSourceCommon::setGain(gain);
00330 
00331     // Set the gain
00332     if ( _Track != NULL )
00333     {
00334         _Track->DrvSource->setGain( gain );
00335     }
00336 }
00337 
00338 void CSimpleSource::setRelativeGain( float gain )
00339 {
00340     CSourceCommon::setRelativeGain(gain);
00341 
00342     // Set the gain
00343     if ( _Track != NULL )
00344     {
00345         _Track->DrvSource->setGain( _Gain );
00346     }
00347 }
00348 
00349 
00350 /* Shift the frequency. 1.0f equals identity, each reduction of 50% equals a pitch shift
00351  * of one octave. 0 is not a legal value.
00352  */
00353 void                    CSimpleSource::setPitch( float pitch )
00354 {
00355     CSourceCommon::setPitch(pitch);
00356 
00357     // Set the pitch
00358     if ( _Track != NULL )
00359     {
00360         _Track->DrvSource->setPitch( pitch );
00361     }
00362 }
00363 
00364 
00365 /*
00366  * Set the source relative mode. If true, positions are interpreted relative to the listener position (default: false)
00367  */
00368 void                    CSimpleSource::setSourceRelativeMode( bool mode )
00369 {
00370     CSourceCommon::setSourceRelativeMode(mode);
00371 
00372     // Set the relative mode
00373     if ( _Track != NULL )
00374     {
00375         _Track->DrvSource->setSourceRelativeMode( mode );
00376     }
00377 }
00378 
00379 /*
00380  * Get playing state. Return false if the source has stopped on its own.
00381  */
00382 bool                    CSimpleSource::isPlaying()
00383 {
00384     return _Playing;
00385 }
00386 
00387 
00388 } // NLSOUND

Generated on Thu Jan 7 08:26:38 2010 for NeL by  doxygen 1.6.1