18 #include "auxeffectslot.h"
19 #include "sourcegroup.h"
24 class ALBufferStream
{
25 SharedPtr
<Decoder
> mDecoder
;
37 Vector
<ALuint
> mBufferIds
;
40 std::pair
<uint64_t,uint64_t> mLoopPts
;
41 std::atomic
<bool> mHasLooped
;
42 std::atomic
<bool> mDone
;
45 ALBufferStream(SharedPtr
<Decoder
> decoder
, ALuint updatelen
, ALuint numupdates
)
46 : mDecoder(decoder
), mUpdateLen(updatelen
), mNumUpdates(numupdates
),
47 mFormat(AL_NONE
), mFrequency(0), mFrameSize(0), mSilence(0),
48 mCurrentIdx(0), mLoopPts
{0,0}, mHasLooped(false), mDone(false)
52 if(!mBufferIds
.empty())
54 alDeleteBuffers(mBufferIds
.size(), &mBufferIds
[0]);
59 uint64_t getLength() const { return mDecoder
->getLength(); }
60 uint64_t getPosition() const { return mDecoder
->getPosition(); }
62 ALuint
getNumUpdates() const { return mNumUpdates
; }
63 ALuint
getUpdateLength() const { return mUpdateLen
; }
65 bool seek(uint64_t pos
)
67 if(!mDecoder
->seek(pos
))
69 mHasLooped
.store(false, std::memory_order_release
);
70 mDone
.store(false, std::memory_order_release
);
76 ALuint srate
= mDecoder
->getFrequency();
77 ChannelConfig chans
= mDecoder
->getChannelConfig();
78 SampleType type
= mDecoder
->getSampleType();
80 mLoopPts
= mDecoder
->getLoopPoints();
81 if(mLoopPts
.first
>= mLoopPts
.second
)
84 mLoopPts
.second
= std::numeric_limits
<uint64_t>::max();
88 mFrameSize
= FramesToBytes(1, chans
, type
);
89 mFormat
= GetFormat(chans
, type
);
90 if(mFormat
== AL_NONE
)
92 std::stringstream sstr
;
93 sstr
<< "Format not supported ("<<GetSampleTypeName(type
)<<", "<<GetChannelConfigName(chans
)<<")";
94 throw std::runtime_error(sstr
.str());
97 mData
.resize(mUpdateLen
* mFrameSize
);
98 if(type
== SampleType::UInt8
) mSilence
= 0x80;
99 else if(type
== SampleType::Mulaw
) mSilence
= 0x7f;
100 else mSilence
= 0x00;
102 mBufferIds
.assign(mNumUpdates
, 0);
103 alGenBuffers(mBufferIds
.size(), &mBufferIds
[0]);
106 uint64_t getLoopStart() const { return mLoopPts
.first
; }
107 uint64_t getLoopEnd() const { return mLoopPts
.second
; }
109 bool hasLooped() const { return mHasLooped
.load(std::memory_order_acquire
); }
110 bool hasMoreData() const { return !mDone
.load(std::memory_order_acquire
); }
111 bool streamMoreData(ALuint srcid
, bool loop
)
113 if(mDone
.load(std::memory_order_acquire
))
118 frames
= mDecoder
->read(&mData
[0], mUpdateLen
);
121 ALuint len
= mUpdateLen
;
122 uint64_t pos
= mDecoder
->getPosition();
123 if(pos
<= mLoopPts
.second
)
124 len
= std::min
<uint64_t>(len
, mLoopPts
.second
- pos
);
128 frames
= mDecoder
->read(&mData
[0], len
);
129 if(frames
< mUpdateLen
&& loop
&& pos
+frames
> 0)
131 if(pos
+frames
< mLoopPts
.second
)
133 mLoopPts
.second
= pos
+frames
;
134 mLoopPts
.first
= std::min(mLoopPts
.first
, mLoopPts
.second
-1);
138 if(!mDecoder
->seek(mLoopPts
.first
))
140 mHasLooped
.store(true, std::memory_order_release
);
142 len
= std::min
<uint64_t>(mUpdateLen
-frames
, mLoopPts
.second
-mLoopPts
.first
);
143 ALuint got
= mDecoder
->read(&mData
[frames
*mFrameSize
], len
);
146 } while(frames
< mUpdateLen
);
149 if(frames
< mUpdateLen
)
151 mDone
.store(true, std::memory_order_release
);
152 if(frames
== 0) return false;
153 std::fill(mData
.begin() + frames
*mFrameSize
, mData
.end(), mSilence
);
156 alBufferData(mBufferIds
[mCurrentIdx
], mFormat
, &mData
[0], mData
.size(), mFrequency
);
157 alSourceQueueBuffers(srcid
, 1, &mBufferIds
[mCurrentIdx
]);
158 mCurrentIdx
= (mCurrentIdx
+1) % mBufferIds
.size();
164 ALSource::ALSource(ALContext
*context
)
165 : mContext(context
), mId(0), mBuffer(0), mGroup(nullptr), mIsAsync(false),
166 mDirectFilter(AL_FILTER_NULL
)
171 ALSource::~ALSource()
176 void ALSource::resetProperties()
179 mGroup
->removeSource(this);
182 mPaused
.store(false, std::memory_order_release
);
190 mMaxDist
= std::numeric_limits
<float>::max();
191 mPosition
= Vector3(0.0f
);
192 mVelocity
= Vector3(0.0f
);
193 mDirection
= Vector3(0.0f
);
194 mOrientation
[0] = Vector3(0.0f
, 0.0f
, -1.0f
);
195 mOrientation
[1] = Vector3(0.0f
, 1.0f
, 0.0f
);
196 mConeInnerAngle
= 360.0f
;
197 mConeOuterAngle
= 360.0f
;
198 mConeOuterGain
= 0.0f
;
199 mConeOuterGainHF
= 1.0f
;
200 mRolloffFactor
= 1.0f
;
201 mRoomRolloffFactor
= 0.0f
;
202 mDopplerFactor
= 1.0f
;
205 mStereoAngles
[0] = F_PI
/ 6.0f
;
206 mStereoAngles
[1] = -F_PI
/ 6.0f
;
207 mAirAbsorptionFactor
= 0.0f
;
208 mDryGainHFAuto
= true;
210 mWetGainHFAuto
= true;
212 mContext
->alDeleteFilters(1, &mDirectFilter
);
214 for(auto &i
: mEffectSlots
)
217 i
.second
.mSlot
->removeSourceSend(this, i
.first
);
219 mContext
->alDeleteFilters(1, &i
.second
.mFilter
);
221 mEffectSlots
.clear();
226 void ALSource::applyProperties(bool looping
, ALuint offset
) const
228 alSourcei(mId
, AL_LOOPING
, looping
? AL_TRUE
: AL_FALSE
);
229 alSourcei(mId
, AL_SAMPLE_OFFSET
, offset
);
232 alSourcef(mId
, AL_PITCH
, mPitch
* mGroup
->getAppliedPitch());
233 alSourcef(mId
, AL_GAIN
, mGain
* mGroup
->getAppliedGain());
237 alSourcef(mId
, AL_PITCH
, mPitch
);
238 alSourcef(mId
, AL_GAIN
, mGain
);
240 alSourcef(mId
, AL_MIN_GAIN
, mMinGain
);
241 alSourcef(mId
, AL_MAX_GAIN
, mMaxGain
);
242 alSourcef(mId
, AL_REFERENCE_DISTANCE
, mRefDist
);
243 alSourcef(mId
, AL_MAX_DISTANCE
, mMaxDist
);
244 alSourcefv(mId
, AL_POSITION
, mPosition
.getPtr());
245 alSourcefv(mId
, AL_VELOCITY
, mVelocity
.getPtr());
246 alSourcefv(mId
, AL_DIRECTION
, mDirection
.getPtr());
247 if(mContext
->hasExtension(EXT_BFORMAT
))
248 alSourcefv(mId
, AL_ORIENTATION
, &mOrientation
[0][0]);
249 alSourcef(mId
, AL_CONE_INNER_ANGLE
, mConeInnerAngle
);
250 alSourcef(mId
, AL_CONE_OUTER_ANGLE
, mConeOuterAngle
);
251 alSourcef(mId
, AL_CONE_OUTER_GAIN
, mConeOuterGain
);
252 alSourcef(mId
, AL_ROLLOFF_FACTOR
, mRolloffFactor
);
253 alSourcef(mId
, AL_DOPPLER_FACTOR
, mDopplerFactor
);
254 if(mContext
->hasExtension(EXT_SOURCE_RADIUS
))
255 alSourcef(mId
, AL_SOURCE_RADIUS
, mRadius
);
256 if(mContext
->hasExtension(EXT_STEREO_ANGLES
))
257 alSourcefv(mId
, AL_STEREO_ANGLES
, mStereoAngles
);
258 alSourcei(mId
, AL_SOURCE_RELATIVE
, mRelative
? AL_TRUE
: AL_FALSE
);
259 if(mContext
->hasExtension(EXT_EFX
))
261 alSourcef(mId
, AL_CONE_OUTER_GAINHF
, mConeOuterGainHF
);
262 alSourcef(mId
, AL_ROOM_ROLLOFF_FACTOR
, mRoomRolloffFactor
);
263 alSourcef(mId
, AL_AIR_ABSORPTION_FACTOR
, mAirAbsorptionFactor
);
264 alSourcei(mId
, AL_DIRECT_FILTER_GAINHF_AUTO
, mDryGainHFAuto
? AL_TRUE
: AL_FALSE
);
265 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
, mWetGainAuto
? AL_TRUE
: AL_FALSE
);
266 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
, mWetGainHFAuto
? AL_TRUE
: AL_FALSE
);
267 alSourcei(mId
, AL_DIRECT_FILTER
, mDirectFilter
);
268 for(const auto &i
: mEffectSlots
)
270 ALuint slotid
= (i
.second
.mSlot
? i
.second
.mSlot
->getId() : 0);
271 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, i
.first
, i
.second
.mFilter
);
277 void ALSource::setGroup(ALSourceGroup
*group
)
280 mGroup
->removeSource(this);
285 void ALSource::unsetGroup()
291 void ALSource::groupUpdate()
297 alSourcef(mId
, AL_PITCH
, mPitch
* mGroup
->getAppliedPitch());
298 alSourcef(mId
, AL_GAIN
, mGain
* mGroup
->getAppliedGain());
302 alSourcef(mId
, AL_PITCH
, mPitch
);
303 alSourcef(mId
, AL_GAIN
, mGain
);
308 void ALSource::groupPropUpdate(ALfloat gain
, ALfloat pitch
)
312 alSourcef(mId
, AL_PITCH
, mPitch
* pitch
);
313 alSourcef(mId
, AL_GAIN
, mGain
* gain
);
318 void ALSource::play(Buffer
*buffer
)
320 ALBuffer
*albuf
= cast
<ALBuffer
*>(buffer
);
321 if(!albuf
) throw std::runtime_error("Buffer is not valid");
322 CheckContext(mContext
);
323 CheckContext(albuf
->getContext());
325 if(!albuf
->isReady())
326 throw std::runtime_error("Buffer is not ready");
328 if(mIsAsync
.load(std::memory_order_acquire
))
330 mContext
->removeStream(this);
331 mIsAsync
.store(false, std::memory_order_release
);
336 mId
= mContext
->getSourceId(mPriority
);
337 applyProperties(mLooping
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
342 alSourcei(mId
, AL_BUFFER
, 0);
343 alSourcei(mId
, AL_LOOPING
, mLooping
? AL_TRUE
: AL_FALSE
);
344 alSourcei(mId
, AL_SAMPLE_OFFSET
, (ALuint
)std::min
<uint64_t>(mOffset
, std::numeric_limits
<ALint
>::max()));
351 mBuffer
->removeSource(this);
353 mBuffer
->addSource(this);
355 alSourcei(mId
, AL_BUFFER
, mBuffer
->getId());
357 mPaused
.store(false, std::memory_order_release
);
360 void ALSource::play(SharedPtr
<Decoder
> decoder
, ALuint updatelen
, ALuint queuesize
)
363 throw std::runtime_error("Update length out of range");
365 throw std::runtime_error("Queue size out of range");
366 CheckContext(mContext
);
368 auto stream
= MakeUnique
<ALBufferStream
>(decoder
, updatelen
, queuesize
);
371 if(mIsAsync
.load(std::memory_order_acquire
))
373 mContext
->removeStream(this);
374 mIsAsync
.store(false, std::memory_order_release
);
379 mId
= mContext
->getSourceId(mPriority
);
380 applyProperties(false, 0);
385 alSourcei(mId
, AL_BUFFER
, 0);
386 alSourcei(mId
, AL_LOOPING
, AL_FALSE
);
387 alSourcei(mId
, AL_SAMPLE_OFFSET
, 0);
391 mBuffer
->removeSource(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
);
412 void ALSource::makeStopped()
414 if(mIsAsync
.load(std::memory_order_acquire
))
416 mContext
->removeStreamNoLock(this);
417 mIsAsync
.store(false, std::memory_order_release
);
423 alSourcei(mId
, AL_BUFFER
, 0);
424 if(mContext
->hasExtension(EXT_EFX
))
426 alSourcei(mId
, AL_DIRECT_FILTER
, AL_FILTER_NULL
);
427 for(auto &i
: mEffectSlots
)
428 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, 0, i
.first
, AL_FILTER_NULL
);
430 mContext
->insertSourceId(mId
);
435 mBuffer
->removeSource(this);
440 mPaused
.store(false, std::memory_order_release
);
443 void ALSource::stop()
445 CheckContext(mContext
);
450 void ALSource::checkPaused()
452 if(mPaused
.load(std::memory_order_acquire
) || mId
== 0)
456 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
457 // Streaming sources may be in a stopped state if underrun
458 mPaused
.store((state
== AL_PAUSED
) ||
459 (state
== AL_STOPPED
&& mStream
&& mStream
->hasMoreData()),
460 std::memory_order_release
);
463 void ALSource::pause()
465 CheckContext(mContext
);
466 if(mPaused
.load(std::memory_order_acquire
))
471 std::lock_guard
<std::mutex
> lock(mMutex
);
474 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
475 // Streaming sources may be in a stopped state if underrun
476 mPaused
.store((state
== AL_PAUSED
) ||
477 (state
== AL_STOPPED
&& mStream
&& mStream
->hasMoreData()),
478 std::memory_order_release
);
482 void ALSource::resume()
484 CheckContext(mContext
);
485 if(!mPaused
.load(std::memory_order_acquire
))
490 mPaused
.store(false, std::memory_order_release
);
494 bool ALSource::isPlaying() const
496 CheckContext(mContext
);
497 if(mId
== 0) return false;
500 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
502 throw std::runtime_error("Source state error");
504 return state
== AL_PLAYING
|| (!mPaused
.load(std::memory_order_acquire
) &&
505 mStream
&& mStream
->hasMoreData());
508 bool ALSource::isPaused() const
510 CheckContext(mContext
);
511 if(mId
== 0) return false;
514 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
516 throw std::runtime_error("Source state error");
518 return state
== AL_PAUSED
|| mPaused
.load(std::memory_order_acquire
);
522 ALint
ALSource::refillBufferStream()
525 alGetSourcei(mId
, AL_BUFFERS_PROCESSED
, &processed
);
529 alSourceUnqueueBuffers(mId
, 1, &buf
);
534 alGetSourcei(mId
, AL_BUFFERS_QUEUED
, &queued
);
535 for(;(ALuint
)queued
< mStream
->getNumUpdates();queued
++)
537 if(!mStream
->streamMoreData(mId
, mLooping
))
545 void ALSource::update()
547 CheckContext(mContext
);
551 void ALSource::updateNoCtxCheck()
558 if(!mIsAsync
.load(std::memory_order_acquire
))
561 mContext
->send(&MessageHandler::sourceStopped
, this);
567 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
568 if(state
!= AL_PLAYING
&& state
!= AL_PAUSED
)
571 mContext
->send(&MessageHandler::sourceStopped
, this);
576 bool ALSource::updateAsync()
578 std::lock_guard
<std::mutex
> lock(mMutex
);
580 ALint queued
= refillBufferStream();
583 mIsAsync
.store(false, std::memory_order_release
);
586 if(!mPaused
.load(std::memory_order_acquire
))
589 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
590 if(state
!= AL_PLAYING
)
597 void ALSource::setPriority(ALuint priority
)
599 mPriority
= priority
;
603 void ALSource::setOffset(uint64_t offset
)
605 CheckContext(mContext
);
614 if(offset
>= std::numeric_limits
<ALint
>::max())
615 throw std::runtime_error("Offset out of range");
617 alSourcei(mId
, AL_SAMPLE_OFFSET
, (ALint
)offset
);
618 if(alGetError() != AL_NO_ERROR
)
619 throw std::runtime_error("Offset out of range");
623 std::lock_guard
<std::mutex
> lock(mMutex
);
624 if(!mStream
->seek(offset
))
625 throw std::runtime_error("Failed to seek to offset");
627 alSourcei(mId
, AL_BUFFER
, 0);
628 ALint queued
= refillBufferStream();
629 if(queued
> 0 && !mPaused
)
634 uint64_t ALSource::getOffset(uint64_t *latency
) const
636 CheckContext(mContext
);
646 std::lock_guard
<std::mutex
> lock(mMutex
);
647 ALint queued
= 0, state
= -1, srcpos
= 0;
648 alGetSourcei(mId
, AL_BUFFERS_QUEUED
, &queued
);
649 if(latency
&& mContext
->hasExtension(SOFT_source_latency
))
652 mContext
->alGetSourcei64vSOFT(mId
, AL_SAMPLE_OFFSET_LATENCY_SOFT
, val
);
658 alGetSourcei(mId
, AL_SAMPLE_OFFSET
, &srcpos
);
659 if(latency
) *latency
= 0;
661 alGetSourcei(mId
, AL_SOURCE_STATE
, &state
);
663 uint64_t pos
= mStream
->getPosition();
664 if(state
!= AL_STOPPED
)
666 // The amount of samples in the queue waiting to play
667 ALuint inqueue
= queued
*mStream
->getUpdateLength() - srcpos
;
672 if(pos
< mStream
->getLoopStart() && mStream
->hasLooped())
674 uint64_t looplen
= mStream
->getLoopEnd() - mStream
->getLoopStart();
677 } while(pos
< mStream
->getLoopStart());
680 else if(!mStream
->hasLooped())
682 // A non-looped stream should never have more samples queued
683 // than have been read...
688 uint64_t looplen
= mStream
->getLoopEnd() - mStream
->getLoopStart();
689 while(pos
< mStream
->getLoopStart())
698 if(latency
&& mContext
->hasExtension(SOFT_source_latency
))
701 mContext
->alGetSourcei64vSOFT(mId
, AL_SAMPLE_OFFSET_LATENCY_SOFT
, val
);
707 alGetSourcei(mId
, AL_SAMPLE_OFFSET
, &srcpos
);
708 if(latency
) *latency
= 0;
714 void ALSource::setLooping(bool looping
)
716 CheckContext(mContext
);
719 alSourcei(mId
, AL_LOOPING
, looping
? AL_TRUE
: AL_FALSE
);
724 void ALSource::setPitch(ALfloat pitch
)
727 throw std::runtime_error("Pitch out of range");
728 CheckContext(mContext
);
730 alSourcef(mId
, AL_PITCH
, pitch
* (mGroup
? mGroup
->getAppliedPitch() : 1.0f
));
735 void ALSource::setGain(ALfloat gain
)
738 throw std::runtime_error("Gain out of range");
739 CheckContext(mContext
);
741 alSourcef(mId
, AL_GAIN
, gain
* (mGroup
? mGroup
->getAppliedGain() : 1.0f
));
745 void ALSource::setGainRange(ALfloat mingain
, ALfloat maxgain
)
747 if(!(mingain
>= 0.0f
&& maxgain
<= 1.0f
&& maxgain
>= mingain
))
748 throw std::runtime_error("Gain range out of range");
749 CheckContext(mContext
);
752 alSourcef(mId
, AL_MIN_GAIN
, mingain
);
753 alSourcef(mId
, AL_MAX_GAIN
, maxgain
);
760 void ALSource::setDistanceRange(ALfloat refdist
, ALfloat maxdist
)
762 if(!(refdist
>= 0.0f
&& maxdist
<= std::numeric_limits
<float>::max() && refdist
<= maxdist
))
763 throw std::runtime_error("Distance range out of range");
764 CheckContext(mContext
);
767 alSourcef(mId
, AL_REFERENCE_DISTANCE
, refdist
);
768 alSourcef(mId
, AL_MAX_DISTANCE
, maxdist
);
775 void ALSource::setPosition(ALfloat x
, ALfloat y
, ALfloat z
)
777 CheckContext(mContext
);
779 alSource3f(mId
, AL_POSITION
, x
, y
, z
);
785 void ALSource::setPosition(const ALfloat
*pos
)
787 CheckContext(mContext
);
789 alSourcefv(mId
, AL_POSITION
, pos
);
790 mPosition
[0] = pos
[0];
791 mPosition
[1] = pos
[1];
792 mPosition
[2] = pos
[2];
795 void ALSource::setVelocity(ALfloat x
, ALfloat y
, ALfloat z
)
797 CheckContext(mContext
);
799 alSource3f(mId
, AL_VELOCITY
, x
, y
, z
);
805 void ALSource::setVelocity(const ALfloat
*vel
)
807 CheckContext(mContext
);
809 alSourcefv(mId
, AL_VELOCITY
, vel
);
810 mVelocity
[0] = vel
[0];
811 mVelocity
[1] = vel
[1];
812 mVelocity
[2] = vel
[2];
815 void ALSource::setDirection(ALfloat x
, ALfloat y
, ALfloat z
)
817 CheckContext(mContext
);
819 alSource3f(mId
, AL_DIRECTION
, x
, y
, z
);
825 void ALSource::setDirection(const ALfloat
*dir
)
827 CheckContext(mContext
);
829 alSourcefv(mId
, AL_DIRECTION
, dir
);
830 mDirection
[0] = dir
[0];
831 mDirection
[1] = dir
[1];
832 mDirection
[2] = dir
[2];
835 void ALSource::setOrientation(ALfloat x1
, ALfloat y1
, ALfloat z1
, ALfloat x2
, ALfloat y2
, ALfloat z2
)
837 CheckContext(mContext
);
840 ALfloat ori
[6] = { x1
, y1
, z1
, x2
, y2
, z2
};
841 if(mContext
->hasExtension(EXT_BFORMAT
))
842 alSourcefv(mId
, AL_ORIENTATION
, ori
);
843 alSourcefv(mId
, AL_DIRECTION
, ori
);
845 mDirection
[0] = mOrientation
[0][0] = x1
;
846 mDirection
[1] = mOrientation
[0][1] = y1
;
847 mDirection
[2] = mOrientation
[0][2] = z1
;
848 mOrientation
[1][0] = x2
;
849 mOrientation
[1][1] = y2
;
850 mOrientation
[1][2] = z2
;
853 void ALSource::setOrientation(const ALfloat
*at
, const ALfloat
*up
)
855 CheckContext(mContext
);
858 ALfloat ori
[6] = { at
[0], at
[1], at
[2], up
[0], up
[1], up
[2] };
859 if(mContext
->hasExtension(EXT_BFORMAT
))
860 alSourcefv(mId
, AL_ORIENTATION
, ori
);
861 alSourcefv(mId
, AL_DIRECTION
, ori
);
863 mDirection
[0] = mOrientation
[0][0] = at
[0];
864 mDirection
[1] = mOrientation
[0][1] = at
[1];
865 mDirection
[2] = mOrientation
[0][2] = at
[2];
866 mOrientation
[1][0] = up
[0];
867 mOrientation
[1][1] = up
[1];
868 mOrientation
[1][2] = up
[2];
871 void ALSource::setOrientation(const ALfloat
*ori
)
873 CheckContext(mContext
);
876 if(mContext
->hasExtension(EXT_BFORMAT
))
877 alSourcefv(mId
, AL_ORIENTATION
, ori
);
878 alSourcefv(mId
, AL_DIRECTION
, ori
);
880 mDirection
[0] = mOrientation
[0][0] = ori
[0];
881 mDirection
[1] = mOrientation
[0][1] = ori
[1];
882 mDirection
[2] = mOrientation
[0][2] = ori
[2];
883 mOrientation
[1][0] = ori
[3];
884 mOrientation
[1][1] = ori
[4];
885 mOrientation
[1][2] = ori
[5];
889 void ALSource::setConeAngles(ALfloat inner
, ALfloat outer
)
891 if(!(inner
>= 0.0f
&& outer
<= 360.0f
&& outer
>= inner
))
892 throw std::runtime_error("Cone angles out of range");
893 CheckContext(mContext
);
896 alSourcef(mId
, AL_CONE_INNER_ANGLE
, inner
);
897 alSourcef(mId
, AL_CONE_OUTER_ANGLE
, outer
);
899 mConeInnerAngle
= inner
;
900 mConeOuterAngle
= outer
;
903 void ALSource::setOuterConeGains(ALfloat gain
, ALfloat gainhf
)
905 if(!(gain
>= 0.0f
&& gain
<= 1.0f
&& gainhf
>= 0.0f
&& gainhf
<= 1.0f
))
906 throw std::runtime_error("Outer cone gain out of range");
907 CheckContext(mContext
);
910 alSourcef(mId
, AL_CONE_OUTER_GAIN
, gain
);
911 if(mContext
->hasExtension(EXT_EFX
))
912 alSourcef(mId
, AL_CONE_OUTER_GAINHF
, gainhf
);
914 mConeOuterGain
= gain
;
915 mConeOuterGainHF
= gainhf
;
919 void ALSource::setRolloffFactors(ALfloat factor
, ALfloat roomfactor
)
921 if(!(factor
>= 0.0f
&& roomfactor
>= 0.0f
))
922 throw std::runtime_error("Rolloff factor out of range");
923 CheckContext(mContext
);
926 alSourcef(mId
, AL_ROLLOFF_FACTOR
, factor
);
927 if(mContext
->hasExtension(EXT_EFX
))
928 alSourcef(mId
, AL_ROOM_ROLLOFF_FACTOR
, roomfactor
);
930 mRolloffFactor
= factor
;
931 mRoomRolloffFactor
= roomfactor
;
934 void ALSource::setDopplerFactor(ALfloat factor
)
936 if(!(factor
>= 0.0f
&& factor
<= 1.0f
))
937 throw std::runtime_error("Doppler factor out of range");
938 CheckContext(mContext
);
940 alSourcef(mId
, AL_DOPPLER_FACTOR
, factor
);
941 mDopplerFactor
= factor
;
944 void ALSource::setAirAbsorptionFactor(ALfloat factor
)
946 if(!(factor
>= 0.0f
&& factor
<= 10.0f
))
947 throw std::runtime_error("Absorption factor out of range");
948 CheckContext(mContext
);
949 if(mId
!= 0 && mContext
->hasExtension(EXT_EFX
))
950 alSourcef(mId
, AL_AIR_ABSORPTION_FACTOR
, factor
);
951 mAirAbsorptionFactor
= factor
;
954 void ALSource::setRadius(ALfloat radius
)
956 if(!(mRadius
>= 0.0f
))
957 throw std::runtime_error("Radius out of range");
958 CheckContext(mContext
);
959 if(mId
!= 0 && mContext
->hasExtension(EXT_SOURCE_RADIUS
))
960 alSourcef(mId
, AL_SOURCE_RADIUS
, radius
);
964 void ALSource::setStereoAngles(ALfloat leftAngle
, ALfloat rightAngle
)
966 CheckContext(mContext
);
967 if(mId
!= 0 && mContext
->hasExtension(EXT_STEREO_ANGLES
))
969 ALfloat angles
[2] = { leftAngle
, rightAngle
};
970 alSourcefv(mId
, AL_STEREO_ANGLES
, angles
);
972 mStereoAngles
[0] = leftAngle
;
973 mStereoAngles
[1] = rightAngle
;
976 void ALSource::setRelative(bool relative
)
978 CheckContext(mContext
);
980 alSourcei(mId
, AL_SOURCE_RELATIVE
, relative
? AL_TRUE
: AL_FALSE
);
981 mRelative
= relative
;
984 void ALSource::setGainAuto(bool directhf
, bool send
, bool sendhf
)
986 CheckContext(mContext
);
987 if(mId
!= 0 && mContext
->hasExtension(EXT_EFX
))
989 alSourcei(mId
, AL_DIRECT_FILTER_GAINHF_AUTO
, directhf
? AL_TRUE
: AL_FALSE
);
990 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
, send
? AL_TRUE
: AL_FALSE
);
991 alSourcei(mId
, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
, sendhf
? AL_TRUE
: AL_FALSE
);
993 mDryGainHFAuto
= directhf
;
995 mWetGainHFAuto
= sendhf
;
999 void ALSource::setFilterParams(ALuint
&filterid
, const FilterParams
¶ms
)
1001 if(!mContext
->hasExtension(EXT_EFX
))
1004 if(!(params
.mGain
< 1.0f
|| params
.mGainHF
< 1.0f
|| params
.mGainLF
< 1.0f
))
1007 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_NULL
);
1014 mContext
->alGenFilters(1, &filterid
);
1015 if(alGetError() != AL_NO_ERROR
)
1016 throw std::runtime_error("Failed to create Filter");
1018 bool filterset
= false;
1019 if(params
.mGainHF
< 1.0f
&& params
.mGainLF
< 1.0f
)
1021 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_BANDPASS
);
1022 if(alGetError() == AL_NO_ERROR
)
1024 mContext
->alFilterf(filterid
, AL_BANDPASS_GAIN
, std::min
<ALfloat
>(params
.mGain
, 1.0f
));
1025 mContext
->alFilterf(filterid
, AL_BANDPASS_GAINHF
, std::min
<ALfloat
>(params
.mGainHF
, 1.0f
));
1026 mContext
->alFilterf(filterid
, AL_BANDPASS_GAINLF
, std::min
<ALfloat
>(params
.mGainLF
, 1.0f
));
1030 if(!filterset
&& !(params
.mGainHF
< 1.0f
) && params
.mGainLF
< 1.0f
)
1032 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_HIGHPASS
);
1033 if(alGetError() == AL_NO_ERROR
)
1035 mContext
->alFilterf(filterid
, AL_HIGHPASS_GAIN
, std::min
<ALfloat
>(params
.mGain
, 1.0f
));
1036 mContext
->alFilterf(filterid
, AL_HIGHPASS_GAINLF
, std::min
<ALfloat
>(params
.mGainLF
, 1.0f
));
1042 mContext
->alFilteri(filterid
, AL_FILTER_TYPE
, AL_FILTER_LOWPASS
);
1043 if(alGetError() == AL_NO_ERROR
)
1045 mContext
->alFilterf(filterid
, AL_LOWPASS_GAIN
, std::min
<ALfloat
>(params
.mGain
, 1.0f
));
1046 mContext
->alFilterf(filterid
, AL_LOWPASS_GAINHF
, std::min
<ALfloat
>(params
.mGainHF
, 1.0f
));
1053 void ALSource::setDirectFilter(const FilterParams
&filter
)
1055 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1056 throw std::runtime_error("Gain value out of range");
1057 CheckContext(mContext
);
1059 setFilterParams(mDirectFilter
, filter
);
1061 alSourcei(mId
, AL_DIRECT_FILTER
, mDirectFilter
);
1064 void ALSource::setSendFilter(ALuint send
, const FilterParams
&filter
)
1066 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1067 throw std::runtime_error("Gain value out of range");
1068 CheckContext(mContext
);
1070 SendPropMap::iterator siter
= mEffectSlots
.find(send
);
1071 if(siter
== mEffectSlots
.end())
1073 ALuint filterid
= 0;
1075 setFilterParams(filterid
, filter
);
1076 if(!filterid
) return;
1078 siter
= mEffectSlots
.insert(std::make_pair(send
, SendProps(filterid
))).first
;
1081 setFilterParams(siter
->second
.mFilter
, filter
);
1085 ALuint slotid
= (siter
->second
.mSlot
? siter
->second
.mSlot
->getId() : 0);
1086 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->second
.mFilter
);
1090 void ALSource::setAuxiliarySend(AuxiliaryEffectSlot
*auxslot
, ALuint send
)
1092 ALAuxiliaryEffectSlot
*slot
= 0;
1095 slot
= cast
<ALAuxiliaryEffectSlot
*>(auxslot
);
1096 if(!slot
) throw std::runtime_error("Invalid AuxiliaryEffectSlot");
1097 CheckContext(slot
->getContext());
1099 CheckContext(mContext
);
1101 SendPropMap::iterator siter
= mEffectSlots
.find(send
);
1102 if(siter
== mEffectSlots
.end())
1105 slot
->addSourceSend(this, send
);
1106 siter
= mEffectSlots
.insert(std::make_pair(send
, SendProps(slot
))).first
;
1108 else if(siter
->second
.mSlot
!= slot
)
1110 if(slot
) slot
->addSourceSend(this, send
);
1111 if(siter
->second
.mSlot
)
1112 siter
->second
.mSlot
->removeSourceSend(this, send
);
1113 siter
->second
.mSlot
= slot
;
1118 ALuint slotid
= (siter
->second
.mSlot
? siter
->second
.mSlot
->getId() : 0);
1119 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->second
.mFilter
);
1123 void ALSource::setAuxiliarySendFilter(AuxiliaryEffectSlot
*auxslot
, ALuint send
, const FilterParams
&filter
)
1125 if(!(filter
.mGain
>= 0.0f
&& filter
.mGainHF
>= 0.0f
&& filter
.mGainLF
>= 0.0f
))
1126 throw std::runtime_error("Gain value out of range");
1127 ALAuxiliaryEffectSlot
*slot
= 0;
1130 slot
= cast
<ALAuxiliaryEffectSlot
*>(auxslot
);
1131 if(!slot
) throw std::runtime_error("Invalid AuxiliaryEffectSlot");
1132 CheckContext(slot
->getContext());
1134 CheckContext(mContext
);
1136 SendPropMap::iterator siter
= mEffectSlots
.find(send
);
1137 if(siter
== mEffectSlots
.end())
1139 ALuint filterid
= 0;
1141 setFilterParams(filterid
, filter
);
1142 if(!filterid
&& !slot
)
1145 if(slot
) slot
->addSourceSend(this, send
);
1146 siter
= mEffectSlots
.insert(std::make_pair(send
, SendProps(slot
, filterid
))).first
;
1150 if(siter
->second
.mSlot
!= slot
)
1152 if(slot
) slot
->addSourceSend(this, send
);
1153 if(siter
->second
.mSlot
)
1154 siter
->second
.mSlot
->removeSourceSend(this, send
);
1155 siter
->second
.mSlot
= slot
;
1157 setFilterParams(siter
->second
.mFilter
, filter
);
1162 ALuint slotid
= (siter
->second
.mSlot
? siter
->second
.mSlot
->getId() : 0);
1163 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, slotid
, send
, siter
->second
.mFilter
);
1168 void ALSource::release()
1170 CheckContext(mContext
);
1172 if(mIsAsync
.load(std::memory_order_acquire
))
1174 mContext
->removeStream(this);
1175 mIsAsync
.store(false, std::memory_order_release
);
1180 alSourceRewind(mId
);
1181 alSourcei(mId
, AL_BUFFER
, 0);
1182 if(mContext
->hasExtension(EXT_EFX
))
1184 alSourcei(mId
, AL_DIRECT_FILTER
, AL_FILTER_NULL
);
1185 for(auto &i
: mEffectSlots
)
1186 alSource3i(mId
, AL_AUXILIARY_SEND_FILTER
, 0, i
.first
, AL_FILTER_NULL
);
1188 mContext
->insertSourceId(mId
);
1192 mContext
->freeSource(this);
1195 mContext
->alDeleteFilters(1, &mDirectFilter
);
1196 mDirectFilter
= AL_FILTER_NULL
;
1198 for(auto &i
: mEffectSlots
)
1201 i
.second
.mSlot
->removeSourceSend(this, i
.first
);
1202 if(i
.second
.mFilter
)
1203 mContext
->alDeleteFilters(1, &i
.second
.mFilter
);
1205 mEffectSlots
.clear();
1208 mBuffer
->removeSource(this);