Fix "no remove aqua speed" bug when player leaves the water
[ryzomcore.git] / nel / src / sound / driver / openal / source_al.cpp
blobf0cf670b7750a9be60f5af933ad104a51a619ef4
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2012 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
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/>.
20 #include "stdopenal.h"
21 #include "sound_driver_al.h"
22 #include "listener_al.h"
23 #include "effect_al.h"
24 #include "buffer_al.h"
25 #include "source_al.h"
26 #include "ext_al.h"
28 #ifdef DEBUG_NEW
29 #define new DEBUG_NEW
30 #endif
32 // #define NLSOUND_DEBUG_GAIN
34 using namespace std;
35 using namespace NLMISC;
37 namespace NLSOUND {
39 CSourceAL::CSourceAL(CSoundDriverAL *soundDriver) :
40 _SoundDriver(NULL), _Buffer(NULL), _Source(AL_NONE),
41 _DirectFilter(AL_FILTER_NULL), _EffectFilter(AL_FILTER_NULL),
42 _IsPlaying(false), _IsPaused(false), _StartTime(0), _IsStreaming(false), _RelativeMode(false),
43 _Pos(0.0f, 0.0f, 0.0f), _Gain(NLSOUND_DEFAULT_GAIN), _Alpha(1.0),
44 _MinDistance(1.0f), _MaxDistance(sqrt(numeric_limits<float>::max())),
45 _Effect(NULL), _Direct(true),
46 _DirectGain(NLSOUND_DEFAULT_DIRECT_GAIN), _EffectGain(NLSOUND_DEFAULT_EFFECT_GAIN),
47 _DirectFilterType(ISource::FilterLowPass), _EffectFilterType(ISource::FilterLowPass),
48 _DirectFilterEnabled(false), _EffectFilterEnabled(false),
49 _DirectFilterPassGain(NLSOUND_DEFAULT_FILTER_PASS_GAIN), _EffectFilterPassGain(NLSOUND_DEFAULT_FILTER_PASS_GAIN)
51 // create the al source
52 alGenSources(1, &_Source);
53 alTestError();
55 // configure rolloff
56 if (soundDriver->getOption(ISoundDriver::OptionManualRolloff))
58 alSourcef(_Source, AL_ROLLOFF_FACTOR, 0);
59 alTestError();
61 else
63 alSourcef(_Source, AL_ROLLOFF_FACTOR, soundDriver->getRolloffFactor());
64 alTestError();
67 // create filters
68 if (soundDriver->getOption(ISoundDriver::OptionEnvironmentEffects))
70 alGenFilters(1, &_DirectFilter);
71 alFilteri(_DirectFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
72 alFilterf(_DirectFilter, AL_LOWPASS_GAIN, NLSOUND_DEFAULT_DIRECT_GAIN);
73 alFilterf(_DirectFilter, AL_LOWPASS_GAINHF, NLSOUND_DEFAULT_FILTER_PASS_GAIN);
74 alTestError();
75 alGenFilters(1, &_EffectFilter);
76 alFilteri(_EffectFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
77 alFilterf(_EffectFilter, AL_LOWPASS_GAIN, NLSOUND_DEFAULT_EFFECT_GAIN);
78 alFilterf(_EffectFilter, AL_LOWPASS_GAINHF, NLSOUND_DEFAULT_FILTER_PASS_GAIN);
79 alTestError();
82 // if everything went well, the source will be added in the sounddriver
83 _SoundDriver = soundDriver;
86 CSourceAL::~CSourceAL()
88 CSoundDriverAL *soundDriver = _SoundDriver;
89 release();
90 if (soundDriver) soundDriver->removeSource(this);
93 void CSourceAL::release()
95 if (_Source != AL_NONE) { alDeleteSources(1, &_Source); _Source = AL_NONE; }
96 if (_DirectFilter != AL_FILTER_NULL) { alDeleteFilters(1, &_DirectFilter); _DirectFilter = AL_FILTER_NULL; }
97 if (_EffectFilter != AL_FILTER_NULL) { alDeleteFilters(1, &_EffectFilter); _EffectFilter = AL_FILTER_NULL; }
98 _SoundDriver = NULL;
101 /// (Internal) Update the 3d changes.
102 void CSourceAL::updateManualRolloff()
104 CVector distanceVector = _RelativeMode ? _Pos : (_Pos - CListenerAL::getInstance()->getPos());
105 float distanceSquare = distanceVector.sqrnorm();
106 float rolloff = ISource::computeManualRolloff(_Alpha, distanceSquare, _MinDistance, _MaxDistance);
107 alSourcef(_Source, AL_GAIN, _Gain * rolloff);
108 alTestError();
109 #ifdef NLSOUND_DEBUG_GAIN
110 ALfloat gain;
111 alGetSourcef(_Source, AL_GAIN, &gain);
112 nlwarning("Called updateManualRolloff(), physical gain is %f, configured gain is %f, distanceSquare is %f, rolloff is %f", gain, _Gain, distanceSquare, rolloff);
113 alTestError();
114 #endif
117 /// Enable or disable streaming mode. Source must be stopped to call this.
118 void CSourceAL::setStreaming(bool streaming)
120 nlassert(isStopped());
122 // bring the source type to AL_UNDETERMINED
123 alSourcei(_Source, AL_BUFFER, AL_NONE);
124 alTestError();
125 _Buffer = NULL;
126 _IsStreaming = streaming;
127 if (_IsStreaming)
129 // make sure looping is disabled on OpenAL side
130 setLooping(false);
134 /* Set the buffer that will be played (no streaming)
135 * If the buffer is stereo, the source mode becomes stereo and the source relative mode is on,
136 * otherwise the source is considered as a 3D source.
138 void CSourceAL::setStaticBuffer( IBuffer *buffer )
140 // Stop source
141 alSourceStop(_Source);
142 alTestError();
144 // Set buffer
145 if ( buffer == NULL )
147 alSourcei(_Source, AL_BUFFER, AL_NONE );
148 alTestError();
149 _Buffer = NULL;
151 else
153 CBufferAL *bufferAL = dynamic_cast<CBufferAL *>(buffer);
154 alSourcei(_Source, AL_BUFFER, bufferAL->bufferName() );
155 alTestError();
157 // Set relative mode if the buffer is stereo
158 setSourceRelativeMode( bufferAL->isStereo() );
160 _Buffer = bufferAL;
165 IBuffer *CSourceAL::getStaticBuffer()
167 return _Buffer;
170 /// Add a buffer to the streaming queue. A buffer of 100ms length is optimal for streaming.
171 /// Should be called by a thread which checks countStreamingBuffers every 100ms.
172 void CSourceAL::submitStreamingBuffer(IBuffer *buffer)
174 CBufferAL *bufferAL = static_cast<CBufferAL *>(buffer);
175 ALuint bufferName = bufferAL->bufferName();
176 nlassert(bufferName);
178 if (!bufferAL->isBufferLoaded())
180 nlwarning("AL: MUSICBUG: Streaming buffer was not loaded, skipping buffer. This should not happen.");
181 return;
184 alSourceQueueBuffers(_Source, 1, &bufferName);
185 alTestError();
186 _QueuedBuffers.push(bufferAL);
188 // Resume playback if the internal OpenAL source stopped due to buffer underrun.
189 ALint srcstate;
190 alGetSourcei(_Source, AL_SOURCE_STATE, &srcstate);
191 alTestError();
192 if (_IsPlaying && (srcstate == AL_STOPPED || srcstate == AL_INITIAL))
194 nlwarning("AL: Streaming buffer underrun, resuming playback.");
195 play();
199 /// Return the amount of buffers in the queue (playing and waiting). 3 buffers is optimal.
200 uint CSourceAL::countStreamingBuffers() const
202 // a bit ugly here, but makes a much easier/simpler implementation on both drivers
203 ALint buffersProcessed;
204 alGetSourcei(_Source, AL_BUFFERS_PROCESSED, &buffersProcessed);
205 if (buffersProcessed && _QueuedBuffers.empty())
207 nlwarning("AL: QueuedBuffers is empty, but OpenAL buffers processed > 0");
209 while (buffersProcessed && !_QueuedBuffers.empty())
211 ALuint bufferName = _QueuedBuffers.front()->bufferName();
212 alSourceUnqueueBuffers(_Source, 1, &bufferName);
213 alTestError();
214 const_cast<std::queue<CBufferAL *> &>(_QueuedBuffers).pop();
215 --buffersProcessed;
217 // return how many are left in the queue
218 //ALint buffersQueued;
219 //alGetSourcei(_SourceName, AL_BUFFERS_QUEUED, &buffersQueued);
220 //alTestError();
221 //return (uint)buffersQueued;
222 return (uint)_QueuedBuffers.size();
225 /// Set looping on/off for future playbacks (default: off)
226 void CSourceAL::setLooping( bool l )
228 alSourcei(_Source, AL_LOOPING, l?AL_TRUE:AL_FALSE );
229 alTestError();
232 /// Return the looping state
233 bool CSourceAL::getLooping() const
235 ALint b;
236 alGetSourcei(_Source, AL_LOOPING, &b );
237 alTestError();
238 return ( b == AL_TRUE );
241 /// Play the static buffer (or stream in and play)
242 bool CSourceAL::play()
244 #ifdef NLSOUND_DEBUG_GAIN
245 if (_IsStreaming)
247 nlwarning("Called play on a streaming source");
249 #endif
251 // Commit 3D changes before starting play
252 if (_SoundDriver->getOption(ISoundDriver::OptionManualRolloff))
253 updateManualRolloff();
255 if (_Buffer)
257 // Static playing mode
258 _IsPaused = false;
259 alSourcePlay(_Source);
260 _IsPlaying = (alGetError() == AL_NO_ERROR);
261 if (_IsPlaying)
262 _StartTime = CTime::getLocalTime();
263 return _IsPlaying;
265 else if (_IsStreaming)
267 _IsPaused = false;
268 /* NEW */
269 // called by user as well as by code to resume after buffer underrun
270 if (!_IsPlaying) // set start time if not playing yet
271 _StartTime = CTime::getLocalTime();
272 _IsPlaying = true; // this play always virtually succeed but may not actually be playing
273 if (!_QueuedBuffers.empty()) // ensure buffers have actually queued
275 alSourcePlay(_Source);
276 if (alGetError() != AL_NO_ERROR)
278 nlwarning("AL: MUSICBUG: Unknown error while trying to play streaming source.");
281 else
283 nlwarning("AL: MUSICBUG: Trying to play stream with no buffers queued.");
285 return true;
286 /* OLD
287 alSourcePlay(_Source);
288 _IsPlaying = (alGetError() == AL_NO_ERROR);
289 if (_IsPlaying)
290 _StartTime = CTime::getLocalTime(); // TODO: Played time should freeze when buffering fails, and be calculated based on the number of buffers played plus passed time. This is necessary for synchronizing animation with sound.
291 return _IsPlaying;
293 // Streaming mode
294 //nlwarning("AL: Cannot play null buffer; streaming not implemented" );
295 //nlstop;
297 else
299 nlwarning("Invalid play call, not streaming and no static buffer assigned");
300 return false;
304 /// Stop playing
305 void CSourceAL::stop()
307 _StartTime = 0;
309 if ( _Buffer != NULL )
311 // Static playing mode
312 _IsPlaying = false;
313 _IsPaused = false;
314 alSourceStop(_Source);
315 alTestError();
317 else
319 // TODO: Verify streaming mode?
320 _IsPlaying = false;
321 _IsPaused = false;
322 alSourceStop(_Source);
323 alTestError();
324 // unqueue buffers
325 while (!_QueuedBuffers.empty())
327 ALuint bufferName = _QueuedBuffers.front()->bufferName();
328 alSourceUnqueueBuffers(_Source, 1, &bufferName);
329 _QueuedBuffers.pop();
330 alTestError();
332 // Streaming mode
333 //nlwarning("AL: Cannot stop null buffer; streaming not implemented" );
334 //nlstop;
338 /// Pause. Call play() to resume.
339 void CSourceAL::pause()
341 if ( _Buffer != NULL )
343 if (_IsPaused) nlwarning("AL: Called pause() while _IsPaused == true!");
345 // Static playing mode
346 if (!isStopped())
348 _IsPaused = true;
349 alSourcePause(_Source);
350 alTestError();
353 else
355 // TODO: Verify streaming mode?
356 _IsPaused = true;
357 alSourcePause(_Source);
358 alTestError();
359 // Streaming mode
360 //nlwarning("AL: Cannot pause null buffer; streaming not implemented" );
361 //nlstop;
365 /// Return true if play() or pause(), false if stop().
366 bool CSourceAL::isPlaying() const
368 //return !isStopped() && !_IsPaused;
369 if (_Buffer != NULL)
371 ALint srcstate;
372 alGetSourcei(_Source, AL_SOURCE_STATE, &srcstate);
373 alTestError();
374 return (srcstate == AL_PLAYING || srcstate == AL_PAUSED);
376 else
378 // streaming mode
379 return _IsPlaying;
383 /// Return true if playing is finished or stop() has been called.
384 bool CSourceAL::isStopped() const
386 if (_Buffer != NULL)
388 ALint srcstate;
389 alGetSourcei(_Source, AL_SOURCE_STATE, &srcstate);
390 alTestError();
391 return (srcstate == AL_STOPPED || srcstate == AL_INITIAL);
393 else
395 // streaming mode
396 return !_IsPlaying;
400 /// Return true if the playing source is paused
401 bool CSourceAL::isPaused() const
403 if (_Buffer != NULL)
405 ALint srcstate;
406 alGetSourcei(_Source, AL_SOURCE_STATE, &srcstate);
407 alTestError();
408 return (srcstate == AL_PAUSED);
410 else
412 // streaming mode
413 return _IsPaused;
417 /// Returns the number of milliseconds the source has been playing
418 uint32 CSourceAL::getTime()
420 if (!_StartTime) return 0;
421 return (uint32)(CTime::getLocalTime() - _StartTime);
424 /// Set the position vector.
425 void CSourceAL::setPos(const NLMISC::CVector& pos, bool /* deffered */)
427 _Pos = pos;
428 // Coordinate system: conversion from NeL to OpenAL/GL:
429 alSource3f(_Source, AL_POSITION, pos.x, pos.z, -pos.y );
430 alTestError();
433 /// Get the position vector.
434 const NLMISC::CVector &CSourceAL::getPos() const
436 return _Pos;
439 /// Set the velocity vector (3D mode only)
440 void CSourceAL::setVelocity( const NLMISC::CVector& vel, bool /* deferred */)
442 // Coordsys conversion
443 alSource3f(_Source, AL_VELOCITY, vel.x, vel.z, -vel.y );
444 alTestError();
447 /// Get the velocity vector
448 void CSourceAL::getVelocity( NLMISC::CVector& vel ) const
450 ALfloat v[3];
451 alGetSourcefv(_Source, AL_VELOCITY, v );
452 alTestError();
453 // Coordsys conversion
454 vel.set( v[0], -v[2], v[1] );
457 /// Set the direction vector (3D mode only)
458 void CSourceAL::setDirection( const NLMISC::CVector& dir )
460 // Coordsys conversion
461 alSource3f(_Source, AL_DIRECTION, dir.x, dir.z, -dir.y );
462 alTestError();
465 /// Get the direction vector
466 void CSourceAL::getDirection( NLMISC::CVector& dir ) const
468 ALfloat v[3];
469 alGetSourcefv(_Source, AL_DIRECTION, v );
470 alTestError();
471 // Coordsys conversion
472 dir.set( v[0], -v[2], v[1] );
475 /// Set the gain (volume value inside [0 , 1]).
476 void CSourceAL::setGain(float gain)
478 _Gain = std::min(std::max(gain, NLSOUND_MIN_GAIN), NLSOUND_MAX_GAIN);
479 if (!_SoundDriver->getOption(ISoundDriver::OptionManualRolloff))
481 alSourcef(_Source, AL_GAIN, _Gain);
482 alTestError();
484 #ifdef NLSOUND_DEBUG_GAIN
485 else
487 nlwarning("Called setGain(), manual rolloff, commit deferred to play or update, physical gain is %f, configured gain is %f", gain, _Gain);
489 #endif
492 /// Get the gain
493 float CSourceAL::getGain() const
495 #ifdef NLSOUND_DEBUG_GAIN
496 ALfloat gain;
497 alGetSourcef(_Source, AL_GAIN, &gain);
498 nlwarning("Called getGain(), physical gain is %f, configured gain is %f", gain, _Gain);
499 alTestError();
500 #endif
501 return _Gain;
504 /// Shift the frequency. 1.0f equals identity, each reduction of 50% equals a pitch shift
505 void CSourceAL::setPitch(float pitch)
507 alSourcef(_Source, AL_PITCH, std::min(std::max(pitch, NLSOUND_MIN_PITCH), NLSOUND_MAX_PITCH));
508 alTestError();
511 /// Get the pitch
512 float CSourceAL::getPitch() const
514 ALfloat pitch;
515 alGetSourcef(_Source, AL_PITCH, &pitch);
516 alTestError();
517 return pitch;
520 /// Set the source relative mode. If true, positions are interpreted relative to the listener position.
521 void CSourceAL::setSourceRelativeMode( bool mode )
523 _RelativeMode = mode;
524 alSourcei(_Source, AL_SOURCE_RELATIVE, mode?AL_TRUE:AL_FALSE );
525 alTestError();
528 /// Get the source relative mode (3D mode only)
529 bool CSourceAL::getSourceRelativeMode() const
531 //ALint b;
532 //alGetSourcei(_Source, AL_SOURCE_RELATIVE, &b );
533 //alTestError();
534 //return (b==AL_TRUE);
535 return _RelativeMode;
538 /// Set the min and max distances (3D mode only)
539 void CSourceAL::setMinMaxDistances( float mindist, float maxdist, bool /* deferred */)
541 nlassert( (mindist >= 0.0f) && (maxdist >= 0.0f) );
543 static float maxSqrt = sqrt(std::numeric_limits<float>::max());
544 if (maxdist >= maxSqrt)
546 nlwarning("SOUND_DEV (OpenAL): Ridiculously high max distance set on source");
547 maxdist = maxSqrt;
550 _MinDistance = mindist;
551 _MaxDistance = maxdist;
552 if (!_SoundDriver->getOption(ISoundDriver::OptionManualRolloff))
554 alSourcef(_Source, AL_REFERENCE_DISTANCE, mindist);
555 alSourcef(_Source, AL_MAX_DISTANCE, maxdist);
556 alTestError();
560 /// Get the min and max distances
561 void CSourceAL::getMinMaxDistances( float& mindist, float& maxdist ) const
563 /*alGetSourcef(_Source, AL_REFERENCE_DISTANCE, &mindist );
564 alGetSourcef(_Source, AL_MAX_DISTANCE, &maxdist );
565 alTestError();*/
566 mindist = _MinDistance;
567 maxdist = _MaxDistance;
570 /// Set the cone angles (in radian) and gain (in [0 , 1]) (3D mode only)
571 void CSourceAL::setCone( float innerAngle, float outerAngle, float outerGain )
573 nlassert( (outerGain >= 0.0f) && (outerGain <= 1.0f ) );
574 alSourcef(_Source, AL_CONE_INNER_ANGLE, radToDeg(innerAngle) );
575 alSourcef(_Source, AL_CONE_OUTER_ANGLE, radToDeg(outerAngle) );
576 alSourcef(_Source, AL_CONE_OUTER_GAIN, outerGain );
577 alTestError();
580 /// Get the cone angles (in radian)
581 void CSourceAL::getCone( float& innerAngle, float& outerAngle, float& outerGain ) const
583 float ina, outa;
584 alGetSourcef(_Source, AL_CONE_INNER_ANGLE, &ina );
585 innerAngle = degToRad(ina);
586 alGetSourcef(_Source, AL_CONE_OUTER_ANGLE, &outa );
587 outerAngle = degToRad(outa);
588 alGetSourcef(_Source, AL_CONE_OUTER_GAIN, &outerGain );
589 alTestError();
592 /** Set the alpha value for the volume-distance curve
594 * Useful only with OptionManualRolloff. value from -1 to 1 (default 0)
596 * alpha.0: the volume will decrease linearly between 0dB and -100 dB
597 * alpha = 1.0: the volume will decrease linearly between 1.0 and 0.0 (linear scale)
598 * alpha = -1.0: the volume will decrease inversely with the distance (1/dist). This
599 * is the default used by DirectSound/OpenAL
601 * For any other value of alpha, an interpolation is be done between the two
602 * adjacent curves. For example, if alpha equals 0.5, the volume will be halfway between
603 * the linear dB curve and the linear amplitude curve.
605 void CSourceAL::setAlpha(double a)
607 _Alpha = a;
610 /// (Internal) Setup the effect send filter.
611 void CSourceAL::setupDirectFilter()
613 if (_Direct && _DirectGain > 0)
615 if (_DirectGain < 1 || (_DirectFilterPassGain < 1 && _DirectFilterEnabled))
617 // direct gain is lowered or a filter is applied
618 alFilterf(_DirectFilter, AL_BANDPASS_GAIN, _DirectGain);
619 if (_DirectFilterEnabled)
621 alFilterf(_DirectFilter, AL_BANDPASS_GAINLF, _DirectFilterPassGain);
622 if (_DirectFilterType == FilterBandPass)
623 alFilterf(_DirectFilter, AL_BANDPASS_GAINHF, _DirectFilterPassGain);
625 else
627 alFilterf(_DirectFilter, AL_BANDPASS_GAINLF, 1.0f);
628 if (_DirectFilterType == FilterBandPass)
629 alFilterf(_DirectFilter, AL_BANDPASS_GAINHF, 1.0f);
631 alSourcei(_Source, AL_DIRECT_FILTER, _DirectFilter);
633 else
635 // no filtering
636 alSourcei(_Source, AL_DIRECT_FILTER, AL_FILTER_NULL);
639 else
641 // mute
642 alFilterf(_DirectFilter, AL_BANDPASS_GAIN, 0.0f);
643 alSourcei(_Source, AL_DIRECT_FILTER, _DirectFilter);
645 alTestError();
648 /// Enable or disable direct output [true/false], default: true
649 void CSourceAL::setDirect(bool enable)
651 _Direct = enable;
652 setupDirectFilter();
655 /// Return if the direct output is enabled
656 bool CSourceAL::getDirect() const
658 return _Direct;
661 /// Set the gain for the direct path
662 void CSourceAL::setDirectGain(float gain)
664 _DirectGain = min(max(gain, NLSOUND_MIN_GAIN), NLSOUND_MAX_GAIN);
665 setupDirectFilter();
668 /// Get the gain for the direct path
669 float CSourceAL::getDirectGain() const
671 return _DirectGain;
674 /// Enable or disable the filter for the direct channel
675 void CSourceAL::enableDirectFilter(bool enable)
677 _DirectFilterEnabled = enable;
678 setupDirectFilter();
681 /// Check if the filter on the direct channel is enabled
682 bool CSourceAL::isDirectFilterEnabled() const
684 return _DirectFilterEnabled;
687 /// Set the filter parameters for the direct channel
688 void CSourceAL::setDirectFilter(TFilter filterType, float /* lowFrequency */, float /* highFrequency */, float passGain)
690 _DirectFilterType = filterType;
691 _DirectFilterPassGain = passGain;
692 switch (filterType)
694 case FilterHighPass:
695 alFilteri(_DirectFilter, AL_FILTER_TYPE, AL_FILTER_HIGHPASS);
696 break;
697 case FilterLowPass:
698 alFilteri(_DirectFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
699 break;
700 case FilterBandPass:
701 alFilteri(_DirectFilter, AL_FILTER_TYPE, AL_FILTER_BANDPASS);
702 break;
704 setupDirectFilter();
707 /// Get the filter parameters for the direct channel
708 void CSourceAL::getDirectFilter(TFilter &filterType, float &lowFrequency, float &highFrequency, float &passGain) const
710 filterType = _DirectFilterType;
711 lowFrequency = NLSOUND_DEFAULT_FILTER_PASS_LF;
712 highFrequency = NLSOUND_DEFAULT_FILTER_PASS_HF;
713 passGain = _DirectFilterPassGain;
716 /// Set the direct filter gain
717 void CSourceAL::setDirectFilterPassGain(float passGain)
719 _DirectFilterPassGain = min(max(passGain, NLSOUND_MIN_GAIN), NLSOUND_MAX_GAIN);
720 setupDirectFilter();
723 /// Get the direct filter gain
724 float CSourceAL::getDirectFilterPassGain() const
726 return _DirectFilterPassGain;
729 /// (Internal) Setup the effect send filter.
730 void CSourceAL::setupEffectFilter()
732 if (_Effect && _EffectGain > 0)
734 if (_EffectGain < 1 || (_EffectFilterPassGain < 1 && _EffectFilterEnabled))
736 // effect gain is lowered or a filter is applied
737 alFilterf(_EffectFilter, AL_BANDPASS_GAIN, _EffectGain);
738 if (_EffectFilterEnabled)
740 alFilterf(_EffectFilter, AL_BANDPASS_GAINLF, _EffectFilterPassGain);
741 if (_EffectFilterType == FilterBandPass)
742 alFilterf(_EffectFilter, AL_BANDPASS_GAINHF, _EffectFilterPassGain);
744 else
746 alFilterf(_EffectFilter, AL_BANDPASS_GAINLF, 1.0f);
747 if (_EffectFilterType == FilterBandPass)
748 alFilterf(_EffectFilter, AL_BANDPASS_GAINHF, 1.0f);
750 alSource3i(_Source, AL_AUXILIARY_SEND_FILTER, _Effect->getAuxEffectSlot(), 0, _EffectFilter);
752 else
754 // no filtering
755 alSource3i(_Source, AL_AUXILIARY_SEND_FILTER, _Effect->getAuxEffectSlot(), 0, AL_FILTER_NULL);
758 else
760 // mute
761 alSource3i(_Source, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL);
763 alTestError();
766 /// Set the effect send for this source, NULL to disable. [IEffect], default: NULL
767 void CSourceAL::setEffect(CEffectAL *effect)
769 _Effect = effect;
770 setupEffectFilter();
773 /// Set the effect send for this source, NULL to disable. [IEffect], default: NULL
774 void CSourceAL::setEffect(IReverbEffect *reverbEffect)
776 setEffect(reverbEffect ? dynamic_cast<CEffectAL *>(reverbEffect) : NULL);
779 /// Get the effect send for this source
780 IEffect *CSourceAL::getEffect() const
782 // return _Effect ? NLMISC::safe_cast<IEffect *>(_Effect) : NULL;
783 return NULL;
786 /// Set the gain for the effect path
787 void CSourceAL::setEffectGain(float gain)
789 _EffectGain = min(max(gain, NLSOUND_MIN_GAIN), NLSOUND_MAX_GAIN);
790 setupEffectFilter();
793 /// Get the gain for the effect path
794 float CSourceAL::getEffectGain() const
796 return _EffectGain;
799 /// Enable or disable the filter for the effect channel
800 void CSourceAL::enableEffectFilter(bool enable)
802 _EffectFilterEnabled = enable;
803 setupEffectFilter();
806 /// Check if the filter on the effect channel is enabled
807 bool CSourceAL::isEffectFilterEnabled() const
809 return _EffectFilterEnabled;
812 /// Set the filter parameters for the effect channel
813 void CSourceAL::setEffectFilter(TFilter filterType, float /* lowFrequency */, float /* highFrequency */, float passGain)
815 _EffectFilterType = filterType;
816 _EffectFilterPassGain = passGain;
817 switch (filterType)
819 case FilterHighPass:
820 alFilteri(_EffectFilter, AL_FILTER_TYPE, AL_FILTER_HIGHPASS);
821 break;
822 case FilterLowPass:
823 alFilteri(_EffectFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
824 break;
825 case FilterBandPass:
826 alFilteri(_EffectFilter, AL_FILTER_TYPE, AL_FILTER_BANDPASS);
827 break;
829 setupEffectFilter();
832 /// Get the filter parameters for the effect channel
833 void CSourceAL::getEffectFilter(TFilter &filterType, float &lowFrequency, float &highFrequency, float &passGain) const
835 filterType = _EffectFilterType;
836 lowFrequency = NLSOUND_DEFAULT_FILTER_PASS_LF;
837 highFrequency = NLSOUND_DEFAULT_FILTER_PASS_HF;
838 passGain = _EffectFilterPassGain;
841 /// Set the effect filter gain
842 void CSourceAL::setEffectFilterPassGain(float passGain)
844 _EffectFilterPassGain = min(max(passGain, NLSOUND_MIN_GAIN), NLSOUND_MAX_GAIN);
845 setupEffectFilter();
848 /// Get the effect filter gain
849 float CSourceAL::getEffectFilterPassGain() const
851 return _EffectFilterPassGain;
854 } // NLSOUND