Add an inline helper to get a SharedFuture's state
[alure.git] / src / source.cpp
blob7091ed9da8958c4ed8ff4c479943f6c4d099d75d
2 #include "config.h"
4 #include "source.h"
6 #include <cstring>
8 #include <stdexcept>
9 #include <sstream>
10 #include <memory>
11 #include <limits>
13 #include "context.h"
14 #include "buffer.h"
15 #include "auxeffectslot.h"
16 #include "sourcegroup.h"
18 namespace alure
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;
32 ALuint mUpdateLen;
33 ALuint mNumUpdates;
35 ALenum mFormat;
36 ALuint mFrequency;
37 ALuint mFrameSize;
39 Vector<ALbyte> mData;
40 ALbyte mSilence;
42 Vector<ALuint> mBufferIds;
43 ALuint mCurrentIdx;
45 uint64_t mSamplePos;
46 std::pair<uint64_t,uint64_t> mLoopPts;
47 bool mHasLooped;
48 std::atomic<bool> mDone;
50 public:
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),
55 mDone(false)
56 { }
57 ~ALBufferStream()
59 if(!mBufferIds.empty())
61 alDeleteBuffers(mBufferIds.size(), mBufferIds.data());
62 mBufferIds.clear();
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))
77 return false;
78 mSamplePos = pos;
79 mHasLooped = false;
80 mDone.store(false, std::memory_order_release);
81 return true;
84 void prepare()
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)
93 mLoopPts.first = 0;
94 mLoopPts.second = std::numeric_limits<uint64_t>::max();
97 mFrequency = srate;
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);
104 str += ", ";
105 str += GetChannelConfigName(chans);
106 str += ")";
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))
127 return false;
129 ALuint frames;
130 ALuint len = mUpdateLen;
131 if(loop && mSamplePos <= mLoopPts.second)
132 len = std::min<uint64_t>(len, mLoopPts.second - mSamplePos);
133 else
134 loop = false;
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);
146 do {
147 if(!mDecoder->seek(mLoopPts.first))
148 break;
149 mSamplePos = mLoopPts.first;
150 mHasLooped = true;
152 len = std::min<uint64_t>(mUpdateLen-frames, mLoopPts.second-mLoopPts.first);
153 ALuint got = mDecoder->read(&mData[frames*mFrameSize], len);
154 if(got == 0) break;
155 mSamplePos += got;
156 frames += got;
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();
170 return true;
175 SourceImpl::SourceImpl(ContextImpl *context)
176 : mContext(context), mId(0), mBuffer(0), mGroup(nullptr), mIsAsync(false),
177 mDirectFilter(AL_FILTER_NULL)
179 resetProperties();
180 mEffectSlots.reserve(mContext->getDevice().getMaxAuxiliarySends());
183 SourceImpl::~SourceImpl()
188 void SourceImpl::resetProperties()
190 if(mGroup)
191 mGroup->eraseSource(this);
192 mGroup = nullptr;
193 mGroupPitch = 1.0f;
194 mGroupGain = 1.0f;
196 mFadeGainTarget = 1.0f;
197 mFadeGain = 1.0f;
199 mPaused.store(false, std::memory_order_release);
200 mOffset = 0;
201 mPitch = 1.0f;
202 mGain = 1.0f;
203 mMinGain = 0.0f;
204 mMaxGain = 1.0f;
205 mRefDist = 1.0f;
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;
220 mRadius = 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;
226 mLooping = false;
227 mRelative = false;
228 mDryGainHFAuto = true;
229 mWetGainAuto = true;
230 mWetGainHFAuto = true;
231 if(mDirectFilter)
232 mContext->alDeleteFilters(1, &mDirectFilter);
233 mDirectFilter = 0;
234 for(auto &i : mEffectSlots)
236 if(i.mSlot)
237 i.mSlot->removeSourceSend({Source(this), i.mSendIdx});
238 if(i.mFilter)
239 mContext->alDeleteFilters(1, &i.mFilter);
241 mEffectSlots.clear();
243 mPriority = 0;
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()
295 mGroup = nullptr;
296 groupPropUpdate(1.0f, 1.0f);
299 void SourceImpl::groupPropUpdate(ALfloat gain, ALfloat pitch)
301 if(mId)
303 alSourcef(mId, AL_PITCH, mPitch * pitch);
304 alSourcef(mId, AL_GAIN, mGain * gain * mFadeGain);
306 mGroupPitch = pitch;
307 mGroupGain = gain;
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);
319 if(mStream)
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();
326 if(mId == 0)
328 mId = mContext->getSourceId(mPriority);
329 applyProperties(mLooping, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
331 else
333 mContext->removeFadingSource(this);
334 mContext->removePlayingSource(this);
335 alSourceRewind(mId);
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()));
340 mOffset = 0;
342 mStream.reset();
343 if(mBuffer)
344 mBuffer->removeSource(Source(this));
345 mBuffer = albuf;
346 mBuffer->addSource(Source(this));
348 alSourcei(mId, AL_BUFFER, mBuffer->getId());
349 alSourcePlay(mId);
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)
358 if(chunk_len < 64)
359 throw std::out_of_range("Update length out of range");
360 if(queue_size < 2)
361 throw std::out_of_range("Queue size out of range");
362 CheckContext(mContext);
364 auto stream = MakeUnique<ALBufferStream>(decoder, chunk_len, queue_size);
365 stream->prepare();
367 if(mStream)
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();
374 if(mId == 0)
376 mId = mContext->getSourceId(mPriority);
377 applyProperties(false, 0);
379 else
381 mContext->removeFadingSource(this);
382 mContext->removePlayingSource(this);
383 alSourceRewind(mId);
384 alSourcei(mId, AL_BUFFER, 0);
385 alSourcei(mId, AL_LOOPING, AL_FALSE);
386 alSourcei(mId, AL_SAMPLE_OFFSET, 0);
389 mStream.reset();
390 if(mBuffer)
391 mBuffer->removeSource(Source(this));
392 mBuffer = 0;
394 mStream = std::move(stream);
396 mStream->seek(mOffset);
397 mOffset = 0;
399 for(ALuint i = 0;i < mStream->getNumUpdates();i++)
401 if(!mStream->streamMoreData(mId, mLooping))
402 break;
404 alSourcePlay(mId);
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());
421 return;
424 CheckContext(mContext);
426 mContext->removeFadingSource(this);
427 mContext->removePlayingSource(this);
428 makeStopped(true);
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)
439 if(mStream)
441 if(dolock)
442 mContext->removeStream(this);
443 else
444 mContext->removeStreamNoLock(this);
446 mIsAsync.store(false, std::memory_order_release);
448 if(mId != 0)
450 alSourceRewind(mId);
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);
459 mId = 0;
462 mStream.reset();
463 if(mBuffer)
464 mBuffer->removeSource(Source(this));
465 mBuffer = 0;
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);
477 makeStopped();
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)
501 return;
503 ALint state = -1;
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))
515 return;
517 if(mId != 0)
519 std::lock_guard<std::mutex> lock(mMutex);
520 alSourcePause(mId);
521 ALint state = -1;
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))
534 return;
536 if(mId != 0)
537 alSourcePlay(mId);
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;
555 ALint state = -1;
556 alGetSourcei(mId, AL_SOURCE_STATE, &state);
557 if(state == -1)
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;
580 if(mGroup)
581 mGroup->eraseSource(this);
582 mGroup = parent;
583 if(mGroup)
585 mGroup->insertSource(this);
586 mGroupPitch = mGroup->getAppliedPitch();
587 mGroupGain = mGroup->getAppliedGain();
589 else
591 mGroupPitch = 1.0f;
592 mGroupGain = 1.0f;
595 if(mId)
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)
606 return true;
608 BufferImpl *buffer = future.get().getHandle();
609 if(UNLIKELY(buffer->getContext() != mContext))
610 return false;
612 if(mId == 0)
614 mId = mContext->getSourceId(mPriority);
615 applyProperties(mLooping, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
617 else
619 alSourceRewind(mId);
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()));
624 mOffset = 0;
626 mBuffer = buffer;
627 mBuffer->addSource(Source(this));
629 alSourcei(mId, AL_BUFFER, mBuffer->getId());
630 alSourcePlay(mId);
631 mPaused.store(false, std::memory_order_release);
632 mContext->addPlayingSource(this, mId);
633 return false;
636 bool SourceImpl::fadeUpdate(std::chrono::steady_clock::time_point cur_fade_time)
638 if((cur_fade_time - mFadeTimeTarget).count() >= 0)
640 mLastFadeTime = mFadeTimeTarget;
641 mFadeGain = 1.0f;
642 if(mFadeGainTarget >= 1.0f)
644 if(mId != 0)
645 alSourcef(mId, AL_GAIN, mGain * mGroupGain);
646 return false;
648 mContext->removePendingSource(this);
649 mContext->removePlayingSource(this);
650 makeStopped(true);
651 return false;
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);
668 mFadeGain = gain;
670 if(mId != 0)
671 alSourcef(mId, AL_GAIN, mGain * mGroupGain * mFadeGain);
672 return true;
675 bool SourceImpl::playUpdate(ALuint id)
677 ALint state = -1;
678 alGetSourcei(id, AL_SOURCE_STATE, &state);
679 if(LIKELY(state == AL_PLAYING || state == AL_PAUSED))
680 return true;
682 makeStopped();
683 mContext->send(&MessageHandler::sourceStopped, Source(this));
684 return false;
687 bool SourceImpl::playUpdate()
689 if(LIKELY(mIsAsync.load(std::memory_order_acquire)))
690 return true;
692 makeStopped();
693 mContext->send(&MessageHandler::sourceStopped, Source(this));
694 return false;
698 ALint SourceImpl::refillBufferStream()
700 ALint processed;
701 alGetSourcei(mId, AL_BUFFERS_PROCESSED, &processed);
702 while(processed > 0)
704 ALuint buf;
705 alSourceUnqueueBuffers(mId, 1, &buf);
706 --processed;
709 ALint queued;
710 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
711 for(;(ALuint)queued < mStream->getNumUpdates();queued++)
713 if(!mStream->streamMoreData(mId, mLooping))
714 break;
717 return queued;
720 bool SourceImpl::updateAsync()
722 std::lock_guard<std::mutex> lock(mMutex);
724 ALint queued = refillBufferStream();
725 if(queued == 0)
727 mIsAsync.store(false, std::memory_order_release);
728 return false;
731 ALint state = -1;
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)
737 alSourcePlay(mId);
739 else
741 // Rewind the source to an initial state if it underrun as it was
742 // paused.
743 if(state == AL_STOPPED)
744 alSourceRewind(mId);
746 return true;
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);
761 if(mId == 0)
763 mOffset = offset;
764 return;
767 if(!mStream)
769 if(offset >= std::numeric_limits<ALint>::max())
770 throw std::out_of_range("Offset out of range");
771 alGetError();
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");
777 else
779 std::lock_guard<std::mutex> lock(mMutex);
780 if(!mStream->seek(offset))
781 throw std::runtime_error("Failed to seek to offset");
782 alSourceRewind(mId);
783 alSourcei(mId, AL_BUFFER, 0);
784 ALint queued = refillBufferStream();
785 if(queued > 0 && !mPaused.load(std::memory_order_acquire))
786 alSourcePlay(mId);
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;
797 if(mStream)
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))
805 ALint64SOFT val[2];
806 mContext->alGetSourcei64vSOFT(mId, AL_SAMPLE_OFFSET_LATENCY_SOFT, val);
807 srcpos = val[0]>>32;
808 ret.second = std::chrono::nanoseconds(val[1]);
810 else
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;
825 else
827 streampos -= inqueue;
828 int64_t looplen = mStream->getLoopEnd() - mStream->getLoopStart();
829 while(streampos < mStream->getLoopStart())
830 streampos += looplen;
834 ret.first = streampos;
835 return ret;
838 ALint srcpos = 0;
839 if(mContext->hasExtension(AL::SOFT_source_latency))
841 ALint64SOFT val[2];
842 mContext->alGetSourcei64vSOFT(mId, AL_SAMPLE_OFFSET_LATENCY_SOFT, val);
843 srcpos = val[0]>>32;
844 ret.second = std::chrono::nanoseconds(val[1]);
846 else
847 alGetSourcei(mId, AL_SAMPLE_OFFSET, &srcpos);
848 ret.first = srcpos;
849 return ret;
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;
859 if(mStream)
861 std::lock_guard<std::mutex> lock(mMutex);
862 ALint queued = 0, state = -1;
863 ALdouble srcpos = 0;
865 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
866 if(mContext->hasExtension(AL::SOFT_source_latency))
868 ALdouble val[2];
869 mContext->alGetSourcedvSOFT(mId, AL_SEC_OFFSET_LATENCY_SOFT, val);
870 srcpos = val[0];
871 ret.second = Seconds(val[1]);
873 else
875 ALfloat f;
876 alGetSourcef(mId, AL_SEC_OFFSET, &f);
877 srcpos = f;
879 alGetSourcei(mId, AL_SOURCE_STATE, &state);
881 ALdouble frac = 0.0;
882 int64_t streampos = mStream->getPosition();
883 if(state != AL_STOPPED)
885 ALdouble ipos;
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;
896 else
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());
906 return ret;
909 if(mContext->hasExtension(AL::SOFT_source_latency))
911 ALdouble val[2];
912 mContext->alGetSourcedvSOFT(mId, AL_SEC_OFFSET_LATENCY_SOFT, val);
913 ret.first = Seconds(val[0]);
914 ret.second = Seconds(val[1]);
916 else
918 ALfloat f;
919 alGetSourcef(mId, AL_SEC_OFFSET, &f);
920 ret.first = Seconds(f);
922 return ret;
926 DECL_THUNK1(void, Source, setLooping,, bool)
927 void SourceImpl::setLooping(bool looping)
929 CheckContext(mContext);
931 if(mId && !mStream)
932 alSourcei(mId, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
933 mLooping = looping;
937 DECL_THUNK1(void, Source, setPitch,, ALfloat)
938 void SourceImpl::setPitch(ALfloat pitch)
940 if(!(pitch > 0.0f))
941 throw std::out_of_range("Pitch out of range");
942 CheckContext(mContext);
943 if(mId != 0)
944 alSourcef(mId, AL_PITCH, pitch * mGroupPitch);
945 mPitch = pitch;
949 DECL_THUNK1(void, Source, setGain,, ALfloat)
950 void SourceImpl::setGain(ALfloat gain)
952 if(!(gain >= 0.0f))
953 throw std::out_of_range("Gain out of range");
954 CheckContext(mContext);
955 if(mId != 0)
956 alSourcef(mId, AL_GAIN, gain * mGroupGain * mFadeGain);
957 mGain = gain;
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);
966 if(mId != 0)
968 alSourcef(mId, AL_MIN_GAIN, mingain);
969 alSourcef(mId, AL_MAX_GAIN, maxgain);
971 mMinGain = mingain;
972 mMaxGain = 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);
982 if(mId != 0)
984 alSourcef(mId, AL_REFERENCE_DISTANCE, refdist);
985 alSourcef(mId, AL_MAX_DISTANCE, maxdist);
987 mRefDist = refdist;
988 mMaxDist = 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);
996 if(mId != 0)
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);
1013 if(mId != 0)
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);
1033 if(mId != 0)
1034 alSource3f(mId, AL_POSITION, x, y, z);
1035 mPosition[0] = x;
1036 mPosition[1] = y;
1037 mPosition[2] = z;
1040 DECL_THUNK1(void, Source, setPosition,, const ALfloat*)
1041 void SourceImpl::setPosition(const ALfloat *pos)
1043 CheckContext(mContext);
1044 if(mId != 0)
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);
1055 if(mId != 0)
1056 alSource3f(mId, AL_VELOCITY, x, y, z);
1057 mVelocity[0] = x;
1058 mVelocity[1] = y;
1059 mVelocity[2] = z;
1062 DECL_THUNK1(void, Source, setVelocity,, const ALfloat*)
1063 void SourceImpl::setVelocity(const ALfloat *vel)
1065 CheckContext(mContext);
1066 if(mId != 0)
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);
1077 if(mId != 0)
1078 alSource3f(mId, AL_DIRECTION, x, y, z);
1079 mDirection[0] = x;
1080 mDirection[1] = y;
1081 mDirection[2] = z;
1084 DECL_THUNK1(void, Source, setDirection,, const ALfloat*)
1085 void SourceImpl::setDirection(const ALfloat *dir)
1087 CheckContext(mContext);
1088 if(mId != 0)
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);
1099 if(mId != 0)
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);
1118 if(mId != 0)
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);
1137 if(mId != 0)
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);
1158 if(mId != 0)
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);
1173 if(mId != 0)
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);
1190 if(mId != 0)
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);
1206 if(mId != 0)
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);
1215 if(mId != 0)
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);
1228 mRadius = 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)
1256 if(index < 0)
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);
1261 mResampler = 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 &params)
1293 if(!mContext->hasExtension(AL::EXT_EFX))
1294 return;
1296 if(!(params.mGain < 1.0f || params.mGainHF < 1.0f || params.mGainLF < 1.0f))
1298 if(filterid)
1299 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_NULL);
1300 return;
1303 alGetError();
1304 if(!filterid)
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));
1320 filterset = true;
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));
1330 filterset = true;
1333 if(!filterset)
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));
1340 filterset = true;
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);
1354 if(mId)
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);
1378 else
1379 setFilterParams(siter->mFilter, filter);
1381 if(mId)
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)
1401 if(!slot) return;
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});
1408 if(siter->mSlot)
1409 siter->mSlot->removeSourceSend({Source(this), send});
1410 siter->mSlot = slot;
1413 if(mId)
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)
1439 return;
1441 if(slot) slot->addSourceSend({Source(this), send});
1442 siter = mEffectSlots.emplace(siter, send, slot, filterid);
1444 else
1446 if(siter->mSlot != slot)
1448 if(slot) slot->addSourceSend({Source(this), send});
1449 if(siter->mSlot)
1450 siter->mSlot->removeSourceSend({Source(this), send});
1451 siter->mSlot = slot;
1453 setFilterParams(siter->mFilter, filter);
1456 if(mId)
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;
1467 pImpl = nullptr;
1468 i->release();
1470 void SourceImpl::release()
1472 stop();
1474 resetProperties();
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)