18 #include "auxeffectslot.h"
19 #include "sourcegroup.h"
24 class ALBufferStream
{
25 SharedPtr
<Decoder
> mDecoder
;
37 Vector
<ALuint
> mBufferIds
;
41 std::pair
<uint64_t,uint64_t> mLoopPts
;
43 std::atomic
<bool> mDone
;
46 ALBufferStream(SharedPtr
<Decoder
> decoder
, ALuint updatelen
, ALuint numupdates
)
47 : mDecoder(decoder
), mUpdateLen(updatelen
), mNumUpdates(numupdates
),
48 mFormat(AL_NONE
), mFrequency(0), mFrameSize(0), mSilence(0),
49 mCurrentIdx(0), mSamplePos(0), mLoopPts
{0,0}, mHasLooped(false),
54 if(!mBufferIds
.empty())
56 alDeleteBuffers(mBufferIds
.size(), mBufferIds
.data());
61 uint64_t getLength() const { return mDecoder
->getLength(); }
62 uint64_t getPosition() const { return mSamplePos
; }
64 ALuint
getNumUpdates() const { return mNumUpdates
; }
65 ALuint
getUpdateLength() const { return mUpdateLen
; }
67 ALuint
getFrequency() const { return mFrequency
; }
69 bool seek(uint64_t pos
)
71 if(!mDecoder
->seek(pos
))
75 mDone
.store(false, std::memory_order_release
);
81 ALuint srate
= mDecoder
->getFrequency();
82 ChannelConfig chans
= mDecoder
->getChannelConfig();
83 SampleType type
= mDecoder
->getSampleType();
85 mLoopPts
= mDecoder
->getLoopPoints();
86 if(mLoopPts
.first
>= mLoopPts
.second
)
89 mLoopPts
.second
= std::numeric_limits
<uint64_t>::max();
93 mFrameSize
= FramesToBytes(1, chans
, type
);
94 mFormat
= GetFormat(chans
, type
);
95 if(mFormat
== AL_NONE
)
97 std::stringstream sstr
;
98 sstr
<< "Format not supported ("<<GetSampleTypeName(type
)<<", "<<GetChannelConfigName(chans
)<<")";
99 throw std::runtime_error(sstr
.str());
102 mData
.resize(mUpdateLen
* mFrameSize
);
103 if(type
== SampleType::UInt8
) mSilence
= 0x80;
104 else if(type
== SampleType::Mulaw
) mSilence
= 0x7f;
105 else mSilence
= 0x00;
107 mBufferIds
.assign(mNumUpdates
, 0);
108 alGenBuffers(mBufferIds
.size(), mBufferIds
.data());
111 int64_t getLoopStart() const { return mLoopPts
.first
; }
112 int64_t getLoopEnd() const { return mLoopPts
.second
; }
114 bool hasLooped() const { return mHasLooped
; }
115 bool hasMoreData() const { return !mDone
.load(std::memory_order_acquire
); }
116 bool streamMoreData(ALuint srcid
, bool loop
)
118 if(mDone
.load(std::memory_order_acquire
))
122 ALuint len
= mUpdateLen
;
123 if(loop
&& mSamplePos
<= mLoopPts
.second
)
124 len
= std::min
<uint64_t>(len
, mLoopPts
.second
- mSamplePos
);
128 frames
= mDecoder
->read(mData
.data(), len
);
129 mSamplePos
+= frames
;
130 if(frames
< mUpdateLen
&& loop
&& mSamplePos
> 0)
132 if(mSamplePos
< mLoopPts
.second
)
134 mLoopPts
.second
= mSamplePos
;
135 mLoopPts
.first
= std::min(mLoopPts
.first
, mLoopPts
.second
-1);
139 if(!mDecoder
->seek(mLoopPts
.first
))
141 mSamplePos
= mLoopPts
.first
;
144 len
= std::min
<uint64_t>(mUpdateLen
-frames
, mLoopPts
.second
-mLoopPts
.first
);
145 ALuint got
= mDecoder
->read(&mData
[frames
*mFrameSize
], len
);
149 } while(frames
< mUpdateLen
);
151 if(frames
< mUpdateLen
)
153 mDone
.store(true, std::memory_order_release
);
154 if(frames
== 0) return false;
155 mSamplePos
+= mUpdateLen
- frames
;
156 std::fill(mData
.begin() + frames
*mFrameSize
, mData
.end(), mSilence
);
159 alBufferData(mBufferIds
[mCurrentIdx
], mFormat
, mData
.data(), mData
.size(), mFrequency
);
160 alSourceQueueBuffers(srcid
, 1, &mBufferIds
[mCurrentIdx
]);
161 mCurrentIdx
= (mCurrentIdx
+1) % mBufferIds
.size();
167 SourceImpl::SourceImpl(ContextImpl
*context
)
168 : mContext(context
), mId(0), mBuffer(0), mGroup(nullptr), mIsAsync(false),
169 mDirectFilter(AL_FILTER_NULL
)
174 SourceImpl::~SourceImpl()
179 void SourceImpl::resetProperties()
182 mGroup
->removeSource(Source(this));
185 mPaused
.store(false, std::memory_order_release
);
192 mMaxDist
= std::numeric_limits
<float>::max();
193 mPosition
= Vector3(0.0f
);
194 mVelocity
= Vector3(0.0f
);
195 mDirection
= Vector3(0.0f
);
196 mOrientation
[0] = Vector3(0.0f
, 0.0f
, -1.0f
);
197 mOrientation
[1] = Vector3(0.0f
, 1.0f
, 0.0f
);
198 mConeInnerAngle
= 360.0f
;
199 mConeOuterAngle
= 360.0f
;
200 mConeOuterGain
= 0.0f
;
201 mConeOuterGainHF
= 1.0f
;
202 mRolloffFactor
= 1.0f
;
203 mRoomRolloffFactor
= 0.0f
;
204 mDopplerFactor
= 1.0f
;
205 mAirAbsorptionFactor
= 0.0f
;
207 mStereoAngles
[0] = F_PI
/ 6.0f
;
208 mStereoAngles
[1] = -F_PI
/ 6.0f
;
209 mSpatialize
= Spatialize::Auto
;
210 mResampler
= mContext
->hasExtension(SOFT_source_resampler
) ?
211 alGetInteger(AL_DEFAULT_RESAMPLER_SOFT
) : 0;
214 mDryGainHFAuto
= true;
216 mWetGainHFAuto
= true;
218 mContext
->alDeleteFilters(1, &mDirectFilter
);
220 for(auto &i
: mEffectSlots
)
223 i
.second
.mSlot
->removeSourceSend(Source(this), i
.first
);
225 mContext
->alDeleteFilters(1, &i
.second
.mFilter
);
227 mEffectSlots
.clear();
232 void SourceImpl::applyProperties(bool looping
, ALuint offset
) const
234 alSourcei(mId
, AL_LOOPING
, looping
? AL_TRUE
: AL_FALSE
);
235 alSourcei(mId
, AL_SAMPLE_OFFSET
, offset
);
238 alSourcef(mId
, AL_PITCH
, mPitch
* mGroup
->getAppliedPitch());
239 alSourcef(mId
, AL_GAIN
, mGain
* mGroup
->getAppliedGain());
243 alSourcef(mId
, AL_PITCH
, mPitch
);
244 alSourcef(mId
, AL_GAIN
, mGain
);
246 alSourcef(mId
, AL_MIN_GAIN
, mMinGain
);
247 alSourcef(mId
, AL_MAX_GAIN
, mMaxGain
);
248 alSourcef(mId
, AL_REFERENCE_DISTANCE
, mRefDist
);
249 alSourcef(mId
, AL_MAX_DISTANCE
, mMaxDist
);
250 alSourcefv(mId
, AL_POSITION
, mPosition
.getPtr());
251 alSourcefv(mId
, AL_VELOCITY
, mVelocity
.getPtr());
252 alSourcefv(mId
, AL_DIRECTION
, mDirection
.getPtr());
253 if(mContext
->hasExtension(EXT_BFORMAT
))
254 alSourcefv(mId
, AL_ORIENTATION
, &mOrientation
[0][0]);
255 alSourcef(mId
, AL_CONE_INNER_ANGLE
, mConeInnerAngle
);
256 alSourcef(mId
, AL_CONE_OUTER_ANGLE
, mConeOuterAngle
);
257 alSourcef(mId
, AL_CONE_OUTER_GAIN
, mConeOuterGain
);
258 alSourcef(mId
, AL_ROLLOFF_FACTOR
, mRolloffFactor
);
259 alSourcef(mId
, AL_DOPPLER_FACTOR
, mDopplerFactor
);
260 if(mContext
->hasExtension(EXT_SOURCE_RADIUS
))
261 alSourcef(mId
, AL_SOURCE_RADIUS
, mRadius
);
262 if(mContext
->hasExtension(EXT_STEREO_ANGLES
))
263 alSourcefv(mId
, AL_STEREO_ANGLES
, mStereoAngles
);
264 if(mContext
->hasExtension(SOFT_source_spatialize
))
265 alSourcei(mId
, AL_SOURCE_SPATIALIZE_SOFT
, (ALint
)mSpatialize
);
266 if(mContext
->hasExtension(SOFT_source_resampler
))
267 alSourcei(mId
, AL_SOURCE_RESAMPLER_SOFT
, mResampler
);
268 alSourcei(mId
, AL_SOURCE_RELATIVE
, mRelative
? AL_TRUE
: AL_FALSE
);
269 if(mContext
->hasExtension(EXT_EFX
))
271 alSourcef(mId
, AL_CONE_OUTER_GAINHF
, mConeOuterGainHF
);
272 alSourcef(mId
, AL_ROOM_ROLLOFF_FACTOR
, mRoomRolloffFactor
);
273 alSourcef(mId
, AL_AIR_ABSORPTION_FACTOR
, mAirAbsorptionFactor
);
274 alSourcei(mId
, AL_DIRECT_FILTER_GAINHF_AUTO
, mDryGainHFAuto
? AL_TRUE
: AL_FALSE
);
275 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
, mWetGainAuto
? AL_TRUE
: AL_FALSE
);
276 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
, mWetGainHFAuto
? AL_TRUE
: AL_FALSE
);
277 alSourcei(mId
, AL_DIRECT_FILTER
, mDirectFilter
);
278 for(const auto &i
: mEffectSlots
)
280 ALuint slotid
= (i
.second
.mSlot
? i
.second
.mSlot
->getId() : 0);
281 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, i
.first
, i
.second
.mFilter
);
287 void SourceImpl::setGroup(SourceGroupImpl
*group
)
290 mGroup
->removeSource(Source(this));
295 void SourceImpl::unsetGroup()
301 void SourceImpl::groupUpdate()
307 alSourcef(mId
, AL_PITCH
, mPitch
* mGroup
->getAppliedPitch());
308 alSourcef(mId
, AL_GAIN
, mGain
* mGroup
->getAppliedGain());
312 alSourcef(mId
, AL_PITCH
, mPitch
);
313 alSourcef(mId
, AL_GAIN
, mGain
);
318 void SourceImpl::groupPropUpdate(ALfloat gain
, ALfloat pitch
)
322 alSourcef(mId
, AL_PITCH
, mPitch
* pitch
);
323 alSourcef(mId
, AL_GAIN
, mGain
* gain
);
328 void SourceImpl::play(Buffer buffer
)
330 BufferImpl
*albuf
= buffer
.getHandle();
331 if(!albuf
) throw std::runtime_error("Buffer is not valid");
332 CheckContext(mContext
);
333 CheckContext(albuf
->getContext());
336 mContext
->removeStream(this);
337 mIsAsync
.store(false, std::memory_order_release
);
341 mId
= mContext
->getSourceId(mPriority
);
342 applyProperties(mLooping
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
346 mContext
->removePlayingSource(this);
348 alSourcei(mId
, AL_BUFFER
, 0);
349 alSourcei(mId
, AL_LOOPING
, mLooping
? AL_TRUE
: AL_FALSE
);
350 alSourcei(mId
, AL_SAMPLE_OFFSET
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
356 mBuffer
->removeSource(Source(this));
358 mBuffer
->addSource(Source(this));
360 alSourcei(mId
, AL_BUFFER
, mBuffer
->getId());
362 mPaused
.store(false, std::memory_order_release
);
363 mContext
->addPlayingSource(this, mId
);
366 void SourceImpl::play(SharedPtr
<Decoder
> decoder
, ALuint updatelen
, ALuint queuesize
)
369 throw std::runtime_error("Update length out of range");
371 throw std::runtime_error("Queue size out of range");
372 CheckContext(mContext
);
374 auto stream
= MakeUnique
<ALBufferStream
>(decoder
, updatelen
, queuesize
);
378 mContext
->removeStream(this);
379 mIsAsync
.store(false, std::memory_order_release
);
383 mId
= mContext
->getSourceId(mPriority
);
384 applyProperties(false, 0);
388 mContext
->removePlayingSource(this);
390 alSourcei(mId
, AL_BUFFER
, 0);
391 alSourcei(mId
, AL_LOOPING
, AL_FALSE
);
392 alSourcei(mId
, AL_SAMPLE_OFFSET
, 0);
397 mBuffer
->removeSource(Source(this));
400 mStream
= std::move(stream
);
402 mStream
->seek(mOffset
);
405 for(ALuint i
= 0;i
< mStream
->getNumUpdates();i
++)
407 if(!mStream
->streamMoreData(mId
, mLooping
))
411 mPaused
.store(false, std::memory_order_release
);
413 mContext
->addStream(this);
414 mIsAsync
.store(true, std::memory_order_release
);
415 mContext
->addPlayingSource(this);
419 void SourceImpl::makeStopped(bool dolock
)
424 mContext
->removeStream(this);
426 mContext
->removeStreamNoLock(this);
428 mIsAsync
.store(false, std::memory_order_release
);
433 alSourcei(mId
, AL_BUFFER
, 0);
434 if(mContext
->hasExtension(EXT_EFX
))
436 alSourcei(mId
, AL_DIRECT_FILTER
, AL_FILTER_NULL
);
437 for(auto &i
: mEffectSlots
)
438 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, 0, i
.first
, AL_FILTER_NULL
);
440 mContext
->insertSourceId(mId
);
446 mBuffer
->removeSource(Source(this));
449 mPaused
.store(false, std::memory_order_release
);
452 void SourceImpl::stop()
454 CheckContext(mContext
);
455 mContext
->removePlayingSource(this);
460 void SourceImpl::checkPaused()
462 if(mPaused
.load(std::memory_order_acquire
) || mId
== 0)
466 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
467 // Streaming sources may be in a stopped state if underrun
468 mPaused
.store((state
== AL_PAUSED
) ||
469 (state
== AL_STOPPED
&& mStream
&& mStream
->hasMoreData()),
470 std::memory_order_release
);
473 void SourceImpl::pause()
475 CheckContext(mContext
);
476 if(mPaused
.load(std::memory_order_acquire
))
481 std::lock_guard
<std::mutex
> lock(mMutex
);
484 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
485 // Streaming sources may be in a stopped state if underrun
486 mPaused
.store((state
== AL_PAUSED
) ||
487 (state
== AL_STOPPED
&& mStream
&& mStream
->hasMoreData()),
488 std::memory_order_release
);
492 void SourceImpl::resume()
494 CheckContext(mContext
);
495 if(!mPaused
.load(std::memory_order_acquire
))
500 mPaused
.store(false, std::memory_order_release
);
504 bool SourceImpl::isPlaying() const
506 CheckContext(mContext
);
507 if(mId
== 0) return false;
510 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
512 throw std::runtime_error("Source state error");
514 return state
== AL_PLAYING
|| (!mPaused
.load(std::memory_order_acquire
) &&
515 mStream
&& mStream
->hasMoreData());
518 bool SourceImpl::isPaused() const
520 CheckContext(mContext
);
521 if(mId
== 0) return false;
524 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
526 throw std::runtime_error("Source state error");
528 return state
== AL_PAUSED
|| mPaused
.load(std::memory_order_acquire
);
532 bool SourceImpl::playUpdate(ALuint id
)
535 alGetSourcei(id
, AL_SOURCE_STATE
, &state
);
536 if(EXPECT((state
== AL_PLAYING
|| state
== AL_PAUSED
), true))
540 mContext
->send(&MessageHandler::sourceStopped
, Source(this));
544 bool SourceImpl::playUpdate()
546 if(EXPECT(mIsAsync
.load(std::memory_order_acquire
), true))
550 mContext
->send(&MessageHandler::sourceStopped
, Source(this));
555 ALint
SourceImpl::refillBufferStream()
558 alGetSourcei(mId
, AL_BUFFERS_PROCESSED
, &processed
);
562 alSourceUnqueueBuffers(mId
, 1, &buf
);
567 alGetSourcei(mId
, AL_BUFFERS_QUEUED
, &queued
);
568 for(;(ALuint
)queued
< mStream
->getNumUpdates();queued
++)
570 if(!mStream
->streamMoreData(mId
, mLooping
))
577 bool SourceImpl::updateAsync()
579 std::lock_guard
<std::mutex
> lock(mMutex
);
581 ALint queued
= refillBufferStream();
584 mIsAsync
.store(false, std::memory_order_release
);
587 if(!mPaused
.load(std::memory_order_acquire
))
590 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
591 if(state
!= AL_PLAYING
)
598 void SourceImpl::setPriority(ALuint priority
)
600 mPriority
= priority
;
604 void SourceImpl::setOffset(uint64_t offset
)
606 CheckContext(mContext
);
615 if(offset
>= std::numeric_limits
<ALint
>::max())
616 throw std::runtime_error("Offset out of range");
618 alSourcei(mId
, AL_SAMPLE_OFFSET
, (ALint
)offset
);
619 if(alGetError() != AL_NO_ERROR
)
620 throw std::runtime_error("Offset out of range");
624 std::lock_guard
<std::mutex
> lock(mMutex
);
625 if(!mStream
->seek(offset
))
626 throw std::runtime_error("Failed to seek to offset");
628 alSourcei(mId
, AL_BUFFER
, 0);
629 ALint queued
= refillBufferStream();
630 if(queued
> 0 && !mPaused
)
635 std::pair
<uint64_t,std::chrono::nanoseconds
> SourceImpl::getSampleOffsetLatency() const
637 std::pair
<uint64_t,std::chrono::nanoseconds
> ret
{0, std::chrono::nanoseconds::zero()};
638 CheckContext(mContext
);
639 if(mId
== 0) return ret
;
643 std::lock_guard
<std::mutex
> lock(mMutex
);
644 ALint queued
= 0, state
= -1, srcpos
= 0;
646 alGetSourcei(mId
, AL_BUFFERS_QUEUED
, &queued
);
647 if(mContext
->hasExtension(SOFT_source_latency
))
650 mContext
->alGetSourcei64vSOFT(mId
, AL_SAMPLE_OFFSET_LATENCY_SOFT
, val
);
652 ret
.second
= std::chrono::nanoseconds(val
[1]);
655 alGetSourcei(mId
, AL_SAMPLE_OFFSET
, &srcpos
);
656 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
658 int64_t streampos
= mStream
->getPosition();
659 if(state
!= AL_STOPPED
)
661 // The amount of samples in the queue waiting to play
662 ALuint inqueue
= queued
*mStream
->getUpdateLength() - srcpos
;
663 if(!mStream
->hasLooped())
665 // A non-looped stream should never have more samples queued
666 // than have been read...
667 streampos
= std::max
<int64_t>(streampos
, inqueue
) - inqueue
;
671 streampos
-= inqueue
;
672 int64_t looplen
= mStream
->getLoopEnd() - mStream
->getLoopStart();
673 while(streampos
< mStream
->getLoopStart())
674 streampos
+= looplen
;
678 ret
.first
= streampos
;
683 if(mContext
->hasExtension(SOFT_source_latency
))
686 mContext
->alGetSourcei64vSOFT(mId
, AL_SAMPLE_OFFSET_LATENCY_SOFT
, val
);
688 ret
.second
= std::chrono::nanoseconds(val
[1]);
691 alGetSourcei(mId
, AL_SAMPLE_OFFSET
, &srcpos
);
696 std::pair
<Seconds
,Seconds
> SourceImpl::getSecOffsetLatency() const
698 std::pair
<Seconds
,Seconds
> ret
{Seconds::zero(), Seconds::zero()};
699 CheckContext(mContext
);
700 if(mId
== 0) return ret
;
704 std::lock_guard
<std::mutex
> lock(mMutex
);
705 ALint queued
= 0, state
= -1;
708 alGetSourcei(mId
, AL_BUFFERS_QUEUED
, &queued
);
709 if(mContext
->hasExtension(SOFT_source_latency
))
712 mContext
->alGetSourcedvSOFT(mId
, AL_SEC_OFFSET_LATENCY_SOFT
, val
);
714 ret
.second
= Seconds(val
[1]);
719 alGetSourcef(mId
, AL_SEC_OFFSET
, &f
);
722 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
725 int64_t streampos
= mStream
->getPosition();
726 if(state
!= AL_STOPPED
)
729 frac
= std::modf(srcpos
* mStream
->getFrequency(), &ipos
);
731 // The amount of samples in the queue waiting to play
732 ALuint inqueue
= queued
*mStream
->getUpdateLength() - (ALuint
)ipos
;
733 if(!mStream
->hasLooped())
735 // A non-looped stream should never have more samples queued
736 // than have been read...
737 streampos
= std::max
<int64_t>(streampos
, inqueue
) - inqueue
;
741 streampos
-= inqueue
;
742 int64_t looplen
= mStream
->getLoopEnd() - mStream
->getLoopStart();
743 while(streampos
< mStream
->getLoopStart())
744 streampos
+= looplen
;
748 ret
.first
= Seconds((streampos
+frac
) / mStream
->getFrequency());
752 ALdouble srcpos
= 0.0;
753 if(mContext
->hasExtension(SOFT_source_latency
))
756 mContext
->alGetSourcedvSOFT(mId
, AL_SEC_OFFSET_LATENCY_SOFT
, val
);
758 ret
.second
= Seconds(val
[1]);
763 alGetSourcef(mId
, AL_SEC_OFFSET
, &f
);
766 ret
.first
= Seconds(srcpos
);
771 void SourceImpl::setLooping(bool looping
)
773 CheckContext(mContext
);
776 alSourcei(mId
, AL_LOOPING
, looping
? AL_TRUE
: AL_FALSE
);
781 void SourceImpl::setPitch(ALfloat pitch
)
784 throw std::runtime_error("Pitch out of range");
785 CheckContext(mContext
);
787 alSourcef(mId
, AL_PITCH
, pitch
* (mGroup
? mGroup
->getAppliedPitch() : 1.0f
));
792 void SourceImpl::setGain(ALfloat gain
)
795 throw std::runtime_error("Gain out of range");
796 CheckContext(mContext
);
798 alSourcef(mId
, AL_GAIN
, gain
* (mGroup
? mGroup
->getAppliedGain() : 1.0f
));
802 void SourceImpl::setGainRange(ALfloat mingain
, ALfloat maxgain
)
804 if(!(mingain
>= 0.0f
&& maxgain
<= 1.0f
&& maxgain
>= mingain
))
805 throw std::runtime_error("Gain range out of range");
806 CheckContext(mContext
);
809 alSourcef(mId
, AL_MIN_GAIN
, mingain
);
810 alSourcef(mId
, AL_MAX_GAIN
, maxgain
);
817 void SourceImpl::setDistanceRange(ALfloat refdist
, ALfloat maxdist
)
819 if(!(refdist
>= 0.0f
&& maxdist
<= std::numeric_limits
<float>::max() && refdist
<= maxdist
))
820 throw std::runtime_error("Distance range out of range");
821 CheckContext(mContext
);
824 alSourcef(mId
, AL_REFERENCE_DISTANCE
, refdist
);
825 alSourcef(mId
, AL_MAX_DISTANCE
, maxdist
);
832 void SourceImpl::set3DParameters(const Vector3
&position
, const Vector3
&velocity
, const Vector3
&direction
)
834 CheckContext(mContext
);
837 Batcher batcher
= mContext
->getBatcher();
838 alSourcefv(mId
, AL_POSITION
, position
.getPtr());
839 alSourcefv(mId
, AL_VELOCITY
, velocity
.getPtr());
840 alSourcefv(mId
, AL_DIRECTION
, direction
.getPtr());
842 mPosition
= position
;
843 mVelocity
= velocity
;
844 mDirection
= direction
;
847 void SourceImpl::set3DParameters(const Vector3
&position
, const Vector3
&velocity
, std::pair
<Vector3
,Vector3
> orientation
)
849 static_assert(sizeof(orientation
) == sizeof(ALfloat
[6]), "Invalid Vector3 pair size");
850 CheckContext(mContext
);
853 Batcher batcher
= mContext
->getBatcher();
854 alSourcefv(mId
, AL_POSITION
, position
.getPtr());
855 alSourcefv(mId
, AL_VELOCITY
, velocity
.getPtr());
856 if(mContext
->hasExtension(EXT_BFORMAT
))
857 alSourcefv(mId
, AL_ORIENTATION
, orientation
.first
.getPtr());
858 alSourcefv(mId
, AL_DIRECTION
, orientation
.first
.getPtr());
860 mPosition
= position
;
861 mVelocity
= velocity
;
862 mDirection
= mOrientation
[0] = orientation
.first
;
863 mOrientation
[1] = orientation
.second
;
867 void SourceImpl::setPosition(ALfloat x
, ALfloat y
, ALfloat z
)
869 CheckContext(mContext
);
871 alSource3f(mId
, AL_POSITION
, x
, y
, z
);
877 void SourceImpl::setPosition(const ALfloat
*pos
)
879 CheckContext(mContext
);
881 alSourcefv(mId
, AL_POSITION
, pos
);
882 mPosition
[0] = pos
[0];
883 mPosition
[1] = pos
[1];
884 mPosition
[2] = pos
[2];
887 void SourceImpl::setVelocity(ALfloat x
, ALfloat y
, ALfloat z
)
889 CheckContext(mContext
);
891 alSource3f(mId
, AL_VELOCITY
, x
, y
, z
);
897 void SourceImpl::setVelocity(const ALfloat
*vel
)
899 CheckContext(mContext
);
901 alSourcefv(mId
, AL_VELOCITY
, vel
);
902 mVelocity
[0] = vel
[0];
903 mVelocity
[1] = vel
[1];
904 mVelocity
[2] = vel
[2];
907 void SourceImpl::setDirection(ALfloat x
, ALfloat y
, ALfloat z
)
909 CheckContext(mContext
);
911 alSource3f(mId
, AL_DIRECTION
, x
, y
, z
);
917 void SourceImpl::setDirection(const ALfloat
*dir
)
919 CheckContext(mContext
);
921 alSourcefv(mId
, AL_DIRECTION
, dir
);
922 mDirection
[0] = dir
[0];
923 mDirection
[1] = dir
[1];
924 mDirection
[2] = dir
[2];
927 void SourceImpl::setOrientation(ALfloat x1
, ALfloat y1
, ALfloat z1
, ALfloat x2
, ALfloat y2
, ALfloat z2
)
929 CheckContext(mContext
);
932 ALfloat ori
[6] = { x1
, y1
, z1
, x2
, y2
, z2
};
933 if(mContext
->hasExtension(EXT_BFORMAT
))
934 alSourcefv(mId
, AL_ORIENTATION
, ori
);
935 alSourcefv(mId
, AL_DIRECTION
, ori
);
937 mDirection
[0] = mOrientation
[0][0] = x1
;
938 mDirection
[1] = mOrientation
[0][1] = y1
;
939 mDirection
[2] = mOrientation
[0][2] = z1
;
940 mOrientation
[1][0] = x2
;
941 mOrientation
[1][1] = y2
;
942 mOrientation
[1][2] = z2
;
945 void SourceImpl::setOrientation(const ALfloat
*at
, const ALfloat
*up
)
947 CheckContext(mContext
);
950 ALfloat ori
[6] = { at
[0], at
[1], at
[2], up
[0], up
[1], up
[2] };
951 if(mContext
->hasExtension(EXT_BFORMAT
))
952 alSourcefv(mId
, AL_ORIENTATION
, ori
);
953 alSourcefv(mId
, AL_DIRECTION
, ori
);
955 mDirection
[0] = mOrientation
[0][0] = at
[0];
956 mDirection
[1] = mOrientation
[0][1] = at
[1];
957 mDirection
[2] = mOrientation
[0][2] = at
[2];
958 mOrientation
[1][0] = up
[0];
959 mOrientation
[1][1] = up
[1];
960 mOrientation
[1][2] = up
[2];
963 void SourceImpl::setOrientation(const ALfloat
*ori
)
965 CheckContext(mContext
);
968 if(mContext
->hasExtension(EXT_BFORMAT
))
969 alSourcefv(mId
, AL_ORIENTATION
, ori
);
970 alSourcefv(mId
, AL_DIRECTION
, ori
);
972 mDirection
[0] = mOrientation
[0][0] = ori
[0];
973 mDirection
[1] = mOrientation
[0][1] = ori
[1];
974 mDirection
[2] = mOrientation
[0][2] = ori
[2];
975 mOrientation
[1][0] = ori
[3];
976 mOrientation
[1][1] = ori
[4];
977 mOrientation
[1][2] = ori
[5];
981 void SourceImpl::setConeAngles(ALfloat inner
, ALfloat outer
)
983 if(!(inner
>= 0.0f
&& outer
<= 360.0f
&& outer
>= inner
))
984 throw std::runtime_error("Cone angles out of range");
985 CheckContext(mContext
);
988 alSourcef(mId
, AL_CONE_INNER_ANGLE
, inner
);
989 alSourcef(mId
, AL_CONE_OUTER_ANGLE
, outer
);
991 mConeInnerAngle
= inner
;
992 mConeOuterAngle
= outer
;
995 void SourceImpl::setOuterConeGains(ALfloat gain
, ALfloat gainhf
)
997 if(!(gain
>= 0.0f
&& gain
<= 1.0f
&& gainhf
>= 0.0f
&& gainhf
<= 1.0f
))
998 throw std::runtime_error("Outer cone gain out of range");
999 CheckContext(mContext
);
1002 alSourcef(mId
, AL_CONE_OUTER_GAIN
, gain
);
1003 if(mContext
->hasExtension(EXT_EFX
))
1004 alSourcef(mId
, AL_CONE_OUTER_GAINHF
, gainhf
);
1006 mConeOuterGain
= gain
;
1007 mConeOuterGainHF
= gainhf
;
1011 void SourceImpl::setRolloffFactors(ALfloat factor
, ALfloat roomfactor
)
1013 if(!(factor
>= 0.0f
&& roomfactor
>= 0.0f
))
1014 throw std::runtime_error("Rolloff factor out of range");
1015 CheckContext(mContext
);
1018 alSourcef(mId
, AL_ROLLOFF_FACTOR
, factor
);
1019 if(mContext
->hasExtension(EXT_EFX
))
1020 alSourcef(mId
, AL_ROOM_ROLLOFF_FACTOR
, roomfactor
);
1022 mRolloffFactor
= factor
;
1023 mRoomRolloffFactor
= roomfactor
;
1026 void SourceImpl::setDopplerFactor(ALfloat factor
)
1028 if(!(factor
>= 0.0f
&& factor
<= 1.0f
))
1029 throw std::runtime_error("Doppler factor out of range");
1030 CheckContext(mContext
);
1032 alSourcef(mId
, AL_DOPPLER_FACTOR
, factor
);
1033 mDopplerFactor
= factor
;
1036 void SourceImpl::setAirAbsorptionFactor(ALfloat factor
)
1038 if(!(factor
>= 0.0f
&& factor
<= 10.0f
))
1039 throw std::runtime_error("Absorption factor out of range");
1040 CheckContext(mContext
);
1041 if(mId
!= 0 && mContext
->hasExtension(EXT_EFX
))
1042 alSourcef(mId
, AL_AIR_ABSORPTION_FACTOR
, factor
);
1043 mAirAbsorptionFactor
= factor
;
1046 void SourceImpl::setRadius(ALfloat radius
)
1048 if(!(mRadius
>= 0.0f
))
1049 throw std::runtime_error("Radius out of range");
1050 CheckContext(mContext
);
1051 if(mId
!= 0 && mContext
->hasExtension(EXT_SOURCE_RADIUS
))
1052 alSourcef(mId
, AL_SOURCE_RADIUS
, radius
);
1056 void SourceImpl::setStereoAngles(ALfloat leftAngle
, ALfloat rightAngle
)
1058 CheckContext(mContext
);
1059 if(mId
!= 0 && mContext
->hasExtension(EXT_STEREO_ANGLES
))
1061 ALfloat angles
[2] = { leftAngle
, rightAngle
};
1062 alSourcefv(mId
, AL_STEREO_ANGLES
, angles
);
1064 mStereoAngles
[0] = leftAngle
;
1065 mStereoAngles
[1] = rightAngle
;
1068 void SourceImpl::set3DSpatialize(Spatialize spatialize
)
1070 CheckContext(mContext
);
1071 if(mId
!= 0 && mContext
->hasExtension(SOFT_source_spatialize
))
1072 alSourcei(mId
, AL_SOURCE_SPATIALIZE_SOFT
, (ALint
)spatialize
);
1073 mSpatialize
= spatialize
;
1076 void SourceImpl::setResamplerIndex(ALsizei index
)
1079 throw std::runtime_error("Resampler index out of range");
1080 index
= std::min
<ALsizei
>(index
, mContext
->getAvailableResamplers().size());
1081 if(mId
!= 0 && mContext
->hasExtension(SOFT_source_resampler
))
1082 alSourcei(mId
, AL_SOURCE_RESAMPLER_SOFT
, index
);
1086 void SourceImpl::setRelative(bool relative
)
1088 CheckContext(mContext
);
1090 alSourcei(mId
, AL_SOURCE_RELATIVE
, relative
? AL_TRUE
: AL_FALSE
);
1091 mRelative
= relative
;
1094 void SourceImpl::setGainAuto(bool directhf
, bool send
, bool sendhf
)
1096 CheckContext(mContext
);
1097 if(mId
!= 0 && mContext
->hasExtension(EXT_EFX
))
1099 alSourcei(mId
, AL_DIRECT_FILTER_GAINHF_AUTO
, directhf
? AL_TRUE
: AL_FALSE
);
1100 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
, send
? AL_TRUE
: AL_FALSE
);
1101 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
, sendhf
? AL_TRUE
: AL_FALSE
);
1103 mDryGainHFAuto
= directhf
;
1104 mWetGainAuto
= send
;
1105 mWetGainHFAuto
= sendhf
;
1109 void SourceImpl::setFilterParams(ALuint
&filterid
, const FilterParams
¶ms
)
1111 if(!mContext
->hasExtension(EXT_EFX
))
1114 if(!(params
.mGain
< 1.0f
|| params
.mGainHF
< 1.0f
|| params
.mGainLF
< 1.0f
))
1117 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_NULL
);
1124 mContext
->alGenFilters(1, &filterid
);
1125 if(alGetError() != AL_NO_ERROR
)
1126 throw std::runtime_error("Failed to create Filter");
1128 bool filterset
= false;
1129 if(params
.mGainHF
< 1.0f
&& params
.mGainLF
< 1.0f
)
1131 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_BANDPASS
);
1132 if(alGetError() == AL_NO_ERROR
)
1134 mContext
->alFilterf(filterid
, AL_BANDPASS_GAIN
, std::min(params
.mGain
, 1.0f
));
1135 mContext
->alFilterf(filterid
, AL_BANDPASS_GAINHF
, std::min(params
.mGainHF
, 1.0f
));
1136 mContext
->alFilterf(filterid
, AL_BANDPASS_GAINLF
, std::min(params
.mGainLF
, 1.0f
));
1140 if(!filterset
&& !(params
.mGainHF
< 1.0f
) && params
.mGainLF
< 1.0f
)
1142 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_HIGHPASS
);
1143 if(alGetError() == AL_NO_ERROR
)
1145 mContext
->alFilterf(filterid
, AL_HIGHPASS_GAIN
, std::min(params
.mGain
, 1.0f
));
1146 mContext
->alFilterf(filterid
, AL_HIGHPASS_GAINLF
, std::min(params
.mGainLF
, 1.0f
));
1152 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_LOWPASS
);
1153 if(alGetError() == AL_NO_ERROR
)
1155 mContext
->alFilterf(filterid
, AL_LOWPASS_GAIN
, std::min(params
.mGain
, 1.0f
));
1156 mContext
->alFilterf(filterid
, AL_LOWPASS_GAINHF
, std::min(params
.mGainHF
, 1.0f
));
1163 void SourceImpl::setDirectFilter(const FilterParams
&filter
)
1165 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1166 throw std::runtime_error("Gain value out of range");
1167 CheckContext(mContext
);
1169 setFilterParams(mDirectFilter
, filter
);
1171 alSourcei(mId
, AL_DIRECT_FILTER
, mDirectFilter
);
1174 void SourceImpl::setSendFilter(ALuint send
, const FilterParams
&filter
)
1176 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1177 throw std::runtime_error("Gain value out of range");
1178 CheckContext(mContext
);
1180 SendPropMap::iterator siter
= mEffectSlots
.find(send
);
1181 if(siter
== mEffectSlots
.end())
1183 ALuint filterid
= 0;
1185 setFilterParams(filterid
, filter
);
1186 if(!filterid
) return;
1188 siter
= mEffectSlots
.insert(std::make_pair(send
, SendProps(filterid
))).first
;
1191 setFilterParams(siter
->second
.mFilter
, filter
);
1195 ALuint slotid
= (siter
->second
.mSlot
? siter
->second
.mSlot
->getId() : 0);
1196 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->second
.mFilter
);
1200 void SourceImpl::setAuxiliarySend(AuxiliaryEffectSlot auxslot
, ALuint send
)
1202 AuxiliaryEffectSlotImpl
*slot
= auxslot
.getHandle();
1203 if(slot
) CheckContext(slot
->getContext());
1204 CheckContext(mContext
);
1206 SendPropMap::iterator siter
= mEffectSlots
.find(send
);
1207 if(siter
== mEffectSlots
.end())
1210 slot
->addSourceSend(Source(this), send
);
1211 siter
= mEffectSlots
.insert(std::make_pair(send
, SendProps(slot
))).first
;
1213 else if(siter
->second
.mSlot
!= slot
)
1215 if(slot
) slot
->addSourceSend(Source(this), send
);
1216 if(siter
->second
.mSlot
)
1217 siter
->second
.mSlot
->removeSourceSend(Source(this), send
);
1218 siter
->second
.mSlot
= slot
;
1223 ALuint slotid
= (siter
->second
.mSlot
? siter
->second
.mSlot
->getId() : 0);
1224 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->second
.mFilter
);
1228 void SourceImpl::setAuxiliarySendFilter(AuxiliaryEffectSlot auxslot
, ALuint send
, const FilterParams
&filter
)
1230 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1231 throw std::runtime_error("Gain value out of range");
1232 AuxiliaryEffectSlotImpl
*slot
= auxslot
.getHandle();
1233 if(slot
) CheckContext(slot
->getContext());
1234 CheckContext(mContext
);
1236 SendPropMap::iterator siter
= mEffectSlots
.find(send
);
1237 if(siter
== mEffectSlots
.end())
1239 ALuint filterid
= 0;
1241 setFilterParams(filterid
, filter
);
1242 if(!filterid
&& !slot
)
1245 if(slot
) slot
->addSourceSend(Source(this), send
);
1246 siter
= mEffectSlots
.insert(std::make_pair(send
, SendProps(slot
, filterid
))).first
;
1250 if(siter
->second
.mSlot
!= slot
)
1252 if(slot
) slot
->addSourceSend(Source(this), send
);
1253 if(siter
->second
.mSlot
)
1254 siter
->second
.mSlot
->removeSourceSend(Source(this), send
);
1255 siter
->second
.mSlot
= slot
;
1257 setFilterParams(siter
->second
.mFilter
, filter
);
1262 ALuint slotid
= (siter
->second
.mSlot
? siter
->second
.mSlot
->getId() : 0);
1263 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->second
.mFilter
);
1268 void SourceImpl::release()
1273 mContext
->alDeleteFilters(1, &mDirectFilter
);
1274 mDirectFilter
= AL_FILTER_NULL
;
1276 for(auto &i
: mEffectSlots
)
1279 i
.second
.mSlot
->removeSourceSend(Source(this), i
.first
);
1280 if(i
.second
.mFilter
)
1281 mContext
->alDeleteFilters(1, &i
.second
.mFilter
);
1283 mEffectSlots
.clear();
1286 mContext
->freeSource(this);
1290 // Need to use these to avoid extraneous commas in macro parameter lists
1291 using UInt64NSecPair
= std::pair
<uint64_t,std::chrono::nanoseconds
>;
1292 using SecondsPair
= std::pair
<Seconds
,Seconds
>;
1293 using ALfloatPair
= std::pair
<ALfloat
,ALfloat
>;
1294 using Vector3Pair
= std::pair
<Vector3
,Vector3
>;
1295 using BoolTriple
= std::tuple
<bool,bool,bool>;
1297 DECL_THUNK1(void, Source
, play
,, Buffer
)
1298 DECL_THUNK3(void, Source
, play
,, SharedPtr
<Decoder
>, ALuint
, ALuint
)
1299 DECL_THUNK0(void, Source
, stop
,)
1300 DECL_THUNK0(void, Source
, pause
,)
1301 DECL_THUNK0(void, Source
, resume
,)
1302 DECL_THUNK0(bool, Source
, isPlaying
, const)
1303 DECL_THUNK0(bool, Source
, isPaused
, const)
1304 DECL_THUNK1(void, Source
, setPriority
,, ALuint
)
1305 DECL_THUNK0(ALuint
, Source
, getPriority
, const)
1306 DECL_THUNK1(void, Source
, setOffset
,, uint64_t)
1307 DECL_THUNK0(UInt64NSecPair
, Source
, getSampleOffsetLatency
, const)
1308 DECL_THUNK0(SecondsPair
, Source
, getSecOffsetLatency
, const)
1309 DECL_THUNK1(void, Source
, setLooping
,, bool)
1310 DECL_THUNK0(bool, Source
, getLooping
, const)
1311 DECL_THUNK1(void, Source
, setPitch
,, ALfloat
)
1312 DECL_THUNK0(ALfloat
, Source
, getPitch
, const)
1313 DECL_THUNK1(void, Source
, setGain
,, ALfloat
)
1314 DECL_THUNK0(ALfloat
, Source
, getGain
, const)
1315 DECL_THUNK2(void, Source
, setGainRange
,, ALfloat
, ALfloat
)
1316 DECL_THUNK0(ALfloatPair
, Source
, getGainRange
, const)
1317 DECL_THUNK2(void, Source
, setDistanceRange
,, ALfloat
, ALfloat
)
1318 DECL_THUNK0(ALfloatPair
, Source
, getDistanceRange
, const)
1319 DECL_THUNK3(void, Source
, set3DParameters
,, const Vector3
&, const Vector3
&, const Vector3
&)
1320 DECL_THUNK3(void, Source
, set3DParameters
,, const Vector3
&, const Vector3
&, Vector3Pair
)
1321 DECL_THUNK3(void, Source
, setPosition
,, ALfloat
, ALfloat
, ALfloat
)
1322 DECL_THUNK1(void, Source
, setPosition
,, const ALfloat
*)
1323 DECL_THUNK0(Vector3
, Source
, getPosition
, const)
1324 DECL_THUNK3(void, Source
, setVelocity
,, ALfloat
, ALfloat
, ALfloat
)
1325 DECL_THUNK1(void, Source
, setVelocity
,, const ALfloat
*)
1326 DECL_THUNK0(Vector3
, Source
, getVelocity
, const)
1327 DECL_THUNK3(void, Source
, setDirection
,, ALfloat
, ALfloat
, ALfloat
)
1328 DECL_THUNK1(void, Source
, setDirection
,, const ALfloat
*)
1329 DECL_THUNK0(Vector3
, Source
, getDirection
, const)
1330 DECL_THUNK6(void, Source
, setOrientation
,, ALfloat
, ALfloat
, ALfloat
, ALfloat
, ALfloat
, ALfloat
)
1331 DECL_THUNK2(void, Source
, setOrientation
,, const ALfloat
*, const ALfloat
*)
1332 DECL_THUNK1(void, Source
, setOrientation
,, const ALfloat
*)
1333 DECL_THUNK0(Vector3Pair
, Source
, getOrientation
, const)
1334 DECL_THUNK2(void, Source
, setConeAngles
,, ALfloat
, ALfloat
)
1335 DECL_THUNK0(ALfloatPair
, Source
, getConeAngles
, const)
1336 DECL_THUNK2(void, Source
, setOuterConeGains
,, ALfloat
, ALfloat
)
1337 DECL_THUNK0(ALfloatPair
, Source
, getOuterConeGains
, const)
1338 DECL_THUNK2(void, Source
, setRolloffFactors
,, ALfloat
, ALfloat
)
1339 DECL_THUNK0(ALfloatPair
, Source
, getRolloffFactors
, const)
1340 DECL_THUNK1(void, Source
, setDopplerFactor
,, ALfloat
)
1341 DECL_THUNK0(ALfloat
, Source
, getDopplerFactor
, const)
1342 DECL_THUNK1(void, Source
, setRelative
,, bool)
1343 DECL_THUNK0(bool, Source
, getRelative
, const)
1344 DECL_THUNK1(void, Source
, setRadius
,, ALfloat
)
1345 DECL_THUNK0(ALfloat
, Source
, getRadius
, const)
1346 DECL_THUNK2(void, Source
, setStereoAngles
,, ALfloat
, ALfloat
)
1347 DECL_THUNK0(ALfloatPair
, Source
, getStereoAngles
, const)
1348 DECL_THUNK1(void, Source
, set3DSpatialize
,, Spatialize
)
1349 DECL_THUNK0(Spatialize
, Source
, get3DSpatialize
, const)
1350 DECL_THUNK1(void, Source
, setResamplerIndex
,, ALsizei
)
1351 DECL_THUNK0(ALsizei
, Source
, getResamplerIndex
, const)
1352 DECL_THUNK1(void, Source
, setAirAbsorptionFactor
,, ALfloat
)
1353 DECL_THUNK0(ALfloat
, Source
, getAirAbsorptionFactor
, const)
1354 DECL_THUNK3(void, Source
, setGainAuto
,, bool, bool, bool)
1355 DECL_THUNK0(BoolTriple
, Source
, getGainAuto
, const)
1356 DECL_THUNK1(void, Source
, setDirectFilter
,, const FilterParams
&)
1357 DECL_THUNK2(void, Source
, setSendFilter
,, ALuint
, const FilterParams
&)
1358 DECL_THUNK2(void, Source
, setAuxiliarySend
,, AuxiliaryEffectSlot
, ALuint
)
1359 DECL_THUNK3(void, Source
, setAuxiliarySendFilter
,, AuxiliaryEffectSlot
, ALuint
, const FilterParams
&)
1360 void Source::release()