15 #include "auxeffectslot.h"
16 #include "sourcegroup.h"
21 class ALBufferStream
{
22 SharedPtr
<Decoder
> mDecoder
;
34 Vector
<ALuint
> mBufferIds
;
38 std::pair
<uint64_t,uint64_t> mLoopPts
;
40 std::atomic
<bool> mDone
;
43 ALBufferStream(SharedPtr
<Decoder
> decoder
, ALuint updatelen
, ALuint numupdates
)
44 : mDecoder(decoder
), mUpdateLen(updatelen
), mNumUpdates(numupdates
),
45 mFormat(AL_NONE
), mFrequency(0), mFrameSize(0), mSilence(0),
46 mCurrentIdx(0), mSamplePos(0), mLoopPts
{0,0}, mHasLooped(false),
51 if(!mBufferIds
.empty())
53 alDeleteBuffers(mBufferIds
.size(), mBufferIds
.data());
58 uint64_t getLength() const { return mDecoder
->getLength(); }
59 uint64_t getPosition() const { return mSamplePos
; }
61 ALuint
getNumUpdates() const { return mNumUpdates
; }
62 ALuint
getUpdateLength() const { return mUpdateLen
; }
64 ALuint
getFrequency() const { return mFrequency
; }
66 bool seek(uint64_t pos
)
68 if(!mDecoder
->seek(pos
))
72 mDone
.store(false, std::memory_order_release
);
78 ALuint srate
= mDecoder
->getFrequency();
79 ChannelConfig chans
= mDecoder
->getChannelConfig();
80 SampleType type
= mDecoder
->getSampleType();
82 mLoopPts
= mDecoder
->getLoopPoints();
83 if(mLoopPts
.first
>= mLoopPts
.second
)
86 mLoopPts
.second
= std::numeric_limits
<uint64_t>::max();
90 mFrameSize
= FramesToBytes(1, chans
, type
);
91 mFormat
= GetFormat(chans
, type
);
92 if(mFormat
== AL_NONE
)
94 String
str("Unsupported format (");
95 str
+= GetSampleTypeName(type
);
97 str
+= GetChannelConfigName(chans
);
99 throw std::runtime_error(str
);
102 mData
.resize(mUpdateLen
* mFrameSize
);
103 if(type
== SampleType::UInt8
) mSilence
= 0x80;
104 else if(type
== SampleType::Mulaw
) mSilence
= 0x7f;
105 else mSilence
= 0x00;
107 mBufferIds
.assign(mNumUpdates
, 0);
108 alGenBuffers(mBufferIds
.size(), mBufferIds
.data());
111 int64_t getLoopStart() const { return mLoopPts
.first
; }
112 int64_t getLoopEnd() const { return mLoopPts
.second
; }
114 bool hasLooped() const { return mHasLooped
; }
115 bool hasMoreData() const { return !mDone
.load(std::memory_order_acquire
); }
116 bool streamMoreData(ALuint srcid
, bool loop
)
118 if(mDone
.load(std::memory_order_acquire
))
122 ALuint len
= mUpdateLen
;
123 if(loop
&& mSamplePos
<= mLoopPts
.second
)
124 len
= std::min
<uint64_t>(len
, mLoopPts
.second
- mSamplePos
);
128 frames
= mDecoder
->read(mData
.data(), len
);
129 mSamplePos
+= frames
;
130 if(frames
< mUpdateLen
&& loop
&& mSamplePos
> 0)
132 if(mSamplePos
< mLoopPts
.second
)
134 mLoopPts
.second
= mSamplePos
;
135 if(mLoopPts
.first
>= mLoopPts
.second
)
140 if(!mDecoder
->seek(mLoopPts
.first
))
142 mSamplePos
= mLoopPts
.first
;
145 len
= std::min
<uint64_t>(mUpdateLen
-frames
, mLoopPts
.second
-mLoopPts
.first
);
146 ALuint got
= mDecoder
->read(&mData
[frames
*mFrameSize
], len
);
150 } while(frames
< mUpdateLen
);
152 if(frames
< mUpdateLen
)
154 mDone
.store(true, std::memory_order_release
);
155 if(frames
== 0) return false;
156 mSamplePos
+= mUpdateLen
- frames
;
157 std::fill(mData
.begin() + frames
*mFrameSize
, mData
.end(), mSilence
);
160 alBufferData(mBufferIds
[mCurrentIdx
], mFormat
, mData
.data(), mData
.size(), mFrequency
);
161 alSourceQueueBuffers(srcid
, 1, &mBufferIds
[mCurrentIdx
]);
162 mCurrentIdx
= (mCurrentIdx
+1) % mBufferIds
.size();
168 SourceImpl::SourceImpl(ContextImpl
*context
)
169 : mContext(context
), mId(0), mBuffer(0), mGroup(nullptr), mIsAsync(false),
170 mDirectFilter(AL_FILTER_NULL
)
173 mEffectSlots
.reserve(mContext
->getDevice().getMaxAuxiliarySends());
176 SourceImpl::~SourceImpl()
181 void SourceImpl::resetProperties()
184 mGroup
->eraseSource(this);
189 mFadeGainTarget
= 1.0f
;
192 mPaused
.store(false, std::memory_order_release
);
199 mMaxDist
= std::numeric_limits
<float>::max();
200 mPosition
= Vector3(0.0f
);
201 mVelocity
= Vector3(0.0f
);
202 mDirection
= Vector3(0.0f
);
203 mOrientation
[0] = Vector3(0.0f
, 0.0f
, -1.0f
);
204 mOrientation
[1] = Vector3(0.0f
, 1.0f
, 0.0f
);
205 mConeInnerAngle
= 360.0f
;
206 mConeOuterAngle
= 360.0f
;
207 mConeOuterGain
= 0.0f
;
208 mConeOuterGainHF
= 1.0f
;
209 mRolloffFactor
= 1.0f
;
210 mRoomRolloffFactor
= 0.0f
;
211 mDopplerFactor
= 1.0f
;
212 mAirAbsorptionFactor
= 0.0f
;
214 mStereoAngles
[0] = F_PI
/ 6.0f
;
215 mStereoAngles
[1] = -F_PI
/ 6.0f
;
216 mSpatialize
= Spatialize::Auto
;
217 mResampler
= mContext
->hasExtension(AL::SOFT_source_resampler
) ?
218 alGetInteger(AL_DEFAULT_RESAMPLER_SOFT
) : 0;
221 mDryGainHFAuto
= true;
223 mWetGainHFAuto
= true;
225 mContext
->alDeleteFilters(1, &mDirectFilter
);
227 for(auto &i
: mEffectSlots
)
230 i
.mSlot
->removeSourceSend({Source(this), i
.mSendIdx
});
232 mContext
->alDeleteFilters(1, &i
.mFilter
);
234 mEffectSlots
.clear();
239 void SourceImpl::applyProperties(bool looping
, ALuint offset
) const
241 alSourcei(mId
, AL_LOOPING
, looping
? AL_TRUE
: AL_FALSE
);
242 alSourcei(mId
, AL_SAMPLE_OFFSET
, offset
);
243 alSourcef(mId
, AL_PITCH
, mPitch
* mGroupPitch
);
244 alSourcef(mId
, AL_GAIN
, mGain
* mGroupGain
* mFadeGain
);
245 alSourcef(mId
, AL_MIN_GAIN
, mMinGain
);
246 alSourcef(mId
, AL_MAX_GAIN
, mMaxGain
);
247 alSourcef(mId
, AL_REFERENCE_DISTANCE
, mRefDist
);
248 alSourcef(mId
, AL_MAX_DISTANCE
, mMaxDist
);
249 alSourcefv(mId
, AL_POSITION
, mPosition
.getPtr());
250 alSourcefv(mId
, AL_VELOCITY
, mVelocity
.getPtr());
251 alSourcefv(mId
, AL_DIRECTION
, mDirection
.getPtr());
252 if(mContext
->hasExtension(AL::EXT_BFORMAT
))
253 alSourcefv(mId
, AL_ORIENTATION
, &mOrientation
[0][0]);
254 alSourcef(mId
, AL_CONE_INNER_ANGLE
, mConeInnerAngle
);
255 alSourcef(mId
, AL_CONE_OUTER_ANGLE
, mConeOuterAngle
);
256 alSourcef(mId
, AL_CONE_OUTER_GAIN
, mConeOuterGain
);
257 alSourcef(mId
, AL_ROLLOFF_FACTOR
, mRolloffFactor
);
258 alSourcef(mId
, AL_DOPPLER_FACTOR
, mDopplerFactor
);
259 if(mContext
->hasExtension(AL::EXT_SOURCE_RADIUS
))
260 alSourcef(mId
, AL_SOURCE_RADIUS
, mRadius
);
261 if(mContext
->hasExtension(AL::EXT_STEREO_ANGLES
))
262 alSourcefv(mId
, AL_STEREO_ANGLES
, mStereoAngles
);
263 if(mContext
->hasExtension(AL::SOFT_source_spatialize
))
264 alSourcei(mId
, AL_SOURCE_SPATIALIZE_SOFT
, (ALint
)mSpatialize
);
265 if(mContext
->hasExtension(AL::SOFT_source_resampler
))
266 alSourcei(mId
, AL_SOURCE_RESAMPLER_SOFT
, mResampler
);
267 alSourcei(mId
, AL_SOURCE_RELATIVE
, mRelative
? AL_TRUE
: AL_FALSE
);
268 if(mContext
->hasExtension(AL::EXT_EFX
))
270 alSourcef(mId
, AL_CONE_OUTER_GAINHF
, mConeOuterGainHF
);
271 alSourcef(mId
, AL_ROOM_ROLLOFF_FACTOR
, mRoomRolloffFactor
);
272 alSourcef(mId
, AL_AIR_ABSORPTION_FACTOR
, mAirAbsorptionFactor
);
273 alSourcei(mId
, AL_DIRECT_FILTER_GAINHF_AUTO
, mDryGainHFAuto
? AL_TRUE
: AL_FALSE
);
274 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
, mWetGainAuto
? AL_TRUE
: AL_FALSE
);
275 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
, mWetGainHFAuto
? AL_TRUE
: AL_FALSE
);
276 alSourcei(mId
, AL_DIRECT_FILTER
, mDirectFilter
);
277 for(const auto &i
: mEffectSlots
)
279 ALuint slotid
= (i
.mSlot
? i
.mSlot
->getId() : 0);
280 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, i
.mSendIdx
, i
.mFilter
);
286 void SourceImpl::unsetGroup()
289 groupPropUpdate(1.0f
, 1.0f
);
292 void SourceImpl::groupPropUpdate(ALfloat gain
, ALfloat pitch
)
296 alSourcef(mId
, AL_PITCH
, mPitch
* pitch
);
297 alSourcef(mId
, AL_GAIN
, mGain
* gain
* mFadeGain
);
304 DECL_THUNK1(void, Source
, play
,, Buffer
)
305 void SourceImpl::play(Buffer buffer
)
307 BufferImpl
*albuf
= buffer
.getHandle();
308 if(!albuf
) throw std::invalid_argument("Buffer is not valid");
309 CheckContexts(mContext
, albuf
->getContext());
310 CheckContext(mContext
);
313 mContext
->removeStream(this);
314 mIsAsync
.store(false, std::memory_order_release
);
316 mFadeGainTarget
= mFadeGain
= 1.0f
;
317 mFadeTimeTarget
= mLastFadeTime
= std::chrono::nanoseconds::zero();
321 mId
= mContext
->getSourceId(mPriority
);
322 applyProperties(mLooping
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
326 mContext
->removeFadingSource(this);
327 mContext
->removePlayingSource(this);
329 alSourcei(mId
, AL_BUFFER
, 0);
330 alSourcei(mId
, AL_LOOPING
, mLooping
? AL_TRUE
: AL_FALSE
);
331 alSourcei(mId
, AL_SAMPLE_OFFSET
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
337 mBuffer
->removeSource(Source(this));
339 mBuffer
->addSource(Source(this));
341 alSourcei(mId
, AL_BUFFER
, mBuffer
->getId());
343 mPaused
.store(false, std::memory_order_release
);
344 mContext
->removePendingSource(this);
345 mContext
->addPlayingSource(this, mId
);
348 DECL_THUNK3(void, Source
, play
,, SharedPtr
<Decoder
>, ALuint
, ALuint
)
349 void SourceImpl::play(SharedPtr
<Decoder
>&& decoder
, ALuint chunk_len
, ALuint queue_size
)
352 throw std::out_of_range("Update length out of range");
354 throw std::out_of_range("Queue size out of range");
355 CheckContext(mContext
);
357 auto stream
= MakeUnique
<ALBufferStream
>(decoder
, chunk_len
, queue_size
);
361 mContext
->removeStream(this);
362 mIsAsync
.store(false, std::memory_order_release
);
364 mFadeGainTarget
= mFadeGain
= 1.0f
;
365 mFadeTimeTarget
= mLastFadeTime
= std::chrono::nanoseconds::zero();
369 mId
= mContext
->getSourceId(mPriority
);
370 applyProperties(false, 0);
374 mContext
->removeFadingSource(this);
375 mContext
->removePlayingSource(this);
377 alSourcei(mId
, AL_BUFFER
, 0);
378 alSourcei(mId
, AL_LOOPING
, AL_FALSE
);
379 alSourcei(mId
, AL_SAMPLE_OFFSET
, 0);
384 mBuffer
->removeSource(Source(this));
387 mStream
= std::move(stream
);
389 mStream
->seek(mOffset
);
392 for(ALuint i
= 0;i
< mStream
->getNumUpdates();i
++)
394 if(!mStream
->streamMoreData(mId
, mLooping
))
398 mPaused
.store(false, std::memory_order_release
);
400 mContext
->addStream(this);
401 mIsAsync
.store(true, std::memory_order_release
);
402 mContext
->removePendingSource(this);
403 mContext
->addPlayingSource(this);
406 DECL_THUNK1(void, Source
, play
,, SharedFuture
<Buffer
>)
407 void SourceImpl::play(SharedFuture
<Buffer
>&& future_buffer
)
409 if(!future_buffer
.valid())
410 throw std::future_error(std::future_errc::no_state
);
411 if(GetFutureState(future_buffer
) == std::future_status::ready
)
413 play(future_buffer
.get());
417 CheckContext(mContext
);
419 mContext
->removeFadingSource(this);
420 mContext
->removePlayingSource(this);
423 mFadeGainTarget
= mFadeGain
= 1.0f
;
424 mFadeTimeTarget
= mLastFadeTime
= std::chrono::nanoseconds::zero();
426 mContext
->addPendingSource(this, std::move(future_buffer
));
430 void SourceImpl::makeStopped(bool dolock
)
435 mContext
->removeStream(this);
437 mContext
->removeStreamNoLock(this);
439 mIsAsync
.store(false, std::memory_order_release
);
444 alSourcei(mId
, AL_BUFFER
, 0);
445 if(mContext
->hasExtension(AL::EXT_EFX
))
447 alSourcei(mId
, AL_DIRECT_FILTER
, AL_FILTER_NULL
);
448 for(auto &i
: mEffectSlots
)
449 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, 0, i
.mSendIdx
, AL_FILTER_NULL
);
451 mContext
->insertSourceId(mId
);
457 mBuffer
->removeSource(Source(this));
460 mPaused
.store(false, std::memory_order_release
);
463 DECL_THUNK0(void, Source
, stop
,)
464 void SourceImpl::stop()
466 CheckContext(mContext
);
467 mContext
->removePendingSource(this);
468 mContext
->removeFadingSource(this);
469 mContext
->removePlayingSource(this);
474 DECL_THUNK2(void, Source
, fadeOutToStop
,, ALfloat
, std::chrono::milliseconds
)
475 void SourceImpl::fadeOutToStop(ALfloat gain
, std::chrono::milliseconds duration
)
477 if(!(gain
< 1.0f
&& gain
>= 0.0f
))
478 throw std::out_of_range("Fade gain target out of range");
479 if(duration
.count() <= 0)
480 throw std::out_of_range("Fade duration out of range");
481 CheckContext(mContext
);
483 mFadeGainTarget
= std::max
<ALfloat
>(gain
, 0.0001f
);
484 mLastFadeTime
= std::chrono::steady_clock::now().time_since_epoch();
485 mFadeTimeTarget
= mLastFadeTime
+ duration
;
487 mContext
->addFadingSource(this);
491 void SourceImpl::checkPaused()
493 if(mPaused
.load(std::memory_order_acquire
) || mId
== 0)
497 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
498 // Streaming sources may be in a stopped or initial state if underrun
499 mPaused
.store(state
== AL_PAUSED
|| (mStream
&& mStream
->hasMoreData()),
500 std::memory_order_release
);
503 DECL_THUNK0(void, Source
, pause
,)
504 void SourceImpl::pause()
506 CheckContext(mContext
);
507 if(mPaused
.load(std::memory_order_acquire
))
512 std::lock_guard
<std::mutex
> lock(mMutex
);
515 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
516 // Streaming sources may be in a stopped or initial state if underrun
517 mPaused
.store(state
== AL_PAUSED
|| (mStream
&& mStream
->hasMoreData()),
518 std::memory_order_release
);
522 DECL_THUNK0(void, Source
, resume
,)
523 void SourceImpl::resume()
525 CheckContext(mContext
);
526 if(!mPaused
.load(std::memory_order_acquire
))
531 mPaused
.store(false, std::memory_order_release
);
535 DECL_THUNK0(bool, Source
, isPending
, const)
536 bool SourceImpl::isPending() const
538 CheckContext(mContext
);
539 return mContext
->isPendingSource(this);
542 DECL_THUNK0(bool, Source
, isPlaying
, const)
543 bool SourceImpl::isPlaying() const
545 CheckContext(mContext
);
546 if(mId
== 0) return false;
549 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
551 throw std::runtime_error("Source state error");
553 return state
== AL_PLAYING
|| (!mPaused
.load(std::memory_order_acquire
) &&
554 mStream
&& mStream
->hasMoreData());
557 DECL_THUNK0(bool, Source
, isPaused
, const)
558 bool SourceImpl::isPaused() const
560 CheckContext(mContext
);
561 return mId
!= 0 && mPaused
.load(std::memory_order_acquire
);
565 DECL_THUNK1(void, Source
, setGroup
,, SourceGroup
)
566 void SourceImpl::setGroup(SourceGroup group
)
568 CheckContext(mContext
);
570 SourceGroupImpl
*parent
= group
.getHandle();
571 if(parent
== mGroup
) return;
574 mGroup
->eraseSource(this);
578 mGroup
->insertSource(this);
579 mGroupPitch
= mGroup
->getAppliedPitch();
580 mGroupGain
= mGroup
->getAppliedGain();
590 alSourcef(mId
, AL_PITCH
, mPitch
* mGroupPitch
);
591 alSourcef(mId
, AL_GAIN
, mGain
* mGroupGain
* mFadeGain
);
596 bool SourceImpl::checkPending(SharedFuture
<Buffer
> &future
)
598 if(GetFutureState(future
) != std::future_status::ready
)
601 BufferImpl
*buffer
= future
.get().getHandle();
602 if(UNLIKELY(!buffer
|| buffer
->getContext() != mContext
))
607 mId
= mContext
->getSourceId(mPriority
);
608 applyProperties(mLooping
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
613 alSourcei(mId
, AL_BUFFER
, 0);
614 alSourcei(mId
, AL_LOOPING
, mLooping
? AL_TRUE
: AL_FALSE
);
615 alSourcei(mId
, AL_SAMPLE_OFFSET
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
620 mBuffer
->addSource(Source(this));
622 alSourcei(mId
, AL_BUFFER
, mBuffer
->getId());
624 mPaused
.store(false, std::memory_order_release
);
625 mContext
->addPlayingSource(this, mId
);
629 bool SourceImpl::fadeUpdate(std::chrono::nanoseconds cur_fade_time
)
631 if((cur_fade_time
- mFadeTimeTarget
).count() >= 0)
633 mLastFadeTime
= mFadeTimeTarget
;
635 if(mFadeGainTarget
>= 1.0f
)
638 alSourcef(mId
, AL_GAIN
, mGain
* mGroupGain
);
641 mContext
->removePendingSource(this);
642 mContext
->removePlayingSource(this);
647 float mult
= std::pow(mFadeGainTarget
/mFadeGain
,
648 float(1.0/Seconds(mFadeTimeTarget
-mLastFadeTime
).count())
651 std::chrono::nanoseconds duration
= cur_fade_time
- mLastFadeTime
;
652 mLastFadeTime
= cur_fade_time
;
654 float gain
= mFadeGain
* std::pow(mult
, (float)Seconds(duration
).count());
655 if(UNLIKELY(gain
== mFadeGain
))
657 // Ensure the gain keeps moving toward its target, in case precision
658 // loss results in no change with small steps.
659 gain
= std::nextafter(gain
, mFadeGainTarget
);
664 alSourcef(mId
, AL_GAIN
, mGain
* mGroupGain
* mFadeGain
);
668 bool SourceImpl::playUpdate(ALuint id
)
671 alGetSourcei(id
, AL_SOURCE_STATE
, &state
);
672 if(LIKELY(state
== AL_PLAYING
|| state
== AL_PAUSED
))
676 mContext
->send(&MessageHandler::sourceStopped
, Source(this));
680 bool SourceImpl::playUpdate()
682 if(LIKELY(mIsAsync
.load(std::memory_order_acquire
)))
686 mContext
->send(&MessageHandler::sourceStopped
, Source(this));
691 ALint
SourceImpl::refillBufferStream()
694 alGetSourcei(mId
, AL_BUFFERS_PROCESSED
, &processed
);
698 alSourceUnqueueBuffers(mId
, 1, &buf
);
703 alGetSourcei(mId
, AL_BUFFERS_QUEUED
, &queued
);
704 for(;(ALuint
)queued
< mStream
->getNumUpdates();queued
++)
706 if(!mStream
->streamMoreData(mId
, mLooping
))
713 bool SourceImpl::updateAsync()
715 std::lock_guard
<std::mutex
> lock(mMutex
);
717 ALint queued
= refillBufferStream();
720 mIsAsync
.store(false, std::memory_order_release
);
725 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
726 if(!mPaused
.load(std::memory_order_acquire
))
728 // Make sure the source is still playing if it's not paused.
729 if(state
!= AL_PLAYING
)
734 // Rewind the source to an initial state if it underrun as it was
736 if(state
== AL_STOPPED
)
743 DECL_THUNK1(void, Source
, setPriority
,, ALuint
)
744 void SourceImpl::setPriority(ALuint priority
)
746 mPriority
= priority
;
750 DECL_THUNK1(void, Source
, setOffset
,, uint64_t)
751 void SourceImpl::setOffset(uint64_t offset
)
753 CheckContext(mContext
);
762 if(offset
>= std::numeric_limits
<ALint
>::max())
763 throw std::out_of_range("Offset out of range");
765 alSourcei(mId
, AL_SAMPLE_OFFSET
, (ALint
)offset
);
766 ALenum err
= alGetError();
767 if(err
!= AL_NO_ERROR
)
768 throw al_error(err
, "Failed to set offset");
772 std::lock_guard
<std::mutex
> lock(mMutex
);
773 if(!mStream
->seek(offset
))
774 throw std::runtime_error("Failed to seek to offset");
776 alSourcei(mId
, AL_BUFFER
, 0);
777 ALint queued
= refillBufferStream();
778 if(queued
> 0 && !mPaused
.load(std::memory_order_acquire
))
783 DECL_THUNK0(UInt64NSecPair
, Source
, getSampleOffsetLatency
, const)
784 std::pair
<uint64_t,std::chrono::nanoseconds
> SourceImpl::getSampleOffsetLatency() const
786 std::pair
<uint64_t,std::chrono::nanoseconds
> ret
{0, std::chrono::nanoseconds::zero()};
787 CheckContext(mContext
);
788 if(mId
== 0) return ret
;
792 std::lock_guard
<std::mutex
> lock(mMutex
);
793 ALint queued
= 0, state
= -1, srcpos
= 0;
795 alGetSourcei(mId
, AL_BUFFERS_QUEUED
, &queued
);
796 if(mContext
->hasExtension(AL::SOFT_source_latency
))
799 mContext
->alGetSourcei64vSOFT(mId
, AL_SAMPLE_OFFSET_LATENCY_SOFT
, val
);
801 ret
.second
= std::chrono::nanoseconds(val
[1]);
804 alGetSourcei(mId
, AL_SAMPLE_OFFSET
, &srcpos
);
805 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
807 int64_t streampos
= mStream
->getPosition();
808 if(state
!= AL_STOPPED
)
810 // The amount of samples in the queue waiting to play
811 ALuint inqueue
= queued
*mStream
->getUpdateLength() - srcpos
;
812 if(!mStream
->hasLooped())
814 // A non-looped stream should never have more samples queued
815 // than have been read...
816 streampos
= std::max
<int64_t>(streampos
, inqueue
) - inqueue
;
820 streampos
-= inqueue
;
821 int64_t looplen
= mStream
->getLoopEnd() - mStream
->getLoopStart();
822 while(streampos
< mStream
->getLoopStart())
823 streampos
+= looplen
;
827 ret
.first
= streampos
;
832 if(mContext
->hasExtension(AL::SOFT_source_latency
))
835 mContext
->alGetSourcei64vSOFT(mId
, AL_SAMPLE_OFFSET_LATENCY_SOFT
, val
);
837 ret
.second
= std::chrono::nanoseconds(val
[1]);
840 alGetSourcei(mId
, AL_SAMPLE_OFFSET
, &srcpos
);
845 DECL_THUNK0(SecondsPair
, Source
, getSecOffsetLatency
, const)
846 std::pair
<Seconds
,Seconds
> SourceImpl::getSecOffsetLatency() const
848 std::pair
<Seconds
,Seconds
> ret
{Seconds::zero(), Seconds::zero()};
849 CheckContext(mContext
);
850 if(mId
== 0) return ret
;
854 std::lock_guard
<std::mutex
> lock(mMutex
);
855 ALint queued
= 0, state
= -1;
858 alGetSourcei(mId
, AL_BUFFERS_QUEUED
, &queued
);
859 if(mContext
->hasExtension(AL::SOFT_source_latency
))
862 mContext
->alGetSourcedvSOFT(mId
, AL_SEC_OFFSET_LATENCY_SOFT
, val
);
864 ret
.second
= Seconds(val
[1]);
869 alGetSourcef(mId
, AL_SEC_OFFSET
, &f
);
872 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
875 int64_t streampos
= mStream
->getPosition();
876 if(state
!= AL_STOPPED
)
879 frac
= std::modf(srcpos
* mStream
->getFrequency(), &ipos
);
881 // The amount of samples in the queue waiting to play
882 ALuint inqueue
= queued
*mStream
->getUpdateLength() - (ALuint
)ipos
;
883 if(!mStream
->hasLooped())
885 // A non-looped stream should never have more samples queued
886 // than have been read...
887 streampos
= std::max
<int64_t>(streampos
, inqueue
) - inqueue
;
891 streampos
-= inqueue
;
892 int64_t looplen
= mStream
->getLoopEnd() - mStream
->getLoopStart();
893 while(streampos
< mStream
->getLoopStart())
894 streampos
+= looplen
;
898 ret
.first
= Seconds((streampos
+frac
) / mStream
->getFrequency());
902 if(mContext
->hasExtension(AL::SOFT_source_latency
))
905 mContext
->alGetSourcedvSOFT(mId
, AL_SEC_OFFSET_LATENCY_SOFT
, val
);
906 ret
.first
= Seconds(val
[0]);
907 ret
.second
= Seconds(val
[1]);
912 alGetSourcef(mId
, AL_SEC_OFFSET
, &f
);
913 ret
.first
= Seconds(f
);
919 DECL_THUNK1(void, Source
, setLooping
,, bool)
920 void SourceImpl::setLooping(bool looping
)
922 CheckContext(mContext
);
925 alSourcei(mId
, AL_LOOPING
, looping
? AL_TRUE
: AL_FALSE
);
930 DECL_THUNK1(void, Source
, setPitch
,, ALfloat
)
931 void SourceImpl::setPitch(ALfloat pitch
)
934 throw std::out_of_range("Pitch out of range");
935 CheckContext(mContext
);
937 alSourcef(mId
, AL_PITCH
, pitch
* mGroupPitch
);
942 DECL_THUNK1(void, Source
, setGain
,, ALfloat
)
943 void SourceImpl::setGain(ALfloat gain
)
946 throw std::out_of_range("Gain out of range");
947 CheckContext(mContext
);
949 alSourcef(mId
, AL_GAIN
, gain
* mGroupGain
* mFadeGain
);
953 DECL_THUNK2(void, Source
, setGainRange
,, ALfloat
, ALfloat
)
954 void SourceImpl::setGainRange(ALfloat mingain
, ALfloat maxgain
)
956 if(!(mingain
>= 0.0f
&& maxgain
<= 1.0f
&& maxgain
>= mingain
))
957 throw std::out_of_range("Gain range out of range");
958 CheckContext(mContext
);
961 alSourcef(mId
, AL_MIN_GAIN
, mingain
);
962 alSourcef(mId
, AL_MAX_GAIN
, maxgain
);
969 DECL_THUNK2(void, Source
, setDistanceRange
,, ALfloat
, ALfloat
)
970 void SourceImpl::setDistanceRange(ALfloat refdist
, ALfloat maxdist
)
972 if(!(refdist
>= 0.0f
&& maxdist
<= std::numeric_limits
<float>::max() && refdist
<= maxdist
))
973 throw std::out_of_range("Distance range out of range");
974 CheckContext(mContext
);
977 alSourcef(mId
, AL_REFERENCE_DISTANCE
, refdist
);
978 alSourcef(mId
, AL_MAX_DISTANCE
, maxdist
);
985 DECL_THUNK3(void, Source
, set3DParameters
,, const Vector3
&, const Vector3
&, const Vector3
&)
986 void SourceImpl::set3DParameters(const Vector3
&position
, const Vector3
&velocity
, const Vector3
&direction
)
988 CheckContext(mContext
);
991 Batcher batcher
= mContext
->getBatcher();
992 alSourcefv(mId
, AL_POSITION
, position
.getPtr());
993 alSourcefv(mId
, AL_VELOCITY
, velocity
.getPtr());
994 alSourcefv(mId
, AL_DIRECTION
, direction
.getPtr());
996 mPosition
= position
;
997 mVelocity
= velocity
;
998 mDirection
= direction
;
1001 DECL_THUNK3(void, Source
, set3DParameters
,, const Vector3
&, const Vector3
&, const Vector3Pair
&)
1002 void SourceImpl::set3DParameters(const Vector3
&position
, const Vector3
&velocity
, const std::pair
<Vector3
,Vector3
> &orientation
)
1004 static_assert(sizeof(orientation
) == sizeof(ALfloat
[6]), "Invalid Vector3 pair size");
1005 CheckContext(mContext
);
1008 Batcher batcher
= mContext
->getBatcher();
1009 alSourcefv(mId
, AL_POSITION
, position
.getPtr());
1010 alSourcefv(mId
, AL_VELOCITY
, velocity
.getPtr());
1011 if(mContext
->hasExtension(AL::EXT_BFORMAT
))
1012 alSourcefv(mId
, AL_ORIENTATION
, orientation
.first
.getPtr());
1013 alSourcefv(mId
, AL_DIRECTION
, orientation
.first
.getPtr());
1015 mPosition
= position
;
1016 mVelocity
= velocity
;
1017 mDirection
= mOrientation
[0] = orientation
.first
;
1018 mOrientation
[1] = orientation
.second
;
1022 DECL_THUNK1(void, Source
, setPosition
,, const Vector3
&)
1023 void SourceImpl::setPosition(const Vector3
&position
)
1025 CheckContext(mContext
);
1027 alSourcefv(mId
, AL_POSITION
, position
.getPtr());
1028 mPosition
= position
;
1031 DECL_THUNK1(void, Source
, setPosition
,, const ALfloat
*)
1032 void SourceImpl::setPosition(const ALfloat
*pos
)
1034 CheckContext(mContext
);
1036 alSourcefv(mId
, AL_POSITION
, pos
);
1037 mPosition
[0] = pos
[0];
1038 mPosition
[1] = pos
[1];
1039 mPosition
[2] = pos
[2];
1042 DECL_THUNK1(void, Source
, setVelocity
,, const Vector3
&)
1043 void SourceImpl::setVelocity(const Vector3
&velocity
)
1045 CheckContext(mContext
);
1047 alSourcefv(mId
, AL_VELOCITY
, velocity
.getPtr());
1048 mVelocity
= velocity
;
1051 DECL_THUNK1(void, Source
, setVelocity
,, const ALfloat
*)
1052 void SourceImpl::setVelocity(const ALfloat
*vel
)
1054 CheckContext(mContext
);
1056 alSourcefv(mId
, AL_VELOCITY
, vel
);
1057 mVelocity
[0] = vel
[0];
1058 mVelocity
[1] = vel
[1];
1059 mVelocity
[2] = vel
[2];
1062 DECL_THUNK1(void, Source
, setDirection
,, const Vector3
&)
1063 void SourceImpl::setDirection(const Vector3
&direction
)
1065 CheckContext(mContext
);
1067 alSourcefv(mId
, AL_DIRECTION
, direction
.getPtr());
1068 mDirection
= direction
;
1071 DECL_THUNK1(void, Source
, setDirection
,, const ALfloat
*)
1072 void SourceImpl::setDirection(const ALfloat
*dir
)
1074 CheckContext(mContext
);
1076 alSourcefv(mId
, AL_DIRECTION
, dir
);
1077 mDirection
[0] = dir
[0];
1078 mDirection
[1] = dir
[1];
1079 mDirection
[2] = dir
[2];
1082 DECL_THUNK1(void, Source
, setOrientation
,, const Vector3Pair
&)
1083 void SourceImpl::setOrientation(const std::pair
<Vector3
,Vector3
> &orientation
)
1085 CheckContext(mContext
);
1088 if(mContext
->hasExtension(AL::EXT_BFORMAT
))
1089 alSourcefv(mId
, AL_ORIENTATION
, orientation
.first
.getPtr());
1090 alSourcefv(mId
, AL_DIRECTION
, orientation
.first
.getPtr());
1092 mDirection
= mOrientation
[0] = orientation
.first
;
1093 mOrientation
[1] = orientation
.second
;
1096 DECL_THUNK2(void, Source
, setOrientation
,, const ALfloat
*, const ALfloat
*)
1097 void SourceImpl::setOrientation(const ALfloat
*at
, const ALfloat
*up
)
1099 CheckContext(mContext
);
1102 ALfloat ori
[6] = { at
[0], at
[1], at
[2], up
[0], up
[1], up
[2] };
1103 if(mContext
->hasExtension(AL::EXT_BFORMAT
))
1104 alSourcefv(mId
, AL_ORIENTATION
, ori
);
1105 alSourcefv(mId
, AL_DIRECTION
, ori
);
1107 mDirection
[0] = mOrientation
[0][0] = at
[0];
1108 mDirection
[1] = mOrientation
[0][1] = at
[1];
1109 mDirection
[2] = mOrientation
[0][2] = at
[2];
1110 mOrientation
[1][0] = up
[0];
1111 mOrientation
[1][1] = up
[1];
1112 mOrientation
[1][2] = up
[2];
1115 DECL_THUNK1(void, Source
, setOrientation
,, const ALfloat
*)
1116 void SourceImpl::setOrientation(const ALfloat
*ori
)
1118 CheckContext(mContext
);
1121 if(mContext
->hasExtension(AL::EXT_BFORMAT
))
1122 alSourcefv(mId
, AL_ORIENTATION
, ori
);
1123 alSourcefv(mId
, AL_DIRECTION
, ori
);
1125 mDirection
[0] = mOrientation
[0][0] = ori
[0];
1126 mDirection
[1] = mOrientation
[0][1] = ori
[1];
1127 mDirection
[2] = mOrientation
[0][2] = ori
[2];
1128 mOrientation
[1][0] = ori
[3];
1129 mOrientation
[1][1] = ori
[4];
1130 mOrientation
[1][2] = ori
[5];
1134 DECL_THUNK2(void, Source
, setConeAngles
,, ALfloat
, ALfloat
)
1135 void SourceImpl::setConeAngles(ALfloat inner
, ALfloat outer
)
1137 if(!(inner
>= 0.0f
&& outer
<= 360.0f
&& outer
>= inner
))
1138 throw std::out_of_range("Cone angles out of range");
1139 CheckContext(mContext
);
1142 alSourcef(mId
, AL_CONE_INNER_ANGLE
, inner
);
1143 alSourcef(mId
, AL_CONE_OUTER_ANGLE
, outer
);
1145 mConeInnerAngle
= inner
;
1146 mConeOuterAngle
= outer
;
1149 DECL_THUNK2(void, Source
, setOuterConeGains
,, ALfloat
, ALfloat
)
1150 void SourceImpl::setOuterConeGains(ALfloat gain
, ALfloat gainhf
)
1152 if(!(gain
>= 0.0f
&& gain
<= 1.0f
&& gainhf
>= 0.0f
&& gainhf
<= 1.0f
))
1153 throw std::out_of_range("Outer cone gain out of range");
1154 CheckContext(mContext
);
1157 alSourcef(mId
, AL_CONE_OUTER_GAIN
, gain
);
1158 if(mContext
->hasExtension(AL::EXT_EFX
))
1159 alSourcef(mId
, AL_CONE_OUTER_GAINHF
, gainhf
);
1161 mConeOuterGain
= gain
;
1162 mConeOuterGainHF
= gainhf
;
1166 DECL_THUNK2(void, Source
, setRolloffFactors
,, ALfloat
, ALfloat
)
1167 void SourceImpl::setRolloffFactors(ALfloat factor
, ALfloat roomfactor
)
1169 if(!(factor
>= 0.0f
&& roomfactor
>= 0.0f
))
1170 throw std::out_of_range("Rolloff factor out of range");
1171 CheckContext(mContext
);
1174 alSourcef(mId
, AL_ROLLOFF_FACTOR
, factor
);
1175 if(mContext
->hasExtension(AL::EXT_EFX
))
1176 alSourcef(mId
, AL_ROOM_ROLLOFF_FACTOR
, roomfactor
);
1178 mRolloffFactor
= factor
;
1179 mRoomRolloffFactor
= roomfactor
;
1182 DECL_THUNK1(void, Source
, setDopplerFactor
,, ALfloat
)
1183 void SourceImpl::setDopplerFactor(ALfloat factor
)
1185 if(!(factor
>= 0.0f
&& factor
<= 1.0f
))
1186 throw std::out_of_range("Doppler factor out of range");
1187 CheckContext(mContext
);
1189 alSourcef(mId
, AL_DOPPLER_FACTOR
, factor
);
1190 mDopplerFactor
= factor
;
1193 DECL_THUNK1(void, Source
, setRelative
,, bool)
1194 void SourceImpl::setRelative(bool relative
)
1196 CheckContext(mContext
);
1198 alSourcei(mId
, AL_SOURCE_RELATIVE
, relative
? AL_TRUE
: AL_FALSE
);
1199 mRelative
= relative
;
1202 DECL_THUNK1(void, Source
, setRadius
,, ALfloat
)
1203 void SourceImpl::setRadius(ALfloat radius
)
1205 if(!(mRadius
>= 0.0f
))
1206 throw std::out_of_range("Radius out of range");
1207 CheckContext(mContext
);
1208 if(mId
!= 0 && mContext
->hasExtension(AL::EXT_SOURCE_RADIUS
))
1209 alSourcef(mId
, AL_SOURCE_RADIUS
, radius
);
1213 DECL_THUNK2(void, Source
, setStereoAngles
,, ALfloat
, ALfloat
)
1214 void SourceImpl::setStereoAngles(ALfloat leftAngle
, ALfloat rightAngle
)
1216 CheckContext(mContext
);
1217 if(mId
!= 0 && mContext
->hasExtension(AL::EXT_STEREO_ANGLES
))
1219 ALfloat angles
[2] = { leftAngle
, rightAngle
};
1220 alSourcefv(mId
, AL_STEREO_ANGLES
, angles
);
1222 mStereoAngles
[0] = leftAngle
;
1223 mStereoAngles
[1] = rightAngle
;
1226 DECL_THUNK1(void, Source
, set3DSpatialize
,, Spatialize
)
1227 void SourceImpl::set3DSpatialize(Spatialize spatialize
)
1229 CheckContext(mContext
);
1230 if(mId
!= 0 && mContext
->hasExtension(AL::SOFT_source_spatialize
))
1231 alSourcei(mId
, AL_SOURCE_SPATIALIZE_SOFT
, (ALint
)spatialize
);
1232 mSpatialize
= spatialize
;
1235 DECL_THUNK1(void, Source
, setResamplerIndex
,, ALsizei
)
1236 void SourceImpl::setResamplerIndex(ALsizei index
)
1239 throw std::out_of_range("Resampler index out of range");
1240 index
= std::min
<ALsizei
>(index
, mContext
->getAvailableResamplers().size());
1241 if(mId
!= 0 && mContext
->hasExtension(AL::SOFT_source_resampler
))
1242 alSourcei(mId
, AL_SOURCE_RESAMPLER_SOFT
, index
);
1246 DECL_THUNK1(void, Source
, setAirAbsorptionFactor
,, ALfloat
)
1247 void SourceImpl::setAirAbsorptionFactor(ALfloat factor
)
1249 if(!(factor
>= 0.0f
&& factor
<= 10.0f
))
1250 throw std::out_of_range("Absorption factor out of range");
1251 CheckContext(mContext
);
1252 if(mId
!= 0 && mContext
->hasExtension(AL::EXT_EFX
))
1253 alSourcef(mId
, AL_AIR_ABSORPTION_FACTOR
, factor
);
1254 mAirAbsorptionFactor
= factor
;
1257 DECL_THUNK3(void, Source
, setGainAuto
,, bool, bool, bool)
1258 void SourceImpl::setGainAuto(bool directhf
, bool send
, bool sendhf
)
1260 CheckContext(mContext
);
1261 if(mId
!= 0 && mContext
->hasExtension(AL::EXT_EFX
))
1263 alSourcei(mId
, AL_DIRECT_FILTER_GAINHF_AUTO
, directhf
? AL_TRUE
: AL_FALSE
);
1264 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
, send
? AL_TRUE
: AL_FALSE
);
1265 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
, sendhf
? AL_TRUE
: AL_FALSE
);
1267 mDryGainHFAuto
= directhf
;
1268 mWetGainAuto
= send
;
1269 mWetGainHFAuto
= sendhf
;
1273 void SourceImpl::setFilterParams(ALuint
&filterid
, const FilterParams
¶ms
)
1275 if(!mContext
->hasExtension(AL::EXT_EFX
))
1278 if(!(params
.mGain
< 1.0f
|| params
.mGainHF
< 1.0f
|| params
.mGainLF
< 1.0f
))
1281 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_NULL
);
1288 mContext
->alGenFilters(1, &filterid
);
1289 ALenum err
= alGetError();
1290 if(err
!= AL_NO_ERROR
)
1291 throw al_error(err
, "Failed to create Filter");
1293 bool filterset
= false;
1294 if(params
.mGainHF
< 1.0f
&& params
.mGainLF
< 1.0f
)
1296 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_BANDPASS
);
1297 if(alGetError() == AL_NO_ERROR
)
1299 mContext
->alFilterf(filterid
, AL_BANDPASS_GAIN
, std::min(params
.mGain
, 1.0f
));
1300 mContext
->alFilterf(filterid
, AL_BANDPASS_GAINHF
, std::min(params
.mGainHF
, 1.0f
));
1301 mContext
->alFilterf(filterid
, AL_BANDPASS_GAINLF
, std::min(params
.mGainLF
, 1.0f
));
1305 if(!filterset
&& !(params
.mGainHF
< 1.0f
) && params
.mGainLF
< 1.0f
)
1307 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_HIGHPASS
);
1308 if(alGetError() == AL_NO_ERROR
)
1310 mContext
->alFilterf(filterid
, AL_HIGHPASS_GAIN
, std::min(params
.mGain
, 1.0f
));
1311 mContext
->alFilterf(filterid
, AL_HIGHPASS_GAINLF
, std::min(params
.mGainLF
, 1.0f
));
1317 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_LOWPASS
);
1318 if(alGetError() == AL_NO_ERROR
)
1320 mContext
->alFilterf(filterid
, AL_LOWPASS_GAIN
, std::min(params
.mGain
, 1.0f
));
1321 mContext
->alFilterf(filterid
, AL_LOWPASS_GAINHF
, std::min(params
.mGainHF
, 1.0f
));
1328 DECL_THUNK1(void, Source
, setDirectFilter
,, const FilterParams
&)
1329 void SourceImpl::setDirectFilter(const FilterParams
&filter
)
1331 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1332 throw std::out_of_range("Gain value out of range");
1333 CheckContext(mContext
);
1335 setFilterParams(mDirectFilter
, filter
);
1337 alSourcei(mId
, AL_DIRECT_FILTER
, mDirectFilter
);
1340 DECL_THUNK2(void, Source
, setSendFilter
,, ALuint
, const FilterParams
&)
1341 void SourceImpl::setSendFilter(ALuint send
, const FilterParams
&filter
)
1343 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1344 throw std::out_of_range("Gain value out of range");
1345 CheckContext(mContext
);
1347 auto siter
= std::lower_bound(mEffectSlots
.begin(), mEffectSlots
.end(), send
,
1348 [](const SendProps
&prop
, ALuint send
) -> bool
1349 { return prop
.mSendIdx
< send
; }
1351 if(siter
== mEffectSlots
.end() || siter
->mSendIdx
!= send
)
1353 ALuint filterid
= 0;
1355 setFilterParams(filterid
, filter
);
1356 if(!filterid
) return;
1358 siter
= mEffectSlots
.emplace(siter
, send
, filterid
);
1361 setFilterParams(siter
->mFilter
, filter
);
1365 ALuint slotid
= (siter
->mSlot
? siter
->mSlot
->getId() : 0);
1366 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->mFilter
);
1370 DECL_THUNK2(void, Source
, setAuxiliarySend
,, AuxiliaryEffectSlot
, ALuint
)
1371 void SourceImpl::setAuxiliarySend(AuxiliaryEffectSlot auxslot
, ALuint send
)
1373 AuxiliaryEffectSlotImpl
*slot
= auxslot
.getHandle();
1374 if(slot
) CheckContexts(mContext
, slot
->getContext());
1375 CheckContext(mContext
);
1377 auto siter
= std::lower_bound(mEffectSlots
.begin(), mEffectSlots
.end(), send
,
1378 [](const SendProps
&prop
, ALuint send
) -> bool
1379 { return prop
.mSendIdx
< send
; }
1381 if(siter
== mEffectSlots
.end() || siter
->mSendIdx
!= send
)
1384 slot
->addSourceSend({Source(this), send
});
1385 siter
= mEffectSlots
.emplace(siter
, send
, slot
);
1387 else if(siter
->mSlot
!= slot
)
1389 if(slot
) slot
->addSourceSend({Source(this), send
});
1391 siter
->mSlot
->removeSourceSend({Source(this), send
});
1392 siter
->mSlot
= slot
;
1397 ALuint slotid
= (siter
->mSlot
? siter
->mSlot
->getId() : 0);
1398 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->mFilter
);
1402 DECL_THUNK3(void, Source
, setAuxiliarySendFilter
,, AuxiliaryEffectSlot
, ALuint
, const FilterParams
&)
1403 void SourceImpl::setAuxiliarySendFilter(AuxiliaryEffectSlot auxslot
, ALuint send
, const FilterParams
&filter
)
1405 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1406 throw std::out_of_range("Gain value out of range");
1407 AuxiliaryEffectSlotImpl
*slot
= auxslot
.getHandle();
1408 if(slot
) CheckContexts(mContext
, slot
->getContext());
1409 CheckContext(mContext
);
1411 auto siter
= std::lower_bound(mEffectSlots
.begin(), mEffectSlots
.end(), send
,
1412 [](const SendProps
&prop
, ALuint send
) -> bool
1413 { return prop
.mSendIdx
< send
; }
1415 if(siter
== mEffectSlots
.end() || siter
->mSendIdx
!= send
)
1417 ALuint filterid
= 0;
1419 setFilterParams(filterid
, filter
);
1420 if(!filterid
&& !slot
)
1423 if(slot
) slot
->addSourceSend({Source(this), send
});
1424 siter
= mEffectSlots
.emplace(siter
, send
, slot
, filterid
);
1428 if(siter
->mSlot
!= slot
)
1430 if(slot
) slot
->addSourceSend({Source(this), send
});
1432 siter
->mSlot
->removeSourceSend({Source(this), send
});
1433 siter
->mSlot
= slot
;
1435 setFilterParams(siter
->mFilter
, filter
);
1440 ALuint slotid
= (siter
->mSlot
? siter
->mSlot
->getId() : 0);
1441 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->mFilter
);
1446 void Source::release()
1448 SourceImpl
*i
= pImpl
;
1452 void SourceImpl::release()
1457 mContext
->freeSource(this);
1461 DECL_THUNK0(SourceGroup
, Source
, getGroup
, const)
1462 DECL_THUNK0(ALuint
, Source
, getPriority
, const)
1463 DECL_THUNK0(bool, Source
, getLooping
, const)
1464 DECL_THUNK0(ALfloat
, Source
, getPitch
, const)
1465 DECL_THUNK0(ALfloat
, Source
, getGain
, const)
1466 DECL_THUNK0(ALfloatPair
, Source
, getGainRange
, const)
1467 DECL_THUNK0(ALfloatPair
, Source
, getDistanceRange
, const)
1468 DECL_THUNK0(Vector3
, Source
, getPosition
, const)
1469 DECL_THUNK0(Vector3
, Source
, getVelocity
, const)
1470 DECL_THUNK0(Vector3
, Source
, getDirection
, const)
1471 DECL_THUNK0(Vector3Pair
, Source
, getOrientation
, const)
1472 DECL_THUNK0(ALfloatPair
, Source
, getConeAngles
, const)
1473 DECL_THUNK0(ALfloatPair
, Source
, getOuterConeGains
, const)
1474 DECL_THUNK0(ALfloatPair
, Source
, getRolloffFactors
, const)
1475 DECL_THUNK0(ALfloat
, Source
, getDopplerFactor
, const)
1476 DECL_THUNK0(bool, Source
, getRelative
, const)
1477 DECL_THUNK0(ALfloat
, Source
, getRadius
, const)
1478 DECL_THUNK0(ALfloatPair
, Source
, getStereoAngles
, const)
1479 DECL_THUNK0(Spatialize
, Source
, get3DSpatialize
, const)
1480 DECL_THUNK0(ALsizei
, Source
, getResamplerIndex
, const)
1481 DECL_THUNK0(ALfloat
, Source
, getAirAbsorptionFactor
, const)
1482 DECL_THUNK0(BoolTriple
, Source
, getGainAuto
, const)