14 #include "auxeffectslot.h"
15 #include "sourcegroup.h"
20 class ALBufferStream
{
21 SharedPtr
<Decoder
> mDecoder
;
24 ALuint mNumUpdates
{0};
26 ALenum mFormat
{AL_NONE
};
33 Vector
<ALuint
> mBufferIds
;
34 ALuint mCurrentIdx
{0};
36 uint64_t mSamplePos
{0};
37 std::pair
<uint64_t,uint64_t> mLoopPts
{0,0};
38 bool mHasLooped
{false};
39 std::atomic
<bool> mDone
{false};
42 ALBufferStream(SharedPtr
<Decoder
> decoder
, ALuint updatelen
, ALuint numupdates
)
43 : mDecoder(decoder
), mUpdateLen(updatelen
), mNumUpdates(numupdates
)
47 if(!mBufferIds
.empty())
49 alDeleteBuffers(mBufferIds
.size(), mBufferIds
.data());
54 uint64_t getLength() const { return mDecoder
->getLength(); }
55 uint64_t getPosition() const { return mSamplePos
; }
57 ALuint
getNumUpdates() const { return mNumUpdates
; }
58 ALuint
getUpdateLength() const { return mUpdateLen
; }
60 ALuint
getFrequency() const { return mFrequency
; }
62 bool seek(uint64_t pos
)
64 if(!mDecoder
->seek(pos
))
68 mDone
.store(false, std::memory_order_release
);
74 ALuint srate
= mDecoder
->getFrequency();
75 ChannelConfig chans
= mDecoder
->getChannelConfig();
76 SampleType type
= mDecoder
->getSampleType();
78 mLoopPts
= mDecoder
->getLoopPoints();
79 if(mLoopPts
.first
>= mLoopPts
.second
)
82 mLoopPts
.second
= std::numeric_limits
<uint64_t>::max();
86 mFrameSize
= FramesToBytes(1, chans
, type
);
87 mFormat
= GetFormat(chans
, type
);
88 if(UNLIKELY(mFormat
== AL_NONE
))
90 auto str
= String("Unsupported format (")+GetSampleTypeName(type
)+", "+
91 GetChannelConfigName(chans
)+")";
92 throw std::runtime_error(str
);
95 mData
.resize(mUpdateLen
* mFrameSize
);
96 if(type
== SampleType::UInt8
) mSilence
= 0x80;
97 else if(type
== SampleType::Mulaw
) mSilence
= 0x7f;
100 mBufferIds
.assign(mNumUpdates
, 0);
101 alGenBuffers(mBufferIds
.size(), mBufferIds
.data());
104 int64_t getLoopStart() const { return mLoopPts
.first
; }
105 int64_t getLoopEnd() const { return mLoopPts
.second
; }
107 bool hasLooped() const { return mHasLooped
; }
108 bool hasMoreData() const { return !mDone
.load(std::memory_order_acquire
); }
109 bool streamMoreData(ALuint srcid
, bool loop
)
111 if(mDone
.load(std::memory_order_acquire
))
115 ALuint len
= mUpdateLen
;
116 if(loop
&& mSamplePos
<= mLoopPts
.second
)
117 len
= static_cast<ALuint
>(std::min
<uint64_t>(len
, mLoopPts
.second
- mSamplePos
));
121 frames
= mDecoder
->read(mData
.data(), len
);
122 mSamplePos
+= frames
;
123 if(frames
< mUpdateLen
&& loop
&& mSamplePos
> 0)
125 if(mSamplePos
< mLoopPts
.second
)
127 mLoopPts
.second
= mSamplePos
;
128 if(mLoopPts
.first
>= mLoopPts
.second
)
133 if(!mDecoder
->seek(mLoopPts
.first
))
135 mSamplePos
= mLoopPts
.first
;
138 len
= static_cast<ALuint
>(
139 std::min
<uint64_t>(mUpdateLen
-frames
, mLoopPts
.second
-mLoopPts
.first
)
141 ALuint got
= mDecoder
->read(&mData
[frames
*mFrameSize
], len
);
145 } while(frames
< mUpdateLen
);
147 if(frames
< mUpdateLen
)
149 mDone
.store(true, std::memory_order_release
);
150 if(frames
== 0) return false;
151 mSamplePos
+= mUpdateLen
- frames
;
152 std::fill(mData
.begin() + frames
*mFrameSize
, mData
.end(), mSilence
);
155 alBufferData(mBufferIds
[mCurrentIdx
], mFormat
, mData
.data(), mData
.size(), mFrequency
);
156 alSourceQueueBuffers(srcid
, 1, &mBufferIds
[mCurrentIdx
]);
157 mCurrentIdx
= (mCurrentIdx
+1) % mBufferIds
.size();
163 SourceImpl::SourceImpl(ContextImpl
&context
)
164 : mContext(context
), mId(0), mBuffer(0), mGroup(nullptr), mIsAsync(false)
165 , mDirectFilter(AL_FILTER_NULL
)
168 mEffectSlots
.reserve(mContext
.getDevice().getMaxAuxiliarySends());
171 SourceImpl::~SourceImpl()
176 void SourceImpl::resetProperties()
179 mGroup
->eraseSource(this);
184 mFadeGainTarget
= 1.0f
;
187 mPaused
.store(false, std::memory_order_release
);
194 mMaxDist
= std::numeric_limits
<float>::max();
195 mPosition
= Vector3(0.0f
);
196 mVelocity
= Vector3(0.0f
);
197 mDirection
= Vector3(0.0f
);
198 mOrientation
[0] = Vector3(0.0f
, 0.0f
, -1.0f
);
199 mOrientation
[1] = Vector3(0.0f
, 1.0f
, 0.0f
);
200 mConeInnerAngle
= 360.0f
;
201 mConeOuterAngle
= 360.0f
;
202 mConeOuterGain
= 0.0f
;
203 mConeOuterGainHF
= 1.0f
;
204 mRolloffFactor
= 1.0f
;
205 mRoomRolloffFactor
= 0.0f
;
206 mDopplerFactor
= 1.0f
;
207 mAirAbsorptionFactor
= 0.0f
;
209 mStereoAngles
[0] = F_PI
/ 6.0f
;
210 mStereoAngles
[1] = -F_PI
/ 6.0f
;
211 mSpatialize
= Spatialize::Auto
;
212 mResampler
= mContext
.hasExtension(AL::SOFT_source_resampler
) ?
213 alGetInteger(AL_DEFAULT_RESAMPLER_SOFT
) : 0;
216 mDryGainHFAuto
= true;
218 mWetGainHFAuto
= true;
220 mContext
.alDeleteFilters(1, &mDirectFilter
);
222 for(auto &i
: mEffectSlots
)
225 i
.mSlot
->removeSourceSend({Source(this), i
.mSendIdx
});
227 mContext
.alDeleteFilters(1, &i
.mFilter
);
229 mEffectSlots
.clear();
234 void SourceImpl::applyProperties(bool looping
, ALuint offset
) const
236 alSourcei(mId
, AL_LOOPING
, looping
? AL_TRUE
: AL_FALSE
);
237 alSourcei(mId
, AL_SAMPLE_OFFSET
, offset
);
238 alSourcef(mId
, AL_PITCH
, mPitch
* mGroupPitch
);
239 alSourcef(mId
, AL_GAIN
, mGain
* mGroupGain
* mFadeGain
);
240 alSourcef(mId
, AL_MIN_GAIN
, mMinGain
);
241 alSourcef(mId
, AL_MAX_GAIN
, mMaxGain
);
242 alSourcef(mId
, AL_REFERENCE_DISTANCE
, mRefDist
);
243 alSourcef(mId
, AL_MAX_DISTANCE
, mMaxDist
);
244 alSourcefv(mId
, AL_POSITION
, mPosition
.getPtr());
245 alSourcefv(mId
, AL_VELOCITY
, mVelocity
.getPtr());
246 alSourcefv(mId
, AL_DIRECTION
, mDirection
.getPtr());
247 if(mContext
.hasExtension(AL::EXT_BFORMAT
))
248 alSourcefv(mId
, AL_ORIENTATION
, &mOrientation
[0][0]);
249 alSourcef(mId
, AL_CONE_INNER_ANGLE
, mConeInnerAngle
);
250 alSourcef(mId
, AL_CONE_OUTER_ANGLE
, mConeOuterAngle
);
251 alSourcef(mId
, AL_CONE_OUTER_GAIN
, mConeOuterGain
);
252 alSourcef(mId
, AL_ROLLOFF_FACTOR
, mRolloffFactor
);
253 alSourcef(mId
, AL_DOPPLER_FACTOR
, mDopplerFactor
);
254 if(mContext
.hasExtension(AL::EXT_SOURCE_RADIUS
))
255 alSourcef(mId
, AL_SOURCE_RADIUS
, mRadius
);
256 if(mContext
.hasExtension(AL::EXT_STEREO_ANGLES
))
257 alSourcefv(mId
, AL_STEREO_ANGLES
, mStereoAngles
);
258 if(mContext
.hasExtension(AL::SOFT_source_spatialize
))
259 alSourcei(mId
, AL_SOURCE_SPATIALIZE_SOFT
, (ALint
)mSpatialize
);
260 if(mContext
.hasExtension(AL::SOFT_source_resampler
))
261 alSourcei(mId
, AL_SOURCE_RESAMPLER_SOFT
, mResampler
);
262 alSourcei(mId
, AL_SOURCE_RELATIVE
, mRelative
? AL_TRUE
: AL_FALSE
);
263 if(mContext
.hasExtension(AL::EXT_EFX
))
265 alSourcef(mId
, AL_CONE_OUTER_GAINHF
, mConeOuterGainHF
);
266 alSourcef(mId
, AL_ROOM_ROLLOFF_FACTOR
, mRoomRolloffFactor
);
267 alSourcef(mId
, AL_AIR_ABSORPTION_FACTOR
, mAirAbsorptionFactor
);
268 alSourcei(mId
, AL_DIRECT_FILTER_GAINHF_AUTO
, mDryGainHFAuto
? AL_TRUE
: AL_FALSE
);
269 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
, mWetGainAuto
? AL_TRUE
: AL_FALSE
);
270 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
, mWetGainHFAuto
? AL_TRUE
: AL_FALSE
);
271 alSourcei(mId
, AL_DIRECT_FILTER
, mDirectFilter
);
272 for(const auto &i
: mEffectSlots
)
274 ALuint slotid
= (i
.mSlot
? i
.mSlot
->getId() : 0);
275 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, i
.mSendIdx
, i
.mFilter
);
281 void SourceImpl::unsetGroup()
284 groupPropUpdate(1.0f
, 1.0f
);
287 void SourceImpl::groupPropUpdate(ALfloat gain
, ALfloat pitch
)
291 alSourcef(mId
, AL_PITCH
, mPitch
* pitch
);
292 alSourcef(mId
, AL_GAIN
, mGain
* gain
* mFadeGain
);
299 DECL_THUNK1(void, Source
, play
,, Buffer
)
300 void SourceImpl::play(Buffer buffer
)
302 BufferImpl
*albuf
= buffer
.getHandle();
303 if(!albuf
) throw std::invalid_argument("Buffer is not valid");
304 CheckContexts(mContext
, albuf
->getContext());
305 CheckContext(mContext
);
308 mContext
.removeStream(this);
309 mIsAsync
.store(false, std::memory_order_release
);
311 mFadeGainTarget
= mFadeGain
= 1.0f
;
312 mFadeTimeTarget
= mLastFadeTime
= std::chrono::nanoseconds::zero();
316 mId
= mContext
.getSourceId(mPriority
);
317 applyProperties(mLooping
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
321 mContext
.removeFadingSource(this);
322 mContext
.removePlayingSource(this);
324 alSourcei(mId
, AL_BUFFER
, 0);
325 alSourcei(mId
, AL_LOOPING
, mLooping
? AL_TRUE
: AL_FALSE
);
326 alSourcei(mId
, AL_SAMPLE_OFFSET
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
332 mBuffer
->removeSource(Source(this));
334 mBuffer
->addSource(Source(this));
336 alSourcei(mId
, AL_BUFFER
, mBuffer
->getId());
338 mPaused
.store(false, std::memory_order_release
);
339 mContext
.removePendingSource(this);
340 mContext
.addPlayingSource(this, mId
);
343 DECL_THUNK3(void, Source
, play
,, SharedPtr
<Decoder
>, ALuint
, ALuint
)
344 void SourceImpl::play(SharedPtr
<Decoder
>&& decoder
, ALuint chunk_len
, ALuint queue_size
)
347 throw std::out_of_range("Update length out of range");
349 throw std::out_of_range("Queue size out of range");
350 CheckContext(mContext
);
352 auto stream
= MakeUnique
<ALBufferStream
>(decoder
, chunk_len
, queue_size
);
356 mContext
.removeStream(this);
357 mIsAsync
.store(false, std::memory_order_release
);
359 mFadeGainTarget
= mFadeGain
= 1.0f
;
360 mFadeTimeTarget
= mLastFadeTime
= std::chrono::nanoseconds::zero();
364 mId
= mContext
.getSourceId(mPriority
);
365 applyProperties(false, 0);
369 mContext
.removeFadingSource(this);
370 mContext
.removePlayingSource(this);
372 alSourcei(mId
, AL_BUFFER
, 0);
373 alSourcei(mId
, AL_LOOPING
, AL_FALSE
);
374 alSourcei(mId
, AL_SAMPLE_OFFSET
, 0);
379 mBuffer
->removeSource(Source(this));
382 mStream
= std::move(stream
);
384 mStream
->seek(mOffset
);
387 for(ALuint i
= 0;i
< mStream
->getNumUpdates();i
++)
389 if(!mStream
->streamMoreData(mId
, mLooping
))
393 mPaused
.store(false, std::memory_order_release
);
395 mContext
.addStream(this);
396 mIsAsync
.store(true, std::memory_order_release
);
397 mContext
.removePendingSource(this);
398 mContext
.addPlayingSource(this);
401 DECL_THUNK1(void, Source
, play
,, SharedFuture
<Buffer
>)
402 void SourceImpl::play(SharedFuture
<Buffer
>&& future_buffer
)
404 if(!future_buffer
.valid())
405 throw std::future_error(std::future_errc::no_state
);
406 if(GetFutureState(future_buffer
) == std::future_status::ready
)
408 play(future_buffer
.get());
412 CheckContext(mContext
);
414 mContext
.removeFadingSource(this);
415 mContext
.removePlayingSource(this);
418 mFadeGainTarget
= mFadeGain
= 1.0f
;
419 mFadeTimeTarget
= mLastFadeTime
= std::chrono::nanoseconds::zero();
421 mContext
.addPendingSource(this, std::move(future_buffer
));
425 DECL_THUNK0(void, Source
, stop
,)
426 void SourceImpl::stop()
428 CheckContext(mContext
);
429 mContext
.removePendingSource(this);
430 mContext
.removeFadingSource(this);
431 mContext
.removePlayingSource(this);
435 void SourceImpl::makeStopped(bool dolock
)
440 mContext
.removeStream(this);
442 mContext
.removeStreamNoLock(this);
444 mIsAsync
.store(false, std::memory_order_release
);
449 alSourcei(mId
, AL_BUFFER
, 0);
450 if(mContext
.hasExtension(AL::EXT_EFX
))
452 alSourcei(mId
, AL_DIRECT_FILTER
, AL_FILTER_NULL
);
453 for(auto &i
: mEffectSlots
)
454 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, 0, i
.mSendIdx
, AL_FILTER_NULL
);
456 mContext
.insertSourceId(mId
);
462 mBuffer
->removeSource(Source(this));
465 mPaused
.store(false, std::memory_order_release
);
469 DECL_THUNK2(void, Source
, fadeOutToStop
,, ALfloat
, std::chrono::milliseconds
)
470 void SourceImpl::fadeOutToStop(ALfloat gain
, std::chrono::milliseconds duration
)
472 if(!(gain
< 1.0f
&& gain
>= 0.0f
))
473 throw std::out_of_range("Fade gain target out of range");
474 if(duration
.count() <= 0)
475 throw std::out_of_range("Fade duration out of range");
476 CheckContext(mContext
);
478 mFadeGainTarget
= std::max
<ALfloat
>(gain
, 0.0001f
);
479 mLastFadeTime
= std::chrono::steady_clock::now().time_since_epoch();
480 mFadeTimeTarget
= mLastFadeTime
+ duration
;
482 mContext
.addFadingSource(this);
486 void SourceImpl::checkPaused()
488 if(mPaused
.load(std::memory_order_acquire
) || mId
== 0)
492 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
493 // Streaming sources may be in a stopped or initial state if underrun
494 mPaused
.store(state
== AL_PAUSED
|| (mStream
&& mStream
->hasMoreData()),
495 std::memory_order_release
);
498 DECL_THUNK0(void, Source
, pause
,)
499 void SourceImpl::pause()
501 CheckContext(mContext
);
502 if(mPaused
.load(std::memory_order_acquire
))
507 std::lock_guard
<std::mutex
> lock(mMutex
);
510 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
511 // Streaming sources may be in a stopped or initial state if underrun
512 mPaused
.store(state
== AL_PAUSED
|| (mStream
&& mStream
->hasMoreData()),
513 std::memory_order_release
);
517 DECL_THUNK0(void, Source
, resume
,)
518 void SourceImpl::resume()
520 CheckContext(mContext
);
521 if(!mPaused
.load(std::memory_order_acquire
))
526 mPaused
.store(false, std::memory_order_release
);
530 DECL_THUNK0(bool, Source
, isPending
, const)
531 bool SourceImpl::isPending() const
533 CheckContext(mContext
);
534 return mContext
.isPendingSource(this);
537 DECL_THUNK0(bool, Source
, isPlaying
, const)
538 bool SourceImpl::isPlaying() const
540 CheckContext(mContext
);
541 if(mId
== 0) return false;
544 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
546 throw std::runtime_error("Source state error");
548 return state
== AL_PLAYING
|| (!mPaused
.load(std::memory_order_acquire
) &&
549 mStream
&& mStream
->hasMoreData());
552 DECL_THUNK0(bool, Source
, isPaused
, const)
553 bool SourceImpl::isPaused() const
555 CheckContext(mContext
);
556 return mId
!= 0 && mPaused
.load(std::memory_order_acquire
);
560 DECL_THUNK1(void, Source
, setGroup
,, SourceGroup
)
561 void SourceImpl::setGroup(SourceGroup group
)
563 CheckContext(mContext
);
565 SourceGroupImpl
*parent
= group
.getHandle();
566 if(parent
== mGroup
) return;
569 mGroup
->eraseSource(this);
573 mGroup
->insertSource(this);
574 mGroupPitch
= mGroup
->getAppliedPitch();
575 mGroupGain
= mGroup
->getAppliedGain();
585 alSourcef(mId
, AL_PITCH
, mPitch
* mGroupPitch
);
586 alSourcef(mId
, AL_GAIN
, mGain
* mGroupGain
* mFadeGain
);
591 bool SourceImpl::checkPending(SharedFuture
<Buffer
> &future
)
593 if(GetFutureState(future
) != std::future_status::ready
)
596 BufferImpl
*buffer
= future
.get().getHandle();
597 if(UNLIKELY(!buffer
|| &(buffer
->getContext()) != &mContext
))
602 mId
= mContext
.getSourceId(mPriority
);
603 applyProperties(mLooping
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
608 alSourcei(mId
, AL_BUFFER
, 0);
609 alSourcei(mId
, AL_LOOPING
, mLooping
? AL_TRUE
: AL_FALSE
);
610 alSourcei(mId
, AL_SAMPLE_OFFSET
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
615 mBuffer
->addSource(Source(this));
617 alSourcei(mId
, AL_BUFFER
, mBuffer
->getId());
619 mPaused
.store(false, std::memory_order_release
);
620 mContext
.addPlayingSource(this, mId
);
624 bool SourceImpl::fadeUpdate(std::chrono::nanoseconds cur_fade_time
)
626 if((cur_fade_time
- mFadeTimeTarget
).count() >= 0)
628 mLastFadeTime
= mFadeTimeTarget
;
630 if(mFadeGainTarget
>= 1.0f
)
633 alSourcef(mId
, AL_GAIN
, mGain
* mGroupGain
);
636 mContext
.removePendingSource(this);
637 mContext
.removePlayingSource(this);
642 float mult
= std::pow(mFadeGainTarget
/mFadeGain
,
643 float(1.0/Seconds(mFadeTimeTarget
-mLastFadeTime
).count())
646 std::chrono::nanoseconds duration
= cur_fade_time
- mLastFadeTime
;
647 mLastFadeTime
= cur_fade_time
;
649 float gain
= mFadeGain
* std::pow(mult
, (float)Seconds(duration
).count());
650 if(UNLIKELY(gain
== mFadeGain
))
652 // Ensure the gain keeps moving toward its target, in case precision
653 // loss results in no change with small steps.
654 gain
= std::nextafter(gain
, mFadeGainTarget
);
659 alSourcef(mId
, AL_GAIN
, mGain
* mGroupGain
* mFadeGain
);
663 bool SourceImpl::playUpdate(ALuint id
)
666 alGetSourcei(id
, AL_SOURCE_STATE
, &state
);
667 if(LIKELY(state
== AL_PLAYING
|| state
== AL_PAUSED
))
671 mContext
.send(&MessageHandler::sourceStopped
, Source(this));
675 bool SourceImpl::playUpdate()
677 if(LIKELY(mIsAsync
.load(std::memory_order_acquire
)))
681 mContext
.send(&MessageHandler::sourceStopped
, Source(this));
686 ALint
SourceImpl::refillBufferStream()
689 alGetSourcei(mId
, AL_BUFFERS_PROCESSED
, &processed
);
693 alSourceUnqueueBuffers(mId
, 1, &buf
);
698 alGetSourcei(mId
, AL_BUFFERS_QUEUED
, &queued
);
699 for(;(ALuint
)queued
< mStream
->getNumUpdates();queued
++)
701 if(!mStream
->streamMoreData(mId
, mLooping
))
708 bool SourceImpl::updateAsync()
710 std::lock_guard
<std::mutex
> lock(mMutex
);
712 ALint queued
= refillBufferStream();
715 mIsAsync
.store(false, std::memory_order_release
);
720 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
721 if(!mPaused
.load(std::memory_order_acquire
))
723 // Make sure the source is still playing if it's not paused.
724 if(state
!= AL_PLAYING
)
729 // Rewind the source to an initial state if it underrun as it was
731 if(state
== AL_STOPPED
)
738 DECL_THUNK1(void, Source
, setPriority
,, ALuint
)
739 void SourceImpl::setPriority(ALuint priority
)
741 mPriority
= priority
;
745 DECL_THUNK1(void, Source
, setOffset
,, uint64_t)
746 void SourceImpl::setOffset(uint64_t offset
)
748 CheckContext(mContext
);
757 if(offset
>= std::numeric_limits
<ALint
>::max())
758 throw std::out_of_range("Offset out of range");
760 alSourcei(mId
, AL_SAMPLE_OFFSET
, (ALint
)offset
);
761 throw_al_error("Failed to set offset");
765 std::lock_guard
<std::mutex
> lock(mMutex
);
766 if(!mStream
->seek(offset
))
767 throw std::runtime_error("Failed to seek to offset");
769 alSourcei(mId
, AL_BUFFER
, 0);
770 ALint queued
= refillBufferStream();
771 if(queued
> 0 && !mPaused
.load(std::memory_order_acquire
))
776 DECL_THUNK0(UInt64NSecPair
, Source
, getSampleOffsetLatency
, const)
777 std::pair
<uint64_t,std::chrono::nanoseconds
> SourceImpl::getSampleOffsetLatency() const
779 std::pair
<uint64_t,std::chrono::nanoseconds
> ret
{0, std::chrono::nanoseconds::zero()};
780 CheckContext(mContext
);
781 if(mId
== 0) return ret
;
785 std::lock_guard
<std::mutex
> lock(mMutex
);
786 ALint queued
= 0, state
= -1, srcpos
= 0;
788 alGetSourcei(mId
, AL_BUFFERS_QUEUED
, &queued
);
789 if(mContext
.hasExtension(AL::SOFT_source_latency
))
792 mContext
.alGetSourcei64vSOFT(mId
, AL_SAMPLE_OFFSET_LATENCY_SOFT
, val
);
794 ret
.second
= std::chrono::nanoseconds(val
[1]);
797 alGetSourcei(mId
, AL_SAMPLE_OFFSET
, &srcpos
);
798 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
800 int64_t streampos
= mStream
->getPosition();
801 if(state
!= AL_STOPPED
)
803 // The amount of samples in the queue waiting to play
804 ALuint inqueue
= queued
*mStream
->getUpdateLength() - srcpos
;
805 if(!mStream
->hasLooped())
807 // A non-looped stream should never have more samples queued
808 // than have been read...
809 streampos
= std::max
<int64_t>(streampos
, inqueue
) - inqueue
;
813 streampos
-= inqueue
;
814 int64_t looplen
= mStream
->getLoopEnd() - mStream
->getLoopStart();
815 while(streampos
< mStream
->getLoopStart())
816 streampos
+= looplen
;
820 ret
.first
= streampos
;
825 if(mContext
.hasExtension(AL::SOFT_source_latency
))
828 mContext
.alGetSourcei64vSOFT(mId
, AL_SAMPLE_OFFSET_LATENCY_SOFT
, val
);
830 ret
.second
= std::chrono::nanoseconds(val
[1]);
833 alGetSourcei(mId
, AL_SAMPLE_OFFSET
, &srcpos
);
838 DECL_THUNK0(SecondsPair
, Source
, getSecOffsetLatency
, const)
839 std::pair
<Seconds
,Seconds
> SourceImpl::getSecOffsetLatency() const
841 std::pair
<Seconds
,Seconds
> ret
{Seconds::zero(), Seconds::zero()};
842 CheckContext(mContext
);
843 if(mId
== 0) return ret
;
847 std::lock_guard
<std::mutex
> lock(mMutex
);
848 ALint queued
= 0, state
= -1;
851 alGetSourcei(mId
, AL_BUFFERS_QUEUED
, &queued
);
852 if(mContext
.hasExtension(AL::SOFT_source_latency
))
855 mContext
.alGetSourcedvSOFT(mId
, AL_SEC_OFFSET_LATENCY_SOFT
, val
);
857 ret
.second
= Seconds(val
[1]);
862 alGetSourcef(mId
, AL_SEC_OFFSET
, &f
);
865 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
868 int64_t streampos
= mStream
->getPosition();
869 if(state
!= AL_STOPPED
)
872 frac
= std::modf(srcpos
* mStream
->getFrequency(), &ipos
);
874 // The amount of samples in the queue waiting to play
875 ALuint inqueue
= queued
*mStream
->getUpdateLength() - (ALuint
)ipos
;
876 if(!mStream
->hasLooped())
878 // A non-looped stream should never have more samples queued
879 // than have been read...
880 streampos
= std::max
<int64_t>(streampos
, inqueue
) - inqueue
;
884 streampos
-= inqueue
;
885 int64_t looplen
= mStream
->getLoopEnd() - mStream
->getLoopStart();
886 while(streampos
< mStream
->getLoopStart())
887 streampos
+= looplen
;
891 ret
.first
= Seconds((streampos
+frac
) / mStream
->getFrequency());
895 if(mContext
.hasExtension(AL::SOFT_source_latency
))
898 mContext
.alGetSourcedvSOFT(mId
, AL_SEC_OFFSET_LATENCY_SOFT
, val
);
899 ret
.first
= Seconds(val
[0]);
900 ret
.second
= Seconds(val
[1]);
905 alGetSourcef(mId
, AL_SEC_OFFSET
, &f
);
906 ret
.first
= Seconds(f
);
912 DECL_THUNK1(void, Source
, setLooping
,, bool)
913 void SourceImpl::setLooping(bool looping
)
915 CheckContext(mContext
);
918 alSourcei(mId
, AL_LOOPING
, looping
? AL_TRUE
: AL_FALSE
);
923 DECL_THUNK1(void, Source
, setPitch
,, ALfloat
)
924 void SourceImpl::setPitch(ALfloat pitch
)
927 throw std::out_of_range("Pitch out of range");
928 CheckContext(mContext
);
930 alSourcef(mId
, AL_PITCH
, pitch
* mGroupPitch
);
935 DECL_THUNK1(void, Source
, setGain
,, ALfloat
)
936 void SourceImpl::setGain(ALfloat gain
)
939 throw std::out_of_range("Gain out of range");
940 CheckContext(mContext
);
942 alSourcef(mId
, AL_GAIN
, gain
* mGroupGain
* mFadeGain
);
946 DECL_THUNK2(void, Source
, setGainRange
,, ALfloat
, ALfloat
)
947 void SourceImpl::setGainRange(ALfloat mingain
, ALfloat maxgain
)
949 if(!(mingain
>= 0.0f
&& maxgain
<= 1.0f
&& maxgain
>= mingain
))
950 throw std::out_of_range("Gain range out of range");
951 CheckContext(mContext
);
954 alSourcef(mId
, AL_MIN_GAIN
, mingain
);
955 alSourcef(mId
, AL_MAX_GAIN
, maxgain
);
962 DECL_THUNK2(void, Source
, setDistanceRange
,, ALfloat
, ALfloat
)
963 void SourceImpl::setDistanceRange(ALfloat refdist
, ALfloat maxdist
)
965 if(!(refdist
>= 0.0f
&& maxdist
<= std::numeric_limits
<float>::max() && refdist
<= maxdist
))
966 throw std::out_of_range("Distance range out of range");
967 CheckContext(mContext
);
970 alSourcef(mId
, AL_REFERENCE_DISTANCE
, refdist
);
971 alSourcef(mId
, AL_MAX_DISTANCE
, maxdist
);
978 DECL_THUNK3(void, Source
, set3DParameters
,, const Vector3
&, const Vector3
&, const Vector3
&)
979 void SourceImpl::set3DParameters(const Vector3
&position
, const Vector3
&velocity
, const Vector3
&direction
)
981 CheckContext(mContext
);
984 Batcher batcher
= mContext
.getBatcher();
985 alSourcefv(mId
, AL_POSITION
, position
.getPtr());
986 alSourcefv(mId
, AL_VELOCITY
, velocity
.getPtr());
987 alSourcefv(mId
, AL_DIRECTION
, direction
.getPtr());
989 mPosition
= position
;
990 mVelocity
= velocity
;
991 mDirection
= direction
;
994 DECL_THUNK3(void, Source
, set3DParameters
,, const Vector3
&, const Vector3
&, const Vector3Pair
&)
995 void SourceImpl::set3DParameters(const Vector3
&position
, const Vector3
&velocity
, const std::pair
<Vector3
,Vector3
> &orientation
)
997 static_assert(sizeof(orientation
) == sizeof(ALfloat
[6]), "Invalid Vector3 pair size");
998 CheckContext(mContext
);
1001 Batcher batcher
= mContext
.getBatcher();
1002 alSourcefv(mId
, AL_POSITION
, position
.getPtr());
1003 alSourcefv(mId
, AL_VELOCITY
, velocity
.getPtr());
1004 if(mContext
.hasExtension(AL::EXT_BFORMAT
))
1005 alSourcefv(mId
, AL_ORIENTATION
, orientation
.first
.getPtr());
1006 alSourcefv(mId
, AL_DIRECTION
, orientation
.first
.getPtr());
1008 mPosition
= position
;
1009 mVelocity
= velocity
;
1010 mDirection
= mOrientation
[0] = orientation
.first
;
1011 mOrientation
[1] = orientation
.second
;
1015 DECL_THUNK1(void, Source
, setPosition
,, const Vector3
&)
1016 void SourceImpl::setPosition(const Vector3
&position
)
1018 CheckContext(mContext
);
1020 alSourcefv(mId
, AL_POSITION
, position
.getPtr());
1021 mPosition
= position
;
1024 DECL_THUNK1(void, Source
, setPosition
,, const ALfloat
*)
1025 void SourceImpl::setPosition(const ALfloat
*pos
)
1027 CheckContext(mContext
);
1029 alSourcefv(mId
, AL_POSITION
, pos
);
1030 mPosition
[0] = pos
[0];
1031 mPosition
[1] = pos
[1];
1032 mPosition
[2] = pos
[2];
1035 DECL_THUNK1(void, Source
, setVelocity
,, const Vector3
&)
1036 void SourceImpl::setVelocity(const Vector3
&velocity
)
1038 CheckContext(mContext
);
1040 alSourcefv(mId
, AL_VELOCITY
, velocity
.getPtr());
1041 mVelocity
= velocity
;
1044 DECL_THUNK1(void, Source
, setVelocity
,, const ALfloat
*)
1045 void SourceImpl::setVelocity(const ALfloat
*vel
)
1047 CheckContext(mContext
);
1049 alSourcefv(mId
, AL_VELOCITY
, vel
);
1050 mVelocity
[0] = vel
[0];
1051 mVelocity
[1] = vel
[1];
1052 mVelocity
[2] = vel
[2];
1055 DECL_THUNK1(void, Source
, setDirection
,, const Vector3
&)
1056 void SourceImpl::setDirection(const Vector3
&direction
)
1058 CheckContext(mContext
);
1060 alSourcefv(mId
, AL_DIRECTION
, direction
.getPtr());
1061 mDirection
= direction
;
1064 DECL_THUNK1(void, Source
, setDirection
,, const ALfloat
*)
1065 void SourceImpl::setDirection(const ALfloat
*dir
)
1067 CheckContext(mContext
);
1069 alSourcefv(mId
, AL_DIRECTION
, dir
);
1070 mDirection
[0] = dir
[0];
1071 mDirection
[1] = dir
[1];
1072 mDirection
[2] = dir
[2];
1075 DECL_THUNK1(void, Source
, setOrientation
,, const Vector3Pair
&)
1076 void SourceImpl::setOrientation(const std::pair
<Vector3
,Vector3
> &orientation
)
1078 CheckContext(mContext
);
1081 if(mContext
.hasExtension(AL::EXT_BFORMAT
))
1082 alSourcefv(mId
, AL_ORIENTATION
, orientation
.first
.getPtr());
1083 alSourcefv(mId
, AL_DIRECTION
, orientation
.first
.getPtr());
1085 mDirection
= mOrientation
[0] = orientation
.first
;
1086 mOrientation
[1] = orientation
.second
;
1089 DECL_THUNK2(void, Source
, setOrientation
,, const ALfloat
*, const ALfloat
*)
1090 void SourceImpl::setOrientation(const ALfloat
*at
, const ALfloat
*up
)
1092 CheckContext(mContext
);
1095 ALfloat ori
[6] = { at
[0], at
[1], at
[2], up
[0], up
[1], up
[2] };
1096 if(mContext
.hasExtension(AL::EXT_BFORMAT
))
1097 alSourcefv(mId
, AL_ORIENTATION
, ori
);
1098 alSourcefv(mId
, AL_DIRECTION
, ori
);
1100 mDirection
[0] = mOrientation
[0][0] = at
[0];
1101 mDirection
[1] = mOrientation
[0][1] = at
[1];
1102 mDirection
[2] = mOrientation
[0][2] = at
[2];
1103 mOrientation
[1][0] = up
[0];
1104 mOrientation
[1][1] = up
[1];
1105 mOrientation
[1][2] = up
[2];
1108 DECL_THUNK1(void, Source
, setOrientation
,, const ALfloat
*)
1109 void SourceImpl::setOrientation(const ALfloat
*ori
)
1111 CheckContext(mContext
);
1114 if(mContext
.hasExtension(AL::EXT_BFORMAT
))
1115 alSourcefv(mId
, AL_ORIENTATION
, ori
);
1116 alSourcefv(mId
, AL_DIRECTION
, ori
);
1118 mDirection
[0] = mOrientation
[0][0] = ori
[0];
1119 mDirection
[1] = mOrientation
[0][1] = ori
[1];
1120 mDirection
[2] = mOrientation
[0][2] = ori
[2];
1121 mOrientation
[1][0] = ori
[3];
1122 mOrientation
[1][1] = ori
[4];
1123 mOrientation
[1][2] = ori
[5];
1127 DECL_THUNK2(void, Source
, setConeAngles
,, ALfloat
, ALfloat
)
1128 void SourceImpl::setConeAngles(ALfloat inner
, ALfloat outer
)
1130 if(!(inner
>= 0.0f
&& outer
<= 360.0f
&& outer
>= inner
))
1131 throw std::out_of_range("Cone angles out of range");
1132 CheckContext(mContext
);
1135 alSourcef(mId
, AL_CONE_INNER_ANGLE
, inner
);
1136 alSourcef(mId
, AL_CONE_OUTER_ANGLE
, outer
);
1138 mConeInnerAngle
= inner
;
1139 mConeOuterAngle
= outer
;
1142 DECL_THUNK2(void, Source
, setOuterConeGains
,, ALfloat
, ALfloat
)
1143 void SourceImpl::setOuterConeGains(ALfloat gain
, ALfloat gainhf
)
1145 if(!(gain
>= 0.0f
&& gain
<= 1.0f
&& gainhf
>= 0.0f
&& gainhf
<= 1.0f
))
1146 throw std::out_of_range("Outer cone gain out of range");
1147 CheckContext(mContext
);
1150 alSourcef(mId
, AL_CONE_OUTER_GAIN
, gain
);
1151 if(mContext
.hasExtension(AL::EXT_EFX
))
1152 alSourcef(mId
, AL_CONE_OUTER_GAINHF
, gainhf
);
1154 mConeOuterGain
= gain
;
1155 mConeOuterGainHF
= gainhf
;
1159 DECL_THUNK2(void, Source
, setRolloffFactors
,, ALfloat
, ALfloat
)
1160 void SourceImpl::setRolloffFactors(ALfloat factor
, ALfloat roomfactor
)
1162 if(!(factor
>= 0.0f
&& roomfactor
>= 0.0f
))
1163 throw std::out_of_range("Rolloff factor out of range");
1164 CheckContext(mContext
);
1167 alSourcef(mId
, AL_ROLLOFF_FACTOR
, factor
);
1168 if(mContext
.hasExtension(AL::EXT_EFX
))
1169 alSourcef(mId
, AL_ROOM_ROLLOFF_FACTOR
, roomfactor
);
1171 mRolloffFactor
= factor
;
1172 mRoomRolloffFactor
= roomfactor
;
1175 DECL_THUNK1(void, Source
, setDopplerFactor
,, ALfloat
)
1176 void SourceImpl::setDopplerFactor(ALfloat factor
)
1178 if(!(factor
>= 0.0f
&& factor
<= 1.0f
))
1179 throw std::out_of_range("Doppler factor out of range");
1180 CheckContext(mContext
);
1182 alSourcef(mId
, AL_DOPPLER_FACTOR
, factor
);
1183 mDopplerFactor
= factor
;
1186 DECL_THUNK1(void, Source
, setRelative
,, bool)
1187 void SourceImpl::setRelative(bool relative
)
1189 CheckContext(mContext
);
1191 alSourcei(mId
, AL_SOURCE_RELATIVE
, relative
? AL_TRUE
: AL_FALSE
);
1192 mRelative
= relative
;
1195 DECL_THUNK1(void, Source
, setRadius
,, ALfloat
)
1196 void SourceImpl::setRadius(ALfloat radius
)
1198 if(!(mRadius
>= 0.0f
))
1199 throw std::out_of_range("Radius out of range");
1200 CheckContext(mContext
);
1201 if(mId
!= 0 && mContext
.hasExtension(AL::EXT_SOURCE_RADIUS
))
1202 alSourcef(mId
, AL_SOURCE_RADIUS
, radius
);
1206 DECL_THUNK2(void, Source
, setStereoAngles
,, ALfloat
, ALfloat
)
1207 void SourceImpl::setStereoAngles(ALfloat leftAngle
, ALfloat rightAngle
)
1209 CheckContext(mContext
);
1210 if(mId
!= 0 && mContext
.hasExtension(AL::EXT_STEREO_ANGLES
))
1212 ALfloat angles
[2] = { leftAngle
, rightAngle
};
1213 alSourcefv(mId
, AL_STEREO_ANGLES
, angles
);
1215 mStereoAngles
[0] = leftAngle
;
1216 mStereoAngles
[1] = rightAngle
;
1219 DECL_THUNK1(void, Source
, set3DSpatialize
,, Spatialize
)
1220 void SourceImpl::set3DSpatialize(Spatialize spatialize
)
1222 CheckContext(mContext
);
1223 if(mId
!= 0 && mContext
.hasExtension(AL::SOFT_source_spatialize
))
1224 alSourcei(mId
, AL_SOURCE_SPATIALIZE_SOFT
, (ALint
)spatialize
);
1225 mSpatialize
= spatialize
;
1228 DECL_THUNK1(void, Source
, setResamplerIndex
,, ALsizei
)
1229 void SourceImpl::setResamplerIndex(ALsizei index
)
1232 throw std::out_of_range("Resampler index out of range");
1233 index
= std::min
<ALsizei
>(index
, mContext
.getAvailableResamplers().size());
1234 if(mId
!= 0 && mContext
.hasExtension(AL::SOFT_source_resampler
))
1235 alSourcei(mId
, AL_SOURCE_RESAMPLER_SOFT
, index
);
1239 DECL_THUNK1(void, Source
, setAirAbsorptionFactor
,, ALfloat
)
1240 void SourceImpl::setAirAbsorptionFactor(ALfloat factor
)
1242 if(!(factor
>= 0.0f
&& factor
<= 10.0f
))
1243 throw std::out_of_range("Absorption factor out of range");
1244 CheckContext(mContext
);
1245 if(mId
!= 0 && mContext
.hasExtension(AL::EXT_EFX
))
1246 alSourcef(mId
, AL_AIR_ABSORPTION_FACTOR
, factor
);
1247 mAirAbsorptionFactor
= factor
;
1250 DECL_THUNK3(void, Source
, setGainAuto
,, bool, bool, bool)
1251 void SourceImpl::setGainAuto(bool directhf
, bool send
, bool sendhf
)
1253 CheckContext(mContext
);
1254 if(mId
!= 0 && mContext
.hasExtension(AL::EXT_EFX
))
1256 alSourcei(mId
, AL_DIRECT_FILTER_GAINHF_AUTO
, directhf
? AL_TRUE
: AL_FALSE
);
1257 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
, send
? AL_TRUE
: AL_FALSE
);
1258 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
, sendhf
? AL_TRUE
: AL_FALSE
);
1260 mDryGainHFAuto
= directhf
;
1261 mWetGainAuto
= send
;
1262 mWetGainHFAuto
= sendhf
;
1266 void SourceImpl::setFilterParams(ALuint
&filterid
, const FilterParams
¶ms
)
1268 if(!mContext
.hasExtension(AL::EXT_EFX
))
1271 if(!(params
.mGain
< 1.0f
|| params
.mGainHF
< 1.0f
|| params
.mGainLF
< 1.0f
))
1274 mContext
.alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_NULL
);
1281 mContext
.alGenFilters(1, &filterid
);
1282 throw_al_error("Failed to create Filter");
1284 bool filterset
= false;
1285 if(params
.mGainHF
< 1.0f
&& params
.mGainLF
< 1.0f
)
1287 mContext
.alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_BANDPASS
);
1288 if(alGetError() == AL_NO_ERROR
)
1290 mContext
.alFilterf(filterid
, AL_BANDPASS_GAIN
, std::min(params
.mGain
, 1.0f
));
1291 mContext
.alFilterf(filterid
, AL_BANDPASS_GAINHF
, std::min(params
.mGainHF
, 1.0f
));
1292 mContext
.alFilterf(filterid
, AL_BANDPASS_GAINLF
, std::min(params
.mGainLF
, 1.0f
));
1296 if(!filterset
&& !(params
.mGainHF
< 1.0f
) && params
.mGainLF
< 1.0f
)
1298 mContext
.alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_HIGHPASS
);
1299 if(alGetError() == AL_NO_ERROR
)
1301 mContext
.alFilterf(filterid
, AL_HIGHPASS_GAIN
, std::min(params
.mGain
, 1.0f
));
1302 mContext
.alFilterf(filterid
, AL_HIGHPASS_GAINLF
, std::min(params
.mGainLF
, 1.0f
));
1308 mContext
.alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_LOWPASS
);
1309 if(alGetError() == AL_NO_ERROR
)
1311 mContext
.alFilterf(filterid
, AL_LOWPASS_GAIN
, std::min(params
.mGain
, 1.0f
));
1312 mContext
.alFilterf(filterid
, AL_LOWPASS_GAINHF
, std::min(params
.mGainHF
, 1.0f
));
1319 DECL_THUNK1(void, Source
, setDirectFilter
,, const FilterParams
&)
1320 void SourceImpl::setDirectFilter(const FilterParams
&filter
)
1322 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1323 throw std::out_of_range("Gain value out of range");
1324 CheckContext(mContext
);
1326 setFilterParams(mDirectFilter
, filter
);
1328 alSourcei(mId
, AL_DIRECT_FILTER
, mDirectFilter
);
1331 DECL_THUNK2(void, Source
, setSendFilter
,, ALuint
, const FilterParams
&)
1332 void SourceImpl::setSendFilter(ALuint send
, const FilterParams
&filter
)
1334 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1335 throw std::out_of_range("Gain value out of range");
1336 CheckContext(mContext
);
1338 auto siter
= std::lower_bound(mEffectSlots
.begin(), mEffectSlots
.end(), send
,
1339 [](const SendProps
&prop
, ALuint send
) -> bool
1340 { return prop
.mSendIdx
< send
; }
1342 if(siter
== mEffectSlots
.end() || siter
->mSendIdx
!= send
)
1344 ALuint filterid
= 0;
1346 setFilterParams(filterid
, filter
);
1347 if(!filterid
) return;
1349 siter
= mEffectSlots
.emplace(siter
, send
, filterid
);
1352 setFilterParams(siter
->mFilter
, filter
);
1356 ALuint slotid
= (siter
->mSlot
? siter
->mSlot
->getId() : 0);
1357 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->mFilter
);
1361 DECL_THUNK2(void, Source
, setAuxiliarySend
,, AuxiliaryEffectSlot
, ALuint
)
1362 void SourceImpl::setAuxiliarySend(AuxiliaryEffectSlot auxslot
, ALuint send
)
1364 AuxiliaryEffectSlotImpl
*slot
= auxslot
.getHandle();
1365 if(slot
) CheckContexts(mContext
, slot
->getContext());
1366 CheckContext(mContext
);
1368 auto siter
= std::lower_bound(mEffectSlots
.begin(), mEffectSlots
.end(), send
,
1369 [](const SendProps
&prop
, ALuint send
) -> bool
1370 { return prop
.mSendIdx
< send
; }
1372 if(siter
== mEffectSlots
.end() || siter
->mSendIdx
!= send
)
1375 slot
->addSourceSend({Source(this), send
});
1376 siter
= mEffectSlots
.emplace(siter
, send
, slot
);
1378 else if(siter
->mSlot
!= slot
)
1380 if(slot
) slot
->addSourceSend({Source(this), send
});
1382 siter
->mSlot
->removeSourceSend({Source(this), send
});
1383 siter
->mSlot
= slot
;
1388 ALuint slotid
= (siter
->mSlot
? siter
->mSlot
->getId() : 0);
1389 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->mFilter
);
1393 DECL_THUNK3(void, Source
, setAuxiliarySendFilter
,, AuxiliaryEffectSlot
, ALuint
, const FilterParams
&)
1394 void SourceImpl::setAuxiliarySendFilter(AuxiliaryEffectSlot auxslot
, ALuint send
, const FilterParams
&filter
)
1396 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1397 throw std::out_of_range("Gain value out of range");
1398 AuxiliaryEffectSlotImpl
*slot
= auxslot
.getHandle();
1399 if(slot
) CheckContexts(mContext
, slot
->getContext());
1400 CheckContext(mContext
);
1402 auto siter
= std::lower_bound(mEffectSlots
.begin(), mEffectSlots
.end(), send
,
1403 [](const SendProps
&prop
, ALuint send
) -> bool
1404 { return prop
.mSendIdx
< send
; }
1406 if(siter
== mEffectSlots
.end() || siter
->mSendIdx
!= send
)
1408 ALuint filterid
= 0;
1410 setFilterParams(filterid
, filter
);
1411 if(!filterid
&& !slot
)
1414 if(slot
) slot
->addSourceSend({Source(this), send
});
1415 siter
= mEffectSlots
.emplace(siter
, send
, slot
, filterid
);
1419 if(siter
->mSlot
!= slot
)
1421 if(slot
) slot
->addSourceSend({Source(this), send
});
1423 siter
->mSlot
->removeSourceSend({Source(this), send
});
1424 siter
->mSlot
= slot
;
1426 setFilterParams(siter
->mFilter
, filter
);
1431 ALuint slotid
= (siter
->mSlot
? siter
->mSlot
->getId() : 0);
1432 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->mFilter
);
1437 void Source::release()
1439 SourceImpl
*i
= pImpl
;
1443 void SourceImpl::release()
1448 mContext
.freeSource(this);
1452 DECL_THUNK0(SourceGroup
, Source
, getGroup
, const)
1453 DECL_THUNK0(ALuint
, Source
, getPriority
, const)
1454 DECL_THUNK0(bool, Source
, getLooping
, const)
1455 DECL_THUNK0(ALfloat
, Source
, getPitch
, const)
1456 DECL_THUNK0(ALfloat
, Source
, getGain
, const)
1457 DECL_THUNK0(ALfloatPair
, Source
, getGainRange
, const)
1458 DECL_THUNK0(ALfloatPair
, Source
, getDistanceRange
, const)
1459 DECL_THUNK0(Vector3
, Source
, getPosition
, const)
1460 DECL_THUNK0(Vector3
, Source
, getVelocity
, const)
1461 DECL_THUNK0(Vector3
, Source
, getDirection
, const)
1462 DECL_THUNK0(Vector3Pair
, Source
, getOrientation
, const)
1463 DECL_THUNK0(ALfloatPair
, Source
, getConeAngles
, const)
1464 DECL_THUNK0(ALfloatPair
, Source
, getOuterConeGains
, const)
1465 DECL_THUNK0(ALfloatPair
, Source
, getRolloffFactors
, const)
1466 DECL_THUNK0(ALfloat
, Source
, getDopplerFactor
, const)
1467 DECL_THUNK0(bool, Source
, getRelative
, const)
1468 DECL_THUNK0(ALfloat
, Source
, getRadius
, const)
1469 DECL_THUNK0(ALfloatPair
, Source
, getStereoAngles
, const)
1470 DECL_THUNK0(Spatialize
, Source
, get3DSpatialize
, const)
1471 DECL_THUNK0(ALsizei
, Source
, getResamplerIndex
, const)
1472 DECL_THUNK0(ALfloat
, Source
, getAirAbsorptionFactor
, const)
1473 DECL_THUNK0(BoolTriple
, Source
, getGainAuto
, const)