17 #include "auxeffectslot.h"
18 #include "sourcegroup.h"
23 class ALBufferStream
{
24 SharedPtr
<Decoder
> mDecoder
;
36 Vector
<ALuint
> mBufferIds
;
39 std::pair
<uint64_t,uint64_t> mLoopPts
;
40 volatile bool mHasLooped
;
44 ALBufferStream(SharedPtr
<Decoder
> decoder
, ALuint updatelen
, ALuint numupdates
)
45 : mDecoder(decoder
), mUpdateLen(updatelen
), mNumUpdates(numupdates
),
46 mFormat(AL_NONE
), mFrequency(0), mFrameSize(0), mSilence(0),
47 mCurrentIdx(0), mLoopPts
{0,0}, mHasLooped(false), mDone(false)
49 virtual ~ALBufferStream()
51 if(!mBufferIds
.empty())
53 alDeleteBuffers(mBufferIds
.size(), &mBufferIds
[0]);
58 uint64_t getLength() const { return mDecoder
->getLength(); }
59 uint64_t getPosition() const { return mDecoder
->getPosition(); }
61 ALuint
getNumUpdates() const { return mNumUpdates
; }
62 ALuint
getUpdateLength() const { return mUpdateLen
; }
64 bool seek(uint64_t pos
)
66 if(!mDecoder
->seek(pos
))
75 ALuint srate
= mDecoder
->getFrequency();
76 ChannelConfig chans
= mDecoder
->getChannelConfig();
77 SampleType type
= mDecoder
->getSampleType();
79 mLoopPts
= mDecoder
->getLoopPoints();
80 if(mLoopPts
.first
>= mLoopPts
.second
)
83 mLoopPts
.second
= std::numeric_limits
<uint64_t>::max();
86 mFormat
= GetFormat(chans
, type
);
88 mFrameSize
= FramesToBytes(1, chans
, type
);
90 mData
.resize(mUpdateLen
* mFrameSize
);
91 if(type
== SampleType::UInt8
) mSilence
= 0x80;
92 else if(type
== SampleType::Mulaw
) mSilence
= 0x7f;
95 mBufferIds
.assign(mNumUpdates
, 0);
96 alGenBuffers(mBufferIds
.size(), &mBufferIds
[0]);
99 uint64_t getLoopStart() const { return mLoopPts
.first
; }
100 uint64_t getLoopEnd() const { return mLoopPts
.second
; }
102 bool hasLooped() const { return mHasLooped
; }
103 bool hasMoreData() const { return !mDone
; }
104 bool streamMoreData(ALuint srcid
, bool loop
)
106 if(mDone
) return false;
108 ALuint len
= mUpdateLen
;
109 uint64_t pos
= mDecoder
->getPosition();
112 if(pos
<= mLoopPts
.second
)
113 len
= std::min
<uint64_t>(len
, mLoopPts
.second
- pos
);
118 ALuint frames
= mDecoder
->read(&mData
[0], len
);
119 if(loop
&& frames
< mUpdateLen
&& pos
+frames
> 0)
121 if(pos
+frames
< mLoopPts
.second
)
123 mLoopPts
.second
= pos
+frames
;
124 mLoopPts
.first
= std::min(mLoopPts
.first
, mLoopPts
.second
-1);
128 if(!mDecoder
->seek(mLoopPts
.first
))
132 len
= std::min
<uint64_t>(mUpdateLen
-frames
, mLoopPts
.second
-mLoopPts
.first
);
133 ALuint got
= mDecoder
->read(&mData
[frames
*mFrameSize
], len
);
136 } while(frames
< mUpdateLen
);
138 if(frames
< mUpdateLen
)
141 if(frames
== 0) return false;
142 std::fill(mData
.begin() + frames
*mFrameSize
, mData
.end(), mSilence
);
145 alBufferData(mBufferIds
[mCurrentIdx
], mFormat
, &mData
[0], mData
.size(), mFrequency
);
146 alSourceQueueBuffers(srcid
, 1, &mBufferIds
[mCurrentIdx
]);
147 mCurrentIdx
= (mCurrentIdx
+1) % mBufferIds
.size();
153 ALSource::ALSource(ALContext
*context
)
154 : mContext(context
), mId(0), mBuffer(0), mGroup(nullptr), mIsAsync(false),
155 mDirectFilter(AL_FILTER_NULL
)
160 ALSource::~ALSource()
165 void ALSource::resetProperties()
168 mGroup
->removeSource(this);
171 mPaused
.store(false, std::memory_order_release
);
179 mMaxDist
= std::numeric_limits
<float>::max();
180 mPosition
= Vector3(0.0f
);
181 mVelocity
= Vector3(0.0f
);
182 mDirection
= Vector3(0.0f
);
183 mOrientation
[0] = Vector3(0.0f
, 0.0f
, -1.0f
);
184 mOrientation
[1] = Vector3(0.0f
, 1.0f
, 0.0f
);
185 mConeInnerAngle
= 360.0f
;
186 mConeOuterAngle
= 360.0f
;
187 mConeOuterGain
= 0.0f
;
188 mConeOuterGainHF
= 1.0f
;
189 mRolloffFactor
= 1.0f
;
190 mRoomRolloffFactor
= 0.0f
;
191 mDopplerFactor
= 1.0f
;
194 mStereoAngles
[0] = F_PI
/ 6.0f
;
195 mStereoAngles
[1] = -F_PI
/ 6.0f
;
196 mAirAbsorptionFactor
= 0.0f
;
197 mDryGainHFAuto
= true;
199 mWetGainHFAuto
= true;
201 mContext
->alDeleteFilters(1, &mDirectFilter
);
203 for(auto &i
: mEffectSlots
)
206 i
.second
.mSlot
->removeSourceSend(this, i
.first
);
208 mContext
->alDeleteFilters(1, &i
.second
.mFilter
);
210 mEffectSlots
.clear();
215 void ALSource::applyProperties(bool looping
, ALuint offset
) const
217 alSourcei(mId
, AL_LOOPING
, looping
? AL_TRUE
: AL_FALSE
);
218 alSourcei(mId
, AL_SAMPLE_OFFSET
, offset
);
221 alSourcef(mId
, AL_PITCH
, mPitch
* mGroup
->getAppliedPitch());
222 alSourcef(mId
, AL_GAIN
, mGain
* mGroup
->getAppliedGain());
226 alSourcef(mId
, AL_PITCH
, mPitch
);
227 alSourcef(mId
, AL_GAIN
, mGain
);
229 alSourcef(mId
, AL_MIN_GAIN
, mMinGain
);
230 alSourcef(mId
, AL_MAX_GAIN
, mMaxGain
);
231 alSourcef(mId
, AL_REFERENCE_DISTANCE
, mRefDist
);
232 alSourcef(mId
, AL_MAX_DISTANCE
, mMaxDist
);
233 alSourcefv(mId
, AL_POSITION
, mPosition
.getPtr());
234 alSourcefv(mId
, AL_VELOCITY
, mVelocity
.getPtr());
235 alSourcefv(mId
, AL_DIRECTION
, mDirection
.getPtr());
236 if(mContext
->hasExtension(EXT_BFORMAT
))
237 alSourcefv(mId
, AL_ORIENTATION
, &mOrientation
[0][0]);
238 alSourcef(mId
, AL_CONE_INNER_ANGLE
, mConeInnerAngle
);
239 alSourcef(mId
, AL_CONE_OUTER_ANGLE
, mConeOuterAngle
);
240 alSourcef(mId
, AL_CONE_OUTER_GAIN
, mConeOuterGain
);
241 alSourcef(mId
, AL_ROLLOFF_FACTOR
, mRolloffFactor
);
242 alSourcef(mId
, AL_DOPPLER_FACTOR
, mDopplerFactor
);
243 if(mContext
->hasExtension(EXT_SOURCE_RADIUS
))
244 alSourcef(mId
, AL_SOURCE_RADIUS
, mRadius
);
245 if(mContext
->hasExtension(EXT_STEREO_ANGLES
))
246 alSourcefv(mId
, AL_STEREO_ANGLES
, mStereoAngles
);
247 alSourcei(mId
, AL_SOURCE_RELATIVE
, mRelative
? AL_TRUE
: AL_FALSE
);
248 if(mContext
->hasExtension(EXT_EFX
))
250 alSourcef(mId
, AL_CONE_OUTER_GAINHF
, mConeOuterGainHF
);
251 alSourcef(mId
, AL_ROOM_ROLLOFF_FACTOR
, mRoomRolloffFactor
);
252 alSourcef(mId
, AL_AIR_ABSORPTION_FACTOR
, mAirAbsorptionFactor
);
253 alSourcei(mId
, AL_DIRECT_FILTER_GAINHF_AUTO
, mDryGainHFAuto
? AL_TRUE
: AL_FALSE
);
254 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
, mWetGainAuto
? AL_TRUE
: AL_FALSE
);
255 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
, mWetGainHFAuto
? AL_TRUE
: AL_FALSE
);
256 alSourcei(mId
, AL_DIRECT_FILTER
, mDirectFilter
);
257 for(const auto &i
: mEffectSlots
)
259 ALuint slotid
= (i
.second
.mSlot
? i
.second
.mSlot
->getId() : 0);
260 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, i
.first
, i
.second
.mFilter
);
266 void ALSource::setGroup(ALSourceGroup
*group
)
269 mGroup
->removeSource(this);
274 void ALSource::unsetGroup()
280 void ALSource::groupUpdate()
286 alSourcef(mId
, AL_PITCH
, mPitch
* mGroup
->getAppliedPitch());
287 alSourcef(mId
, AL_GAIN
, mGain
* mGroup
->getAppliedGain());
291 alSourcef(mId
, AL_PITCH
, mPitch
);
292 alSourcef(mId
, AL_GAIN
, mGain
);
297 void ALSource::groupPropUpdate(ALfloat gain
, ALfloat pitch
)
301 alSourcef(mId
, AL_PITCH
, mPitch
* pitch
);
302 alSourcef(mId
, AL_GAIN
, mGain
* gain
);
307 void ALSource::play(Buffer
*buffer
)
309 ALBuffer
*albuf
= cast
<ALBuffer
*>(buffer
);
310 if(!albuf
) throw std::runtime_error("Buffer is not valid");
311 CheckContext(mContext
);
312 CheckContext(albuf
->getContext());
314 if(!albuf
->isReady())
315 throw std::runtime_error("Buffer is not ready");
317 if(mIsAsync
.load(std::memory_order_acquire
))
319 mContext
->removeStream(this);
320 mIsAsync
.store(false, std::memory_order_release
);
325 mId
= mContext
->getSourceId(mPriority
);
326 applyProperties(mLooping
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
331 alSourcei(mId
, AL_BUFFER
, 0);
332 alSourcei(mId
, AL_LOOPING
, mLooping
? AL_TRUE
: AL_FALSE
);
333 alSourcei(mId
, AL_SAMPLE_OFFSET
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
340 mBuffer
->removeSource(this);
342 mBuffer
->addSource(this);
344 alSourcei(mId
, AL_BUFFER
, mBuffer
->getId());
346 mPaused
.store(false, std::memory_order_release
);
349 void ALSource::play(SharedPtr
<Decoder
> decoder
, ALuint updatelen
, ALuint queuesize
)
352 throw std::runtime_error("Update length out of range");
354 throw std::runtime_error("Queue size out of range");
355 CheckContext(mContext
);
357 std::unique_ptr
<ALBufferStream
> stream(new ALBufferStream(decoder
, updatelen
, queuesize
));
360 if(mIsAsync
.load(std::memory_order_acquire
))
362 mContext
->removeStream(this);
363 mIsAsync
.store(false, std::memory_order_release
);
368 mId
= mContext
->getSourceId(mPriority
);
369 applyProperties(false, 0);
374 alSourcei(mId
, AL_BUFFER
, 0);
375 alSourcei(mId
, AL_LOOPING
, AL_FALSE
);
376 alSourcei(mId
, AL_SAMPLE_OFFSET
, 0);
380 mBuffer
->removeSource(this);
383 mStream
= std::move(stream
);
385 mStream
->seek(mOffset
);
388 for(ALuint i
= 0;i
< mStream
->getNumUpdates();i
++)
390 if(!mStream
->streamMoreData(mId
, mLooping
))
394 mPaused
.store(false, std::memory_order_release
);
396 mContext
->addStream(this);
397 mIsAsync
.store(true, std::memory_order_release
);
401 void ALSource::makeStopped()
403 if(mIsAsync
.load(std::memory_order_acquire
))
405 mContext
->removeStreamNoLock(this);
406 mIsAsync
.store(false, std::memory_order_release
);
411 alSourcei(mId
, AL_BUFFER
, 0);
412 if(mContext
->hasExtension(EXT_EFX
))
414 alSourcei(mId
, AL_DIRECT_FILTER
, AL_FILTER_NULL
);
415 for(auto &i
: mEffectSlots
)
416 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, 0, i
.first
, AL_FILTER_NULL
);
418 mContext
->insertSourceId(mId
);
423 mBuffer
->removeSource(this);
428 mPaused
.store(false, std::memory_order_release
);
430 mContext
->send(&MessageHandler::sourceStopped
, this, true);
433 void ALSource::stop()
435 CheckContext(mContext
);
437 if(mIsAsync
.load(std::memory_order_acquire
))
439 mContext
->removeStream(this);
440 mIsAsync
.store(false, std::memory_order_release
);
446 alSourcei(mId
, AL_BUFFER
, 0);
447 if(mContext
->hasExtension(EXT_EFX
))
449 alSourcei(mId
, AL_DIRECT_FILTER
, AL_FILTER_NULL
);
450 for(auto &i
: mEffectSlots
)
451 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, 0, i
.first
, AL_FILTER_NULL
);
453 mContext
->insertSourceId(mId
);
458 mBuffer
->removeSource(this);
463 mPaused
.store(false, std::memory_order_release
);
467 void ALSource::checkPaused()
469 if(mPaused
.load(std::memory_order_acquire
) || mId
== 0)
473 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
474 // Streaming sources may be in a stopped state if underrun
475 mPaused
.store((state
== AL_PAUSED
) ||
476 (state
== AL_STOPPED
&& mStream
&& mStream
->hasMoreData()),
477 std::memory_order_release
);
480 void ALSource::pause()
482 CheckContext(mContext
);
483 if(mPaused
.load(std::memory_order_acquire
))
488 std::lock_guard
<std::mutex
> lock(mMutex
);
491 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
492 // Streaming sources may be in a stopped state if underrun
493 mPaused
.store((state
== AL_PAUSED
) ||
494 (state
== AL_STOPPED
&& mStream
&& mStream
->hasMoreData()),
495 std::memory_order_release
);
499 void ALSource::resume()
501 CheckContext(mContext
);
502 if(!mPaused
.load(std::memory_order_acquire
))
507 mPaused
.store(false, std::memory_order_release
);
511 bool ALSource::isPlaying() const
513 CheckContext(mContext
);
514 if(mId
== 0) return false;
517 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
519 throw std::runtime_error("Source state error");
521 return state
== AL_PLAYING
|| (!mPaused
.load(std::memory_order_acquire
) &&
522 mStream
&& mStream
->hasMoreData());
525 bool ALSource::isPaused() const
527 CheckContext(mContext
);
528 if(mId
== 0) return false;
531 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
533 throw std::runtime_error("Source state error");
535 return state
== AL_PAUSED
|| mPaused
.load(std::memory_order_acquire
);
539 ALint
ALSource::refillBufferStream()
542 alGetSourcei(mId
, AL_BUFFERS_PROCESSED
, &processed
);
546 alSourceUnqueueBuffers(mId
, 1, &buf
);
551 alGetSourcei(mId
, AL_BUFFERS_QUEUED
, &queued
);
552 for(;(ALuint
)queued
< mStream
->getNumUpdates();queued
++)
554 if(!mStream
->streamMoreData(mId
, mLooping
))
562 void ALSource::update()
564 CheckContext(mContext
);
568 void ALSource::updateNoCtxCheck()
575 if(!mIsAsync
.load(std::memory_order_acquire
))
578 mContext
->send(&MessageHandler::sourceStopped
, this, false);
584 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
585 if(state
!= AL_PLAYING
&& state
!= AL_PAUSED
)
588 mContext
->send(&MessageHandler::sourceStopped
, this, false);
593 bool ALSource::updateAsync()
595 std::lock_guard
<std::mutex
> lock(mMutex
);
597 ALint queued
= refillBufferStream();
600 mIsAsync
.store(false, std::memory_order_release
);
603 if(!mPaused
.load(std::memory_order_acquire
))
606 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
607 if(state
!= AL_PLAYING
)
609 refillBufferStream();
617 void ALSource::setPriority(ALuint priority
)
619 mPriority
= priority
;
623 void ALSource::setOffset(uint64_t offset
)
625 CheckContext(mContext
);
634 if(offset
>= std::numeric_limits
<ALint
>::max())
635 throw std::runtime_error("Offset out of range");
637 alSourcei(mId
, AL_SAMPLE_OFFSET
, (ALint
)offset
);
638 if(alGetError() != AL_NO_ERROR
)
639 throw std::runtime_error("Offset out of range");
643 std::lock_guard
<std::mutex
> lock(mMutex
);
644 if(!mStream
->seek(offset
))
645 throw std::runtime_error("Failed to seek to offset");
647 alSourcei(mId
, AL_BUFFER
, 0);
648 ALint queued
= refillBufferStream();
649 if(queued
> 0 && !mPaused
)
654 uint64_t ALSource::getOffset(uint64_t *latency
) const
656 CheckContext(mContext
);
666 std::lock_guard
<std::mutex
> lock(mMutex
);
667 ALint queued
= 0, state
= -1, srcpos
= 0;
668 alGetSourcei(mId
, AL_BUFFERS_QUEUED
, &queued
);
669 if(latency
&& mContext
->hasExtension(SOFT_source_latency
))
672 mContext
->alGetSourcei64vSOFT(mId
, AL_SAMPLE_OFFSET_LATENCY_SOFT
, val
);
678 alGetSourcei(mId
, AL_SAMPLE_OFFSET
, &srcpos
);
679 if(latency
) *latency
= 0;
681 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
683 uint64_t pos
= mStream
->getPosition();
684 if(state
!= AL_STOPPED
)
686 // The amount of samples in the queue waiting to play
687 ALuint inqueue
= queued
*mStream
->getUpdateLength() - srcpos
;
692 if(pos
< mStream
->getLoopStart() && mStream
->hasLooped())
694 uint64_t looplen
= mStream
->getLoopEnd() - mStream
->getLoopStart();
697 } while(pos
< mStream
->getLoopStart());
700 else if(!mStream
->hasLooped())
702 // A non-looped stream should never have more samples queued
703 // than have been read...
708 uint64_t looplen
= mStream
->getLoopEnd() - mStream
->getLoopStart();
709 while(pos
< mStream
->getLoopStart())
718 if(latency
&& mContext
->hasExtension(SOFT_source_latency
))
721 mContext
->alGetSourcei64vSOFT(mId
, AL_SAMPLE_OFFSET_LATENCY_SOFT
, val
);
727 alGetSourcei(mId
, AL_SAMPLE_OFFSET
, &srcpos
);
728 if(latency
) *latency
= 0;
734 void ALSource::setLooping(bool looping
)
736 CheckContext(mContext
);
739 alSourcei(mId
, AL_LOOPING
, looping
? AL_TRUE
: AL_FALSE
);
744 void ALSource::setPitch(ALfloat pitch
)
747 throw std::runtime_error("Pitch out of range");
748 CheckContext(mContext
);
750 alSourcef(mId
, AL_PITCH
, pitch
* (mGroup
? mGroup
->getAppliedPitch() : 1.0f
));
755 void ALSource::setGain(ALfloat gain
)
758 throw std::runtime_error("Gain out of range");
759 CheckContext(mContext
);
761 alSourcef(mId
, AL_GAIN
, gain
* (mGroup
? mGroup
->getAppliedGain() : 1.0f
));
765 void ALSource::setGainRange(ALfloat mingain
, ALfloat maxgain
)
767 if(!(mingain
>= 0.0f
&& maxgain
<= 1.0f
&& maxgain
>= mingain
))
768 throw std::runtime_error("Gain range out of range");
769 CheckContext(mContext
);
772 alSourcef(mId
, AL_MIN_GAIN
, mingain
);
773 alSourcef(mId
, AL_MAX_GAIN
, maxgain
);
780 void ALSource::setDistanceRange(ALfloat refdist
, ALfloat maxdist
)
782 if(!(refdist
>= 0.0f
&& maxdist
<= std::numeric_limits
<float>::max() && refdist
<= maxdist
))
783 throw std::runtime_error("Distance range out of range");
784 CheckContext(mContext
);
787 alSourcef(mId
, AL_REFERENCE_DISTANCE
, refdist
);
788 alSourcef(mId
, AL_MAX_DISTANCE
, maxdist
);
795 void ALSource::setPosition(ALfloat x
, ALfloat y
, ALfloat z
)
797 CheckContext(mContext
);
799 alSource3f(mId
, AL_POSITION
, x
, y
, z
);
805 void ALSource::setPosition(const ALfloat
*pos
)
807 CheckContext(mContext
);
809 alSourcefv(mId
, AL_POSITION
, pos
);
810 mPosition
[0] = pos
[0];
811 mPosition
[1] = pos
[1];
812 mPosition
[2] = pos
[2];
815 void ALSource::setVelocity(ALfloat x
, ALfloat y
, ALfloat z
)
817 CheckContext(mContext
);
819 alSource3f(mId
, AL_VELOCITY
, x
, y
, z
);
825 void ALSource::setVelocity(const ALfloat
*vel
)
827 CheckContext(mContext
);
829 alSourcefv(mId
, AL_VELOCITY
, vel
);
830 mVelocity
[0] = vel
[0];
831 mVelocity
[1] = vel
[1];
832 mVelocity
[2] = vel
[2];
835 void ALSource::setDirection(ALfloat x
, ALfloat y
, ALfloat z
)
837 CheckContext(mContext
);
839 alSource3f(mId
, AL_DIRECTION
, x
, y
, z
);
845 void ALSource::setDirection(const ALfloat
*dir
)
847 CheckContext(mContext
);
849 alSourcefv(mId
, AL_DIRECTION
, dir
);
850 mDirection
[0] = dir
[0];
851 mDirection
[1] = dir
[1];
852 mDirection
[2] = dir
[2];
855 void ALSource::setOrientation(ALfloat x1
, ALfloat y1
, ALfloat z1
, ALfloat x2
, ALfloat y2
, ALfloat z2
)
857 CheckContext(mContext
);
860 ALfloat ori
[6] = { x1
, y1
, z1
, x2
, y2
, z2
};
861 if(mContext
->hasExtension(EXT_BFORMAT
))
862 alSourcefv(mId
, AL_ORIENTATION
, ori
);
863 alSourcefv(mId
, AL_DIRECTION
, ori
);
865 mDirection
[0] = mOrientation
[0][0] = x1
;
866 mDirection
[1] = mOrientation
[0][1] = y1
;
867 mDirection
[2] = mOrientation
[0][2] = z1
;
868 mOrientation
[1][0] = x2
;
869 mOrientation
[1][1] = y2
;
870 mOrientation
[1][2] = z2
;
873 void ALSource::setOrientation(const ALfloat
*at
, const ALfloat
*up
)
875 CheckContext(mContext
);
878 ALfloat ori
[6] = { at
[0], at
[1], at
[2], up
[0], up
[1], up
[2] };
879 if(mContext
->hasExtension(EXT_BFORMAT
))
880 alSourcefv(mId
, AL_ORIENTATION
, ori
);
881 alSourcefv(mId
, AL_DIRECTION
, ori
);
883 mDirection
[0] = mOrientation
[0][0] = at
[0];
884 mDirection
[1] = mOrientation
[0][1] = at
[1];
885 mDirection
[2] = mOrientation
[0][2] = at
[2];
886 mOrientation
[1][0] = up
[0];
887 mOrientation
[1][1] = up
[1];
888 mOrientation
[1][2] = up
[2];
891 void ALSource::setOrientation(const ALfloat
*ori
)
893 CheckContext(mContext
);
896 if(mContext
->hasExtension(EXT_BFORMAT
))
897 alSourcefv(mId
, AL_ORIENTATION
, ori
);
898 alSourcefv(mId
, AL_DIRECTION
, ori
);
900 mDirection
[0] = mOrientation
[0][0] = ori
[0];
901 mDirection
[1] = mOrientation
[0][1] = ori
[1];
902 mDirection
[2] = mOrientation
[0][2] = ori
[2];
903 mOrientation
[1][0] = ori
[3];
904 mOrientation
[1][1] = ori
[4];
905 mOrientation
[1][2] = ori
[5];
909 void ALSource::setConeAngles(ALfloat inner
, ALfloat outer
)
911 if(!(inner
>= 0.0f
&& outer
<= 360.0f
&& outer
>= inner
))
912 throw std::runtime_error("Cone angles out of range");
913 CheckContext(mContext
);
916 alSourcef(mId
, AL_CONE_INNER_ANGLE
, inner
);
917 alSourcef(mId
, AL_CONE_OUTER_ANGLE
, outer
);
919 mConeInnerAngle
= inner
;
920 mConeOuterAngle
= outer
;
923 void ALSource::setOuterConeGains(ALfloat gain
, ALfloat gainhf
)
925 if(!(gain
>= 0.0f
&& gain
<= 1.0f
&& gainhf
>= 0.0f
&& gainhf
<= 1.0f
))
926 throw std::runtime_error("Outer cone gain out of range");
927 CheckContext(mContext
);
930 alSourcef(mId
, AL_CONE_OUTER_GAIN
, gain
);
931 if(mContext
->hasExtension(EXT_EFX
))
932 alSourcef(mId
, AL_CONE_OUTER_GAINHF
, gainhf
);
934 mConeOuterGain
= gain
;
935 mConeOuterGainHF
= gainhf
;
939 void ALSource::setRolloffFactors(ALfloat factor
, ALfloat roomfactor
)
941 if(!(factor
>= 0.0f
&& roomfactor
>= 0.0f
))
942 throw std::runtime_error("Rolloff factor out of range");
943 CheckContext(mContext
);
946 alSourcef(mId
, AL_ROLLOFF_FACTOR
, factor
);
947 if(mContext
->hasExtension(EXT_EFX
))
948 alSourcef(mId
, AL_ROOM_ROLLOFF_FACTOR
, roomfactor
);
950 mRolloffFactor
= factor
;
951 mRoomRolloffFactor
= roomfactor
;
954 void ALSource::setDopplerFactor(ALfloat factor
)
956 if(!(factor
>= 0.0f
&& factor
<= 1.0f
))
957 throw std::runtime_error("Doppler factor out of range");
958 CheckContext(mContext
);
960 alSourcef(mId
, AL_DOPPLER_FACTOR
, factor
);
961 mDopplerFactor
= factor
;
964 void ALSource::setAirAbsorptionFactor(ALfloat factor
)
966 if(!(factor
>= 0.0f
&& factor
<= 10.0f
))
967 throw std::runtime_error("Absorption factor out of range");
968 CheckContext(mContext
);
969 if(mId
!= 0 && mContext
->hasExtension(EXT_EFX
))
970 alSourcef(mId
, AL_AIR_ABSORPTION_FACTOR
, factor
);
971 mAirAbsorptionFactor
= factor
;
974 void ALSource::setRadius(ALfloat radius
)
976 if(!(mRadius
>= 0.0f
))
977 throw std::runtime_error("Radius out of range");
978 CheckContext(mContext
);
979 if(mId
!= 0 && mContext
->hasExtension(EXT_SOURCE_RADIUS
))
980 alSourcef(mId
, AL_SOURCE_RADIUS
, radius
);
984 void ALSource::setStereoAngles(ALfloat leftAngle
, ALfloat rightAngle
)
986 CheckContext(mContext
);
987 if(mId
!= 0 && mContext
->hasExtension(EXT_STEREO_ANGLES
))
989 ALfloat angles
[2] = { leftAngle
, rightAngle
};
990 alSourcefv(mId
, AL_STEREO_ANGLES
, angles
);
992 mStereoAngles
[0] = leftAngle
;
993 mStereoAngles
[1] = rightAngle
;
996 void ALSource::setRelative(bool relative
)
998 CheckContext(mContext
);
1000 alSourcei(mId
, AL_SOURCE_RELATIVE
, relative
? AL_TRUE
: AL_FALSE
);
1001 mRelative
= relative
;
1004 void ALSource::setGainAuto(bool directhf
, bool send
, bool sendhf
)
1006 CheckContext(mContext
);
1007 if(mId
!= 0 && mContext
->hasExtension(EXT_EFX
))
1009 alSourcei(mId
, AL_DIRECT_FILTER_GAINHF_AUTO
, directhf
? AL_TRUE
: AL_FALSE
);
1010 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
, send
? AL_TRUE
: AL_FALSE
);
1011 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
, sendhf
? AL_TRUE
: AL_FALSE
);
1013 mDryGainHFAuto
= directhf
;
1014 mWetGainAuto
= send
;
1015 mWetGainHFAuto
= sendhf
;
1019 void ALSource::setFilterParams(ALuint
&filterid
, const FilterParams
¶ms
)
1021 if(!mContext
->hasExtension(EXT_EFX
))
1024 if(!(params
.mGain
< 1.0f
|| params
.mGainHF
< 1.0f
|| params
.mGainLF
< 1.0f
))
1027 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_NULL
);
1034 mContext
->alGenFilters(1, &filterid
);
1035 if(alGetError() != AL_NO_ERROR
)
1036 throw std::runtime_error("Failed to create Filter");
1038 bool filterset
= false;
1039 if(params
.mGainHF
< 1.0f
&& params
.mGainLF
< 1.0f
)
1041 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_BANDPASS
);
1042 if(alGetError() == AL_NO_ERROR
)
1044 mContext
->alFilterf(filterid
, AL_BANDPASS_GAIN
, std::min
<ALfloat
>(params
.mGain
, 1.0f
));
1045 mContext
->alFilterf(filterid
, AL_BANDPASS_GAINHF
, std::min
<ALfloat
>(params
.mGainHF
, 1.0f
));
1046 mContext
->alFilterf(filterid
, AL_BANDPASS_GAINLF
, std::min
<ALfloat
>(params
.mGainLF
, 1.0f
));
1050 if(!filterset
&& !(params
.mGainHF
< 1.0f
) && params
.mGainLF
< 1.0f
)
1052 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_HIGHPASS
);
1053 if(alGetError() == AL_NO_ERROR
)
1055 mContext
->alFilterf(filterid
, AL_HIGHPASS_GAIN
, std::min
<ALfloat
>(params
.mGain
, 1.0f
));
1056 mContext
->alFilterf(filterid
, AL_HIGHPASS_GAINLF
, std::min
<ALfloat
>(params
.mGainLF
, 1.0f
));
1062 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_LOWPASS
);
1063 if(alGetError() == AL_NO_ERROR
)
1065 mContext
->alFilterf(filterid
, AL_LOWPASS_GAIN
, std::min
<ALfloat
>(params
.mGain
, 1.0f
));
1066 mContext
->alFilterf(filterid
, AL_LOWPASS_GAINHF
, std::min
<ALfloat
>(params
.mGainHF
, 1.0f
));
1073 void ALSource::setDirectFilter(const FilterParams
&filter
)
1075 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1076 throw std::runtime_error("Gain value out of range");
1077 CheckContext(mContext
);
1079 setFilterParams(mDirectFilter
, filter
);
1081 alSourcei(mId
, AL_DIRECT_FILTER
, mDirectFilter
);
1084 void ALSource::setSendFilter(ALuint send
, const FilterParams
&filter
)
1086 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1087 throw std::runtime_error("Gain value out of range");
1088 CheckContext(mContext
);
1090 SendPropMap::iterator siter
= mEffectSlots
.find(send
);
1091 if(siter
== mEffectSlots
.end())
1093 ALuint filterid
= 0;
1095 setFilterParams(filterid
, filter
);
1096 if(!filterid
) return;
1098 siter
= mEffectSlots
.insert(std::make_pair(send
, SendProps(filterid
))).first
;
1101 setFilterParams(siter
->second
.mFilter
, filter
);
1105 ALuint slotid
= (siter
->second
.mSlot
? siter
->second
.mSlot
->getId() : 0);
1106 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->second
.mFilter
);
1110 void ALSource::setAuxiliarySend(AuxiliaryEffectSlot
*auxslot
, ALuint send
)
1112 ALAuxiliaryEffectSlot
*slot
= 0;
1115 slot
= cast
<ALAuxiliaryEffectSlot
*>(auxslot
);
1116 if(!slot
) throw std::runtime_error("Invalid AuxiliaryEffectSlot");
1117 CheckContext(slot
->getContext());
1119 CheckContext(mContext
);
1121 SendPropMap::iterator siter
= mEffectSlots
.find(send
);
1122 if(siter
== mEffectSlots
.end())
1125 slot
->addSourceSend(this, send
);
1126 siter
= mEffectSlots
.insert(std::make_pair(send
, SendProps(slot
))).first
;
1128 else if(siter
->second
.mSlot
!= slot
)
1130 if(slot
) slot
->addSourceSend(this, send
);
1131 if(siter
->second
.mSlot
)
1132 siter
->second
.mSlot
->removeSourceSend(this, send
);
1133 siter
->second
.mSlot
= slot
;
1138 ALuint slotid
= (siter
->second
.mSlot
? siter
->second
.mSlot
->getId() : 0);
1139 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->second
.mFilter
);
1143 void ALSource::setAuxiliarySendFilter(AuxiliaryEffectSlot
*auxslot
, ALuint send
, const FilterParams
&filter
)
1145 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1146 throw std::runtime_error("Gain value out of range");
1147 ALAuxiliaryEffectSlot
*slot
= 0;
1150 slot
= cast
<ALAuxiliaryEffectSlot
*>(auxslot
);
1151 if(!slot
) throw std::runtime_error("Invalid AuxiliaryEffectSlot");
1152 CheckContext(slot
->getContext());
1154 CheckContext(mContext
);
1156 SendPropMap::iterator siter
= mEffectSlots
.find(send
);
1157 if(siter
== mEffectSlots
.end())
1159 ALuint filterid
= 0;
1161 setFilterParams(filterid
, filter
);
1162 if(!filterid
&& !slot
)
1165 if(slot
) slot
->addSourceSend(this, send
);
1166 siter
= mEffectSlots
.insert(std::make_pair(send
, SendProps(slot
, filterid
))).first
;
1170 if(siter
->second
.mSlot
!= slot
)
1172 if(slot
) slot
->addSourceSend(this, send
);
1173 if(siter
->second
.mSlot
)
1174 siter
->second
.mSlot
->removeSourceSend(this, send
);
1175 siter
->second
.mSlot
= slot
;
1177 setFilterParams(siter
->second
.mFilter
, filter
);
1182 ALuint slotid
= (siter
->second
.mSlot
? siter
->second
.mSlot
->getId() : 0);
1183 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->second
.mFilter
);
1188 void ALSource::release()
1190 CheckContext(mContext
);
1192 if(mIsAsync
.load(std::memory_order_acquire
))
1194 mContext
->removeStream(this);
1195 mIsAsync
.store(false, std::memory_order_release
);
1200 alSourceRewind(mId
);
1201 alSourcei(mId
, AL_BUFFER
, 0);
1202 if(mContext
->hasExtension(EXT_EFX
))
1204 alSourcei(mId
, AL_DIRECT_FILTER
, AL_FILTER_NULL
);
1205 for(auto &i
: mEffectSlots
)
1206 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, 0, i
.first
, AL_FILTER_NULL
);
1208 mContext
->insertSourceId(mId
);
1212 mContext
->freeSource(this);
1215 mContext
->alDeleteFilters(1, &mDirectFilter
);
1216 mDirectFilter
= AL_FILTER_NULL
;
1218 for(auto &i
: mEffectSlots
)
1221 i
.second
.mSlot
->removeSourceSend(this, i
.first
);
1222 if(i
.second
.mFilter
)
1223 mContext
->alDeleteFilters(1, &i
.second
.mFilter
);
1225 mEffectSlots
.clear();
1228 mBuffer
->removeSource(this);