14 #include "auxeffectslot.h"
15 #include "sourcegroup.h"
20 class ALBufferStream
{
21 SharedPtr
<Decoder
> mDecoder
;
23 ALsizei mUpdateLen
{0};
24 ALsizei mNumUpdates
{0};
26 ALenum mFormat
{AL_NONE
};
33 struct BufferLengthPair
{ ALuint mId
; ALsizei mFrameLength
; };
34 Vector
<BufferLengthPair
> mBuffers
;
38 size_t mTotalBuffered
{0};
39 uint64_t mSamplePos
{0};
40 std::pair
<uint64_t,uint64_t> mLoopPts
{0,0};
41 bool mHasLooped
{false};
42 std::atomic
<bool> mDone
{false};
45 ALBufferStream(SharedPtr
<Decoder
> decoder
, ALsizei updatelen
, ALsizei numupdates
)
46 : mDecoder(decoder
), mUpdateLen(updatelen
), mNumUpdates(numupdates
)
50 for(auto &buflen
: mBuffers
)
51 alDeleteBuffers(1, &buflen
.mId
);
55 uint64_t getPosition() const { return mSamplePos
; }
56 size_t getTotalBuffered() const { return mTotalBuffered
; }
58 ALsizei
getNumUpdates() const { return mNumUpdates
; }
59 ALsizei
getUpdateLength() const { return mUpdateLen
; }
61 ALuint
getFrequency() const { return mFrequency
; }
63 bool seek(uint64_t pos
)
65 if(!mDecoder
->seek(pos
))
69 mDone
.store(false, std::memory_order_release
);
75 ALuint srate
= mDecoder
->getFrequency();
76 ChannelConfig chans
= mDecoder
->getChannelConfig();
77 SampleType type
= mDecoder
->getSampleType();
79 mLoopPts
= mDecoder
->getLoopPoints();
80 if(mLoopPts
.first
>= mLoopPts
.second
)
83 mLoopPts
.second
= std::numeric_limits
<uint64_t>::max();
87 mFrameSize
= FramesToBytes(1, chans
, type
);
88 mFormat
= GetFormat(chans
, type
);
89 if(UNLIKELY(mFormat
== AL_NONE
))
91 auto str
= String("Unsupported format (")+GetSampleTypeName(type
)+", "+
92 GetChannelConfigName(chans
)+")";
93 throw std::runtime_error(str
);
96 mData
.resize(mUpdateLen
* mFrameSize
);
97 if(type
== SampleType::UInt8
) mSilence
= -128;
98 else if(type
== SampleType::Mulaw
) mSilence
= 127;
101 mBuffers
.assign(mNumUpdates
, {0,0});
102 for(auto &buflen
: mBuffers
)
103 alGenBuffers(1, &buflen
.mId
);
106 int64_t getLoopStart() const { return mLoopPts
.first
; }
107 int64_t getLoopEnd() const { return mLoopPts
.second
; }
109 ALsizei
resetQueue(ALuint srcid
, bool looping
)
111 alSourcei(srcid
, AL_BUFFER
, 0);
113 mReadIdx
= mWriteIdx
= 0;
116 for(;queued
< mNumUpdates
;queued
++)
118 if(!streamMoreData(srcid
, looping
))
124 void popBuffer(ALuint srcid
)
127 alSourceUnqueueBuffers(srcid
, 1, &bid
);
129 mTotalBuffered
-= mBuffers
[mReadIdx
].mFrameLength
;
130 mReadIdx
= (mReadIdx
+1) % mBuffers
.size();
133 bool hasLooped() const { return mHasLooped
; }
134 bool hasMoreData() const { return !mDone
.load(std::memory_order_acquire
); }
135 bool streamMoreData(ALuint srcid
, bool loop
)
137 if(mDone
.load(std::memory_order_acquire
))
140 ALsizei len
= mUpdateLen
;
141 if(loop
&& mSamplePos
< mLoopPts
.second
)
142 len
= static_cast<ALsizei
>(std::min
<uint64_t>(len
, mLoopPts
.second
- mSamplePos
));
146 ALsizei frames
= mDecoder
->read(mData
.data(), len
);
147 mSamplePos
+= frames
;
148 if(loop
&& ((frames
< mUpdateLen
&& mSamplePos
> 0) || (mSamplePos
== mLoopPts
.second
)))
150 if(mSamplePos
< mLoopPts
.second
)
152 mLoopPts
.second
= mSamplePos
;
153 if(mLoopPts
.first
>= mLoopPts
.second
)
158 if(!mDecoder
->seek(mLoopPts
.first
))
160 len
= mUpdateLen
-frames
;
163 ALuint got
= mDecoder
->read(&mData
[frames
*mFrameSize
], len
);
169 mSamplePos
= mLoopPts
.first
;
172 len
= static_cast<ALsizei
>(
173 std::min
<uint64_t>(mUpdateLen
-frames
, mLoopPts
.second
-mLoopPts
.first
)
176 ALuint got
= mDecoder
->read(&mData
[frames
*mFrameSize
], len
);
180 } while(frames
< mUpdateLen
);
182 if(frames
< mUpdateLen
)
184 mDone
.store(true, std::memory_order_release
);
185 if(frames
== 0) return false;
188 alBufferData(mBuffers
[mWriteIdx
].mId
,
189 mFormat
, mData
.data(), frames
* mFrameSize
, mFrequency
191 alSourceQueueBuffers(srcid
, 1, &mBuffers
[mWriteIdx
].mId
);
192 mBuffers
[mWriteIdx
].mFrameLength
= frames
;
193 mTotalBuffered
+= frames
;
195 mWriteIdx
= (mWriteIdx
+1) % mBuffers
.size();
201 SourceImpl::SourceImpl(ContextImpl
&context
)
202 : mContext(context
), mId(0), mBuffer(0), mGroup(nullptr), mIsAsync(false)
203 , mDirectFilter(AL_FILTER_NULL
)
206 mEffectSlots
.reserve(mContext
.getDevice().getMaxAuxiliarySends());
209 SourceImpl::~SourceImpl()
211 if(alcGetCurrentContext() == mContext
.getALCcontext())
214 mContext
.alDeleteFilters(1, &mDirectFilter
);
215 mDirectFilter
= AL_FILTER_NULL
;
216 for(auto &i
: mEffectSlots
)
219 mContext
.alDeleteFilters(1, &i
.mFilter
);
220 i
.mFilter
= AL_FILTER_NULL
;
224 mContext
.insertSourceId(mId
);
229 void SourceImpl::resetProperties()
232 mGroup
->eraseSource(this);
239 mPaused
.store(false, std::memory_order_release
);
246 mMaxDist
= std::numeric_limits
<float>::max();
247 mPosition
= Vector3(0.0f
);
248 mVelocity
= Vector3(0.0f
);
249 mDirection
= Vector3(0.0f
);
250 mOrientation
[0] = Vector3(0.0f
, 0.0f
, -1.0f
);
251 mOrientation
[1] = Vector3(0.0f
, 1.0f
, 0.0f
);
252 mConeInnerAngle
= 360.0f
;
253 mConeOuterAngle
= 360.0f
;
254 mConeOuterGain
= 0.0f
;
255 mConeOuterGainHF
= 1.0f
;
256 mRolloffFactor
= 1.0f
;
257 mRoomRolloffFactor
= 0.0f
;
258 mDopplerFactor
= 1.0f
;
259 mAirAbsorptionFactor
= 0.0f
;
261 mStereoAngles
[0] = F_PI
/ 6.0f
;
262 mStereoAngles
[1] = -F_PI
/ 6.0f
;
263 mSpatialize
= Spatialize::Auto
;
264 mResampler
= mContext
.hasExtension(AL::SOFT_source_resampler
) ?
265 alGetInteger(AL_DEFAULT_RESAMPLER_SOFT
) : 0;
268 mDryGainHFAuto
= true;
270 mWetGainHFAuto
= true;
272 mContext
.alDeleteFilters(1, &mDirectFilter
);
274 for(auto &i
: mEffectSlots
)
277 i
.mSlot
->removeSourceSend({Source(this), i
.mSendIdx
});
279 mContext
.alDeleteFilters(1, &i
.mFilter
);
281 mEffectSlots
.clear();
286 void SourceImpl::applyProperties(bool looping
) const
288 alSourcei(mId
, AL_LOOPING
, looping
? AL_TRUE
: AL_FALSE
);
289 alSourcef(mId
, AL_PITCH
, mPitch
* mGroupPitch
);
290 alSourcef(mId
, AL_GAIN
, mGain
* mGroupGain
* mFadeGain
);
291 alSourcef(mId
, AL_MIN_GAIN
, mMinGain
);
292 alSourcef(mId
, AL_MAX_GAIN
, mMaxGain
);
293 alSourcef(mId
, AL_REFERENCE_DISTANCE
, mRefDist
);
294 alSourcef(mId
, AL_MAX_DISTANCE
, mMaxDist
);
295 alSourcefv(mId
, AL_POSITION
, mPosition
.getPtr());
296 alSourcefv(mId
, AL_VELOCITY
, mVelocity
.getPtr());
297 alSourcefv(mId
, AL_DIRECTION
, mDirection
.getPtr());
298 if(mContext
.hasExtension(AL::EXT_BFORMAT
))
299 alSourcefv(mId
, AL_ORIENTATION
, &mOrientation
[0][0]);
300 alSourcef(mId
, AL_CONE_INNER_ANGLE
, mConeInnerAngle
);
301 alSourcef(mId
, AL_CONE_OUTER_ANGLE
, mConeOuterAngle
);
302 alSourcef(mId
, AL_CONE_OUTER_GAIN
, mConeOuterGain
);
303 alSourcef(mId
, AL_ROLLOFF_FACTOR
, mRolloffFactor
);
304 alSourcef(mId
, AL_DOPPLER_FACTOR
, mDopplerFactor
);
305 if(mContext
.hasExtension(AL::EXT_SOURCE_RADIUS
))
306 alSourcef(mId
, AL_SOURCE_RADIUS
, mRadius
);
307 if(mContext
.hasExtension(AL::EXT_STEREO_ANGLES
))
308 alSourcefv(mId
, AL_STEREO_ANGLES
, mStereoAngles
);
309 if(mContext
.hasExtension(AL::SOFT_source_spatialize
))
310 alSourcei(mId
, AL_SOURCE_SPATIALIZE_SOFT
, (ALint
)mSpatialize
);
311 if(mContext
.hasExtension(AL::SOFT_source_resampler
))
312 alSourcei(mId
, AL_SOURCE_RESAMPLER_SOFT
, mResampler
);
313 alSourcei(mId
, AL_SOURCE_RELATIVE
, mRelative
? AL_TRUE
: AL_FALSE
);
314 if(mContext
.hasExtension(AL::EXT_EFX
))
316 alSourcef(mId
, AL_CONE_OUTER_GAINHF
, mConeOuterGainHF
);
317 alSourcef(mId
, AL_ROOM_ROLLOFF_FACTOR
, mRoomRolloffFactor
);
318 alSourcef(mId
, AL_AIR_ABSORPTION_FACTOR
, mAirAbsorptionFactor
);
319 alSourcei(mId
, AL_DIRECT_FILTER_GAINHF_AUTO
, mDryGainHFAuto
? AL_TRUE
: AL_FALSE
);
320 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
, mWetGainAuto
? AL_TRUE
: AL_FALSE
);
321 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
, mWetGainHFAuto
? AL_TRUE
: AL_FALSE
);
322 alSourcei(mId
, AL_DIRECT_FILTER
, mDirectFilter
);
323 for(const auto &i
: mEffectSlots
)
325 ALuint slotid
= (i
.mSlot
? i
.mSlot
->getId() : 0);
326 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, i
.mSendIdx
, i
.mFilter
);
332 void SourceImpl::unsetGroup()
335 groupPropUpdate(1.0f
, 1.0f
);
338 void SourceImpl::groupPropUpdate(ALfloat gain
, ALfloat pitch
)
342 alSourcef(mId
, AL_PITCH
, mPitch
* pitch
);
343 alSourcef(mId
, AL_GAIN
, mGain
* gain
* mFadeGain
);
350 DECL_THUNK1(void, Source
, play
,, Buffer
)
351 void SourceImpl::play(Buffer buffer
)
353 BufferImpl
*albuf
= buffer
.getHandle();
354 if(!albuf
) throw std::invalid_argument("Buffer is not valid");
355 CheckContexts(mContext
, albuf
->getContext());
356 CheckContext(mContext
);
359 mContext
.removeStream(this);
360 mIsAsync
.store(false, std::memory_order_release
);
364 mId
= mContext
.getSourceId(mPriority
);
365 applyProperties(mLooping
);
369 mContext
.removeFadingSource(this);
370 mContext
.removePlayingSource(this);
372 alSourcei(mId
, AL_BUFFER
, 0);
373 alSourcei(mId
, AL_LOOPING
, mLooping
? AL_TRUE
: AL_FALSE
);
378 mBuffer
->removeSource(Source(this));
380 mBuffer
->addSource(Source(this));
382 alSourcei(mId
, AL_BUFFER
, mBuffer
->getId());
383 alSourcei(mId
, AL_SAMPLE_OFFSET
,
384 (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
387 mPaused
.store(false, std::memory_order_release
);
388 mContext
.removePendingSource(this);
389 mContext
.addPlayingSource(this, mId
);
392 DECL_THUNK3(void, Source
, play
,, SharedPtr
<Decoder
>, ALsizei
, ALsizei
)
393 void SourceImpl::play(SharedPtr
<Decoder
>&& decoder
, ALsizei chunk_len
, ALsizei queue_size
)
396 throw std::domain_error("Update length out of range");
398 throw std::domain_error("Queue size out of range");
399 CheckContext(mContext
);
401 auto stream
= MakeUnique
<ALBufferStream
>(decoder
, chunk_len
, queue_size
);
405 mContext
.removeStream(this);
406 mIsAsync
.store(false, std::memory_order_release
);
410 mId
= mContext
.getSourceId(mPriority
);
411 applyProperties(false);
415 mContext
.removeFadingSource(this);
416 mContext
.removePlayingSource(this);
418 alSourcei(mId
, AL_BUFFER
, 0);
419 alSourcei(mId
, AL_LOOPING
, AL_FALSE
);
424 mBuffer
->removeSource(Source(this));
427 mStream
= std::move(stream
);
429 mStream
->seek(mOffset
);
432 for(ALsizei i
= 0;i
< mStream
->getNumUpdates();i
++)
434 if(!mStream
->streamMoreData(mId
, mLooping
))
437 alSourcei(mId
, AL_SAMPLE_OFFSET
, 0);
439 mPaused
.store(false, std::memory_order_release
);
441 mContext
.addStream(this);
442 mIsAsync
.store(true, std::memory_order_release
);
443 mContext
.removePendingSource(this);
444 mContext
.addPlayingSource(this);
447 DECL_THUNK1(void, Source
, play
,, SharedFuture
<Buffer
>)
448 void SourceImpl::play(SharedFuture
<Buffer
>&& future_buffer
)
450 if(!future_buffer
.valid())
451 throw std::future_error(std::future_errc::no_state
);
452 if(GetFutureState(future_buffer
) == std::future_status::ready
)
454 play(future_buffer
.get());
458 CheckContext(mContext
);
460 mContext
.removeFadingSource(this);
461 mContext
.removePlayingSource(this);
464 mContext
.addPendingSource(this, std::move(future_buffer
));
468 DECL_THUNK0(void, Source
, stop
,)
469 void SourceImpl::stop()
471 CheckContext(mContext
);
472 mContext
.removePendingSource(this);
473 mContext
.removeFadingSource(this);
474 mContext
.removePlayingSource(this);
478 void SourceImpl::makeStopped(bool dolock
)
483 mContext
.removeStream(this);
485 mContext
.removeStreamNoLock(this);
487 mIsAsync
.store(false, std::memory_order_release
);
493 alSourcei(mId
, AL_BUFFER
, 0);
494 if(mContext
.hasExtension(AL::EXT_EFX
))
496 alSourcei(mId
, AL_DIRECT_FILTER
, AL_FILTER_NULL
);
497 for(auto &i
: mEffectSlots
)
498 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, 0, i
.mSendIdx
, AL_FILTER_NULL
);
500 mContext
.insertSourceId(mId
);
506 mBuffer
->removeSource(Source(this));
509 mPaused
.store(false, std::memory_order_release
);
513 DECL_THUNK2(void, Source
, fadeOutToStop
,, ALfloat
, std::chrono::milliseconds
)
514 void SourceImpl::fadeOutToStop(ALfloat gain
, std::chrono::milliseconds duration
)
516 if(!(gain
< 1.0f
&& gain
>= 0.0f
))
517 throw std::domain_error("Fade gain target out of range");
518 if(duration
.count() <= 0)
519 throw std::domain_error("Fade duration out of range");
520 CheckContext(mContext
);
522 gain
= std::max
<ALfloat
>(gain
, 0.0001f
);
523 float mult
= std::pow(gain
, float(1.0/Seconds(duration
).count()));
525 mContext
.addFadingSource(this, duration
, mult
);
529 void SourceImpl::checkPaused()
531 if(mPaused
.load(std::memory_order_acquire
) || mId
== 0)
535 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
536 // Streaming sources may be in a stopped or initial state if underrun
537 mPaused
.store(state
== AL_PAUSED
|| (mStream
&& mStream
->hasMoreData()),
538 std::memory_order_release
);
541 DECL_THUNK0(void, Source
, pause
,)
542 void SourceImpl::pause()
544 CheckContext(mContext
);
545 if(mPaused
.load(std::memory_order_acquire
))
550 std::lock_guard
<std::mutex
> lock(mMutex
);
553 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
554 // Streaming sources may be in a stopped or initial state if underrun
555 mPaused
.store(state
== AL_PAUSED
|| (mStream
&& mStream
->hasMoreData()),
556 std::memory_order_release
);
560 DECL_THUNK0(void, Source
, resume
,)
561 void SourceImpl::resume()
563 CheckContext(mContext
);
564 if(!mPaused
.load(std::memory_order_acquire
))
569 mPaused
.store(false, std::memory_order_release
);
573 DECL_THUNK0(bool, Source
, isPending
, const)
574 bool SourceImpl::isPending() const
576 CheckContext(mContext
);
577 return mContext
.isPendingSource(this);
580 DECL_THUNK0(bool, Source
, isPlaying
, const)
581 bool SourceImpl::isPlaying() const
583 CheckContext(mContext
);
584 if(mId
== 0) return false;
587 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
589 throw std::runtime_error("Source state error");
591 return state
== AL_PLAYING
|| (!mPaused
.load(std::memory_order_acquire
) &&
592 mStream
&& mStream
->hasMoreData());
595 DECL_THUNK0(bool, Source
, isPaused
, const)
596 bool SourceImpl::isPaused() const
598 CheckContext(mContext
);
599 return mId
!= 0 && mPaused
.load(std::memory_order_acquire
);
602 DECL_THUNK0(bool, Source
, isPlayingOrPending
, const)
603 bool SourceImpl::isPlayingOrPending() const
605 CheckContext(mContext
);
607 bool playing
= false;
611 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
613 throw std::runtime_error("Source state error");
615 playing
= (state
== AL_PLAYING
) ||
616 (!mPaused
.load(std::memory_order_acquire
) &&
617 mStream
&& mStream
->hasMoreData());
619 return playing
|| mContext
.isPendingSource(this);
623 DECL_THUNK1(void, Source
, setGroup
,, SourceGroup
)
624 void SourceImpl::setGroup(SourceGroup group
)
626 CheckContext(mContext
);
628 SourceGroupImpl
*parent
= group
.getHandle();
629 if(parent
== mGroup
) return;
632 mGroup
->eraseSource(this);
636 mGroup
->insertSource(this);
637 mGroupPitch
= mGroup
->getAppliedPitch();
638 mGroupGain
= mGroup
->getAppliedGain();
648 alSourcef(mId
, AL_PITCH
, mPitch
* mGroupPitch
);
649 alSourcef(mId
, AL_GAIN
, mGain
* mGroupGain
* mFadeGain
);
654 bool SourceImpl::checkPending(SharedFuture
<Buffer
> &future
)
656 if(GetFutureState(future
) != std::future_status::ready
)
659 BufferImpl
*buffer
= future
.get().getHandle();
660 if(UNLIKELY(!buffer
|| &(buffer
->getContext()) != &mContext
))
665 mId
= mContext
.getSourceId(mPriority
);
666 applyProperties(mLooping
);
671 alSourcei(mId
, AL_BUFFER
, 0);
672 alSourcei(mId
, AL_LOOPING
, mLooping
? AL_TRUE
: AL_FALSE
);
676 mBuffer
->addSource(Source(this));
678 alSourcei(mId
, AL_BUFFER
, mBuffer
->getId());
679 alSourcei(mId
, AL_SAMPLE_OFFSET
,
680 (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
683 mPaused
.store(false, std::memory_order_release
);
684 mContext
.addPlayingSource(this, mId
);
688 bool SourceImpl::fadeUpdate(std::chrono::nanoseconds cur_fade_time
, SourceFadeUpdateEntry
&fade
)
690 std::chrono::nanoseconds duration
= cur_fade_time
- fade
.mFadeTimeStart
;
691 if(duration
.count() < 0) return true;
692 std::chrono::nanoseconds dur_total
= fade
.mFadeTimeTarget
- fade
.mFadeTimeStart
;
694 if(duration
>= dur_total
)
700 alSourcef(mId
, AL_GAIN
, mGain
* mGroupGain
);
703 mContext
.removePendingSource(this);
704 mContext
.removePlayingSource(this);
709 if(!fade
.mIsFadeOut
) duration
= dur_total
- duration
;
710 mFadeGain
= std::pow(fade
.mFadeGainMult
, float(Seconds(duration
).count()));
713 alSourcef(mId
, AL_GAIN
, mGain
* mGroupGain
* mFadeGain
);
717 bool SourceImpl::playUpdate(ALuint id
)
720 alGetSourcei(id
, AL_SOURCE_STATE
, &state
);
721 if(LIKELY(state
== AL_PLAYING
|| state
== AL_PAUSED
))
725 mContext
.send(&MessageHandler::sourceStopped
, Source(this));
729 bool SourceImpl::playUpdate()
731 if(LIKELY(mIsAsync
.load(std::memory_order_acquire
)))
735 mContext
.send(&MessageHandler::sourceStopped
, Source(this));
740 ALint
SourceImpl::refillBufferStream()
743 alGetSourcei(mId
, AL_BUFFERS_PROCESSED
, &processed
);
746 mStream
->popBuffer(mId
);
751 alGetSourcei(mId
, AL_BUFFERS_QUEUED
, &queued
);
752 for(;queued
< mStream
->getNumUpdates();queued
++)
754 if(!mStream
->streamMoreData(mId
, mLooping
))
761 bool SourceImpl::updateAsync()
763 std::lock_guard
<std::mutex
> lock(mMutex
);
765 ALint queued
= refillBufferStream();
768 mIsAsync
.store(false, std::memory_order_release
);
773 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
774 if(!mPaused
.load(std::memory_order_acquire
))
776 // Make sure the source is still playing if it's not paused.
777 if(state
!= AL_PLAYING
)
782 // Rewind the source to an initial state if it underrun as it was
784 if(state
== AL_STOPPED
)
791 DECL_THUNK1(void, Source
, setPriority
,, ALuint
)
792 void SourceImpl::setPriority(ALuint priority
)
794 mPriority
= priority
;
798 DECL_THUNK1(void, Source
, setOffset
,, uint64_t)
799 void SourceImpl::setOffset(uint64_t offset
)
801 CheckContext(mContext
);
810 if(offset
>= std::numeric_limits
<ALint
>::max())
811 throw std::domain_error("Offset out of range");
813 alSourcei(mId
, AL_SAMPLE_OFFSET
, (ALint
)offset
);
814 throw_al_error("Failed to set offset");
818 std::lock_guard
<std::mutex
> lock(mMutex
);
819 if(!mStream
->seek(offset
))
820 throw std::domain_error("Failed to seek to offset");
822 ALsizei queued
= mStream
->resetQueue(mId
, mLooping
);
823 if(queued
> 0 && !mPaused
.load(std::memory_order_acquire
))
828 DECL_THUNK0(UInt64NSecPair
, Source
, getSampleOffsetLatency
, const)
829 std::pair
<uint64_t,std::chrono::nanoseconds
> SourceImpl::getSampleOffsetLatency() const
831 std::pair
<uint64_t,std::chrono::nanoseconds
> ret
{0, std::chrono::nanoseconds::zero()};
832 CheckContext(mContext
);
833 if(mId
== 0) return ret
;
837 std::lock_guard
<std::mutex
> lock(mMutex
);
838 ALint state
= -1, srcpos
= 0;
840 if(mContext
.hasExtension(AL::SOFT_source_latency
))
843 mContext
.alGetSourcei64vSOFT(mId
, AL_SAMPLE_OFFSET_LATENCY_SOFT
, val
);
845 ret
.second
= std::chrono::nanoseconds(val
[1]);
848 alGetSourcei(mId
, AL_SAMPLE_OFFSET
, &srcpos
);
849 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
851 int64_t streampos
= mStream
->getPosition();
852 if(state
!= AL_STOPPED
)
854 // The amount of samples in the queue waiting to play
855 ALuint inqueue
= mStream
->getTotalBuffered() - srcpos
;
856 if(!mStream
->hasLooped())
858 // A non-looped stream should never have more samples queued
859 // than have been read...
860 streampos
= std::max
<int64_t>(streampos
, inqueue
) - inqueue
;
864 streampos
-= inqueue
;
865 int64_t looplen
= mStream
->getLoopEnd() - mStream
->getLoopStart();
866 while(streampos
< mStream
->getLoopStart())
867 streampos
+= looplen
;
871 ret
.first
= streampos
;
876 if(mContext
.hasExtension(AL::SOFT_source_latency
))
879 mContext
.alGetSourcei64vSOFT(mId
, AL_SAMPLE_OFFSET_LATENCY_SOFT
, val
);
881 ret
.second
= std::chrono::nanoseconds(val
[1]);
884 alGetSourcei(mId
, AL_SAMPLE_OFFSET
, &srcpos
);
889 DECL_THUNK0(SecondsPair
, Source
, getSecOffsetLatency
, const)
890 std::pair
<Seconds
,Seconds
> SourceImpl::getSecOffsetLatency() const
892 std::pair
<Seconds
,Seconds
> ret
{Seconds::zero(), Seconds::zero()};
893 CheckContext(mContext
);
894 if(mId
== 0) return ret
;
898 std::lock_guard
<std::mutex
> lock(mMutex
);
902 if(mContext
.hasExtension(AL::SOFT_source_latency
))
905 mContext
.alGetSourcedvSOFT(mId
, AL_SEC_OFFSET_LATENCY_SOFT
, val
);
907 ret
.second
= Seconds(val
[1]);
912 alGetSourcef(mId
, AL_SEC_OFFSET
, &f
);
915 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
918 int64_t streampos
= mStream
->getPosition();
919 if(state
!= AL_STOPPED
)
922 frac
= std::modf(srcpos
* mStream
->getFrequency(), &ipos
);
924 // The amount of samples in the queue waiting to play
925 ALuint inqueue
= mStream
->getTotalBuffered() - (ALuint
)ipos
;
926 if(!mStream
->hasLooped())
928 // A non-looped stream should never have more samples queued
929 // than have been read...
930 streampos
= std::max
<int64_t>(streampos
, inqueue
) - inqueue
;
934 streampos
-= inqueue
;
935 int64_t looplen
= mStream
->getLoopEnd() - mStream
->getLoopStart();
936 while(streampos
< mStream
->getLoopStart())
937 streampos
+= looplen
;
941 ret
.first
= Seconds((streampos
+frac
) / mStream
->getFrequency());
945 if(mContext
.hasExtension(AL::SOFT_source_latency
))
948 mContext
.alGetSourcedvSOFT(mId
, AL_SEC_OFFSET_LATENCY_SOFT
, val
);
949 ret
.first
= Seconds(val
[0]);
950 ret
.second
= Seconds(val
[1]);
955 alGetSourcef(mId
, AL_SEC_OFFSET
, &f
);
956 ret
.first
= Seconds(f
);
962 DECL_THUNK1(void, Source
, setLooping
,, bool)
963 void SourceImpl::setLooping(bool looping
)
965 CheckContext(mContext
);
968 alSourcei(mId
, AL_LOOPING
, looping
? AL_TRUE
: AL_FALSE
);
973 DECL_THUNK1(void, Source
, setPitch
,, ALfloat
)
974 void SourceImpl::setPitch(ALfloat pitch
)
977 throw std::domain_error("Pitch out of range");
978 CheckContext(mContext
);
980 alSourcef(mId
, AL_PITCH
, pitch
* mGroupPitch
);
985 DECL_THUNK1(void, Source
, setGain
,, ALfloat
)
986 void SourceImpl::setGain(ALfloat gain
)
989 throw std::domain_error("Gain out of range");
990 CheckContext(mContext
);
992 alSourcef(mId
, AL_GAIN
, gain
* mGroupGain
* mFadeGain
);
996 DECL_THUNK2(void, Source
, setGainRange
,, ALfloat
, ALfloat
)
997 void SourceImpl::setGainRange(ALfloat mingain
, ALfloat maxgain
)
999 if(!(mingain
>= 0.0f
&& maxgain
<= 1.0f
&& maxgain
>= mingain
))
1000 throw std::domain_error("Gain range out of range");
1001 CheckContext(mContext
);
1004 alSourcef(mId
, AL_MIN_GAIN
, mingain
);
1005 alSourcef(mId
, AL_MAX_GAIN
, maxgain
);
1012 DECL_THUNK2(void, Source
, setDistanceRange
,, ALfloat
, ALfloat
)
1013 void SourceImpl::setDistanceRange(ALfloat refdist
, ALfloat maxdist
)
1015 if(!(refdist
>= 0.0f
&& maxdist
<= std::numeric_limits
<float>::max() && refdist
<= maxdist
))
1016 throw std::domain_error("Distance range out of range");
1017 CheckContext(mContext
);
1020 alSourcef(mId
, AL_REFERENCE_DISTANCE
, refdist
);
1021 alSourcef(mId
, AL_MAX_DISTANCE
, maxdist
);
1028 DECL_THUNK3(void, Source
, set3DParameters
,, const Vector3
&, const Vector3
&, const Vector3
&)
1029 void SourceImpl::set3DParameters(const Vector3
&position
, const Vector3
&velocity
, const Vector3
&direction
)
1031 CheckContext(mContext
);
1034 Batcher batcher
= mContext
.getBatcher();
1035 alSourcefv(mId
, AL_POSITION
, position
.getPtr());
1036 alSourcefv(mId
, AL_VELOCITY
, velocity
.getPtr());
1037 alSourcefv(mId
, AL_DIRECTION
, direction
.getPtr());
1039 mPosition
= position
;
1040 mVelocity
= velocity
;
1041 mDirection
= direction
;
1044 DECL_THUNK3(void, Source
, set3DParameters
,, const Vector3
&, const Vector3
&, const Vector3Pair
&)
1045 void SourceImpl::set3DParameters(const Vector3
&position
, const Vector3
&velocity
, const std::pair
<Vector3
,Vector3
> &orientation
)
1047 static_assert(sizeof(orientation
) == sizeof(ALfloat
[6]), "Invalid Vector3 pair size");
1048 CheckContext(mContext
);
1051 Batcher batcher
= mContext
.getBatcher();
1052 alSourcefv(mId
, AL_POSITION
, position
.getPtr());
1053 alSourcefv(mId
, AL_VELOCITY
, velocity
.getPtr());
1054 if(mContext
.hasExtension(AL::EXT_BFORMAT
))
1055 alSourcefv(mId
, AL_ORIENTATION
, orientation
.first
.getPtr());
1056 alSourcefv(mId
, AL_DIRECTION
, orientation
.first
.getPtr());
1058 mPosition
= position
;
1059 mVelocity
= velocity
;
1060 mDirection
= mOrientation
[0] = orientation
.first
;
1061 mOrientation
[1] = orientation
.second
;
1065 DECL_THUNK1(void, Source
, setPosition
,, const Vector3
&)
1066 void SourceImpl::setPosition(const Vector3
&position
)
1068 CheckContext(mContext
);
1070 alSourcefv(mId
, AL_POSITION
, position
.getPtr());
1071 mPosition
= position
;
1074 DECL_THUNK1(void, Source
, setPosition
,, const ALfloat
*)
1075 void SourceImpl::setPosition(const ALfloat
*pos
)
1077 CheckContext(mContext
);
1079 alSourcefv(mId
, AL_POSITION
, pos
);
1080 mPosition
[0] = pos
[0];
1081 mPosition
[1] = pos
[1];
1082 mPosition
[2] = pos
[2];
1085 DECL_THUNK1(void, Source
, setVelocity
,, const Vector3
&)
1086 void SourceImpl::setVelocity(const Vector3
&velocity
)
1088 CheckContext(mContext
);
1090 alSourcefv(mId
, AL_VELOCITY
, velocity
.getPtr());
1091 mVelocity
= velocity
;
1094 DECL_THUNK1(void, Source
, setVelocity
,, const ALfloat
*)
1095 void SourceImpl::setVelocity(const ALfloat
*vel
)
1097 CheckContext(mContext
);
1099 alSourcefv(mId
, AL_VELOCITY
, vel
);
1100 mVelocity
[0] = vel
[0];
1101 mVelocity
[1] = vel
[1];
1102 mVelocity
[2] = vel
[2];
1105 DECL_THUNK1(void, Source
, setDirection
,, const Vector3
&)
1106 void SourceImpl::setDirection(const Vector3
&direction
)
1108 CheckContext(mContext
);
1110 alSourcefv(mId
, AL_DIRECTION
, direction
.getPtr());
1111 mDirection
= direction
;
1114 DECL_THUNK1(void, Source
, setDirection
,, const ALfloat
*)
1115 void SourceImpl::setDirection(const ALfloat
*dir
)
1117 CheckContext(mContext
);
1119 alSourcefv(mId
, AL_DIRECTION
, dir
);
1120 mDirection
[0] = dir
[0];
1121 mDirection
[1] = dir
[1];
1122 mDirection
[2] = dir
[2];
1125 DECL_THUNK1(void, Source
, setOrientation
,, const Vector3Pair
&)
1126 void SourceImpl::setOrientation(const std::pair
<Vector3
,Vector3
> &orientation
)
1128 CheckContext(mContext
);
1131 if(mContext
.hasExtension(AL::EXT_BFORMAT
))
1132 alSourcefv(mId
, AL_ORIENTATION
, orientation
.first
.getPtr());
1133 alSourcefv(mId
, AL_DIRECTION
, orientation
.first
.getPtr());
1135 mDirection
= mOrientation
[0] = orientation
.first
;
1136 mOrientation
[1] = orientation
.second
;
1139 DECL_THUNK2(void, Source
, setOrientation
,, const ALfloat
*, const ALfloat
*)
1140 void SourceImpl::setOrientation(const ALfloat
*at
, const ALfloat
*up
)
1142 CheckContext(mContext
);
1145 ALfloat ori
[6] = { at
[0], at
[1], at
[2], up
[0], up
[1], up
[2] };
1146 if(mContext
.hasExtension(AL::EXT_BFORMAT
))
1147 alSourcefv(mId
, AL_ORIENTATION
, ori
);
1148 alSourcefv(mId
, AL_DIRECTION
, ori
);
1150 mDirection
[0] = mOrientation
[0][0] = at
[0];
1151 mDirection
[1] = mOrientation
[0][1] = at
[1];
1152 mDirection
[2] = mOrientation
[0][2] = at
[2];
1153 mOrientation
[1][0] = up
[0];
1154 mOrientation
[1][1] = up
[1];
1155 mOrientation
[1][2] = up
[2];
1158 DECL_THUNK1(void, Source
, setOrientation
,, const ALfloat
*)
1159 void SourceImpl::setOrientation(const ALfloat
*ori
)
1161 CheckContext(mContext
);
1164 if(mContext
.hasExtension(AL::EXT_BFORMAT
))
1165 alSourcefv(mId
, AL_ORIENTATION
, ori
);
1166 alSourcefv(mId
, AL_DIRECTION
, ori
);
1168 mDirection
[0] = mOrientation
[0][0] = ori
[0];
1169 mDirection
[1] = mOrientation
[0][1] = ori
[1];
1170 mDirection
[2] = mOrientation
[0][2] = ori
[2];
1171 mOrientation
[1][0] = ori
[3];
1172 mOrientation
[1][1] = ori
[4];
1173 mOrientation
[1][2] = ori
[5];
1177 DECL_THUNK2(void, Source
, setConeAngles
,, ALfloat
, ALfloat
)
1178 void SourceImpl::setConeAngles(ALfloat inner
, ALfloat outer
)
1180 if(!(inner
>= 0.0f
&& outer
<= 360.0f
&& outer
>= inner
))
1181 throw std::domain_error("Cone angles out of range");
1182 CheckContext(mContext
);
1185 alSourcef(mId
, AL_CONE_INNER_ANGLE
, inner
);
1186 alSourcef(mId
, AL_CONE_OUTER_ANGLE
, outer
);
1188 mConeInnerAngle
= inner
;
1189 mConeOuterAngle
= outer
;
1192 DECL_THUNK2(void, Source
, setOuterConeGains
,, ALfloat
, ALfloat
)
1193 void SourceImpl::setOuterConeGains(ALfloat gain
, ALfloat gainhf
)
1195 if(!(gain
>= 0.0f
&& gain
<= 1.0f
&& gainhf
>= 0.0f
&& gainhf
<= 1.0f
))
1196 throw std::domain_error("Outer cone gain out of range");
1197 CheckContext(mContext
);
1200 alSourcef(mId
, AL_CONE_OUTER_GAIN
, gain
);
1201 if(mContext
.hasExtension(AL::EXT_EFX
))
1202 alSourcef(mId
, AL_CONE_OUTER_GAINHF
, gainhf
);
1204 mConeOuterGain
= gain
;
1205 mConeOuterGainHF
= gainhf
;
1209 DECL_THUNK2(void, Source
, setRolloffFactors
,, ALfloat
, ALfloat
)
1210 void SourceImpl::setRolloffFactors(ALfloat factor
, ALfloat roomfactor
)
1212 if(!(factor
>= 0.0f
&& roomfactor
>= 0.0f
))
1213 throw std::domain_error("Rolloff factor out of range");
1214 CheckContext(mContext
);
1217 alSourcef(mId
, AL_ROLLOFF_FACTOR
, factor
);
1218 if(mContext
.hasExtension(AL::EXT_EFX
))
1219 alSourcef(mId
, AL_ROOM_ROLLOFF_FACTOR
, roomfactor
);
1221 mRolloffFactor
= factor
;
1222 mRoomRolloffFactor
= roomfactor
;
1225 DECL_THUNK1(void, Source
, setDopplerFactor
,, ALfloat
)
1226 void SourceImpl::setDopplerFactor(ALfloat factor
)
1228 if(!(factor
>= 0.0f
&& factor
<= 1.0f
))
1229 throw std::domain_error("Doppler factor out of range");
1230 CheckContext(mContext
);
1232 alSourcef(mId
, AL_DOPPLER_FACTOR
, factor
);
1233 mDopplerFactor
= factor
;
1236 DECL_THUNK1(void, Source
, setRelative
,, bool)
1237 void SourceImpl::setRelative(bool relative
)
1239 CheckContext(mContext
);
1241 alSourcei(mId
, AL_SOURCE_RELATIVE
, relative
? AL_TRUE
: AL_FALSE
);
1242 mRelative
= relative
;
1245 DECL_THUNK1(void, Source
, setRadius
,, ALfloat
)
1246 void SourceImpl::setRadius(ALfloat radius
)
1248 if(!(radius
>= 0.0f
))
1249 throw std::domain_error("Radius out of range");
1250 CheckContext(mContext
);
1251 if(mId
!= 0 && mContext
.hasExtension(AL::EXT_SOURCE_RADIUS
))
1252 alSourcef(mId
, AL_SOURCE_RADIUS
, radius
);
1256 DECL_THUNK2(void, Source
, setStereoAngles
,, ALfloat
, ALfloat
)
1257 void SourceImpl::setStereoAngles(ALfloat leftAngle
, ALfloat rightAngle
)
1259 CheckContext(mContext
);
1260 if(mId
!= 0 && mContext
.hasExtension(AL::EXT_STEREO_ANGLES
))
1262 ALfloat angles
[2] = { leftAngle
, rightAngle
};
1263 alSourcefv(mId
, AL_STEREO_ANGLES
, angles
);
1265 mStereoAngles
[0] = leftAngle
;
1266 mStereoAngles
[1] = rightAngle
;
1269 DECL_THUNK1(void, Source
, set3DSpatialize
,, Spatialize
)
1270 void SourceImpl::set3DSpatialize(Spatialize spatialize
)
1272 CheckContext(mContext
);
1273 if(mId
!= 0 && mContext
.hasExtension(AL::SOFT_source_spatialize
))
1274 alSourcei(mId
, AL_SOURCE_SPATIALIZE_SOFT
, (ALint
)spatialize
);
1275 mSpatialize
= spatialize
;
1278 DECL_THUNK1(void, Source
, setResamplerIndex
,, ALsizei
)
1279 void SourceImpl::setResamplerIndex(ALsizei index
)
1282 throw std::domain_error("Resampler index out of range");
1283 if(mId
!= 0 && mContext
.hasExtension(AL::SOFT_source_resampler
))
1284 alSourcei(mId
, AL_SOURCE_RESAMPLER_SOFT
,
1285 std::min(index
, static_cast<ALsizei
>(mContext
.getAvailableResamplers().size()))
1290 DECL_THUNK1(void, Source
, setAirAbsorptionFactor
,, ALfloat
)
1291 void SourceImpl::setAirAbsorptionFactor(ALfloat factor
)
1293 if(!(factor
>= 0.0f
&& factor
<= 10.0f
))
1294 throw std::domain_error("Absorption factor out of range");
1295 CheckContext(mContext
);
1296 if(mId
!= 0 && mContext
.hasExtension(AL::EXT_EFX
))
1297 alSourcef(mId
, AL_AIR_ABSORPTION_FACTOR
, factor
);
1298 mAirAbsorptionFactor
= factor
;
1301 DECL_THUNK3(void, Source
, setGainAuto
,, bool, bool, bool)
1302 void SourceImpl::setGainAuto(bool directhf
, bool send
, bool sendhf
)
1304 CheckContext(mContext
);
1305 if(mId
!= 0 && mContext
.hasExtension(AL::EXT_EFX
))
1307 alSourcei(mId
, AL_DIRECT_FILTER_GAINHF_AUTO
, directhf
? AL_TRUE
: AL_FALSE
);
1308 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
, send
? AL_TRUE
: AL_FALSE
);
1309 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
, sendhf
? AL_TRUE
: AL_FALSE
);
1311 mDryGainHFAuto
= directhf
;
1312 mWetGainAuto
= send
;
1313 mWetGainHFAuto
= sendhf
;
1317 void SourceImpl::setFilterParams(ALuint
&filterid
, const FilterParams
¶ms
)
1319 if(!mContext
.hasExtension(AL::EXT_EFX
))
1322 if(!(params
.mGain
< 1.0f
|| params
.mGainHF
< 1.0f
|| params
.mGainLF
< 1.0f
))
1325 mContext
.alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_NULL
);
1332 mContext
.alGenFilters(1, &filterid
);
1333 throw_al_error("Failed to create Filter");
1335 bool filterset
= false;
1336 if(params
.mGainHF
< 1.0f
&& params
.mGainLF
< 1.0f
)
1338 mContext
.alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_BANDPASS
);
1339 if(alGetError() == AL_NO_ERROR
)
1341 mContext
.alFilterf(filterid
, AL_BANDPASS_GAIN
, std::min(params
.mGain
, 1.0f
));
1342 mContext
.alFilterf(filterid
, AL_BANDPASS_GAINHF
, std::min(params
.mGainHF
, 1.0f
));
1343 mContext
.alFilterf(filterid
, AL_BANDPASS_GAINLF
, std::min(params
.mGainLF
, 1.0f
));
1347 if(!filterset
&& !(params
.mGainHF
< 1.0f
) && params
.mGainLF
< 1.0f
)
1349 mContext
.alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_HIGHPASS
);
1350 if(alGetError() == AL_NO_ERROR
)
1352 mContext
.alFilterf(filterid
, AL_HIGHPASS_GAIN
, std::min(params
.mGain
, 1.0f
));
1353 mContext
.alFilterf(filterid
, AL_HIGHPASS_GAINLF
, std::min(params
.mGainLF
, 1.0f
));
1359 mContext
.alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_LOWPASS
);
1360 if(alGetError() == AL_NO_ERROR
)
1362 mContext
.alFilterf(filterid
, AL_LOWPASS_GAIN
, std::min(params
.mGain
, 1.0f
));
1363 mContext
.alFilterf(filterid
, AL_LOWPASS_GAINHF
, std::min(params
.mGainHF
, 1.0f
));
1370 DECL_THUNK1(void, Source
, setDirectFilter
,, const FilterParams
&)
1371 void SourceImpl::setDirectFilter(const FilterParams
&filter
)
1373 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1374 throw std::domain_error("Gain value out of range");
1375 CheckContext(mContext
);
1377 setFilterParams(mDirectFilter
, filter
);
1379 alSourcei(mId
, AL_DIRECT_FILTER
, mDirectFilter
);
1382 DECL_THUNK2(void, Source
, setSendFilter
,, ALuint
, const FilterParams
&)
1383 void SourceImpl::setSendFilter(ALuint send
, const FilterParams
&filter
)
1385 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1386 throw std::domain_error("Gain value out of range");
1387 CheckContext(mContext
);
1389 auto siter
= std::lower_bound(mEffectSlots
.begin(), mEffectSlots
.end(), send
,
1390 [](const SendProps
&prop
, ALuint send
) -> bool
1391 { return prop
.mSendIdx
< send
; }
1393 if(siter
== mEffectSlots
.end() || siter
->mSendIdx
!= send
)
1395 ALuint filterid
= 0;
1397 setFilterParams(filterid
, filter
);
1398 if(!filterid
) return;
1400 siter
= mEffectSlots
.emplace(siter
, send
, filterid
);
1403 setFilterParams(siter
->mFilter
, filter
);
1407 ALuint slotid
= (siter
->mSlot
? siter
->mSlot
->getId() : 0);
1408 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->mFilter
);
1412 DECL_THUNK2(void, Source
, setAuxiliarySend
,, AuxiliaryEffectSlot
, ALuint
)
1413 void SourceImpl::setAuxiliarySend(AuxiliaryEffectSlot auxslot
, ALuint send
)
1415 AuxiliaryEffectSlotImpl
*slot
= auxslot
.getHandle();
1416 if(slot
) CheckContexts(mContext
, slot
->getContext());
1417 CheckContext(mContext
);
1419 auto siter
= std::lower_bound(mEffectSlots
.begin(), mEffectSlots
.end(), send
,
1420 [](const SendProps
&prop
, ALuint send
) -> bool
1421 { return prop
.mSendIdx
< send
; }
1423 if(siter
== mEffectSlots
.end() || siter
->mSendIdx
!= send
)
1426 slot
->addSourceSend({Source(this), send
});
1427 siter
= mEffectSlots
.emplace(siter
, send
, slot
);
1429 else if(siter
->mSlot
!= slot
)
1431 if(slot
) slot
->addSourceSend({Source(this), send
});
1433 siter
->mSlot
->removeSourceSend({Source(this), send
});
1434 siter
->mSlot
= slot
;
1439 ALuint slotid
= (siter
->mSlot
? siter
->mSlot
->getId() : 0);
1440 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->mFilter
);
1444 DECL_THUNK3(void, Source
, setAuxiliarySendFilter
,, AuxiliaryEffectSlot
, ALuint
, const FilterParams
&)
1445 void SourceImpl::setAuxiliarySendFilter(AuxiliaryEffectSlot auxslot
, ALuint send
, const FilterParams
&filter
)
1447 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1448 throw std::domain_error("Gain value out of range");
1449 AuxiliaryEffectSlotImpl
*slot
= auxslot
.getHandle();
1450 if(slot
) CheckContexts(mContext
, slot
->getContext());
1451 CheckContext(mContext
);
1453 auto siter
= std::lower_bound(mEffectSlots
.begin(), mEffectSlots
.end(), send
,
1454 [](const SendProps
&prop
, ALuint send
) -> bool
1455 { return prop
.mSendIdx
< send
; }
1457 if(siter
== mEffectSlots
.end() || siter
->mSendIdx
!= send
)
1459 ALuint filterid
= 0;
1461 setFilterParams(filterid
, filter
);
1462 if(!filterid
&& !slot
)
1465 if(slot
) slot
->addSourceSend({Source(this), send
});
1466 siter
= mEffectSlots
.emplace(siter
, send
, slot
, filterid
);
1470 if(siter
->mSlot
!= slot
)
1472 if(slot
) slot
->addSourceSend({Source(this), send
});
1474 siter
->mSlot
->removeSourceSend({Source(this), send
});
1475 siter
->mSlot
= slot
;
1477 setFilterParams(siter
->mFilter
, filter
);
1482 ALuint slotid
= (siter
->mSlot
? siter
->mSlot
->getId() : 0);
1483 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->mFilter
);
1488 void Source::destroy()
1490 SourceImpl
*i
= pImpl
;
1494 void SourceImpl::destroy()
1499 mContext
.freeSource(this);
1503 DECL_THUNK0(SourceGroup
, Source
, getGroup
, const)
1504 DECL_THUNK0(ALuint
, Source
, getPriority
, const)
1505 DECL_THUNK0(bool, Source
, getLooping
, const)
1506 DECL_THUNK0(ALfloat
, Source
, getPitch
, const)
1507 DECL_THUNK0(ALfloat
, Source
, getGain
, const)
1508 DECL_THUNK0(ALfloatPair
, Source
, getGainRange
, const)
1509 DECL_THUNK0(ALfloatPair
, Source
, getDistanceRange
, const)
1510 DECL_THUNK0(Vector3
, Source
, getPosition
, const)
1511 DECL_THUNK0(Vector3
, Source
, getVelocity
, const)
1512 DECL_THUNK0(Vector3
, Source
, getDirection
, const)
1513 DECL_THUNK0(Vector3Pair
, Source
, getOrientation
, const)
1514 DECL_THUNK0(ALfloatPair
, Source
, getConeAngles
, const)
1515 DECL_THUNK0(ALfloatPair
, Source
, getOuterConeGains
, const)
1516 DECL_THUNK0(ALfloatPair
, Source
, getRolloffFactors
, const)
1517 DECL_THUNK0(ALfloat
, Source
, getDopplerFactor
, const)
1518 DECL_THUNK0(bool, Source
, getRelative
, const)
1519 DECL_THUNK0(ALfloat
, Source
, getRadius
, const)
1520 DECL_THUNK0(ALfloatPair
, Source
, getStereoAngles
, const)
1521 DECL_THUNK0(Spatialize
, Source
, get3DSpatialize
, const)
1522 DECL_THUNK0(ALsizei
, Source
, getResamplerIndex
, const)
1523 DECL_THUNK0(ALfloat
, Source
, getAirAbsorptionFactor
, const)
1524 DECL_THUNK0(BoolTriple
, Source
, getGainAuto
, const)