Fix "no remove aqua speed" bug when player leaves the water
[ryzomcore.git] / nel / src / sound / simple_source.cpp
blob6c71c4174f1ce5c7d6175ee4cbe19257644b9970
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 // Copyright (C) 2012 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "stdsound.h"
23 #include "nel/sound/driver/buffer.h"
24 #include "nel/sound/driver/source.h"
26 #include "nel/sound/simple_source.h"
27 #include "nel/sound/mixing_track.h"
28 #include "nel/sound/simple_sound.h"
29 #include "nel/sound/clustered_sound.h"
31 using namespace NLMISC;
33 namespace NLSOUND {
35 CSimpleSource::CSimpleSource(CSimpleSound *simpleSound, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster, CGroupController *groupController)
36 : CSourceCommon(simpleSound, spawn, cb, cbUserParam, cluster, groupController),
37 _SimpleSound(simpleSound),
38 _Track(NULL),
39 _PlayMuted(false),
40 _WaitingForPlay(false)
42 nlassert(_SimpleSound != 0);
44 // get a local copy of the simple sound parameter
45 _Alpha = _SimpleSound->getAlpha();
48 CSimpleSource::~CSimpleSource()
50 if (_Playing)
51 stop();
52 // Yoyo: security. with prec stop(), should not be needed, but a crash still raise
53 // in "currentEvent->onEvent();" in audio_mixer_user.cpp
54 // [KAETEMI TODO: Take a look at previous comment.]
55 CAudioMixerUser::instance()->removeEvents(this);
58 void CSimpleSource::initPhysicalSource()
60 CAudioMixerUser *mixer = CAudioMixerUser::instance();
61 CTrack *track = mixer->getFreeTrack(this);
62 if (track != NULL)
64 nlassert(track->hasPhysicalSource());
65 _Track = track;
69 void CSimpleSource::releasePhysicalSource()
71 if (hasPhysicalSource())
73 CAudioMixerUser *mixer = CAudioMixerUser::instance();
74 ISource *pSource = getPhysicalSource();
75 nlassert(pSource != NULL);
77 // free the track
78 pSource->stop();
79 pSource->setStaticBuffer(NULL);
80 mixer->freeTrack(_Track);
81 _Track = NULL;
85 uint32 CSimpleSource::getTime()
87 if (hasPhysicalSource())
88 return getPhysicalSource()->getTime();
89 else
90 return 0;
93 IBuffer *CSimpleSource::getBuffer()
95 return _SimpleSound->getBuffer();
98 /// Set looping on/off for future playbacks (default: off)
99 void CSimpleSource::setLooping(bool l)
101 CSourceCommon::setLooping(l);
102 if (hasPhysicalSource())
103 getPhysicalSource()->setLooping( l );
106 CVector CSimpleSource::getVirtualPos() const
108 if (getCluster() != 0)
110 // need to check the cluster status
111 const CClusteredSound::CClusterSoundStatus *css = CAudioMixerUser::instance()->getClusteredSound()->getClusterSoundStatus(getCluster());
112 if (css != 0)
114 // there is some data here, update the virtual position of the sound.
115 float dist = (css->Position - getPos()).norm();
116 CVector vpos(CAudioMixerUser::instance()->getListenPosVector() + css->Direction * (css->Dist + dist));
117 vpos = _Position * (1-css->PosAlpha) + vpos*(css->PosAlpha);
118 return vpos;
122 return getPos();
125 /// Play
126 void CSimpleSource::play()
128 // nldebug("CSimpleSource %p : play", this);
130 CAudioMixerUser *mixer = CAudioMixerUser::instance();
132 // -- Some test to check if we can play the source
134 // Check if sample buffer is available and if the sound source is not too far
135 if (_SimpleSound->getBuffer() == 0
136 || !_SimpleSound->getBuffer()->isBufferLoaded()
137 //|| (mixer->getListenPosVector() - _Position).sqrnorm() > _SimpleSound->getMaxDistance() * _SimpleSound->getMaxDistance())
138 || (_RelativeMode ? getPos().sqrnorm() : (mixer->getListenPosVector() - getPos()).sqrnorm()) > _SimpleSound->getMaxDistance() * _SimpleSound->getMaxDistance())
140 // The sample buffer is not available, don't play (we don't know the length)
141 _WaitingForPlay = false;
142 if (_Spawn)
144 if (_SpawnEndCb != 0)
145 _SpawnEndCb(this, _CbUserParam);
147 delete this;
149 // nldebug("CSimpleSource %p : play FAILED !", (CAudioMixerUser::IMixerEvent*)this);
150 return;
153 // -- Here we can play the source, either in a real track or as a muted source.
155 // Try to obtain a track
156 if (!hasPhysicalSource())
157 initPhysicalSource();
159 if (hasPhysicalSource())
161 ISource *pSource = getPhysicalSource();
162 nlassert(pSource != NULL);
164 // ok, we have a track to realy play, fill the data into the track
165 pSource->setStaticBuffer(_SimpleSound->getBuffer());
167 // pSource->setPos( _Position, false);
168 pSource->setPos(getVirtualPos(), false);
169 if (!_SimpleSound->getBuffer()->isStereo())
171 pSource->setMinMaxDistances(_SimpleSound->getMinDistance(), _SimpleSound->getMaxDistance(), false);
172 setDirection(_Direction); // because there is a workaround inside
173 pSource->setVelocity(_Velocity);
175 pSource->setGain(getFinalGain());
176 pSource->setSourceRelativeMode(_RelativeMode);
177 pSource->setLooping(_Looping);
178 pSource->setPitch(_Pitch);
179 pSource->setAlpha(_Alpha);
181 // and play the sound
182 bool play = pSource->play();
184 #ifdef NL_DEBUG
185 nlassert(play);
186 #else
187 if (!play)
188 nlwarning("Failed to play physical sound source. This is a serious error");
189 #endif
191 // nldebug("CSimpleSource %p : REAL play done", (CAudioMixerUser::IMixerEvent*)this);
193 else
195 if (_Priority == HighestPri)
197 // This sound is not discardable, add it in waiting playlist
198 mixer->addSourceWaitingForPlay(this);
199 _WaitingForPlay = true;
200 return;
202 // there is no available track, just do a 'muted' play
203 mixer->addEvent(this, CTime::getLocalTime() + _SimpleSound->getDuration());
204 _PlayMuted = true;
205 mixer->incPlayingSourceMuted();
206 // nldebug("CSimpleSource %p : MUTED play done", (CAudioMixerUser::IMixerEvent*)this);
209 CSourceCommon::play();
210 _WaitingForPlay = false;
213 /// Mixer event call when doing muted play
214 void CSimpleSource::onEvent()
216 // nldebug("CSimpleSource %p : stop EVENT", (CAudioMixerUser::IMixerEvent*)this);
218 // A muted play is terminated.
220 if (!_Playing)
221 return;
222 // nlassert(_Playing);
223 // nlassert(_Track == 0);
225 _PlayMuted = false;
226 CAudioMixerUser::instance()->decPlayingSourceMuted();
228 stop();
231 /// Stop playing
232 void CSimpleSource::stop()
234 // nldebug("CSimpleSource %p : stop", (CAudioMixerUser::IMixerEvent*)this);
235 // nlassert(_Playing);
237 if (_WaitingForPlay)
239 nlassert(!_Playing); // cannot already be playing if waiting for play
240 CAudioMixerUser *mixer = CAudioMixerUser::instance();
241 mixer->removeSourceWaitingForPlay(this);
244 if (!_Playing)
245 return;
247 if (hasPhysicalSource())
249 releasePhysicalSource();
251 else if (_PlayMuted)
253 CAudioMixerUser *mixer = CAudioMixerUser::instance();
254 // clear the registered event because of a stop before normal end of play
255 mixer->decPlayingSourceMuted();
256 mixer->removeEvents(this);
259 CSourceCommon::stop();
261 if (_Spawn)
263 if (_SpawnEndCb != NULL)
265 _SpawnEndCb(this, _CbUserParam);
268 delete this;
272 /* Set the position vector (default: (0,0,0)).
273 * 3D mode -> 3D position
274 * st mode -> x is the pan value (from left (-1) to right (1)), set y and z to 0
276 void CSimpleSource::setPos(const NLMISC::CVector& pos)
278 CSourceCommon::setPos(pos);
280 // Set the position
281 if (hasPhysicalSource())
283 // getPhysicalSource()->setPos(pos);
284 getPhysicalSource()->setPos(getVirtualPos());
290 * Set the velocity vector (3D mode only, ignored in stereo mode) (default: (0,0,0))
292 void CSimpleSource::setVelocity(const NLMISC::CVector& vel)
294 CSourceCommon::setVelocity(vel);
296 // Set the velocity
297 if (hasPhysicalSource())
299 // TODO : uncomment, test only
300 getPhysicalSource()->setVelocity(vel);
306 * Set the direction vector (3D mode only, ignored in stereo mode) (default: (0,0,0) as non-directional)
308 void CSimpleSource::setDirection(const NLMISC::CVector& dir)
310 CSourceCommon::setDirection(dir);
312 // Set the direction
313 if (hasPhysicalSource())
315 if (!_SimpleSound->getBuffer()->isStereo())
317 static bool coneset = false;
318 if (dir.isNull()) // workaround
320 getPhysicalSource()->setCone(float(Pi * 2), float(Pi * 2), 1.0f); // because the direction with 0 is not enough for a non-directional source!
321 getPhysicalSource()->setDirection(CVector::I); // Don't send a 0 vector, DSound will complain. Send (1,0,0), it's omnidirectional anyway.
322 coneset = false;
324 else
326 // if (!coneset)
328 getPhysicalSource()->setCone(_SimpleSound->getConeInnerAngle(), _SimpleSound->getConeOuterAngle(), _SimpleSound->getConeOuterGain());
329 coneset = true;
331 getPhysicalSource()->setDirection(dir);
337 void CSimpleSource::updateFinalGain()
339 // Set the gain
340 if (hasPhysicalSource())
341 getPhysicalSource()->setGain(getFinalGain());
344 /* Shift the frequency. 1.0f equals identity, each reduction of 50% equals a pitch shift
345 * of one octave. 0 is not a legal value.
347 void CSimpleSource::setPitch(float pitch)
349 CSourceCommon::setPitch(pitch);
351 // Set the pitch
352 if (hasPhysicalSource())
354 getPhysicalSource()->setPitch( pitch );
360 * Set the source relative mode. If true, positions are interpreted relative to the listener position (default: false)
362 void CSimpleSource::setSourceRelativeMode(bool mode)
364 CSourceCommon::setSourceRelativeMode(mode);
366 // Set the relative mode
367 if (hasPhysicalSource())
369 getPhysicalSource()->setSourceRelativeMode( mode );
374 * Get playing state. Return false if the source has stopped on its own.
376 bool CSimpleSource::isPlaying()
378 return _Playing;
381 } // NLSOUND