15 #include "auxeffectslot.h"
16 #include "sourcegroup.h"
21 // Need to use these to avoid extraneous commas in macro parameter lists
22 using UInt64NSecPair
= std::pair
<uint64_t,std::chrono::nanoseconds
>;
23 using SecondsPair
= std::pair
<Seconds
,Seconds
>;
24 using ALfloatPair
= std::pair
<ALfloat
,ALfloat
>;
25 using Vector3Pair
= std::pair
<Vector3
,Vector3
>;
26 using BoolTriple
= std::tuple
<bool,bool,bool>;
29 class ALBufferStream
{
30 SharedPtr
<Decoder
> mDecoder
;
42 Vector
<ALuint
> mBufferIds
;
46 std::pair
<uint64_t,uint64_t> mLoopPts
;
48 std::atomic
<bool> mDone
;
51 ALBufferStream(SharedPtr
<Decoder
> decoder
, ALuint updatelen
, ALuint numupdates
)
52 : mDecoder(decoder
), mUpdateLen(updatelen
), mNumUpdates(numupdates
),
53 mFormat(AL_NONE
), mFrequency(0), mFrameSize(0), mSilence(0),
54 mCurrentIdx(0), mSamplePos(0), mLoopPts
{0,0}, mHasLooped(false),
59 if(!mBufferIds
.empty())
61 alDeleteBuffers(mBufferIds
.size(), mBufferIds
.data());
66 uint64_t getLength() const { return mDecoder
->getLength(); }
67 uint64_t getPosition() const { return mSamplePos
; }
69 ALuint
getNumUpdates() const { return mNumUpdates
; }
70 ALuint
getUpdateLength() const { return mUpdateLen
; }
72 ALuint
getFrequency() const { return mFrequency
; }
74 bool seek(uint64_t pos
)
76 if(!mDecoder
->seek(pos
))
80 mDone
.store(false, std::memory_order_release
);
86 ALuint srate
= mDecoder
->getFrequency();
87 ChannelConfig chans
= mDecoder
->getChannelConfig();
88 SampleType type
= mDecoder
->getSampleType();
90 mLoopPts
= mDecoder
->getLoopPoints();
91 if(mLoopPts
.first
>= mLoopPts
.second
)
94 mLoopPts
.second
= std::numeric_limits
<uint64_t>::max();
98 mFrameSize
= FramesToBytes(1, chans
, type
);
99 mFormat
= GetFormat(chans
, type
);
100 if(mFormat
== AL_NONE
)
102 String
str("Unsupported format (");
103 str
+= GetSampleTypeName(type
);
105 str
+= GetChannelConfigName(chans
);
107 throw std::runtime_error(str
);
110 mData
.resize(mUpdateLen
* mFrameSize
);
111 if(type
== SampleType::UInt8
) mSilence
= 0x80;
112 else if(type
== SampleType::Mulaw
) mSilence
= 0x7f;
113 else mSilence
= 0x00;
115 mBufferIds
.assign(mNumUpdates
, 0);
116 alGenBuffers(mBufferIds
.size(), mBufferIds
.data());
119 int64_t getLoopStart() const { return mLoopPts
.first
; }
120 int64_t getLoopEnd() const { return mLoopPts
.second
; }
122 bool hasLooped() const { return mHasLooped
; }
123 bool hasMoreData() const { return !mDone
.load(std::memory_order_acquire
); }
124 bool streamMoreData(ALuint srcid
, bool loop
)
126 if(mDone
.load(std::memory_order_acquire
))
130 ALuint len
= mUpdateLen
;
131 if(loop
&& mSamplePos
<= mLoopPts
.second
)
132 len
= std::min
<uint64_t>(len
, mLoopPts
.second
- mSamplePos
);
136 frames
= mDecoder
->read(mData
.data(), len
);
137 mSamplePos
+= frames
;
138 if(frames
< mUpdateLen
&& loop
&& mSamplePos
> 0)
140 if(mSamplePos
< mLoopPts
.second
)
142 mLoopPts
.second
= mSamplePos
;
143 mLoopPts
.first
= std::min(mLoopPts
.first
, mLoopPts
.second
-1);
147 if(!mDecoder
->seek(mLoopPts
.first
))
149 mSamplePos
= mLoopPts
.first
;
152 len
= std::min
<uint64_t>(mUpdateLen
-frames
, mLoopPts
.second
-mLoopPts
.first
);
153 ALuint got
= mDecoder
->read(&mData
[frames
*mFrameSize
], len
);
157 } while(frames
< mUpdateLen
);
159 if(frames
< mUpdateLen
)
161 mDone
.store(true, std::memory_order_release
);
162 if(frames
== 0) return false;
163 mSamplePos
+= mUpdateLen
- frames
;
164 std::fill(mData
.begin() + frames
*mFrameSize
, mData
.end(), mSilence
);
167 alBufferData(mBufferIds
[mCurrentIdx
], mFormat
, mData
.data(), mData
.size(), mFrequency
);
168 alSourceQueueBuffers(srcid
, 1, &mBufferIds
[mCurrentIdx
]);
169 mCurrentIdx
= (mCurrentIdx
+1) % mBufferIds
.size();
175 SourceImpl::SourceImpl(ContextImpl
*context
)
176 : mContext(context
), mId(0), mBuffer(0), mGroup(nullptr), mIsAsync(false),
177 mDirectFilter(AL_FILTER_NULL
)
180 mEffectSlots
.reserve(mContext
->getDevice().getMaxAuxiliarySends());
183 SourceImpl::~SourceImpl()
188 void SourceImpl::resetProperties()
191 mGroup
->eraseSource(this);
196 mFadeGainTarget
= 1.0f
;
199 mPaused
.store(false, std::memory_order_release
);
206 mMaxDist
= std::numeric_limits
<float>::max();
207 mPosition
= Vector3(0.0f
);
208 mVelocity
= Vector3(0.0f
);
209 mDirection
= Vector3(0.0f
);
210 mOrientation
[0] = Vector3(0.0f
, 0.0f
, -1.0f
);
211 mOrientation
[1] = Vector3(0.0f
, 1.0f
, 0.0f
);
212 mConeInnerAngle
= 360.0f
;
213 mConeOuterAngle
= 360.0f
;
214 mConeOuterGain
= 0.0f
;
215 mConeOuterGainHF
= 1.0f
;
216 mRolloffFactor
= 1.0f
;
217 mRoomRolloffFactor
= 0.0f
;
218 mDopplerFactor
= 1.0f
;
219 mAirAbsorptionFactor
= 0.0f
;
221 mStereoAngles
[0] = F_PI
/ 6.0f
;
222 mStereoAngles
[1] = -F_PI
/ 6.0f
;
223 mSpatialize
= Spatialize::Auto
;
224 mResampler
= mContext
->hasExtension(AL::SOFT_source_resampler
) ?
225 alGetInteger(AL_DEFAULT_RESAMPLER_SOFT
) : 0;
228 mDryGainHFAuto
= true;
230 mWetGainHFAuto
= true;
232 mContext
->alDeleteFilters(1, &mDirectFilter
);
234 for(auto &i
: mEffectSlots
)
237 i
.mSlot
->removeSourceSend({Source(this), i
.mSendIdx
});
239 mContext
->alDeleteFilters(1, &i
.mFilter
);
241 mEffectSlots
.clear();
246 void SourceImpl::applyProperties(bool looping
, ALuint offset
) const
248 alSourcei(mId
, AL_LOOPING
, looping
? AL_TRUE
: AL_FALSE
);
249 alSourcei(mId
, AL_SAMPLE_OFFSET
, offset
);
250 alSourcef(mId
, AL_PITCH
, mPitch
* mGroupPitch
);
251 alSourcef(mId
, AL_GAIN
, mGain
* mGroupGain
* mFadeGain
);
252 alSourcef(mId
, AL_MIN_GAIN
, mMinGain
);
253 alSourcef(mId
, AL_MAX_GAIN
, mMaxGain
);
254 alSourcef(mId
, AL_REFERENCE_DISTANCE
, mRefDist
);
255 alSourcef(mId
, AL_MAX_DISTANCE
, mMaxDist
);
256 alSourcefv(mId
, AL_POSITION
, mPosition
.getPtr());
257 alSourcefv(mId
, AL_VELOCITY
, mVelocity
.getPtr());
258 alSourcefv(mId
, AL_DIRECTION
, mDirection
.getPtr());
259 if(mContext
->hasExtension(AL::EXT_BFORMAT
))
260 alSourcefv(mId
, AL_ORIENTATION
, &mOrientation
[0][0]);
261 alSourcef(mId
, AL_CONE_INNER_ANGLE
, mConeInnerAngle
);
262 alSourcef(mId
, AL_CONE_OUTER_ANGLE
, mConeOuterAngle
);
263 alSourcef(mId
, AL_CONE_OUTER_GAIN
, mConeOuterGain
);
264 alSourcef(mId
, AL_ROLLOFF_FACTOR
, mRolloffFactor
);
265 alSourcef(mId
, AL_DOPPLER_FACTOR
, mDopplerFactor
);
266 if(mContext
->hasExtension(AL::EXT_SOURCE_RADIUS
))
267 alSourcef(mId
, AL_SOURCE_RADIUS
, mRadius
);
268 if(mContext
->hasExtension(AL::EXT_STEREO_ANGLES
))
269 alSourcefv(mId
, AL_STEREO_ANGLES
, mStereoAngles
);
270 if(mContext
->hasExtension(AL::SOFT_source_spatialize
))
271 alSourcei(mId
, AL_SOURCE_SPATIALIZE_SOFT
, (ALint
)mSpatialize
);
272 if(mContext
->hasExtension(AL::SOFT_source_resampler
))
273 alSourcei(mId
, AL_SOURCE_RESAMPLER_SOFT
, mResampler
);
274 alSourcei(mId
, AL_SOURCE_RELATIVE
, mRelative
? AL_TRUE
: AL_FALSE
);
275 if(mContext
->hasExtension(AL::EXT_EFX
))
277 alSourcef(mId
, AL_CONE_OUTER_GAINHF
, mConeOuterGainHF
);
278 alSourcef(mId
, AL_ROOM_ROLLOFF_FACTOR
, mRoomRolloffFactor
);
279 alSourcef(mId
, AL_AIR_ABSORPTION_FACTOR
, mAirAbsorptionFactor
);
280 alSourcei(mId
, AL_DIRECT_FILTER_GAINHF_AUTO
, mDryGainHFAuto
? AL_TRUE
: AL_FALSE
);
281 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
, mWetGainAuto
? AL_TRUE
: AL_FALSE
);
282 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
, mWetGainHFAuto
? AL_TRUE
: AL_FALSE
);
283 alSourcei(mId
, AL_DIRECT_FILTER
, mDirectFilter
);
284 for(const auto &i
: mEffectSlots
)
286 ALuint slotid
= (i
.mSlot
? i
.mSlot
->getId() : 0);
287 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, i
.mSendIdx
, i
.mFilter
);
293 void SourceImpl::unsetGroup()
296 groupPropUpdate(1.0f
, 1.0f
);
299 void SourceImpl::groupPropUpdate(ALfloat gain
, ALfloat pitch
)
303 alSourcef(mId
, AL_PITCH
, mPitch
* pitch
);
304 alSourcef(mId
, AL_GAIN
, mGain
* gain
* mFadeGain
);
311 DECL_THUNK1(void, Source
, play
,, Buffer
)
312 void SourceImpl::play(Buffer buffer
)
314 BufferImpl
*albuf
= buffer
.getHandle();
315 if(!albuf
) throw std::invalid_argument("Buffer is not valid");
316 CheckContexts(mContext
, albuf
->getContext());
317 CheckContext(mContext
);
320 mContext
->removeStream(this);
321 mIsAsync
.store(false, std::memory_order_release
);
323 mFadeGainTarget
= mFadeGain
= 1.0f
;
324 mFadeTimeTarget
= mLastFadeTime
= std::chrono::steady_clock::time_point();
328 mId
= mContext
->getSourceId(mPriority
);
329 applyProperties(mLooping
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
333 mContext
->removeFadingSource(this);
334 mContext
->removePlayingSource(this);
336 alSourcei(mId
, AL_BUFFER
, 0);
337 alSourcei(mId
, AL_LOOPING
, mLooping
? AL_TRUE
: AL_FALSE
);
338 alSourcei(mId
, AL_SAMPLE_OFFSET
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
344 mBuffer
->removeSource(Source(this));
346 mBuffer
->addSource(Source(this));
348 alSourcei(mId
, AL_BUFFER
, mBuffer
->getId());
350 mPaused
.store(false, std::memory_order_release
);
351 mContext
->removePendingSource(this);
352 mContext
->addPlayingSource(this, mId
);
355 DECL_THUNK3(void, Source
, play
,, SharedPtr
<Decoder
>, ALuint
, ALuint
)
356 void SourceImpl::play(SharedPtr
<Decoder
>&& decoder
, ALuint chunk_len
, ALuint queue_size
)
359 throw std::out_of_range("Update length out of range");
361 throw std::out_of_range("Queue size out of range");
362 CheckContext(mContext
);
364 auto stream
= MakeUnique
<ALBufferStream
>(decoder
, chunk_len
, queue_size
);
368 mContext
->removeStream(this);
369 mIsAsync
.store(false, std::memory_order_release
);
371 mFadeGainTarget
= mFadeGain
= 1.0f
;
372 mFadeTimeTarget
= mLastFadeTime
= std::chrono::steady_clock::time_point();
376 mId
= mContext
->getSourceId(mPriority
);
377 applyProperties(false, 0);
381 mContext
->removeFadingSource(this);
382 mContext
->removePlayingSource(this);
384 alSourcei(mId
, AL_BUFFER
, 0);
385 alSourcei(mId
, AL_LOOPING
, AL_FALSE
);
386 alSourcei(mId
, AL_SAMPLE_OFFSET
, 0);
391 mBuffer
->removeSource(Source(this));
394 mStream
= std::move(stream
);
396 mStream
->seek(mOffset
);
399 for(ALuint i
= 0;i
< mStream
->getNumUpdates();i
++)
401 if(!mStream
->streamMoreData(mId
, mLooping
))
405 mPaused
.store(false, std::memory_order_release
);
407 mContext
->addStream(this);
408 mIsAsync
.store(true, std::memory_order_release
);
409 mContext
->removePendingSource(this);
410 mContext
->addPlayingSource(this);
413 DECL_THUNK1(void, Source
, play
,, SharedFuture
<Buffer
>)
414 void SourceImpl::play(SharedFuture
<Buffer
>&& future_buffer
)
416 if(!future_buffer
.valid())
417 throw std::future_error(std::future_errc::no_state
);
418 if(GetFutureState(future_buffer
) == std::future_status::ready
)
420 play(future_buffer
.get());
424 CheckContext(mContext
);
426 mContext
->removeFadingSource(this);
427 mContext
->removePlayingSource(this);
430 mFadeGainTarget
= mFadeGain
= 1.0f
;
431 mFadeTimeTarget
= mLastFadeTime
= std::chrono::steady_clock::time_point();
433 mContext
->addPendingSource(this, std::move(future_buffer
));
437 void SourceImpl::makeStopped(bool dolock
)
442 mContext
->removeStream(this);
444 mContext
->removeStreamNoLock(this);
446 mIsAsync
.store(false, std::memory_order_release
);
451 alSourcei(mId
, AL_BUFFER
, 0);
452 if(mContext
->hasExtension(AL::EXT_EFX
))
454 alSourcei(mId
, AL_DIRECT_FILTER
, AL_FILTER_NULL
);
455 for(auto &i
: mEffectSlots
)
456 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, 0, i
.mSendIdx
, AL_FILTER_NULL
);
458 mContext
->insertSourceId(mId
);
464 mBuffer
->removeSource(Source(this));
467 mPaused
.store(false, std::memory_order_release
);
470 DECL_THUNK0(void, Source
, stop
,)
471 void SourceImpl::stop()
473 CheckContext(mContext
);
474 mContext
->removePendingSource(this);
475 mContext
->removeFadingSource(this);
476 mContext
->removePlayingSource(this);
481 DECL_THUNK2(void, Source
, fadeOutToStop
,, ALfloat
, std::chrono::milliseconds
)
482 void SourceImpl::fadeOutToStop(ALfloat gain
, std::chrono::milliseconds duration
)
484 if(!(gain
< 1.0f
&& gain
>= 0.0f
))
485 throw std::out_of_range("Fade gain target out of range");
486 if(duration
.count() <= 0)
487 throw std::out_of_range("Fade duration out of range");
488 CheckContext(mContext
);
490 mFadeGainTarget
= std::max
<ALfloat
>(gain
, 0.0001f
);
491 mLastFadeTime
= std::chrono::steady_clock::now();
492 mFadeTimeTarget
= mLastFadeTime
+ duration
;
494 mContext
->addFadingSource(this);
498 void SourceImpl::checkPaused()
500 if(mPaused
.load(std::memory_order_acquire
) || mId
== 0)
504 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
505 // Streaming sources may be in a stopped or initial state if underrun
506 mPaused
.store(state
== AL_PAUSED
|| (mStream
&& mStream
->hasMoreData()),
507 std::memory_order_release
);
510 DECL_THUNK0(void, Source
, pause
,)
511 void SourceImpl::pause()
513 CheckContext(mContext
);
514 if(mPaused
.load(std::memory_order_acquire
))
519 std::lock_guard
<std::mutex
> lock(mMutex
);
522 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
523 // Streaming sources may be in a stopped or initial state if underrun
524 mPaused
.store(state
== AL_PAUSED
|| (mStream
&& mStream
->hasMoreData()),
525 std::memory_order_release
);
529 DECL_THUNK0(void, Source
, resume
,)
530 void SourceImpl::resume()
532 CheckContext(mContext
);
533 if(!mPaused
.load(std::memory_order_acquire
))
538 mPaused
.store(false, std::memory_order_release
);
542 DECL_THUNK0(bool, Source
, isPending
, const)
543 bool SourceImpl::isPending() const
545 CheckContext(mContext
);
546 return mContext
->isPendingSource(this);
549 DECL_THUNK0(bool, Source
, isPlaying
, const)
550 bool SourceImpl::isPlaying() const
552 CheckContext(mContext
);
553 if(mId
== 0) return false;
556 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
558 throw std::runtime_error("Source state error");
560 return state
== AL_PLAYING
|| (!mPaused
.load(std::memory_order_acquire
) &&
561 mStream
&& mStream
->hasMoreData());
564 DECL_THUNK0(bool, Source
, isPaused
, const)
565 bool SourceImpl::isPaused() const
567 CheckContext(mContext
);
568 return mId
!= 0 && mPaused
.load(std::memory_order_acquire
);
572 DECL_THUNK1(void, Source
, setGroup
,, SourceGroup
)
573 void SourceImpl::setGroup(SourceGroup group
)
575 CheckContext(mContext
);
577 SourceGroupImpl
*parent
= group
.getHandle();
578 if(parent
== mGroup
) return;
581 mGroup
->eraseSource(this);
585 mGroup
->insertSource(this);
586 mGroupPitch
= mGroup
->getAppliedPitch();
587 mGroupGain
= mGroup
->getAppliedGain();
597 alSourcef(mId
, AL_PITCH
, mPitch
* mGroupPitch
);
598 alSourcef(mId
, AL_GAIN
, mGain
* mGroupGain
* mFadeGain
);
603 bool SourceImpl::checkPending(SharedFuture
<Buffer
> &future
)
605 if(GetFutureState(future
) != std::future_status::ready
)
608 BufferImpl
*buffer
= future
.get().getHandle();
609 if(UNLIKELY(buffer
->getContext() != mContext
))
614 mId
= mContext
->getSourceId(mPriority
);
615 applyProperties(mLooping
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
620 alSourcei(mId
, AL_BUFFER
, 0);
621 alSourcei(mId
, AL_LOOPING
, mLooping
? AL_TRUE
: AL_FALSE
);
622 alSourcei(mId
, AL_SAMPLE_OFFSET
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
627 mBuffer
->addSource(Source(this));
629 alSourcei(mId
, AL_BUFFER
, mBuffer
->getId());
631 mPaused
.store(false, std::memory_order_release
);
632 mContext
->addPlayingSource(this, mId
);
636 bool SourceImpl::fadeUpdate(std::chrono::steady_clock::time_point cur_fade_time
)
638 if((cur_fade_time
- mFadeTimeTarget
).count() >= 0)
640 mLastFadeTime
= mFadeTimeTarget
;
642 if(mFadeGainTarget
>= 1.0f
)
645 alSourcef(mId
, AL_GAIN
, mGain
* mGroupGain
);
648 mContext
->removePendingSource(this);
649 mContext
->removePlayingSource(this);
654 float mult
= std::pow(mFadeGainTarget
/mFadeGain
,
655 float(1.0/Seconds(mFadeTimeTarget
-mLastFadeTime
).count())
658 std::chrono::steady_clock::duration duration
= cur_fade_time
- mLastFadeTime
;
659 mLastFadeTime
= cur_fade_time
;
661 float gain
= mFadeGain
* std::pow(mult
, (float)Seconds(duration
).count());
662 if(UNLIKELY(gain
== mFadeGain
))
664 // Ensure the gain keeps moving toward its target, in case precision
665 // loss results in no change with small steps.
666 gain
= std::nextafter(gain
, mFadeGainTarget
);
671 alSourcef(mId
, AL_GAIN
, mGain
* mGroupGain
* mFadeGain
);
675 bool SourceImpl::playUpdate(ALuint id
)
678 alGetSourcei(id
, AL_SOURCE_STATE
, &state
);
679 if(LIKELY(state
== AL_PLAYING
|| state
== AL_PAUSED
))
683 mContext
->send(&MessageHandler::sourceStopped
, Source(this));
687 bool SourceImpl::playUpdate()
689 if(LIKELY(mIsAsync
.load(std::memory_order_acquire
)))
693 mContext
->send(&MessageHandler::sourceStopped
, Source(this));
698 ALint
SourceImpl::refillBufferStream()
701 alGetSourcei(mId
, AL_BUFFERS_PROCESSED
, &processed
);
705 alSourceUnqueueBuffers(mId
, 1, &buf
);
710 alGetSourcei(mId
, AL_BUFFERS_QUEUED
, &queued
);
711 for(;(ALuint
)queued
< mStream
->getNumUpdates();queued
++)
713 if(!mStream
->streamMoreData(mId
, mLooping
))
720 bool SourceImpl::updateAsync()
722 std::lock_guard
<std::mutex
> lock(mMutex
);
724 ALint queued
= refillBufferStream();
727 mIsAsync
.store(false, std::memory_order_release
);
732 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
733 if(!mPaused
.load(std::memory_order_acquire
))
735 // Make sure the source is still playing if it's not paused.
736 if(state
!= AL_PLAYING
)
741 // Rewind the source to an initial state if it underrun as it was
743 if(state
== AL_STOPPED
)
750 DECL_THUNK1(void, Source
, setPriority
,, ALuint
)
751 void SourceImpl::setPriority(ALuint priority
)
753 mPriority
= priority
;
757 DECL_THUNK1(void, Source
, setOffset
,, uint64_t)
758 void SourceImpl::setOffset(uint64_t offset
)
760 CheckContext(mContext
);
769 if(offset
>= std::numeric_limits
<ALint
>::max())
770 throw std::out_of_range("Offset out of range");
772 alSourcei(mId
, AL_SAMPLE_OFFSET
, (ALint
)offset
);
773 ALenum err
= alGetError();
774 if(err
!= AL_NO_ERROR
)
775 throw al_error(err
, "Failed to set offset");
779 std::lock_guard
<std::mutex
> lock(mMutex
);
780 if(!mStream
->seek(offset
))
781 throw std::runtime_error("Failed to seek to offset");
783 alSourcei(mId
, AL_BUFFER
, 0);
784 ALint queued
= refillBufferStream();
785 if(queued
> 0 && !mPaused
.load(std::memory_order_acquire
))
790 DECL_THUNK0(UInt64NSecPair
, Source
, getSampleOffsetLatency
, const)
791 std::pair
<uint64_t,std::chrono::nanoseconds
> SourceImpl::getSampleOffsetLatency() const
793 std::pair
<uint64_t,std::chrono::nanoseconds
> ret
{0, std::chrono::nanoseconds::zero()};
794 CheckContext(mContext
);
795 if(mId
== 0) return ret
;
799 std::lock_guard
<std::mutex
> lock(mMutex
);
800 ALint queued
= 0, state
= -1, srcpos
= 0;
802 alGetSourcei(mId
, AL_BUFFERS_QUEUED
, &queued
);
803 if(mContext
->hasExtension(AL::SOFT_source_latency
))
806 mContext
->alGetSourcei64vSOFT(mId
, AL_SAMPLE_OFFSET_LATENCY_SOFT
, val
);
808 ret
.second
= std::chrono::nanoseconds(val
[1]);
811 alGetSourcei(mId
, AL_SAMPLE_OFFSET
, &srcpos
);
812 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
814 int64_t streampos
= mStream
->getPosition();
815 if(state
!= AL_STOPPED
)
817 // The amount of samples in the queue waiting to play
818 ALuint inqueue
= queued
*mStream
->getUpdateLength() - srcpos
;
819 if(!mStream
->hasLooped())
821 // A non-looped stream should never have more samples queued
822 // than have been read...
823 streampos
= std::max
<int64_t>(streampos
, inqueue
) - inqueue
;
827 streampos
-= inqueue
;
828 int64_t looplen
= mStream
->getLoopEnd() - mStream
->getLoopStart();
829 while(streampos
< mStream
->getLoopStart())
830 streampos
+= looplen
;
834 ret
.first
= streampos
;
839 if(mContext
->hasExtension(AL::SOFT_source_latency
))
842 mContext
->alGetSourcei64vSOFT(mId
, AL_SAMPLE_OFFSET_LATENCY_SOFT
, val
);
844 ret
.second
= std::chrono::nanoseconds(val
[1]);
847 alGetSourcei(mId
, AL_SAMPLE_OFFSET
, &srcpos
);
852 DECL_THUNK0(SecondsPair
, Source
, getSecOffsetLatency
, const)
853 std::pair
<Seconds
,Seconds
> SourceImpl::getSecOffsetLatency() const
855 std::pair
<Seconds
,Seconds
> ret
{Seconds::zero(), Seconds::zero()};
856 CheckContext(mContext
);
857 if(mId
== 0) return ret
;
861 std::lock_guard
<std::mutex
> lock(mMutex
);
862 ALint queued
= 0, state
= -1;
865 alGetSourcei(mId
, AL_BUFFERS_QUEUED
, &queued
);
866 if(mContext
->hasExtension(AL::SOFT_source_latency
))
869 mContext
->alGetSourcedvSOFT(mId
, AL_SEC_OFFSET_LATENCY_SOFT
, val
);
871 ret
.second
= Seconds(val
[1]);
876 alGetSourcef(mId
, AL_SEC_OFFSET
, &f
);
879 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
882 int64_t streampos
= mStream
->getPosition();
883 if(state
!= AL_STOPPED
)
886 frac
= std::modf(srcpos
* mStream
->getFrequency(), &ipos
);
888 // The amount of samples in the queue waiting to play
889 ALuint inqueue
= queued
*mStream
->getUpdateLength() - (ALuint
)ipos
;
890 if(!mStream
->hasLooped())
892 // A non-looped stream should never have more samples queued
893 // than have been read...
894 streampos
= std::max
<int64_t>(streampos
, inqueue
) - inqueue
;
898 streampos
-= inqueue
;
899 int64_t looplen
= mStream
->getLoopEnd() - mStream
->getLoopStart();
900 while(streampos
< mStream
->getLoopStart())
901 streampos
+= looplen
;
905 ret
.first
= Seconds((streampos
+frac
) / mStream
->getFrequency());
909 if(mContext
->hasExtension(AL::SOFT_source_latency
))
912 mContext
->alGetSourcedvSOFT(mId
, AL_SEC_OFFSET_LATENCY_SOFT
, val
);
913 ret
.first
= Seconds(val
[0]);
914 ret
.second
= Seconds(val
[1]);
919 alGetSourcef(mId
, AL_SEC_OFFSET
, &f
);
920 ret
.first
= Seconds(f
);
926 DECL_THUNK1(void, Source
, setLooping
,, bool)
927 void SourceImpl::setLooping(bool looping
)
929 CheckContext(mContext
);
932 alSourcei(mId
, AL_LOOPING
, looping
? AL_TRUE
: AL_FALSE
);
937 DECL_THUNK1(void, Source
, setPitch
,, ALfloat
)
938 void SourceImpl::setPitch(ALfloat pitch
)
941 throw std::out_of_range("Pitch out of range");
942 CheckContext(mContext
);
944 alSourcef(mId
, AL_PITCH
, pitch
* mGroupPitch
);
949 DECL_THUNK1(void, Source
, setGain
,, ALfloat
)
950 void SourceImpl::setGain(ALfloat gain
)
953 throw std::out_of_range("Gain out of range");
954 CheckContext(mContext
);
956 alSourcef(mId
, AL_GAIN
, gain
* mGroupGain
* mFadeGain
);
960 DECL_THUNK2(void, Source
, setGainRange
,, ALfloat
, ALfloat
)
961 void SourceImpl::setGainRange(ALfloat mingain
, ALfloat maxgain
)
963 if(!(mingain
>= 0.0f
&& maxgain
<= 1.0f
&& maxgain
>= mingain
))
964 throw std::out_of_range("Gain range out of range");
965 CheckContext(mContext
);
968 alSourcef(mId
, AL_MIN_GAIN
, mingain
);
969 alSourcef(mId
, AL_MAX_GAIN
, maxgain
);
976 DECL_THUNK2(void, Source
, setDistanceRange
,, ALfloat
, ALfloat
)
977 void SourceImpl::setDistanceRange(ALfloat refdist
, ALfloat maxdist
)
979 if(!(refdist
>= 0.0f
&& maxdist
<= std::numeric_limits
<float>::max() && refdist
<= maxdist
))
980 throw std::out_of_range("Distance range out of range");
981 CheckContext(mContext
);
984 alSourcef(mId
, AL_REFERENCE_DISTANCE
, refdist
);
985 alSourcef(mId
, AL_MAX_DISTANCE
, maxdist
);
992 DECL_THUNK3(void, Source
, set3DParameters
,, const Vector3
&, const Vector3
&, const Vector3
&)
993 void SourceImpl::set3DParameters(const Vector3
&position
, const Vector3
&velocity
, const Vector3
&direction
)
995 CheckContext(mContext
);
998 Batcher batcher
= mContext
->getBatcher();
999 alSourcefv(mId
, AL_POSITION
, position
.getPtr());
1000 alSourcefv(mId
, AL_VELOCITY
, velocity
.getPtr());
1001 alSourcefv(mId
, AL_DIRECTION
, direction
.getPtr());
1003 mPosition
= position
;
1004 mVelocity
= velocity
;
1005 mDirection
= direction
;
1008 DECL_THUNK3(void, Source
, set3DParameters
,, const Vector3
&, const Vector3
&, const Vector3Pair
&)
1009 void SourceImpl::set3DParameters(const Vector3
&position
, const Vector3
&velocity
, const std::pair
<Vector3
,Vector3
> &orientation
)
1011 static_assert(sizeof(orientation
) == sizeof(ALfloat
[6]), "Invalid Vector3 pair size");
1012 CheckContext(mContext
);
1015 Batcher batcher
= mContext
->getBatcher();
1016 alSourcefv(mId
, AL_POSITION
, position
.getPtr());
1017 alSourcefv(mId
, AL_VELOCITY
, velocity
.getPtr());
1018 if(mContext
->hasExtension(AL::EXT_BFORMAT
))
1019 alSourcefv(mId
, AL_ORIENTATION
, orientation
.first
.getPtr());
1020 alSourcefv(mId
, AL_DIRECTION
, orientation
.first
.getPtr());
1022 mPosition
= position
;
1023 mVelocity
= velocity
;
1024 mDirection
= mOrientation
[0] = orientation
.first
;
1025 mOrientation
[1] = orientation
.second
;
1029 DECL_THUNK3(void, Source
, setPosition
,, ALfloat
, ALfloat
, ALfloat
)
1030 void SourceImpl::setPosition(ALfloat x
, ALfloat y
, ALfloat z
)
1032 CheckContext(mContext
);
1034 alSource3f(mId
, AL_POSITION
, x
, y
, z
);
1040 DECL_THUNK1(void, Source
, setPosition
,, const ALfloat
*)
1041 void SourceImpl::setPosition(const ALfloat
*pos
)
1043 CheckContext(mContext
);
1045 alSourcefv(mId
, AL_POSITION
, pos
);
1046 mPosition
[0] = pos
[0];
1047 mPosition
[1] = pos
[1];
1048 mPosition
[2] = pos
[2];
1051 DECL_THUNK3(void, Source
, setVelocity
,, ALfloat
, ALfloat
, ALfloat
)
1052 void SourceImpl::setVelocity(ALfloat x
, ALfloat y
, ALfloat z
)
1054 CheckContext(mContext
);
1056 alSource3f(mId
, AL_VELOCITY
, x
, y
, z
);
1062 DECL_THUNK1(void, Source
, setVelocity
,, const ALfloat
*)
1063 void SourceImpl::setVelocity(const ALfloat
*vel
)
1065 CheckContext(mContext
);
1067 alSourcefv(mId
, AL_VELOCITY
, vel
);
1068 mVelocity
[0] = vel
[0];
1069 mVelocity
[1] = vel
[1];
1070 mVelocity
[2] = vel
[2];
1073 DECL_THUNK3(void, Source
, setDirection
,, ALfloat
, ALfloat
, ALfloat
)
1074 void SourceImpl::setDirection(ALfloat x
, ALfloat y
, ALfloat z
)
1076 CheckContext(mContext
);
1078 alSource3f(mId
, AL_DIRECTION
, x
, y
, z
);
1084 DECL_THUNK1(void, Source
, setDirection
,, const ALfloat
*)
1085 void SourceImpl::setDirection(const ALfloat
*dir
)
1087 CheckContext(mContext
);
1089 alSourcefv(mId
, AL_DIRECTION
, dir
);
1090 mDirection
[0] = dir
[0];
1091 mDirection
[1] = dir
[1];
1092 mDirection
[2] = dir
[2];
1095 DECL_THUNK6(void, Source
, setOrientation
,, ALfloat
, ALfloat
, ALfloat
, ALfloat
, ALfloat
, ALfloat
)
1096 void SourceImpl::setOrientation(ALfloat x1
, ALfloat y1
, ALfloat z1
, ALfloat x2
, ALfloat y2
, ALfloat z2
)
1098 CheckContext(mContext
);
1101 ALfloat ori
[6] = { x1
, y1
, z1
, x2
, y2
, z2
};
1102 if(mContext
->hasExtension(AL::EXT_BFORMAT
))
1103 alSourcefv(mId
, AL_ORIENTATION
, ori
);
1104 alSourcefv(mId
, AL_DIRECTION
, ori
);
1106 mDirection
[0] = mOrientation
[0][0] = x1
;
1107 mDirection
[1] = mOrientation
[0][1] = y1
;
1108 mDirection
[2] = mOrientation
[0][2] = z1
;
1109 mOrientation
[1][0] = x2
;
1110 mOrientation
[1][1] = y2
;
1111 mOrientation
[1][2] = z2
;
1114 DECL_THUNK2(void, Source
, setOrientation
,, const ALfloat
*, const ALfloat
*)
1115 void SourceImpl::setOrientation(const ALfloat
*at
, const ALfloat
*up
)
1117 CheckContext(mContext
);
1120 ALfloat ori
[6] = { at
[0], at
[1], at
[2], up
[0], up
[1], up
[2] };
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] = at
[0];
1126 mDirection
[1] = mOrientation
[0][1] = at
[1];
1127 mDirection
[2] = mOrientation
[0][2] = at
[2];
1128 mOrientation
[1][0] = up
[0];
1129 mOrientation
[1][1] = up
[1];
1130 mOrientation
[1][2] = up
[2];
1133 DECL_THUNK1(void, Source
, setOrientation
,, const ALfloat
*)
1134 void SourceImpl::setOrientation(const ALfloat
*ori
)
1136 CheckContext(mContext
);
1139 if(mContext
->hasExtension(AL::EXT_BFORMAT
))
1140 alSourcefv(mId
, AL_ORIENTATION
, ori
);
1141 alSourcefv(mId
, AL_DIRECTION
, ori
);
1143 mDirection
[0] = mOrientation
[0][0] = ori
[0];
1144 mDirection
[1] = mOrientation
[0][1] = ori
[1];
1145 mDirection
[2] = mOrientation
[0][2] = ori
[2];
1146 mOrientation
[1][0] = ori
[3];
1147 mOrientation
[1][1] = ori
[4];
1148 mOrientation
[1][2] = ori
[5];
1152 DECL_THUNK2(void, Source
, setConeAngles
,, ALfloat
, ALfloat
)
1153 void SourceImpl::setConeAngles(ALfloat inner
, ALfloat outer
)
1155 if(!(inner
>= 0.0f
&& outer
<= 360.0f
&& outer
>= inner
))
1156 throw std::out_of_range("Cone angles out of range");
1157 CheckContext(mContext
);
1160 alSourcef(mId
, AL_CONE_INNER_ANGLE
, inner
);
1161 alSourcef(mId
, AL_CONE_OUTER_ANGLE
, outer
);
1163 mConeInnerAngle
= inner
;
1164 mConeOuterAngle
= outer
;
1167 DECL_THUNK2(void, Source
, setOuterConeGains
,, ALfloat
, ALfloat
)
1168 void SourceImpl::setOuterConeGains(ALfloat gain
, ALfloat gainhf
)
1170 if(!(gain
>= 0.0f
&& gain
<= 1.0f
&& gainhf
>= 0.0f
&& gainhf
<= 1.0f
))
1171 throw std::out_of_range("Outer cone gain out of range");
1172 CheckContext(mContext
);
1175 alSourcef(mId
, AL_CONE_OUTER_GAIN
, gain
);
1176 if(mContext
->hasExtension(AL::EXT_EFX
))
1177 alSourcef(mId
, AL_CONE_OUTER_GAINHF
, gainhf
);
1179 mConeOuterGain
= gain
;
1180 mConeOuterGainHF
= gainhf
;
1184 DECL_THUNK2(void, Source
, setRolloffFactors
,, ALfloat
, ALfloat
)
1185 void SourceImpl::setRolloffFactors(ALfloat factor
, ALfloat roomfactor
)
1187 if(!(factor
>= 0.0f
&& roomfactor
>= 0.0f
))
1188 throw std::out_of_range("Rolloff factor out of range");
1189 CheckContext(mContext
);
1192 alSourcef(mId
, AL_ROLLOFF_FACTOR
, factor
);
1193 if(mContext
->hasExtension(AL::EXT_EFX
))
1194 alSourcef(mId
, AL_ROOM_ROLLOFF_FACTOR
, roomfactor
);
1196 mRolloffFactor
= factor
;
1197 mRoomRolloffFactor
= roomfactor
;
1200 DECL_THUNK1(void, Source
, setDopplerFactor
,, ALfloat
)
1201 void SourceImpl::setDopplerFactor(ALfloat factor
)
1203 if(!(factor
>= 0.0f
&& factor
<= 1.0f
))
1204 throw std::out_of_range("Doppler factor out of range");
1205 CheckContext(mContext
);
1207 alSourcef(mId
, AL_DOPPLER_FACTOR
, factor
);
1208 mDopplerFactor
= factor
;
1211 DECL_THUNK1(void, Source
, setRelative
,, bool)
1212 void SourceImpl::setRelative(bool relative
)
1214 CheckContext(mContext
);
1216 alSourcei(mId
, AL_SOURCE_RELATIVE
, relative
? AL_TRUE
: AL_FALSE
);
1217 mRelative
= relative
;
1220 DECL_THUNK1(void, Source
, setRadius
,, ALfloat
)
1221 void SourceImpl::setRadius(ALfloat radius
)
1223 if(!(mRadius
>= 0.0f
))
1224 throw std::out_of_range("Radius out of range");
1225 CheckContext(mContext
);
1226 if(mId
!= 0 && mContext
->hasExtension(AL::EXT_SOURCE_RADIUS
))
1227 alSourcef(mId
, AL_SOURCE_RADIUS
, radius
);
1231 DECL_THUNK2(void, Source
, setStereoAngles
,, ALfloat
, ALfloat
)
1232 void SourceImpl::setStereoAngles(ALfloat leftAngle
, ALfloat rightAngle
)
1234 CheckContext(mContext
);
1235 if(mId
!= 0 && mContext
->hasExtension(AL::EXT_STEREO_ANGLES
))
1237 ALfloat angles
[2] = { leftAngle
, rightAngle
};
1238 alSourcefv(mId
, AL_STEREO_ANGLES
, angles
);
1240 mStereoAngles
[0] = leftAngle
;
1241 mStereoAngles
[1] = rightAngle
;
1244 DECL_THUNK1(void, Source
, set3DSpatialize
,, Spatialize
)
1245 void SourceImpl::set3DSpatialize(Spatialize spatialize
)
1247 CheckContext(mContext
);
1248 if(mId
!= 0 && mContext
->hasExtension(AL::SOFT_source_spatialize
))
1249 alSourcei(mId
, AL_SOURCE_SPATIALIZE_SOFT
, (ALint
)spatialize
);
1250 mSpatialize
= spatialize
;
1253 DECL_THUNK1(void, Source
, setResamplerIndex
,, ALsizei
)
1254 void SourceImpl::setResamplerIndex(ALsizei index
)
1257 throw std::out_of_range("Resampler index out of range");
1258 index
= std::min
<ALsizei
>(index
, mContext
->getAvailableResamplers().size());
1259 if(mId
!= 0 && mContext
->hasExtension(AL::SOFT_source_resampler
))
1260 alSourcei(mId
, AL_SOURCE_RESAMPLER_SOFT
, index
);
1264 DECL_THUNK1(void, Source
, setAirAbsorptionFactor
,, ALfloat
)
1265 void SourceImpl::setAirAbsorptionFactor(ALfloat factor
)
1267 if(!(factor
>= 0.0f
&& factor
<= 10.0f
))
1268 throw std::out_of_range("Absorption factor out of range");
1269 CheckContext(mContext
);
1270 if(mId
!= 0 && mContext
->hasExtension(AL::EXT_EFX
))
1271 alSourcef(mId
, AL_AIR_ABSORPTION_FACTOR
, factor
);
1272 mAirAbsorptionFactor
= factor
;
1275 DECL_THUNK3(void, Source
, setGainAuto
,, bool, bool, bool)
1276 void SourceImpl::setGainAuto(bool directhf
, bool send
, bool sendhf
)
1278 CheckContext(mContext
);
1279 if(mId
!= 0 && mContext
->hasExtension(AL::EXT_EFX
))
1281 alSourcei(mId
, AL_DIRECT_FILTER_GAINHF_AUTO
, directhf
? AL_TRUE
: AL_FALSE
);
1282 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
, send
? AL_TRUE
: AL_FALSE
);
1283 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
, sendhf
? AL_TRUE
: AL_FALSE
);
1285 mDryGainHFAuto
= directhf
;
1286 mWetGainAuto
= send
;
1287 mWetGainHFAuto
= sendhf
;
1291 void SourceImpl::setFilterParams(ALuint
&filterid
, const FilterParams
¶ms
)
1293 if(!mContext
->hasExtension(AL::EXT_EFX
))
1296 if(!(params
.mGain
< 1.0f
|| params
.mGainHF
< 1.0f
|| params
.mGainLF
< 1.0f
))
1299 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_NULL
);
1306 mContext
->alGenFilters(1, &filterid
);
1307 ALenum err
= alGetError();
1308 if(err
!= AL_NO_ERROR
)
1309 throw al_error(err
, "Failed to create Filter");
1311 bool filterset
= false;
1312 if(params
.mGainHF
< 1.0f
&& params
.mGainLF
< 1.0f
)
1314 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_BANDPASS
);
1315 if(alGetError() == AL_NO_ERROR
)
1317 mContext
->alFilterf(filterid
, AL_BANDPASS_GAIN
, std::min(params
.mGain
, 1.0f
));
1318 mContext
->alFilterf(filterid
, AL_BANDPASS_GAINHF
, std::min(params
.mGainHF
, 1.0f
));
1319 mContext
->alFilterf(filterid
, AL_BANDPASS_GAINLF
, std::min(params
.mGainLF
, 1.0f
));
1323 if(!filterset
&& !(params
.mGainHF
< 1.0f
) && params
.mGainLF
< 1.0f
)
1325 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_HIGHPASS
);
1326 if(alGetError() == AL_NO_ERROR
)
1328 mContext
->alFilterf(filterid
, AL_HIGHPASS_GAIN
, std::min(params
.mGain
, 1.0f
));
1329 mContext
->alFilterf(filterid
, AL_HIGHPASS_GAINLF
, std::min(params
.mGainLF
, 1.0f
));
1335 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_LOWPASS
);
1336 if(alGetError() == AL_NO_ERROR
)
1338 mContext
->alFilterf(filterid
, AL_LOWPASS_GAIN
, std::min(params
.mGain
, 1.0f
));
1339 mContext
->alFilterf(filterid
, AL_LOWPASS_GAINHF
, std::min(params
.mGainHF
, 1.0f
));
1346 DECL_THUNK1(void, Source
, setDirectFilter
,, const FilterParams
&)
1347 void SourceImpl::setDirectFilter(const FilterParams
&filter
)
1349 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1350 throw std::out_of_range("Gain value out of range");
1351 CheckContext(mContext
);
1353 setFilterParams(mDirectFilter
, filter
);
1355 alSourcei(mId
, AL_DIRECT_FILTER
, mDirectFilter
);
1358 DECL_THUNK2(void, Source
, setSendFilter
,, ALuint
, const FilterParams
&)
1359 void SourceImpl::setSendFilter(ALuint send
, const FilterParams
&filter
)
1361 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1362 throw std::out_of_range("Gain value out of range");
1363 CheckContext(mContext
);
1365 auto siter
= std::lower_bound(mEffectSlots
.begin(), mEffectSlots
.end(), send
,
1366 [](const SendProps
&prop
, ALuint send
) -> bool
1367 { return prop
.mSendIdx
< send
; }
1369 if(siter
== mEffectSlots
.end() || siter
->mSendIdx
!= send
)
1371 ALuint filterid
= 0;
1373 setFilterParams(filterid
, filter
);
1374 if(!filterid
) return;
1376 siter
= mEffectSlots
.emplace(siter
, send
, filterid
);
1379 setFilterParams(siter
->mFilter
, filter
);
1383 ALuint slotid
= (siter
->mSlot
? siter
->mSlot
->getId() : 0);
1384 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->mFilter
);
1388 DECL_THUNK2(void, Source
, setAuxiliarySend
,, AuxiliaryEffectSlot
, ALuint
)
1389 void SourceImpl::setAuxiliarySend(AuxiliaryEffectSlot auxslot
, ALuint send
)
1391 AuxiliaryEffectSlotImpl
*slot
= auxslot
.getHandle();
1392 if(slot
) CheckContexts(mContext
, slot
->getContext());
1393 CheckContext(mContext
);
1395 auto siter
= std::lower_bound(mEffectSlots
.begin(), mEffectSlots
.end(), send
,
1396 [](const SendProps
&prop
, ALuint send
) -> bool
1397 { return prop
.mSendIdx
< send
; }
1399 if(siter
== mEffectSlots
.end() || siter
->mSendIdx
!= send
)
1402 slot
->addSourceSend({Source(this), send
});
1403 siter
= mEffectSlots
.emplace(siter
, send
, slot
);
1405 else if(siter
->mSlot
!= slot
)
1407 if(slot
) slot
->addSourceSend({Source(this), send
});
1409 siter
->mSlot
->removeSourceSend({Source(this), send
});
1410 siter
->mSlot
= slot
;
1415 ALuint slotid
= (siter
->mSlot
? siter
->mSlot
->getId() : 0);
1416 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->mFilter
);
1420 DECL_THUNK3(void, Source
, setAuxiliarySendFilter
,, AuxiliaryEffectSlot
, ALuint
, const FilterParams
&)
1421 void SourceImpl::setAuxiliarySendFilter(AuxiliaryEffectSlot auxslot
, ALuint send
, const FilterParams
&filter
)
1423 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1424 throw std::out_of_range("Gain value out of range");
1425 AuxiliaryEffectSlotImpl
*slot
= auxslot
.getHandle();
1426 if(slot
) CheckContexts(mContext
, slot
->getContext());
1427 CheckContext(mContext
);
1429 auto siter
= std::lower_bound(mEffectSlots
.begin(), mEffectSlots
.end(), send
,
1430 [](const SendProps
&prop
, ALuint send
) -> bool
1431 { return prop
.mSendIdx
< send
; }
1433 if(siter
== mEffectSlots
.end() || siter
->mSendIdx
!= send
)
1435 ALuint filterid
= 0;
1437 setFilterParams(filterid
, filter
);
1438 if(!filterid
&& !slot
)
1441 if(slot
) slot
->addSourceSend({Source(this), send
});
1442 siter
= mEffectSlots
.emplace(siter
, send
, slot
, filterid
);
1446 if(siter
->mSlot
!= slot
)
1448 if(slot
) slot
->addSourceSend({Source(this), send
});
1450 siter
->mSlot
->removeSourceSend({Source(this), send
});
1451 siter
->mSlot
= slot
;
1453 setFilterParams(siter
->mFilter
, filter
);
1458 ALuint slotid
= (siter
->mSlot
? siter
->mSlot
->getId() : 0);
1459 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->mFilter
);
1464 void Source::release()
1466 SourceImpl
*i
= pImpl
;
1470 void SourceImpl::release()
1475 mContext
->freeSource(this);
1479 DECL_THUNK0(SourceGroup
, Source
, getGroup
, const)
1480 DECL_THUNK0(ALuint
, Source
, getPriority
, const)
1481 DECL_THUNK0(bool, Source
, getLooping
, const)
1482 DECL_THUNK0(ALfloat
, Source
, getPitch
, const)
1483 DECL_THUNK0(ALfloat
, Source
, getGain
, const)
1484 DECL_THUNK0(ALfloatPair
, Source
, getGainRange
, const)
1485 DECL_THUNK0(ALfloatPair
, Source
, getDistanceRange
, const)
1486 DECL_THUNK0(Vector3
, Source
, getPosition
, const)
1487 DECL_THUNK0(Vector3
, Source
, getVelocity
, const)
1488 DECL_THUNK0(Vector3
, Source
, getDirection
, const)
1489 DECL_THUNK0(Vector3Pair
, Source
, getOrientation
, const)
1490 DECL_THUNK0(ALfloatPair
, Source
, getConeAngles
, const)
1491 DECL_THUNK0(ALfloatPair
, Source
, getOuterConeGains
, const)
1492 DECL_THUNK0(ALfloatPair
, Source
, getRolloffFactors
, const)
1493 DECL_THUNK0(ALfloat
, Source
, getDopplerFactor
, const)
1494 DECL_THUNK0(bool, Source
, getRelative
, const)
1495 DECL_THUNK0(ALfloat
, Source
, getRadius
, const)
1496 DECL_THUNK0(ALfloatPair
, Source
, getStereoAngles
, const)
1497 DECL_THUNK0(Spatialize
, Source
, get3DSpatialize
, const)
1498 DECL_THUNK0(ALsizei
, Source
, getResamplerIndex
, const)
1499 DECL_THUNK0(ALfloat
, Source
, getAirAbsorptionFactor
, const)
1500 DECL_THUNK0(BoolTriple
, Source
, getGainAuto
, const)