Fix types and casts for MSVC
[alure.git] / src / source.cpp
blobaddf893c1652e8ddf3f372af4f116a23797cfbfb
2 #include "config.h"
4 #include "source.h"
6 #include <cstring>
8 #include <stdexcept>
9 #include <memory>
10 #include <limits>
12 #include "context.h"
13 #include "buffer.h"
14 #include "auxeffectslot.h"
15 #include "sourcegroup.h"
17 namespace alure
20 class ALBufferStream {
21 SharedPtr<Decoder> mDecoder;
23 ALuint mUpdateLen{0};
24 ALuint mNumUpdates{0};
26 ALenum mFormat{AL_NONE};
27 ALuint mFrequency{0};
28 ALuint mFrameSize{0};
30 Vector<ALbyte> mData;
31 ALbyte mSilence{0};
33 Vector<ALuint> mBufferIds;
34 ALuint mCurrentIdx{0};
36 uint64_t mSamplePos{0};
37 std::pair<uint64_t,uint64_t> mLoopPts{0,0};
38 bool mHasLooped{false};
39 std::atomic<bool> mDone{false};
41 public:
42 ALBufferStream(SharedPtr<Decoder> decoder, ALuint updatelen, ALuint numupdates)
43 : mDecoder(decoder), mUpdateLen(updatelen), mNumUpdates(numupdates)
44 { }
45 ~ALBufferStream()
47 if(!mBufferIds.empty())
49 alDeleteBuffers(mBufferIds.size(), mBufferIds.data());
50 mBufferIds.clear();
54 uint64_t getLength() const { return mDecoder->getLength(); }
55 uint64_t getPosition() const { return mSamplePos; }
57 ALuint getNumUpdates() const { return mNumUpdates; }
58 ALuint getUpdateLength() const { return mUpdateLen; }
60 ALuint getFrequency() const { return mFrequency; }
62 bool seek(uint64_t pos)
64 if(!mDecoder->seek(pos))
65 return false;
66 mSamplePos = pos;
67 mHasLooped = false;
68 mDone.store(false, std::memory_order_release);
69 return true;
72 void prepare()
74 ALuint srate = mDecoder->getFrequency();
75 ChannelConfig chans = mDecoder->getChannelConfig();
76 SampleType type = mDecoder->getSampleType();
78 mLoopPts = mDecoder->getLoopPoints();
79 if(mLoopPts.first >= mLoopPts.second)
81 mLoopPts.first = 0;
82 mLoopPts.second = std::numeric_limits<uint64_t>::max();
85 mFrequency = srate;
86 mFrameSize = FramesToBytes(1, chans, type);
87 mFormat = GetFormat(chans, type);
88 if(UNLIKELY(mFormat == AL_NONE))
90 auto str = String("Unsupported format (")+GetSampleTypeName(type)+", "+
91 GetChannelConfigName(chans)+")";
92 throw std::runtime_error(str);
95 mData.resize(mUpdateLen * mFrameSize);
96 if(type == SampleType::UInt8) mSilence = 0x80;
97 else if(type == SampleType::Mulaw) mSilence = 0x7f;
98 else mSilence = 0x00;
100 mBufferIds.assign(mNumUpdates, 0);
101 alGenBuffers(mBufferIds.size(), mBufferIds.data());
104 int64_t getLoopStart() const { return mLoopPts.first; }
105 int64_t getLoopEnd() const { return mLoopPts.second; }
107 bool hasLooped() const { return mHasLooped; }
108 bool hasMoreData() const { return !mDone.load(std::memory_order_acquire); }
109 bool streamMoreData(ALuint srcid, bool loop)
111 if(mDone.load(std::memory_order_acquire))
112 return false;
114 ALuint frames;
115 ALuint len = mUpdateLen;
116 if(loop && mSamplePos <= mLoopPts.second)
117 len = static_cast<ALuint>(std::min<uint64_t>(len, mLoopPts.second - mSamplePos));
118 else
119 loop = false;
121 frames = mDecoder->read(mData.data(), len);
122 mSamplePos += frames;
123 if(frames < mUpdateLen && loop && mSamplePos > 0)
125 if(mSamplePos < mLoopPts.second)
127 mLoopPts.second = mSamplePos;
128 if(mLoopPts.first >= mLoopPts.second)
129 mLoopPts.first = 0;
132 do {
133 if(!mDecoder->seek(mLoopPts.first))
134 break;
135 mSamplePos = mLoopPts.first;
136 mHasLooped = true;
138 len = static_cast<ALuint>(
139 std::min<uint64_t>(mUpdateLen-frames, mLoopPts.second-mLoopPts.first)
141 ALuint got = mDecoder->read(&mData[frames*mFrameSize], len);
142 if(got == 0) break;
143 mSamplePos += got;
144 frames += got;
145 } while(frames < mUpdateLen);
147 if(frames < mUpdateLen)
149 mDone.store(true, std::memory_order_release);
150 if(frames == 0) return false;
151 mSamplePos += mUpdateLen - frames;
152 std::fill(mData.begin() + frames*mFrameSize, mData.end(), mSilence);
155 alBufferData(mBufferIds[mCurrentIdx], mFormat, mData.data(), mData.size(), mFrequency);
156 alSourceQueueBuffers(srcid, 1, &mBufferIds[mCurrentIdx]);
157 mCurrentIdx = (mCurrentIdx+1) % mBufferIds.size();
158 return true;
163 SourceImpl::SourceImpl(ContextImpl &context)
164 : mContext(context), mId(0), mBuffer(0), mGroup(nullptr), mIsAsync(false)
165 , mDirectFilter(AL_FILTER_NULL)
167 resetProperties();
168 mEffectSlots.reserve(mContext.getDevice().getMaxAuxiliarySends());
171 SourceImpl::~SourceImpl()
176 void SourceImpl::resetProperties()
178 if(mGroup)
179 mGroup->eraseSource(this);
180 mGroup = nullptr;
181 mGroupPitch = 1.0f;
182 mGroupGain = 1.0f;
184 mFadeGainTarget = 1.0f;
185 mFadeGain = 1.0f;
187 mPaused.store(false, std::memory_order_release);
188 mOffset = 0;
189 mPitch = 1.0f;
190 mGain = 1.0f;
191 mMinGain = 0.0f;
192 mMaxGain = 1.0f;
193 mRefDist = 1.0f;
194 mMaxDist = std::numeric_limits<float>::max();
195 mPosition = Vector3(0.0f);
196 mVelocity = Vector3(0.0f);
197 mDirection = Vector3(0.0f);
198 mOrientation[0] = Vector3(0.0f, 0.0f, -1.0f);
199 mOrientation[1] = Vector3(0.0f, 1.0f, 0.0f);
200 mConeInnerAngle = 360.0f;
201 mConeOuterAngle = 360.0f;
202 mConeOuterGain = 0.0f;
203 mConeOuterGainHF = 1.0f;
204 mRolloffFactor = 1.0f;
205 mRoomRolloffFactor = 0.0f;
206 mDopplerFactor = 1.0f;
207 mAirAbsorptionFactor = 0.0f;
208 mRadius = 0.0f;
209 mStereoAngles[0] = F_PI / 6.0f;
210 mStereoAngles[1] = -F_PI / 6.0f;
211 mSpatialize = Spatialize::Auto;
212 mResampler = mContext.hasExtension(AL::SOFT_source_resampler) ?
213 alGetInteger(AL_DEFAULT_RESAMPLER_SOFT) : 0;
214 mLooping = false;
215 mRelative = false;
216 mDryGainHFAuto = true;
217 mWetGainAuto = true;
218 mWetGainHFAuto = true;
219 if(mDirectFilter)
220 mContext.alDeleteFilters(1, &mDirectFilter);
221 mDirectFilter = 0;
222 for(auto &i : mEffectSlots)
224 if(i.mSlot)
225 i.mSlot->removeSourceSend({Source(this), i.mSendIdx});
226 if(i.mFilter)
227 mContext.alDeleteFilters(1, &i.mFilter);
229 mEffectSlots.clear();
231 mPriority = 0;
234 void SourceImpl::applyProperties(bool looping, ALuint offset) const
236 alSourcei(mId, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
237 alSourcei(mId, AL_SAMPLE_OFFSET, offset);
238 alSourcef(mId, AL_PITCH, mPitch * mGroupPitch);
239 alSourcef(mId, AL_GAIN, mGain * mGroupGain * mFadeGain);
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(AL::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(AL::EXT_SOURCE_RADIUS))
255 alSourcef(mId, AL_SOURCE_RADIUS, mRadius);
256 if(mContext.hasExtension(AL::EXT_STEREO_ANGLES))
257 alSourcefv(mId, AL_STEREO_ANGLES, mStereoAngles);
258 if(mContext.hasExtension(AL::SOFT_source_spatialize))
259 alSourcei(mId, AL_SOURCE_SPATIALIZE_SOFT, (ALint)mSpatialize);
260 if(mContext.hasExtension(AL::SOFT_source_resampler))
261 alSourcei(mId, AL_SOURCE_RESAMPLER_SOFT, mResampler);
262 alSourcei(mId, AL_SOURCE_RELATIVE, mRelative ? AL_TRUE : AL_FALSE);
263 if(mContext.hasExtension(AL::EXT_EFX))
265 alSourcef(mId, AL_CONE_OUTER_GAINHF, mConeOuterGainHF);
266 alSourcef(mId, AL_ROOM_ROLLOFF_FACTOR, mRoomRolloffFactor);
267 alSourcef(mId, AL_AIR_ABSORPTION_FACTOR, mAirAbsorptionFactor);
268 alSourcei(mId, AL_DIRECT_FILTER_GAINHF_AUTO, mDryGainHFAuto ? AL_TRUE : AL_FALSE);
269 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, mWetGainAuto ? AL_TRUE : AL_FALSE);
270 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, mWetGainHFAuto ? AL_TRUE : AL_FALSE);
271 alSourcei(mId, AL_DIRECT_FILTER, mDirectFilter);
272 for(const auto &i : mEffectSlots)
274 ALuint slotid = (i.mSlot ? i.mSlot->getId() : 0);
275 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, i.mSendIdx, i.mFilter);
281 void SourceImpl::unsetGroup()
283 mGroup = nullptr;
284 groupPropUpdate(1.0f, 1.0f);
287 void SourceImpl::groupPropUpdate(ALfloat gain, ALfloat pitch)
289 if(mId)
291 alSourcef(mId, AL_PITCH, mPitch * pitch);
292 alSourcef(mId, AL_GAIN, mGain * gain * mFadeGain);
294 mGroupPitch = pitch;
295 mGroupGain = gain;
299 DECL_THUNK1(void, Source, play,, Buffer)
300 void SourceImpl::play(Buffer buffer)
302 BufferImpl *albuf = buffer.getHandle();
303 if(!albuf) throw std::invalid_argument("Buffer is not valid");
304 CheckContexts(mContext, albuf->getContext());
305 CheckContext(mContext);
307 if(mStream)
308 mContext.removeStream(this);
309 mIsAsync.store(false, std::memory_order_release);
311 mFadeGainTarget = mFadeGain = 1.0f;
312 mFadeTimeTarget = mLastFadeTime = std::chrono::nanoseconds::zero();
314 if(mId == 0)
316 mId = mContext.getSourceId(mPriority);
317 applyProperties(mLooping, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
319 else
321 mContext.removeFadingSource(this);
322 mContext.removePlayingSource(this);
323 alSourceRewind(mId);
324 alSourcei(mId, AL_BUFFER, 0);
325 alSourcei(mId, AL_LOOPING, mLooping ? AL_TRUE : AL_FALSE);
326 alSourcei(mId, AL_SAMPLE_OFFSET, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
328 mOffset = 0;
330 mStream.reset();
331 if(mBuffer)
332 mBuffer->removeSource(Source(this));
333 mBuffer = albuf;
334 mBuffer->addSource(Source(this));
336 alSourcei(mId, AL_BUFFER, mBuffer->getId());
337 alSourcePlay(mId);
338 mPaused.store(false, std::memory_order_release);
339 mContext.removePendingSource(this);
340 mContext.addPlayingSource(this, mId);
343 DECL_THUNK3(void, Source, play,, SharedPtr<Decoder>, ALuint, ALuint)
344 void SourceImpl::play(SharedPtr<Decoder>&& decoder, ALuint chunk_len, ALuint queue_size)
346 if(chunk_len < 64)
347 throw std::out_of_range("Update length out of range");
348 if(queue_size < 2)
349 throw std::out_of_range("Queue size out of range");
350 CheckContext(mContext);
352 auto stream = MakeUnique<ALBufferStream>(decoder, chunk_len, queue_size);
353 stream->prepare();
355 if(mStream)
356 mContext.removeStream(this);
357 mIsAsync.store(false, std::memory_order_release);
359 mFadeGainTarget = mFadeGain = 1.0f;
360 mFadeTimeTarget = mLastFadeTime = std::chrono::nanoseconds::zero();
362 if(mId == 0)
364 mId = mContext.getSourceId(mPriority);
365 applyProperties(false, 0);
367 else
369 mContext.removeFadingSource(this);
370 mContext.removePlayingSource(this);
371 alSourceRewind(mId);
372 alSourcei(mId, AL_BUFFER, 0);
373 alSourcei(mId, AL_LOOPING, AL_FALSE);
374 alSourcei(mId, AL_SAMPLE_OFFSET, 0);
377 mStream.reset();
378 if(mBuffer)
379 mBuffer->removeSource(Source(this));
380 mBuffer = 0;
382 mStream = std::move(stream);
384 mStream->seek(mOffset);
385 mOffset = 0;
387 for(ALuint i = 0;i < mStream->getNumUpdates();i++)
389 if(!mStream->streamMoreData(mId, mLooping))
390 break;
392 alSourcePlay(mId);
393 mPaused.store(false, std::memory_order_release);
395 mContext.addStream(this);
396 mIsAsync.store(true, std::memory_order_release);
397 mContext.removePendingSource(this);
398 mContext.addPlayingSource(this);
401 DECL_THUNK1(void, Source, play,, SharedFuture<Buffer>)
402 void SourceImpl::play(SharedFuture<Buffer>&& future_buffer)
404 if(!future_buffer.valid())
405 throw std::future_error(std::future_errc::no_state);
406 if(GetFutureState(future_buffer) == std::future_status::ready)
408 play(future_buffer.get());
409 return;
412 CheckContext(mContext);
414 mContext.removeFadingSource(this);
415 mContext.removePlayingSource(this);
416 makeStopped(true);
418 mFadeGainTarget = mFadeGain = 1.0f;
419 mFadeTimeTarget = mLastFadeTime = std::chrono::nanoseconds::zero();
421 mContext.addPendingSource(this, std::move(future_buffer));
425 DECL_THUNK0(void, Source, stop,)
426 void SourceImpl::stop()
428 CheckContext(mContext);
429 mContext.removePendingSource(this);
430 mContext.removeFadingSource(this);
431 mContext.removePlayingSource(this);
432 makeStopped();
435 void SourceImpl::makeStopped(bool dolock)
437 if(mStream)
439 if(dolock)
440 mContext.removeStream(this);
441 else
442 mContext.removeStreamNoLock(this);
444 mIsAsync.store(false, std::memory_order_release);
446 if(mId != 0)
448 alSourceRewind(mId);
449 alSourcei(mId, AL_BUFFER, 0);
450 if(mContext.hasExtension(AL::EXT_EFX))
452 alSourcei(mId, AL_DIRECT_FILTER, AL_FILTER_NULL);
453 for(auto &i : mEffectSlots)
454 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, 0, i.mSendIdx, AL_FILTER_NULL);
456 mContext.insertSourceId(mId);
457 mId = 0;
460 mStream.reset();
461 if(mBuffer)
462 mBuffer->removeSource(Source(this));
463 mBuffer = 0;
465 mPaused.store(false, std::memory_order_release);
469 DECL_THUNK2(void, Source, fadeOutToStop,, ALfloat, std::chrono::milliseconds)
470 void SourceImpl::fadeOutToStop(ALfloat gain, std::chrono::milliseconds duration)
472 if(!(gain < 1.0f && gain >= 0.0f))
473 throw std::out_of_range("Fade gain target out of range");
474 if(duration.count() <= 0)
475 throw std::out_of_range("Fade duration out of range");
476 CheckContext(mContext);
478 mFadeGainTarget = std::max<ALfloat>(gain, 0.0001f);
479 mLastFadeTime = std::chrono::steady_clock::now().time_since_epoch();
480 mFadeTimeTarget = mLastFadeTime + duration;
482 mContext.addFadingSource(this);
486 void SourceImpl::checkPaused()
488 if(mPaused.load(std::memory_order_acquire) || mId == 0)
489 return;
491 ALint state = -1;
492 alGetSourcei(mId, AL_SOURCE_STATE, &state);
493 // Streaming sources may be in a stopped or initial state if underrun
494 mPaused.store(state == AL_PAUSED || (mStream && mStream->hasMoreData()),
495 std::memory_order_release);
498 DECL_THUNK0(void, Source, pause,)
499 void SourceImpl::pause()
501 CheckContext(mContext);
502 if(mPaused.load(std::memory_order_acquire))
503 return;
505 if(mId != 0)
507 std::lock_guard<std::mutex> lock(mMutex);
508 alSourcePause(mId);
509 ALint state = -1;
510 alGetSourcei(mId, AL_SOURCE_STATE, &state);
511 // Streaming sources may be in a stopped or initial state if underrun
512 mPaused.store(state == AL_PAUSED || (mStream && mStream->hasMoreData()),
513 std::memory_order_release);
517 DECL_THUNK0(void, Source, resume,)
518 void SourceImpl::resume()
520 CheckContext(mContext);
521 if(!mPaused.load(std::memory_order_acquire))
522 return;
524 if(mId != 0)
525 alSourcePlay(mId);
526 mPaused.store(false, std::memory_order_release);
530 DECL_THUNK0(bool, Source, isPending, const)
531 bool SourceImpl::isPending() const
533 CheckContext(mContext);
534 return mContext.isPendingSource(this);
537 DECL_THUNK0(bool, Source, isPlaying, const)
538 bool SourceImpl::isPlaying() const
540 CheckContext(mContext);
541 if(mId == 0) return false;
543 ALint state = -1;
544 alGetSourcei(mId, AL_SOURCE_STATE, &state);
545 if(state == -1)
546 throw std::runtime_error("Source state error");
548 return state == AL_PLAYING || (!mPaused.load(std::memory_order_acquire) &&
549 mStream && mStream->hasMoreData());
552 DECL_THUNK0(bool, Source, isPaused, const)
553 bool SourceImpl::isPaused() const
555 CheckContext(mContext);
556 return mId != 0 && mPaused.load(std::memory_order_acquire);
560 DECL_THUNK1(void, Source, setGroup,, SourceGroup)
561 void SourceImpl::setGroup(SourceGroup group)
563 CheckContext(mContext);
565 SourceGroupImpl *parent = group.getHandle();
566 if(parent == mGroup) return;
568 if(mGroup)
569 mGroup->eraseSource(this);
570 mGroup = parent;
571 if(mGroup)
573 mGroup->insertSource(this);
574 mGroupPitch = mGroup->getAppliedPitch();
575 mGroupGain = mGroup->getAppliedGain();
577 else
579 mGroupPitch = 1.0f;
580 mGroupGain = 1.0f;
583 if(mId)
585 alSourcef(mId, AL_PITCH, mPitch * mGroupPitch);
586 alSourcef(mId, AL_GAIN, mGain * mGroupGain * mFadeGain);
591 bool SourceImpl::checkPending(SharedFuture<Buffer> &future)
593 if(GetFutureState(future) != std::future_status::ready)
594 return true;
596 BufferImpl *buffer = future.get().getHandle();
597 if(UNLIKELY(!buffer || &(buffer->getContext()) != &mContext))
598 return false;
600 if(mId == 0)
602 mId = mContext.getSourceId(mPriority);
603 applyProperties(mLooping, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
605 else
607 alSourceRewind(mId);
608 alSourcei(mId, AL_BUFFER, 0);
609 alSourcei(mId, AL_LOOPING, mLooping ? AL_TRUE : AL_FALSE);
610 alSourcei(mId, AL_SAMPLE_OFFSET, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
612 mOffset = 0;
614 mBuffer = buffer;
615 mBuffer->addSource(Source(this));
617 alSourcei(mId, AL_BUFFER, mBuffer->getId());
618 alSourcePlay(mId);
619 mPaused.store(false, std::memory_order_release);
620 mContext.addPlayingSource(this, mId);
621 return false;
624 bool SourceImpl::fadeUpdate(std::chrono::nanoseconds cur_fade_time)
626 if((cur_fade_time - mFadeTimeTarget).count() >= 0)
628 mLastFadeTime = mFadeTimeTarget;
629 mFadeGain = 1.0f;
630 if(mFadeGainTarget >= 1.0f)
632 if(mId != 0)
633 alSourcef(mId, AL_GAIN, mGain * mGroupGain);
634 return false;
636 mContext.removePendingSource(this);
637 mContext.removePlayingSource(this);
638 makeStopped(true);
639 return false;
642 float mult = std::pow(mFadeGainTarget/mFadeGain,
643 float(1.0/Seconds(mFadeTimeTarget-mLastFadeTime).count())
646 std::chrono::nanoseconds duration = cur_fade_time - mLastFadeTime;
647 mLastFadeTime = cur_fade_time;
649 float gain = mFadeGain * std::pow(mult, (float)Seconds(duration).count());
650 if(UNLIKELY(gain == mFadeGain))
652 // Ensure the gain keeps moving toward its target, in case precision
653 // loss results in no change with small steps.
654 gain = std::nextafter(gain, mFadeGainTarget);
656 mFadeGain = gain;
658 if(mId != 0)
659 alSourcef(mId, AL_GAIN, mGain * mGroupGain * mFadeGain);
660 return true;
663 bool SourceImpl::playUpdate(ALuint id)
665 ALint state = -1;
666 alGetSourcei(id, AL_SOURCE_STATE, &state);
667 if(LIKELY(state == AL_PLAYING || state == AL_PAUSED))
668 return true;
670 makeStopped();
671 mContext.send(&MessageHandler::sourceStopped, Source(this));
672 return false;
675 bool SourceImpl::playUpdate()
677 if(LIKELY(mIsAsync.load(std::memory_order_acquire)))
678 return true;
680 makeStopped();
681 mContext.send(&MessageHandler::sourceStopped, Source(this));
682 return false;
686 ALint SourceImpl::refillBufferStream()
688 ALint processed;
689 alGetSourcei(mId, AL_BUFFERS_PROCESSED, &processed);
690 while(processed > 0)
692 ALuint buf;
693 alSourceUnqueueBuffers(mId, 1, &buf);
694 --processed;
697 ALint queued;
698 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
699 for(;(ALuint)queued < mStream->getNumUpdates();queued++)
701 if(!mStream->streamMoreData(mId, mLooping))
702 break;
705 return queued;
708 bool SourceImpl::updateAsync()
710 std::lock_guard<std::mutex> lock(mMutex);
712 ALint queued = refillBufferStream();
713 if(queued == 0)
715 mIsAsync.store(false, std::memory_order_release);
716 return false;
719 ALint state = -1;
720 alGetSourcei(mId, AL_SOURCE_STATE, &state);
721 if(!mPaused.load(std::memory_order_acquire))
723 // Make sure the source is still playing if it's not paused.
724 if(state != AL_PLAYING)
725 alSourcePlay(mId);
727 else
729 // Rewind the source to an initial state if it underrun as it was
730 // paused.
731 if(state == AL_STOPPED)
732 alSourceRewind(mId);
734 return true;
738 DECL_THUNK1(void, Source, setPriority,, ALuint)
739 void SourceImpl::setPriority(ALuint priority)
741 mPriority = priority;
745 DECL_THUNK1(void, Source, setOffset,, uint64_t)
746 void SourceImpl::setOffset(uint64_t offset)
748 CheckContext(mContext);
749 if(mId == 0)
751 mOffset = offset;
752 return;
755 if(!mStream)
757 if(offset >= std::numeric_limits<ALint>::max())
758 throw std::out_of_range("Offset out of range");
759 alGetError();
760 alSourcei(mId, AL_SAMPLE_OFFSET, (ALint)offset);
761 throw_al_error("Failed to set offset");
763 else
765 std::lock_guard<std::mutex> lock(mMutex);
766 if(!mStream->seek(offset))
767 throw std::runtime_error("Failed to seek to offset");
768 alSourceRewind(mId);
769 alSourcei(mId, AL_BUFFER, 0);
770 ALint queued = refillBufferStream();
771 if(queued > 0 && !mPaused.load(std::memory_order_acquire))
772 alSourcePlay(mId);
776 DECL_THUNK0(UInt64NSecPair, Source, getSampleOffsetLatency, const)
777 std::pair<uint64_t,std::chrono::nanoseconds> SourceImpl::getSampleOffsetLatency() const
779 std::pair<uint64_t,std::chrono::nanoseconds> ret{0, std::chrono::nanoseconds::zero()};
780 CheckContext(mContext);
781 if(mId == 0) return ret;
783 if(mStream)
785 std::lock_guard<std::mutex> lock(mMutex);
786 ALint queued = 0, state = -1, srcpos = 0;
788 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
789 if(mContext.hasExtension(AL::SOFT_source_latency))
791 ALint64SOFT val[2];
792 mContext.alGetSourcei64vSOFT(mId, AL_SAMPLE_OFFSET_LATENCY_SOFT, val);
793 srcpos = val[0]>>32;
794 ret.second = std::chrono::nanoseconds(val[1]);
796 else
797 alGetSourcei(mId, AL_SAMPLE_OFFSET, &srcpos);
798 alGetSourcei(mId, AL_SOURCE_STATE, &state);
800 int64_t streampos = mStream->getPosition();
801 if(state != AL_STOPPED)
803 // The amount of samples in the queue waiting to play
804 ALuint inqueue = queued*mStream->getUpdateLength() - srcpos;
805 if(!mStream->hasLooped())
807 // A non-looped stream should never have more samples queued
808 // than have been read...
809 streampos = std::max<int64_t>(streampos, inqueue) - inqueue;
811 else
813 streampos -= inqueue;
814 int64_t looplen = mStream->getLoopEnd() - mStream->getLoopStart();
815 while(streampos < mStream->getLoopStart())
816 streampos += looplen;
820 ret.first = streampos;
821 return ret;
824 ALint srcpos = 0;
825 if(mContext.hasExtension(AL::SOFT_source_latency))
827 ALint64SOFT val[2];
828 mContext.alGetSourcei64vSOFT(mId, AL_SAMPLE_OFFSET_LATENCY_SOFT, val);
829 srcpos = val[0]>>32;
830 ret.second = std::chrono::nanoseconds(val[1]);
832 else
833 alGetSourcei(mId, AL_SAMPLE_OFFSET, &srcpos);
834 ret.first = srcpos;
835 return ret;
838 DECL_THUNK0(SecondsPair, Source, getSecOffsetLatency, const)
839 std::pair<Seconds,Seconds> SourceImpl::getSecOffsetLatency() const
841 std::pair<Seconds,Seconds> ret{Seconds::zero(), Seconds::zero()};
842 CheckContext(mContext);
843 if(mId == 0) return ret;
845 if(mStream)
847 std::lock_guard<std::mutex> lock(mMutex);
848 ALint queued = 0, state = -1;
849 ALdouble srcpos = 0;
851 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
852 if(mContext.hasExtension(AL::SOFT_source_latency))
854 ALdouble val[2];
855 mContext.alGetSourcedvSOFT(mId, AL_SEC_OFFSET_LATENCY_SOFT, val);
856 srcpos = val[0];
857 ret.second = Seconds(val[1]);
859 else
861 ALfloat f;
862 alGetSourcef(mId, AL_SEC_OFFSET, &f);
863 srcpos = f;
865 alGetSourcei(mId, AL_SOURCE_STATE, &state);
867 ALdouble frac = 0.0;
868 int64_t streampos = mStream->getPosition();
869 if(state != AL_STOPPED)
871 ALdouble ipos;
872 frac = std::modf(srcpos * mStream->getFrequency(), &ipos);
874 // The amount of samples in the queue waiting to play
875 ALuint inqueue = queued*mStream->getUpdateLength() - (ALuint)ipos;
876 if(!mStream->hasLooped())
878 // A non-looped stream should never have more samples queued
879 // than have been read...
880 streampos = std::max<int64_t>(streampos, inqueue) - inqueue;
882 else
884 streampos -= inqueue;
885 int64_t looplen = mStream->getLoopEnd() - mStream->getLoopStart();
886 while(streampos < mStream->getLoopStart())
887 streampos += looplen;
891 ret.first = Seconds((streampos+frac) / mStream->getFrequency());
892 return ret;
895 if(mContext.hasExtension(AL::SOFT_source_latency))
897 ALdouble val[2];
898 mContext.alGetSourcedvSOFT(mId, AL_SEC_OFFSET_LATENCY_SOFT, val);
899 ret.first = Seconds(val[0]);
900 ret.second = Seconds(val[1]);
902 else
904 ALfloat f;
905 alGetSourcef(mId, AL_SEC_OFFSET, &f);
906 ret.first = Seconds(f);
908 return ret;
912 DECL_THUNK1(void, Source, setLooping,, bool)
913 void SourceImpl::setLooping(bool looping)
915 CheckContext(mContext);
917 if(mId && !mStream)
918 alSourcei(mId, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
919 mLooping = looping;
923 DECL_THUNK1(void, Source, setPitch,, ALfloat)
924 void SourceImpl::setPitch(ALfloat pitch)
926 if(!(pitch > 0.0f))
927 throw std::out_of_range("Pitch out of range");
928 CheckContext(mContext);
929 if(mId != 0)
930 alSourcef(mId, AL_PITCH, pitch * mGroupPitch);
931 mPitch = pitch;
935 DECL_THUNK1(void, Source, setGain,, ALfloat)
936 void SourceImpl::setGain(ALfloat gain)
938 if(!(gain >= 0.0f))
939 throw std::out_of_range("Gain out of range");
940 CheckContext(mContext);
941 if(mId != 0)
942 alSourcef(mId, AL_GAIN, gain * mGroupGain * mFadeGain);
943 mGain = gain;
946 DECL_THUNK2(void, Source, setGainRange,, ALfloat, ALfloat)
947 void SourceImpl::setGainRange(ALfloat mingain, ALfloat maxgain)
949 if(!(mingain >= 0.0f && maxgain <= 1.0f && maxgain >= mingain))
950 throw std::out_of_range("Gain range out of range");
951 CheckContext(mContext);
952 if(mId != 0)
954 alSourcef(mId, AL_MIN_GAIN, mingain);
955 alSourcef(mId, AL_MAX_GAIN, maxgain);
957 mMinGain = mingain;
958 mMaxGain = maxgain;
962 DECL_THUNK2(void, Source, setDistanceRange,, ALfloat, ALfloat)
963 void SourceImpl::setDistanceRange(ALfloat refdist, ALfloat maxdist)
965 if(!(refdist >= 0.0f && maxdist <= std::numeric_limits<float>::max() && refdist <= maxdist))
966 throw std::out_of_range("Distance range out of range");
967 CheckContext(mContext);
968 if(mId != 0)
970 alSourcef(mId, AL_REFERENCE_DISTANCE, refdist);
971 alSourcef(mId, AL_MAX_DISTANCE, maxdist);
973 mRefDist = refdist;
974 mMaxDist = maxdist;
978 DECL_THUNK3(void, Source, set3DParameters,, const Vector3&, const Vector3&, const Vector3&)
979 void SourceImpl::set3DParameters(const Vector3 &position, const Vector3 &velocity, const Vector3 &direction)
981 CheckContext(mContext);
982 if(mId != 0)
984 Batcher batcher = mContext.getBatcher();
985 alSourcefv(mId, AL_POSITION, position.getPtr());
986 alSourcefv(mId, AL_VELOCITY, velocity.getPtr());
987 alSourcefv(mId, AL_DIRECTION, direction.getPtr());
989 mPosition = position;
990 mVelocity = velocity;
991 mDirection = direction;
994 DECL_THUNK3(void, Source, set3DParameters,, const Vector3&, const Vector3&, const Vector3Pair&)
995 void SourceImpl::set3DParameters(const Vector3 &position, const Vector3 &velocity, const std::pair<Vector3,Vector3> &orientation)
997 static_assert(sizeof(orientation) == sizeof(ALfloat[6]), "Invalid Vector3 pair size");
998 CheckContext(mContext);
999 if(mId != 0)
1001 Batcher batcher = mContext.getBatcher();
1002 alSourcefv(mId, AL_POSITION, position.getPtr());
1003 alSourcefv(mId, AL_VELOCITY, velocity.getPtr());
1004 if(mContext.hasExtension(AL::EXT_BFORMAT))
1005 alSourcefv(mId, AL_ORIENTATION, orientation.first.getPtr());
1006 alSourcefv(mId, AL_DIRECTION, orientation.first.getPtr());
1008 mPosition = position;
1009 mVelocity = velocity;
1010 mDirection = mOrientation[0] = orientation.first;
1011 mOrientation[1] = orientation.second;
1015 DECL_THUNK1(void, Source, setPosition,, const Vector3&)
1016 void SourceImpl::setPosition(const Vector3 &position)
1018 CheckContext(mContext);
1019 if(mId != 0)
1020 alSourcefv(mId, AL_POSITION, position.getPtr());
1021 mPosition = position;
1024 DECL_THUNK1(void, Source, setPosition,, const ALfloat*)
1025 void SourceImpl::setPosition(const ALfloat *pos)
1027 CheckContext(mContext);
1028 if(mId != 0)
1029 alSourcefv(mId, AL_POSITION, pos);
1030 mPosition[0] = pos[0];
1031 mPosition[1] = pos[1];
1032 mPosition[2] = pos[2];
1035 DECL_THUNK1(void, Source, setVelocity,, const Vector3&)
1036 void SourceImpl::setVelocity(const Vector3 &velocity)
1038 CheckContext(mContext);
1039 if(mId != 0)
1040 alSourcefv(mId, AL_VELOCITY, velocity.getPtr());
1041 mVelocity = velocity;
1044 DECL_THUNK1(void, Source, setVelocity,, const ALfloat*)
1045 void SourceImpl::setVelocity(const ALfloat *vel)
1047 CheckContext(mContext);
1048 if(mId != 0)
1049 alSourcefv(mId, AL_VELOCITY, vel);
1050 mVelocity[0] = vel[0];
1051 mVelocity[1] = vel[1];
1052 mVelocity[2] = vel[2];
1055 DECL_THUNK1(void, Source, setDirection,, const Vector3&)
1056 void SourceImpl::setDirection(const Vector3 &direction)
1058 CheckContext(mContext);
1059 if(mId != 0)
1060 alSourcefv(mId, AL_DIRECTION, direction.getPtr());
1061 mDirection = direction;
1064 DECL_THUNK1(void, Source, setDirection,, const ALfloat*)
1065 void SourceImpl::setDirection(const ALfloat *dir)
1067 CheckContext(mContext);
1068 if(mId != 0)
1069 alSourcefv(mId, AL_DIRECTION, dir);
1070 mDirection[0] = dir[0];
1071 mDirection[1] = dir[1];
1072 mDirection[2] = dir[2];
1075 DECL_THUNK1(void, Source, setOrientation,, const Vector3Pair&)
1076 void SourceImpl::setOrientation(const std::pair<Vector3,Vector3> &orientation)
1078 CheckContext(mContext);
1079 if(mId != 0)
1081 if(mContext.hasExtension(AL::EXT_BFORMAT))
1082 alSourcefv(mId, AL_ORIENTATION, orientation.first.getPtr());
1083 alSourcefv(mId, AL_DIRECTION, orientation.first.getPtr());
1085 mDirection = mOrientation[0] = orientation.first;
1086 mOrientation[1] = orientation.second;
1089 DECL_THUNK2(void, Source, setOrientation,, const ALfloat*, const ALfloat*)
1090 void SourceImpl::setOrientation(const ALfloat *at, const ALfloat *up)
1092 CheckContext(mContext);
1093 if(mId != 0)
1095 ALfloat ori[6] = { at[0], at[1], at[2], up[0], up[1], up[2] };
1096 if(mContext.hasExtension(AL::EXT_BFORMAT))
1097 alSourcefv(mId, AL_ORIENTATION, ori);
1098 alSourcefv(mId, AL_DIRECTION, ori);
1100 mDirection[0] = mOrientation[0][0] = at[0];
1101 mDirection[1] = mOrientation[0][1] = at[1];
1102 mDirection[2] = mOrientation[0][2] = at[2];
1103 mOrientation[1][0] = up[0];
1104 mOrientation[1][1] = up[1];
1105 mOrientation[1][2] = up[2];
1108 DECL_THUNK1(void, Source, setOrientation,, const ALfloat*)
1109 void SourceImpl::setOrientation(const ALfloat *ori)
1111 CheckContext(mContext);
1112 if(mId != 0)
1114 if(mContext.hasExtension(AL::EXT_BFORMAT))
1115 alSourcefv(mId, AL_ORIENTATION, ori);
1116 alSourcefv(mId, AL_DIRECTION, ori);
1118 mDirection[0] = mOrientation[0][0] = ori[0];
1119 mDirection[1] = mOrientation[0][1] = ori[1];
1120 mDirection[2] = mOrientation[0][2] = ori[2];
1121 mOrientation[1][0] = ori[3];
1122 mOrientation[1][1] = ori[4];
1123 mOrientation[1][2] = ori[5];
1127 DECL_THUNK2(void, Source, setConeAngles,, ALfloat, ALfloat)
1128 void SourceImpl::setConeAngles(ALfloat inner, ALfloat outer)
1130 if(!(inner >= 0.0f && outer <= 360.0f && outer >= inner))
1131 throw std::out_of_range("Cone angles out of range");
1132 CheckContext(mContext);
1133 if(mId != 0)
1135 alSourcef(mId, AL_CONE_INNER_ANGLE, inner);
1136 alSourcef(mId, AL_CONE_OUTER_ANGLE, outer);
1138 mConeInnerAngle = inner;
1139 mConeOuterAngle = outer;
1142 DECL_THUNK2(void, Source, setOuterConeGains,, ALfloat, ALfloat)
1143 void SourceImpl::setOuterConeGains(ALfloat gain, ALfloat gainhf)
1145 if(!(gain >= 0.0f && gain <= 1.0f && gainhf >= 0.0f && gainhf <= 1.0f))
1146 throw std::out_of_range("Outer cone gain out of range");
1147 CheckContext(mContext);
1148 if(mId != 0)
1150 alSourcef(mId, AL_CONE_OUTER_GAIN, gain);
1151 if(mContext.hasExtension(AL::EXT_EFX))
1152 alSourcef(mId, AL_CONE_OUTER_GAINHF, gainhf);
1154 mConeOuterGain = gain;
1155 mConeOuterGainHF = gainhf;
1159 DECL_THUNK2(void, Source, setRolloffFactors,, ALfloat, ALfloat)
1160 void SourceImpl::setRolloffFactors(ALfloat factor, ALfloat roomfactor)
1162 if(!(factor >= 0.0f && roomfactor >= 0.0f))
1163 throw std::out_of_range("Rolloff factor out of range");
1164 CheckContext(mContext);
1165 if(mId != 0)
1167 alSourcef(mId, AL_ROLLOFF_FACTOR, factor);
1168 if(mContext.hasExtension(AL::EXT_EFX))
1169 alSourcef(mId, AL_ROOM_ROLLOFF_FACTOR, roomfactor);
1171 mRolloffFactor = factor;
1172 mRoomRolloffFactor = roomfactor;
1175 DECL_THUNK1(void, Source, setDopplerFactor,, ALfloat)
1176 void SourceImpl::setDopplerFactor(ALfloat factor)
1178 if(!(factor >= 0.0f && factor <= 1.0f))
1179 throw std::out_of_range("Doppler factor out of range");
1180 CheckContext(mContext);
1181 if(mId != 0)
1182 alSourcef(mId, AL_DOPPLER_FACTOR, factor);
1183 mDopplerFactor = factor;
1186 DECL_THUNK1(void, Source, setRelative,, bool)
1187 void SourceImpl::setRelative(bool relative)
1189 CheckContext(mContext);
1190 if(mId != 0)
1191 alSourcei(mId, AL_SOURCE_RELATIVE, relative ? AL_TRUE : AL_FALSE);
1192 mRelative = relative;
1195 DECL_THUNK1(void, Source, setRadius,, ALfloat)
1196 void SourceImpl::setRadius(ALfloat radius)
1198 if(!(mRadius >= 0.0f))
1199 throw std::out_of_range("Radius out of range");
1200 CheckContext(mContext);
1201 if(mId != 0 && mContext.hasExtension(AL::EXT_SOURCE_RADIUS))
1202 alSourcef(mId, AL_SOURCE_RADIUS, radius);
1203 mRadius = radius;
1206 DECL_THUNK2(void, Source, setStereoAngles,, ALfloat, ALfloat)
1207 void SourceImpl::setStereoAngles(ALfloat leftAngle, ALfloat rightAngle)
1209 CheckContext(mContext);
1210 if(mId != 0 && mContext.hasExtension(AL::EXT_STEREO_ANGLES))
1212 ALfloat angles[2] = { leftAngle, rightAngle };
1213 alSourcefv(mId, AL_STEREO_ANGLES, angles);
1215 mStereoAngles[0] = leftAngle;
1216 mStereoAngles[1] = rightAngle;
1219 DECL_THUNK1(void, Source, set3DSpatialize,, Spatialize)
1220 void SourceImpl::set3DSpatialize(Spatialize spatialize)
1222 CheckContext(mContext);
1223 if(mId != 0 && mContext.hasExtension(AL::SOFT_source_spatialize))
1224 alSourcei(mId, AL_SOURCE_SPATIALIZE_SOFT, (ALint)spatialize);
1225 mSpatialize = spatialize;
1228 DECL_THUNK1(void, Source, setResamplerIndex,, ALsizei)
1229 void SourceImpl::setResamplerIndex(ALsizei index)
1231 if(index < 0)
1232 throw std::out_of_range("Resampler index out of range");
1233 index = std::min<ALsizei>(index, mContext.getAvailableResamplers().size());
1234 if(mId != 0 && mContext.hasExtension(AL::SOFT_source_resampler))
1235 alSourcei(mId, AL_SOURCE_RESAMPLER_SOFT, index);
1236 mResampler = index;
1239 DECL_THUNK1(void, Source, setAirAbsorptionFactor,, ALfloat)
1240 void SourceImpl::setAirAbsorptionFactor(ALfloat factor)
1242 if(!(factor >= 0.0f && factor <= 10.0f))
1243 throw std::out_of_range("Absorption factor out of range");
1244 CheckContext(mContext);
1245 if(mId != 0 && mContext.hasExtension(AL::EXT_EFX))
1246 alSourcef(mId, AL_AIR_ABSORPTION_FACTOR, factor);
1247 mAirAbsorptionFactor = factor;
1250 DECL_THUNK3(void, Source, setGainAuto,, bool, bool, bool)
1251 void SourceImpl::setGainAuto(bool directhf, bool send, bool sendhf)
1253 CheckContext(mContext);
1254 if(mId != 0 && mContext.hasExtension(AL::EXT_EFX))
1256 alSourcei(mId, AL_DIRECT_FILTER_GAINHF_AUTO, directhf ? AL_TRUE : AL_FALSE);
1257 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, send ? AL_TRUE : AL_FALSE);
1258 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, sendhf ? AL_TRUE : AL_FALSE);
1260 mDryGainHFAuto = directhf;
1261 mWetGainAuto = send;
1262 mWetGainHFAuto = sendhf;
1266 void SourceImpl::setFilterParams(ALuint &filterid, const FilterParams &params)
1268 if(!mContext.hasExtension(AL::EXT_EFX))
1269 return;
1271 if(!(params.mGain < 1.0f || params.mGainHF < 1.0f || params.mGainLF < 1.0f))
1273 if(filterid)
1274 mContext.alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_NULL);
1275 return;
1278 alGetError();
1279 if(!filterid)
1281 mContext.alGenFilters(1, &filterid);
1282 throw_al_error("Failed to create Filter");
1284 bool filterset = false;
1285 if(params.mGainHF < 1.0f && params.mGainLF < 1.0f)
1287 mContext.alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_BANDPASS);
1288 if(alGetError() == AL_NO_ERROR)
1290 mContext.alFilterf(filterid, AL_BANDPASS_GAIN, std::min(params.mGain, 1.0f));
1291 mContext.alFilterf(filterid, AL_BANDPASS_GAINHF, std::min(params.mGainHF, 1.0f));
1292 mContext.alFilterf(filterid, AL_BANDPASS_GAINLF, std::min(params.mGainLF, 1.0f));
1293 filterset = true;
1296 if(!filterset && !(params.mGainHF < 1.0f) && params.mGainLF < 1.0f)
1298 mContext.alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_HIGHPASS);
1299 if(alGetError() == AL_NO_ERROR)
1301 mContext.alFilterf(filterid, AL_HIGHPASS_GAIN, std::min(params.mGain, 1.0f));
1302 mContext.alFilterf(filterid, AL_HIGHPASS_GAINLF, std::min(params.mGainLF, 1.0f));
1303 filterset = true;
1306 if(!filterset)
1308 mContext.alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1309 if(alGetError() == AL_NO_ERROR)
1311 mContext.alFilterf(filterid, AL_LOWPASS_GAIN, std::min(params.mGain, 1.0f));
1312 mContext.alFilterf(filterid, AL_LOWPASS_GAINHF, std::min(params.mGainHF, 1.0f));
1313 filterset = true;
1319 DECL_THUNK1(void, Source, setDirectFilter,, const FilterParams&)
1320 void SourceImpl::setDirectFilter(const FilterParams &filter)
1322 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1323 throw std::out_of_range("Gain value out of range");
1324 CheckContext(mContext);
1326 setFilterParams(mDirectFilter, filter);
1327 if(mId)
1328 alSourcei(mId, AL_DIRECT_FILTER, mDirectFilter);
1331 DECL_THUNK2(void, Source, setSendFilter,, ALuint, const FilterParams&)
1332 void SourceImpl::setSendFilter(ALuint send, const FilterParams &filter)
1334 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1335 throw std::out_of_range("Gain value out of range");
1336 CheckContext(mContext);
1338 auto siter = std::lower_bound(mEffectSlots.begin(), mEffectSlots.end(), send,
1339 [](const SendProps &prop, ALuint send) -> bool
1340 { return prop.mSendIdx < send; }
1342 if(siter == mEffectSlots.end() || siter->mSendIdx != send)
1344 ALuint filterid = 0;
1346 setFilterParams(filterid, filter);
1347 if(!filterid) return;
1349 siter = mEffectSlots.emplace(siter, send, filterid);
1351 else
1352 setFilterParams(siter->mFilter, filter);
1354 if(mId)
1356 ALuint slotid = (siter->mSlot ? siter->mSlot->getId() : 0);
1357 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->mFilter);
1361 DECL_THUNK2(void, Source, setAuxiliarySend,, AuxiliaryEffectSlot, ALuint)
1362 void SourceImpl::setAuxiliarySend(AuxiliaryEffectSlot auxslot, ALuint send)
1364 AuxiliaryEffectSlotImpl *slot = auxslot.getHandle();
1365 if(slot) CheckContexts(mContext, slot->getContext());
1366 CheckContext(mContext);
1368 auto siter = std::lower_bound(mEffectSlots.begin(), mEffectSlots.end(), send,
1369 [](const SendProps &prop, ALuint send) -> bool
1370 { return prop.mSendIdx < send; }
1372 if(siter == mEffectSlots.end() || siter->mSendIdx != send)
1374 if(!slot) return;
1375 slot->addSourceSend({Source(this), send});
1376 siter = mEffectSlots.emplace(siter, send, slot);
1378 else if(siter->mSlot != slot)
1380 if(slot) slot->addSourceSend({Source(this), send});
1381 if(siter->mSlot)
1382 siter->mSlot->removeSourceSend({Source(this), send});
1383 siter->mSlot = slot;
1386 if(mId)
1388 ALuint slotid = (siter->mSlot ? siter->mSlot->getId() : 0);
1389 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->mFilter);
1393 DECL_THUNK3(void, Source, setAuxiliarySendFilter,, AuxiliaryEffectSlot, ALuint, const FilterParams&)
1394 void SourceImpl::setAuxiliarySendFilter(AuxiliaryEffectSlot auxslot, ALuint send, const FilterParams &filter)
1396 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1397 throw std::out_of_range("Gain value out of range");
1398 AuxiliaryEffectSlotImpl *slot = auxslot.getHandle();
1399 if(slot) CheckContexts(mContext, slot->getContext());
1400 CheckContext(mContext);
1402 auto siter = std::lower_bound(mEffectSlots.begin(), mEffectSlots.end(), send,
1403 [](const SendProps &prop, ALuint send) -> bool
1404 { return prop.mSendIdx < send; }
1406 if(siter == mEffectSlots.end() || siter->mSendIdx != send)
1408 ALuint filterid = 0;
1410 setFilterParams(filterid, filter);
1411 if(!filterid && !slot)
1412 return;
1414 if(slot) slot->addSourceSend({Source(this), send});
1415 siter = mEffectSlots.emplace(siter, send, slot, filterid);
1417 else
1419 if(siter->mSlot != slot)
1421 if(slot) slot->addSourceSend({Source(this), send});
1422 if(siter->mSlot)
1423 siter->mSlot->removeSourceSend({Source(this), send});
1424 siter->mSlot = slot;
1426 setFilterParams(siter->mFilter, filter);
1429 if(mId)
1431 ALuint slotid = (siter->mSlot ? siter->mSlot->getId() : 0);
1432 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->mFilter);
1437 void Source::release()
1439 SourceImpl *i = pImpl;
1440 pImpl = nullptr;
1441 i->release();
1443 void SourceImpl::release()
1445 stop();
1447 resetProperties();
1448 mContext.freeSource(this);
1452 DECL_THUNK0(SourceGroup, Source, getGroup, const)
1453 DECL_THUNK0(ALuint, Source, getPriority, const)
1454 DECL_THUNK0(bool, Source, getLooping, const)
1455 DECL_THUNK0(ALfloat, Source, getPitch, const)
1456 DECL_THUNK0(ALfloat, Source, getGain, const)
1457 DECL_THUNK0(ALfloatPair, Source, getGainRange, const)
1458 DECL_THUNK0(ALfloatPair, Source, getDistanceRange, const)
1459 DECL_THUNK0(Vector3, Source, getPosition, const)
1460 DECL_THUNK0(Vector3, Source, getVelocity, const)
1461 DECL_THUNK0(Vector3, Source, getDirection, const)
1462 DECL_THUNK0(Vector3Pair, Source, getOrientation, const)
1463 DECL_THUNK0(ALfloatPair, Source, getConeAngles, const)
1464 DECL_THUNK0(ALfloatPair, Source, getOuterConeGains, const)
1465 DECL_THUNK0(ALfloatPair, Source, getRolloffFactors, const)
1466 DECL_THUNK0(ALfloat, Source, getDopplerFactor, const)
1467 DECL_THUNK0(bool, Source, getRelative, const)
1468 DECL_THUNK0(ALfloat, Source, getRadius, const)
1469 DECL_THUNK0(ALfloatPair, Source, getStereoAngles, const)
1470 DECL_THUNK0(Spatialize, Source, get3DSpatialize, const)
1471 DECL_THUNK0(ALsizei, Source, getResamplerIndex, const)
1472 DECL_THUNK0(ALfloat, Source, getAirAbsorptionFactor, const)
1473 DECL_THUNK0(BoolTriple, Source, getGainAuto, const)