Rename AL* implementation classes to *Impl
[alure.git] / src / source.cpp
blob184b506e5b8ddfdea256af3762c62652da512cae
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 "al.h"
14 #include "alext.h"
16 #include "context.h"
17 #include "buffer.h"
18 #include "auxeffectslot.h"
19 #include "sourcegroup.h"
21 namespace alure
24 class ALBufferStream {
25 SharedPtr<Decoder> mDecoder;
27 ALuint mUpdateLen;
28 ALuint mNumUpdates;
30 ALenum mFormat;
31 ALuint mFrequency;
32 ALuint mFrameSize;
34 Vector<ALbyte> mData;
35 ALbyte mSilence;
37 Vector<ALuint> mBufferIds;
38 ALuint mCurrentIdx;
40 uint64_t mSamplePos;
41 std::pair<uint64_t,uint64_t> mLoopPts;
42 bool mHasLooped;
43 std::atomic<bool> mDone;
45 public:
46 ALBufferStream(SharedPtr<Decoder> decoder, ALuint updatelen, ALuint numupdates)
47 : mDecoder(decoder), mUpdateLen(updatelen), mNumUpdates(numupdates),
48 mFormat(AL_NONE), mFrequency(0), mFrameSize(0), mSilence(0),
49 mCurrentIdx(0), mSamplePos(0), mLoopPts{0,0}, mHasLooped(false),
50 mDone(false)
51 { }
52 ~ALBufferStream()
54 if(!mBufferIds.empty())
56 alDeleteBuffers(mBufferIds.size(), mBufferIds.data());
57 mBufferIds.clear();
61 uint64_t getLength() const { return mDecoder->getLength(); }
62 uint64_t getPosition() const { return mSamplePos; }
64 ALuint getNumUpdates() const { return mNumUpdates; }
65 ALuint getUpdateLength() const { return mUpdateLen; }
67 ALuint getFrequency() const { return mFrequency; }
69 bool seek(uint64_t pos)
71 if(!mDecoder->seek(pos))
72 return false;
73 mSamplePos = pos;
74 mHasLooped = false;
75 mDone.store(false, std::memory_order_release);
76 return true;
79 void prepare()
81 ALuint srate = mDecoder->getFrequency();
82 ChannelConfig chans = mDecoder->getChannelConfig();
83 SampleType type = mDecoder->getSampleType();
85 mLoopPts = mDecoder->getLoopPoints();
86 if(mLoopPts.first >= mLoopPts.second)
88 mLoopPts.first = 0;
89 mLoopPts.second = std::numeric_limits<uint64_t>::max();
92 mFrequency = srate;
93 mFrameSize = FramesToBytes(1, chans, type);
94 mFormat = GetFormat(chans, type);
95 if(mFormat == AL_NONE)
97 std::stringstream sstr;
98 sstr<< "Format not supported ("<<GetSampleTypeName(type)<<", "<<GetChannelConfigName(chans)<<")";
99 throw std::runtime_error(sstr.str());
102 mData.resize(mUpdateLen * mFrameSize);
103 if(type == SampleType::UInt8) mSilence = 0x80;
104 else if(type == SampleType::Mulaw) mSilence = 0x7f;
105 else mSilence = 0x00;
107 mBufferIds.assign(mNumUpdates, 0);
108 alGenBuffers(mBufferIds.size(), mBufferIds.data());
111 int64_t getLoopStart() const { return mLoopPts.first; }
112 int64_t getLoopEnd() const { return mLoopPts.second; }
114 bool hasLooped() const { return mHasLooped; }
115 bool hasMoreData() const { return !mDone.load(std::memory_order_acquire); }
116 bool streamMoreData(ALuint srcid, bool loop)
118 if(mDone.load(std::memory_order_acquire))
119 return false;
121 ALuint frames;
122 ALuint len = mUpdateLen;
123 if(loop && mSamplePos <= mLoopPts.second)
124 len = std::min<uint64_t>(len, mLoopPts.second - mSamplePos);
125 else
126 loop = false;
128 frames = mDecoder->read(mData.data(), len);
129 mSamplePos += frames;
130 if(frames < mUpdateLen && loop && mSamplePos > 0)
132 if(mSamplePos < mLoopPts.second)
134 mLoopPts.second = mSamplePos;
135 mLoopPts.first = std::min(mLoopPts.first, mLoopPts.second-1);
138 do {
139 if(!mDecoder->seek(mLoopPts.first))
140 break;
141 mSamplePos = mLoopPts.first;
142 mHasLooped = true;
144 len = std::min<uint64_t>(mUpdateLen-frames, mLoopPts.second-mLoopPts.first);
145 ALuint got = mDecoder->read(&mData[frames*mFrameSize], len);
146 if(got == 0) break;
147 mSamplePos += got;
148 frames += got;
149 } while(frames < mUpdateLen);
151 if(frames < mUpdateLen)
153 mDone.store(true, std::memory_order_release);
154 if(frames == 0) return false;
155 mSamplePos += mUpdateLen - frames;
156 std::fill(mData.begin() + frames*mFrameSize, mData.end(), mSilence);
159 alBufferData(mBufferIds[mCurrentIdx], mFormat, mData.data(), mData.size(), mFrequency);
160 alSourceQueueBuffers(srcid, 1, &mBufferIds[mCurrentIdx]);
161 mCurrentIdx = (mCurrentIdx+1) % mBufferIds.size();
162 return true;
167 SourceImpl::SourceImpl(ContextImpl *context)
168 : mContext(context), mId(0), mBuffer(0), mGroup(nullptr), mIsAsync(false),
169 mDirectFilter(AL_FILTER_NULL)
171 resetProperties();
174 SourceImpl::~SourceImpl()
179 void SourceImpl::resetProperties()
181 if(mGroup)
182 mGroup->removeSource(Source(this));
183 mGroup = nullptr;
185 mPaused.store(false, std::memory_order_release);
186 mOffset = 0;
187 mPitch = 1.0f;
188 mGain = 1.0f;
189 mMinGain = 0.0f;
190 mMaxGain = 1.0f;
191 mRefDist = 1.0f;
192 mMaxDist = std::numeric_limits<float>::max();
193 mPosition = Vector3(0.0f);
194 mVelocity = Vector3(0.0f);
195 mDirection = Vector3(0.0f);
196 mOrientation[0] = Vector3(0.0f, 0.0f, -1.0f);
197 mOrientation[1] = Vector3(0.0f, 1.0f, 0.0f);
198 mConeInnerAngle = 360.0f;
199 mConeOuterAngle = 360.0f;
200 mConeOuterGain = 0.0f;
201 mConeOuterGainHF = 1.0f;
202 mRolloffFactor = 1.0f;
203 mRoomRolloffFactor = 0.0f;
204 mDopplerFactor = 1.0f;
205 mAirAbsorptionFactor = 0.0f;
206 mRadius = 0.0f;
207 mStereoAngles[0] = F_PI / 6.0f;
208 mStereoAngles[1] = -F_PI / 6.0f;
209 mSpatialize = Spatialize::Auto;
210 mResampler = mContext->hasExtension(SOFT_source_resampler) ?
211 alGetInteger(AL_DEFAULT_RESAMPLER_SOFT) : 0;
212 mLooping = false;
213 mRelative = false;
214 mDryGainHFAuto = true;
215 mWetGainAuto = true;
216 mWetGainHFAuto = true;
217 if(mDirectFilter)
218 mContext->alDeleteFilters(1, &mDirectFilter);
219 mDirectFilter = 0;
220 for(auto &i : mEffectSlots)
222 if(i.second.mSlot)
223 i.second.mSlot->removeSourceSend(Source(this), i.first);
224 if(i.second.mFilter)
225 mContext->alDeleteFilters(1, &i.second.mFilter);
227 mEffectSlots.clear();
229 mPriority = 0;
232 void SourceImpl::applyProperties(bool looping, ALuint offset) const
234 alSourcei(mId, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
235 alSourcei(mId, AL_SAMPLE_OFFSET, offset);
236 if(mGroup)
238 alSourcef(mId, AL_PITCH, mPitch * mGroup->getAppliedPitch());
239 alSourcef(mId, AL_GAIN, mGain * mGroup->getAppliedGain());
241 else
243 alSourcef(mId, AL_PITCH, mPitch);
244 alSourcef(mId, AL_GAIN, mGain);
246 alSourcef(mId, AL_MIN_GAIN, mMinGain);
247 alSourcef(mId, AL_MAX_GAIN, mMaxGain);
248 alSourcef(mId, AL_REFERENCE_DISTANCE, mRefDist);
249 alSourcef(mId, AL_MAX_DISTANCE, mMaxDist);
250 alSourcefv(mId, AL_POSITION, mPosition.getPtr());
251 alSourcefv(mId, AL_VELOCITY, mVelocity.getPtr());
252 alSourcefv(mId, AL_DIRECTION, mDirection.getPtr());
253 if(mContext->hasExtension(EXT_BFORMAT))
254 alSourcefv(mId, AL_ORIENTATION, &mOrientation[0][0]);
255 alSourcef(mId, AL_CONE_INNER_ANGLE, mConeInnerAngle);
256 alSourcef(mId, AL_CONE_OUTER_ANGLE, mConeOuterAngle);
257 alSourcef(mId, AL_CONE_OUTER_GAIN, mConeOuterGain);
258 alSourcef(mId, AL_ROLLOFF_FACTOR, mRolloffFactor);
259 alSourcef(mId, AL_DOPPLER_FACTOR, mDopplerFactor);
260 if(mContext->hasExtension(EXT_SOURCE_RADIUS))
261 alSourcef(mId, AL_SOURCE_RADIUS, mRadius);
262 if(mContext->hasExtension(EXT_STEREO_ANGLES))
263 alSourcefv(mId, AL_STEREO_ANGLES, mStereoAngles);
264 if(mContext->hasExtension(SOFT_source_spatialize))
265 alSourcei(mId, AL_SOURCE_SPATIALIZE_SOFT, (ALint)mSpatialize);
266 if(mContext->hasExtension(SOFT_source_resampler))
267 alSourcei(mId, AL_SOURCE_RESAMPLER_SOFT, mResampler);
268 alSourcei(mId, AL_SOURCE_RELATIVE, mRelative ? AL_TRUE : AL_FALSE);
269 if(mContext->hasExtension(EXT_EFX))
271 alSourcef(mId, AL_CONE_OUTER_GAINHF, mConeOuterGainHF);
272 alSourcef(mId, AL_ROOM_ROLLOFF_FACTOR, mRoomRolloffFactor);
273 alSourcef(mId, AL_AIR_ABSORPTION_FACTOR, mAirAbsorptionFactor);
274 alSourcei(mId, AL_DIRECT_FILTER_GAINHF_AUTO, mDryGainHFAuto ? AL_TRUE : AL_FALSE);
275 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, mWetGainAuto ? AL_TRUE : AL_FALSE);
276 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, mWetGainHFAuto ? AL_TRUE : AL_FALSE);
277 alSourcei(mId, AL_DIRECT_FILTER, mDirectFilter);
278 for(const auto &i : mEffectSlots)
280 ALuint slotid = (i.second.mSlot ? i.second.mSlot->getId() : 0);
281 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, i.first, i.second.mFilter);
287 void SourceImpl::setGroup(SourceGroupImpl *group)
289 if(mGroup)
290 mGroup->removeSource(Source(this));
291 mGroup = group;
292 groupUpdate();
295 void SourceImpl::unsetGroup()
297 mGroup = nullptr;
298 groupUpdate();
301 void SourceImpl::groupUpdate()
303 if(mId)
305 if(mGroup)
307 alSourcef(mId, AL_PITCH, mPitch * mGroup->getAppliedPitch());
308 alSourcef(mId, AL_GAIN, mGain * mGroup->getAppliedGain());
310 else
312 alSourcef(mId, AL_PITCH, mPitch);
313 alSourcef(mId, AL_GAIN, mGain);
318 void SourceImpl::groupPropUpdate(ALfloat gain, ALfloat pitch)
320 if(mId)
322 alSourcef(mId, AL_PITCH, mPitch * pitch);
323 alSourcef(mId, AL_GAIN, mGain * gain);
328 void SourceImpl::play(Buffer buffer)
330 BufferImpl *albuf = buffer.getHandle();
331 if(!albuf) throw std::runtime_error("Buffer is not valid");
332 CheckContext(mContext);
333 CheckContext(albuf->getContext());
335 if(!albuf->isReady())
336 throw std::runtime_error("Buffer is not ready");
338 if(mIsAsync.load(std::memory_order_acquire))
340 mContext->removeStream(this);
341 mIsAsync.store(false, std::memory_order_release);
344 if(mId == 0)
346 mId = mContext->getSourceId(mPriority);
347 applyProperties(mLooping, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
349 else
351 alSourceRewind(mId);
352 alSourcei(mId, AL_BUFFER, 0);
353 alSourcei(mId, AL_LOOPING, mLooping ? AL_TRUE : AL_FALSE);
354 alSourcei(mId, AL_SAMPLE_OFFSET, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
356 mOffset = 0;
358 mStream.reset();
360 if(mBuffer)
361 mBuffer->removeSource(Source(this));
362 mBuffer = albuf;
363 mBuffer->addSource(Source(this));
365 alSourcei(mId, AL_BUFFER, mBuffer->getId());
366 alSourcePlay(mId);
367 mPaused.store(false, std::memory_order_release);
370 void SourceImpl::play(SharedPtr<Decoder> decoder, ALuint updatelen, ALuint queuesize)
372 if(updatelen < 64)
373 throw std::runtime_error("Update length out of range");
374 if(queuesize < 2)
375 throw std::runtime_error("Queue size out of range");
376 CheckContext(mContext);
378 auto stream = MakeUnique<ALBufferStream>(decoder, updatelen, queuesize);
379 stream->prepare();
381 if(mIsAsync.load(std::memory_order_acquire))
383 mContext->removeStream(this);
384 mIsAsync.store(false, std::memory_order_release);
387 if(mId == 0)
389 mId = mContext->getSourceId(mPriority);
390 applyProperties(false, 0);
392 else
394 alSourceRewind(mId);
395 alSourcei(mId, AL_BUFFER, 0);
396 alSourcei(mId, AL_LOOPING, AL_FALSE);
397 alSourcei(mId, AL_SAMPLE_OFFSET, 0);
400 if(mBuffer)
401 mBuffer->removeSource(Source(this));
402 mBuffer = 0;
404 mStream = std::move(stream);
406 mStream->seek(mOffset);
407 mOffset = 0;
409 for(ALuint i = 0;i < mStream->getNumUpdates();i++)
411 if(!mStream->streamMoreData(mId, mLooping))
412 break;
414 alSourcePlay(mId);
415 mPaused.store(false, std::memory_order_release);
417 mContext->addStream(this);
418 mIsAsync.store(true, std::memory_order_release);
422 void SourceImpl::makeStopped()
424 if(mIsAsync.load(std::memory_order_acquire))
426 mContext->removeStreamNoLock(this);
427 mIsAsync.store(false, std::memory_order_release);
430 if(mId != 0)
432 alSourceRewind(mId);
433 alSourcei(mId, AL_BUFFER, 0);
434 if(mContext->hasExtension(EXT_EFX))
436 alSourcei(mId, AL_DIRECT_FILTER, AL_FILTER_NULL);
437 for(auto &i : mEffectSlots)
438 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, 0, i.first, AL_FILTER_NULL);
440 mContext->insertSourceId(mId);
441 mId = 0;
444 if(mBuffer)
445 mBuffer->removeSource(Source(this));
446 mBuffer = 0;
448 mStream.reset();
450 mPaused.store(false, std::memory_order_release);
453 void SourceImpl::stop()
455 CheckContext(mContext);
456 if(mIsAsync.load(std::memory_order_acquire))
458 mContext->removeStream(this);
459 mIsAsync.store(false, std::memory_order_release);
461 makeStopped();
465 void SourceImpl::checkPaused()
467 if(mPaused.load(std::memory_order_acquire) || mId == 0)
468 return;
470 ALint state = -1;
471 alGetSourcei(mId, AL_SOURCE_STATE, &state);
472 // Streaming sources may be in a stopped state if underrun
473 mPaused.store((state == AL_PAUSED) ||
474 (state == AL_STOPPED && mStream && mStream->hasMoreData()),
475 std::memory_order_release);
478 void SourceImpl::pause()
480 CheckContext(mContext);
481 if(mPaused.load(std::memory_order_acquire))
482 return;
484 if(mId != 0)
486 std::lock_guard<std::mutex> lock(mMutex);
487 alSourcePause(mId);
488 ALint state = -1;
489 alGetSourcei(mId, AL_SOURCE_STATE, &state);
490 // Streaming sources may be in a stopped state if underrun
491 mPaused.store((state == AL_PAUSED) ||
492 (state == AL_STOPPED && mStream && mStream->hasMoreData()),
493 std::memory_order_release);
497 void SourceImpl::resume()
499 CheckContext(mContext);
500 if(!mPaused.load(std::memory_order_acquire))
501 return;
503 if(mId != 0)
504 alSourcePlay(mId);
505 mPaused.store(false, std::memory_order_release);
509 bool SourceImpl::isPlaying() const
511 CheckContext(mContext);
512 if(mId == 0) return false;
514 ALint state = -1;
515 alGetSourcei(mId, AL_SOURCE_STATE, &state);
516 if(state == -1)
517 throw std::runtime_error("Source state error");
519 return state == AL_PLAYING || (!mPaused.load(std::memory_order_acquire) &&
520 mStream && mStream->hasMoreData());
523 bool SourceImpl::isPaused() const
525 CheckContext(mContext);
526 if(mId == 0) return false;
528 ALint state = -1;
529 alGetSourcei(mId, AL_SOURCE_STATE, &state);
530 if(state == -1)
531 throw std::runtime_error("Source state error");
533 return state == AL_PAUSED || mPaused.load(std::memory_order_acquire);
537 ALint SourceImpl::refillBufferStream()
539 ALint processed;
540 alGetSourcei(mId, AL_BUFFERS_PROCESSED, &processed);
541 while(processed > 0)
543 ALuint buf;
544 alSourceUnqueueBuffers(mId, 1, &buf);
545 --processed;
548 ALint queued;
549 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
550 for(;(ALuint)queued < mStream->getNumUpdates();queued++)
552 if(!mStream->streamMoreData(mId, mLooping))
553 break;
556 return queued;
560 void SourceImpl::updateNoCtxCheck()
562 if(mId == 0)
563 return;
565 if(mStream)
567 if(!mIsAsync.load(std::memory_order_acquire))
569 stop();
570 mContext->send(&MessageHandler::sourceStopped, Source(this));
573 else
575 ALint state = -1;
576 alGetSourcei(mId, AL_SOURCE_STATE, &state);
577 if(state != AL_PLAYING && state != AL_PAUSED)
579 stop();
580 mContext->send(&MessageHandler::sourceStopped, Source(this));
585 bool SourceImpl::updateAsync()
587 std::lock_guard<std::mutex> lock(mMutex);
589 ALint queued = refillBufferStream();
590 if(queued == 0)
592 mIsAsync.store(false, std::memory_order_release);
593 return false;
595 if(!mPaused.load(std::memory_order_acquire))
597 ALint state = -1;
598 alGetSourcei(mId, AL_SOURCE_STATE, &state);
599 if(state != AL_PLAYING)
600 alSourcePlay(mId);
602 return true;
606 void SourceImpl::setPriority(ALuint priority)
608 mPriority = priority;
612 void SourceImpl::setOffset(uint64_t offset)
614 CheckContext(mContext);
615 if(mId == 0)
617 mOffset = offset;
618 return;
621 if(!mStream)
623 if(offset >= std::numeric_limits<ALint>::max())
624 throw std::runtime_error("Offset out of range");
625 alGetError();
626 alSourcei(mId, AL_SAMPLE_OFFSET, (ALint)offset);
627 if(alGetError() != AL_NO_ERROR)
628 throw std::runtime_error("Offset out of range");
630 else
632 std::lock_guard<std::mutex> lock(mMutex);
633 if(!mStream->seek(offset))
634 throw std::runtime_error("Failed to seek to offset");
635 alSourceRewind(mId);
636 alSourcei(mId, AL_BUFFER, 0);
637 ALint queued = refillBufferStream();
638 if(queued > 0 && !mPaused)
639 alSourcePlay(mId);
643 std::pair<uint64_t,std::chrono::nanoseconds> SourceImpl::getSampleOffsetLatency() const
645 CheckContext(mContext);
646 if(mId == 0)
647 return { 0, std::chrono::nanoseconds::zero() };
649 if(mStream)
651 std::lock_guard<std::mutex> lock(mMutex);
652 ALint queued = 0, state = -1, srcpos = 0;
653 std::chrono::nanoseconds latency(0);
655 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
656 if(mContext->hasExtension(SOFT_source_latency))
658 ALint64SOFT val[2];
659 mContext->alGetSourcei64vSOFT(mId, AL_SAMPLE_OFFSET_LATENCY_SOFT, val);
660 srcpos = val[0]>>32;
661 latency = std::chrono::nanoseconds(val[1]);
663 else
664 alGetSourcei(mId, AL_SAMPLE_OFFSET, &srcpos);
665 alGetSourcei(mId, AL_SOURCE_STATE, &state);
667 int64_t streampos = mStream->getPosition();
668 if(state != AL_STOPPED)
670 // The amount of samples in the queue waiting to play
671 ALuint inqueue = queued*mStream->getUpdateLength() - srcpos;
672 if(!mStream->hasLooped())
674 // A non-looped stream should never have more samples queued
675 // than have been read...
676 streampos = std::max<int64_t>(streampos, inqueue) - inqueue;
678 else
680 streampos -= inqueue;
681 int64_t looplen = mStream->getLoopEnd() - mStream->getLoopStart();
682 while(streampos < mStream->getLoopStart())
683 streampos += looplen;
687 return { streampos, latency };
690 std::chrono::nanoseconds latency(0);
691 ALint srcpos = 0;
692 if(mContext->hasExtension(SOFT_source_latency))
694 ALint64SOFT val[2];
695 mContext->alGetSourcei64vSOFT(mId, AL_SAMPLE_OFFSET_LATENCY_SOFT, val);
696 srcpos = val[0]>>32;
697 latency = std::chrono::nanoseconds(val[1]);
699 else
700 alGetSourcei(mId, AL_SAMPLE_OFFSET, &srcpos);
701 return { srcpos, latency };
704 std::pair<Seconds,Seconds> SourceImpl::getSecOffsetLatency() const
706 CheckContext(mContext);
707 if(mId == 0)
708 return { Seconds::zero(), Seconds::zero() };
710 if(mStream)
712 std::lock_guard<std::mutex> lock(mMutex);
713 ALint queued = 0, state = -1;
714 ALdouble srcpos = 0;
715 Seconds latency(0.0);
717 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
718 if(mContext->hasExtension(SOFT_source_latency))
720 ALdouble val[2];
721 mContext->alGetSourcedvSOFT(mId, AL_SEC_OFFSET_LATENCY_SOFT, val);
722 srcpos = val[0];
723 latency = Seconds(val[1]);
725 else
727 ALfloat f;
728 alGetSourcef(mId, AL_SEC_OFFSET, &f);
729 srcpos = f;
731 alGetSourcei(mId, AL_SOURCE_STATE, &state);
733 ALdouble frac = 0.0;
734 int64_t streampos = mStream->getPosition();
735 if(state != AL_STOPPED)
737 ALdouble ipos;
738 frac = std::modf(srcpos * mStream->getFrequency(), &ipos);
740 // The amount of samples in the queue waiting to play
741 ALuint inqueue = queued*mStream->getUpdateLength() - (ALuint)ipos;
742 if(!mStream->hasLooped())
744 // A non-looped stream should never have more samples queued
745 // than have been read...
746 streampos = std::max<int64_t>(streampos, inqueue) - inqueue;
748 else
750 streampos -= inqueue;
751 int64_t looplen = mStream->getLoopEnd() - mStream->getLoopStart();
752 while(streampos < mStream->getLoopStart())
753 streampos += looplen;
757 return { Seconds((streampos+frac) / mStream->getFrequency()), latency };
760 ALdouble srcpos = 0.0;
761 Seconds latency(0.0);
762 if(mContext->hasExtension(SOFT_source_latency))
764 ALdouble val[2];
765 mContext->alGetSourcedvSOFT(mId, AL_SEC_OFFSET_LATENCY_SOFT, val);
766 srcpos = val[0];
767 latency = Seconds(val[1]);
769 else
771 ALfloat f;
772 alGetSourcef(mId, AL_SEC_OFFSET, &f);
773 srcpos = f;
775 return { Seconds(srcpos), latency };
779 void SourceImpl::setLooping(bool looping)
781 CheckContext(mContext);
783 if(mId && !mStream)
784 alSourcei(mId, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
785 mLooping = looping;
789 void SourceImpl::setPitch(ALfloat pitch)
791 if(!(pitch > 0.0f))
792 throw std::runtime_error("Pitch out of range");
793 CheckContext(mContext);
794 if(mId != 0)
795 alSourcef(mId, AL_PITCH, pitch * (mGroup ? mGroup->getAppliedPitch() : 1.0f));
796 mPitch = pitch;
800 void SourceImpl::setGain(ALfloat gain)
802 if(!(gain >= 0.0f))
803 throw std::runtime_error("Gain out of range");
804 CheckContext(mContext);
805 if(mId != 0)
806 alSourcef(mId, AL_GAIN, gain * (mGroup ? mGroup->getAppliedGain() : 1.0f));
807 mGain = gain;
810 void SourceImpl::setGainRange(ALfloat mingain, ALfloat maxgain)
812 if(!(mingain >= 0.0f && maxgain <= 1.0f && maxgain >= mingain))
813 throw std::runtime_error("Gain range out of range");
814 CheckContext(mContext);
815 if(mId != 0)
817 alSourcef(mId, AL_MIN_GAIN, mingain);
818 alSourcef(mId, AL_MAX_GAIN, maxgain);
820 mMinGain = mingain;
821 mMaxGain = maxgain;
825 void SourceImpl::setDistanceRange(ALfloat refdist, ALfloat maxdist)
827 if(!(refdist >= 0.0f && maxdist <= std::numeric_limits<float>::max() && refdist <= maxdist))
828 throw std::runtime_error("Distance range out of range");
829 CheckContext(mContext);
830 if(mId != 0)
832 alSourcef(mId, AL_REFERENCE_DISTANCE, refdist);
833 alSourcef(mId, AL_MAX_DISTANCE, maxdist);
835 mRefDist = refdist;
836 mMaxDist = maxdist;
840 void SourceImpl::set3DParameters(const Vector3 &position, const Vector3 &velocity, const Vector3 &direction)
842 CheckContext(mContext);
843 if(mId != 0)
845 Batcher batcher = mContext->getBatcher();
846 alSourcefv(mId, AL_POSITION, position.getPtr());
847 alSourcefv(mId, AL_VELOCITY, velocity.getPtr());
848 alSourcefv(mId, AL_DIRECTION, direction.getPtr());
850 mPosition = position;
851 mVelocity = velocity;
852 mDirection = direction;
855 void SourceImpl::set3DParameters(const Vector3 &position, const Vector3 &velocity, std::pair<Vector3,Vector3> orientation)
857 static_assert(sizeof(orientation) == sizeof(ALfloat[6]), "Invalid Vector3 pair size");
858 CheckContext(mContext);
859 if(mId != 0)
861 Batcher batcher = mContext->getBatcher();
862 alSourcefv(mId, AL_POSITION, position.getPtr());
863 alSourcefv(mId, AL_VELOCITY, velocity.getPtr());
864 if(mContext->hasExtension(EXT_BFORMAT))
865 alSourcefv(mId, AL_ORIENTATION, orientation.first.getPtr());
866 alSourcefv(mId, AL_DIRECTION, orientation.first.getPtr());
868 mPosition = position;
869 mVelocity = velocity;
870 mDirection = mOrientation[0] = orientation.first;
871 mOrientation[1] = orientation.second;
875 void SourceImpl::setPosition(ALfloat x, ALfloat y, ALfloat z)
877 CheckContext(mContext);
878 if(mId != 0)
879 alSource3f(mId, AL_POSITION, x, y, z);
880 mPosition[0] = x;
881 mPosition[1] = y;
882 mPosition[2] = z;
885 void SourceImpl::setPosition(const ALfloat *pos)
887 CheckContext(mContext);
888 if(mId != 0)
889 alSourcefv(mId, AL_POSITION, pos);
890 mPosition[0] = pos[0];
891 mPosition[1] = pos[1];
892 mPosition[2] = pos[2];
895 void SourceImpl::setVelocity(ALfloat x, ALfloat y, ALfloat z)
897 CheckContext(mContext);
898 if(mId != 0)
899 alSource3f(mId, AL_VELOCITY, x, y, z);
900 mVelocity[0] = x;
901 mVelocity[1] = y;
902 mVelocity[2] = z;
905 void SourceImpl::setVelocity(const ALfloat *vel)
907 CheckContext(mContext);
908 if(mId != 0)
909 alSourcefv(mId, AL_VELOCITY, vel);
910 mVelocity[0] = vel[0];
911 mVelocity[1] = vel[1];
912 mVelocity[2] = vel[2];
915 void SourceImpl::setDirection(ALfloat x, ALfloat y, ALfloat z)
917 CheckContext(mContext);
918 if(mId != 0)
919 alSource3f(mId, AL_DIRECTION, x, y, z);
920 mDirection[0] = x;
921 mDirection[1] = y;
922 mDirection[2] = z;
925 void SourceImpl::setDirection(const ALfloat *dir)
927 CheckContext(mContext);
928 if(mId != 0)
929 alSourcefv(mId, AL_DIRECTION, dir);
930 mDirection[0] = dir[0];
931 mDirection[1] = dir[1];
932 mDirection[2] = dir[2];
935 void SourceImpl::setOrientation(ALfloat x1, ALfloat y1, ALfloat z1, ALfloat x2, ALfloat y2, ALfloat z2)
937 CheckContext(mContext);
938 if(mId != 0)
940 ALfloat ori[6] = { x1, y1, z1, x2, y2, z2 };
941 if(mContext->hasExtension(EXT_BFORMAT))
942 alSourcefv(mId, AL_ORIENTATION, ori);
943 alSourcefv(mId, AL_DIRECTION, ori);
945 mDirection[0] = mOrientation[0][0] = x1;
946 mDirection[1] = mOrientation[0][1] = y1;
947 mDirection[2] = mOrientation[0][2] = z1;
948 mOrientation[1][0] = x2;
949 mOrientation[1][1] = y2;
950 mOrientation[1][2] = z2;
953 void SourceImpl::setOrientation(const ALfloat *at, const ALfloat *up)
955 CheckContext(mContext);
956 if(mId != 0)
958 ALfloat ori[6] = { at[0], at[1], at[2], up[0], up[1], up[2] };
959 if(mContext->hasExtension(EXT_BFORMAT))
960 alSourcefv(mId, AL_ORIENTATION, ori);
961 alSourcefv(mId, AL_DIRECTION, ori);
963 mDirection[0] = mOrientation[0][0] = at[0];
964 mDirection[1] = mOrientation[0][1] = at[1];
965 mDirection[2] = mOrientation[0][2] = at[2];
966 mOrientation[1][0] = up[0];
967 mOrientation[1][1] = up[1];
968 mOrientation[1][2] = up[2];
971 void SourceImpl::setOrientation(const ALfloat *ori)
973 CheckContext(mContext);
974 if(mId != 0)
976 if(mContext->hasExtension(EXT_BFORMAT))
977 alSourcefv(mId, AL_ORIENTATION, ori);
978 alSourcefv(mId, AL_DIRECTION, ori);
980 mDirection[0] = mOrientation[0][0] = ori[0];
981 mDirection[1] = mOrientation[0][1] = ori[1];
982 mDirection[2] = mOrientation[0][2] = ori[2];
983 mOrientation[1][0] = ori[3];
984 mOrientation[1][1] = ori[4];
985 mOrientation[1][2] = ori[5];
989 void SourceImpl::setConeAngles(ALfloat inner, ALfloat outer)
991 if(!(inner >= 0.0f && outer <= 360.0f && outer >= inner))
992 throw std::runtime_error("Cone angles out of range");
993 CheckContext(mContext);
994 if(mId != 0)
996 alSourcef(mId, AL_CONE_INNER_ANGLE, inner);
997 alSourcef(mId, AL_CONE_OUTER_ANGLE, outer);
999 mConeInnerAngle = inner;
1000 mConeOuterAngle = outer;
1003 void SourceImpl::setOuterConeGains(ALfloat gain, ALfloat gainhf)
1005 if(!(gain >= 0.0f && gain <= 1.0f && gainhf >= 0.0f && gainhf <= 1.0f))
1006 throw std::runtime_error("Outer cone gain out of range");
1007 CheckContext(mContext);
1008 if(mId != 0)
1010 alSourcef(mId, AL_CONE_OUTER_GAIN, gain);
1011 if(mContext->hasExtension(EXT_EFX))
1012 alSourcef(mId, AL_CONE_OUTER_GAINHF, gainhf);
1014 mConeOuterGain = gain;
1015 mConeOuterGainHF = gainhf;
1019 void SourceImpl::setRolloffFactors(ALfloat factor, ALfloat roomfactor)
1021 if(!(factor >= 0.0f && roomfactor >= 0.0f))
1022 throw std::runtime_error("Rolloff factor out of range");
1023 CheckContext(mContext);
1024 if(mId != 0)
1026 alSourcef(mId, AL_ROLLOFF_FACTOR, factor);
1027 if(mContext->hasExtension(EXT_EFX))
1028 alSourcef(mId, AL_ROOM_ROLLOFF_FACTOR, roomfactor);
1030 mRolloffFactor = factor;
1031 mRoomRolloffFactor = roomfactor;
1034 void SourceImpl::setDopplerFactor(ALfloat factor)
1036 if(!(factor >= 0.0f && factor <= 1.0f))
1037 throw std::runtime_error("Doppler factor out of range");
1038 CheckContext(mContext);
1039 if(mId != 0)
1040 alSourcef(mId, AL_DOPPLER_FACTOR, factor);
1041 mDopplerFactor = factor;
1044 void SourceImpl::setAirAbsorptionFactor(ALfloat factor)
1046 if(!(factor >= 0.0f && factor <= 10.0f))
1047 throw std::runtime_error("Absorption factor out of range");
1048 CheckContext(mContext);
1049 if(mId != 0 && mContext->hasExtension(EXT_EFX))
1050 alSourcef(mId, AL_AIR_ABSORPTION_FACTOR, factor);
1051 mAirAbsorptionFactor = factor;
1054 void SourceImpl::setRadius(ALfloat radius)
1056 if(!(mRadius >= 0.0f))
1057 throw std::runtime_error("Radius out of range");
1058 CheckContext(mContext);
1059 if(mId != 0 && mContext->hasExtension(EXT_SOURCE_RADIUS))
1060 alSourcef(mId, AL_SOURCE_RADIUS, radius);
1061 mRadius = radius;
1064 void SourceImpl::setStereoAngles(ALfloat leftAngle, ALfloat rightAngle)
1066 CheckContext(mContext);
1067 if(mId != 0 && mContext->hasExtension(EXT_STEREO_ANGLES))
1069 ALfloat angles[2] = { leftAngle, rightAngle };
1070 alSourcefv(mId, AL_STEREO_ANGLES, angles);
1072 mStereoAngles[0] = leftAngle;
1073 mStereoAngles[1] = rightAngle;
1076 void SourceImpl::set3DSpatialize(Spatialize spatialize)
1078 CheckContext(mContext);
1079 if(mId != 0 && mContext->hasExtension(SOFT_source_spatialize))
1080 alSourcei(mId, AL_SOURCE_SPATIALIZE_SOFT, (ALint)spatialize);
1081 mSpatialize = spatialize;
1084 void SourceImpl::setResamplerIndex(ALsizei index)
1086 if(index < 0)
1087 throw std::runtime_error("Resampler index out of range");
1088 index = std::min<ALsizei>(index, mContext->getAvailableResamplers().size());
1089 if(mId != 0 && mContext->hasExtension(SOFT_source_resampler))
1090 alSourcei(mId, AL_SOURCE_RESAMPLER_SOFT, index);
1091 mResampler = index;
1094 void SourceImpl::setRelative(bool relative)
1096 CheckContext(mContext);
1097 if(mId != 0)
1098 alSourcei(mId, AL_SOURCE_RELATIVE, relative ? AL_TRUE : AL_FALSE);
1099 mRelative = relative;
1102 void SourceImpl::setGainAuto(bool directhf, bool send, bool sendhf)
1104 CheckContext(mContext);
1105 if(mId != 0 && mContext->hasExtension(EXT_EFX))
1107 alSourcei(mId, AL_DIRECT_FILTER_GAINHF_AUTO, directhf ? AL_TRUE : AL_FALSE);
1108 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, send ? AL_TRUE : AL_FALSE);
1109 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, sendhf ? AL_TRUE : AL_FALSE);
1111 mDryGainHFAuto = directhf;
1112 mWetGainAuto = send;
1113 mWetGainHFAuto = sendhf;
1117 void SourceImpl::setFilterParams(ALuint &filterid, const FilterParams &params)
1119 if(!mContext->hasExtension(EXT_EFX))
1120 return;
1122 if(!(params.mGain < 1.0f || params.mGainHF < 1.0f || params.mGainLF < 1.0f))
1124 if(filterid)
1125 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_NULL);
1126 return;
1129 alGetError();
1130 if(!filterid)
1132 mContext->alGenFilters(1, &filterid);
1133 if(alGetError() != AL_NO_ERROR)
1134 throw std::runtime_error("Failed to create Filter");
1136 bool filterset = false;
1137 if(params.mGainHF < 1.0f && params.mGainLF < 1.0f)
1139 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_BANDPASS);
1140 if(alGetError() == AL_NO_ERROR)
1142 mContext->alFilterf(filterid, AL_BANDPASS_GAIN, std::min(params.mGain, 1.0f));
1143 mContext->alFilterf(filterid, AL_BANDPASS_GAINHF, std::min(params.mGainHF, 1.0f));
1144 mContext->alFilterf(filterid, AL_BANDPASS_GAINLF, std::min(params.mGainLF, 1.0f));
1145 filterset = true;
1148 if(!filterset && !(params.mGainHF < 1.0f) && params.mGainLF < 1.0f)
1150 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_HIGHPASS);
1151 if(alGetError() == AL_NO_ERROR)
1153 mContext->alFilterf(filterid, AL_HIGHPASS_GAIN, std::min(params.mGain, 1.0f));
1154 mContext->alFilterf(filterid, AL_HIGHPASS_GAINLF, std::min(params.mGainLF, 1.0f));
1155 filterset = true;
1158 if(!filterset)
1160 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1161 if(alGetError() == AL_NO_ERROR)
1163 mContext->alFilterf(filterid, AL_LOWPASS_GAIN, std::min(params.mGain, 1.0f));
1164 mContext->alFilterf(filterid, AL_LOWPASS_GAINHF, std::min(params.mGainHF, 1.0f));
1165 filterset = true;
1171 void SourceImpl::setDirectFilter(const FilterParams &filter)
1173 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1174 throw std::runtime_error("Gain value out of range");
1175 CheckContext(mContext);
1177 setFilterParams(mDirectFilter, filter);
1178 if(mId)
1179 alSourcei(mId, AL_DIRECT_FILTER, mDirectFilter);
1182 void SourceImpl::setSendFilter(ALuint send, const FilterParams &filter)
1184 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1185 throw std::runtime_error("Gain value out of range");
1186 CheckContext(mContext);
1188 SendPropMap::iterator siter = mEffectSlots.find(send);
1189 if(siter == mEffectSlots.end())
1191 ALuint filterid = 0;
1193 setFilterParams(filterid, filter);
1194 if(!filterid) return;
1196 siter = mEffectSlots.insert(std::make_pair(send, SendProps(filterid))).first;
1198 else
1199 setFilterParams(siter->second.mFilter, filter);
1201 if(mId)
1203 ALuint slotid = (siter->second.mSlot ? siter->second.mSlot->getId() : 0);
1204 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->second.mFilter);
1208 void SourceImpl::setAuxiliarySend(AuxiliaryEffectSlot auxslot, ALuint send)
1210 AuxiliaryEffectSlotImpl *slot = auxslot.getHandle();
1211 if(slot) CheckContext(slot->getContext());
1212 CheckContext(mContext);
1214 SendPropMap::iterator siter = mEffectSlots.find(send);
1215 if(siter == mEffectSlots.end())
1217 if(!slot) return;
1218 slot->addSourceSend(Source(this), send);
1219 siter = mEffectSlots.insert(std::make_pair(send, SendProps(slot))).first;
1221 else if(siter->second.mSlot != slot)
1223 if(slot) slot->addSourceSend(Source(this), send);
1224 if(siter->second.mSlot)
1225 siter->second.mSlot->removeSourceSend(Source(this), send);
1226 siter->second.mSlot = slot;
1229 if(mId)
1231 ALuint slotid = (siter->second.mSlot ? siter->second.mSlot->getId() : 0);
1232 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->second.mFilter);
1236 void SourceImpl::setAuxiliarySendFilter(AuxiliaryEffectSlot auxslot, ALuint send, const FilterParams &filter)
1238 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1239 throw std::runtime_error("Gain value out of range");
1240 AuxiliaryEffectSlotImpl *slot = auxslot.getHandle();
1241 if(slot) CheckContext(slot->getContext());
1242 CheckContext(mContext);
1244 SendPropMap::iterator siter = mEffectSlots.find(send);
1245 if(siter == mEffectSlots.end())
1247 ALuint filterid = 0;
1249 setFilterParams(filterid, filter);
1250 if(!filterid && !slot)
1251 return;
1253 if(slot) slot->addSourceSend(Source(this), send);
1254 siter = mEffectSlots.insert(std::make_pair(send, SendProps(slot, filterid))).first;
1256 else
1258 if(siter->second.mSlot != slot)
1260 if(slot) slot->addSourceSend(Source(this), send);
1261 if(siter->second.mSlot)
1262 siter->second.mSlot->removeSourceSend(Source(this), send);
1263 siter->second.mSlot = slot;
1265 setFilterParams(siter->second.mFilter, filter);
1268 if(mId)
1270 ALuint slotid = (siter->second.mSlot ? siter->second.mSlot->getId() : 0);
1271 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->second.mFilter);
1276 void SourceImpl::release()
1278 CheckContext(mContext);
1280 if(mIsAsync.load(std::memory_order_acquire))
1282 mContext->removeStream(this);
1283 mIsAsync.store(false, std::memory_order_release);
1286 if(mId != 0)
1288 alSourceRewind(mId);
1289 alSourcei(mId, AL_BUFFER, 0);
1290 if(mContext->hasExtension(EXT_EFX))
1292 alSourcei(mId, AL_DIRECT_FILTER, AL_FILTER_NULL);
1293 for(auto &i : mEffectSlots)
1294 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, 0, i.first, AL_FILTER_NULL);
1296 mContext->insertSourceId(mId);
1297 mId = 0;
1300 mContext->freeSource(this);
1302 if(mDirectFilter)
1303 mContext->alDeleteFilters(1, &mDirectFilter);
1304 mDirectFilter = AL_FILTER_NULL;
1306 for(auto &i : mEffectSlots)
1308 if(i.second.mSlot)
1309 i.second.mSlot->removeSourceSend(Source(this), i.first);
1310 if(i.second.mFilter)
1311 mContext->alDeleteFilters(1, &i.second.mFilter);
1313 mEffectSlots.clear();
1315 if(mBuffer)
1316 mBuffer->removeSource(Source(this));
1317 mBuffer = 0;
1319 mStream.reset();
1321 resetProperties();
1325 // Need to use these to avoid extraneous commas in macro parameter lists
1326 using UInt64NSecPair = std::pair<uint64_t,std::chrono::nanoseconds>;
1327 using SecondsPair = std::pair<Seconds,Seconds>;
1328 using ALfloatPair = std::pair<ALfloat,ALfloat>;
1329 using Vector3Pair = std::pair<Vector3,Vector3>;
1330 using BoolTriple = std::tuple<bool,bool,bool>;
1332 DECL_THUNK1(void, Source, play,, Buffer)
1333 DECL_THUNK3(void, Source, play,, SharedPtr<Decoder>, ALuint, ALuint)
1334 DECL_THUNK0(void, Source, stop,)
1335 DECL_THUNK0(void, Source, pause,)
1336 DECL_THUNK0(void, Source, resume,)
1337 DECL_THUNK0(bool, Source, isPlaying, const)
1338 DECL_THUNK0(bool, Source, isPaused, const)
1339 DECL_THUNK1(void, Source, setPriority,, ALuint)
1340 DECL_THUNK0(ALuint, Source, getPriority, const)
1341 DECL_THUNK1(void, Source, setOffset,, uint64_t)
1342 DECL_THUNK0(UInt64NSecPair, Source, getSampleOffsetLatency, const)
1343 DECL_THUNK0(SecondsPair, Source, getSecOffsetLatency, const)
1344 DECL_THUNK1(void, Source, setLooping,, bool)
1345 DECL_THUNK0(bool, Source, getLooping, const)
1346 DECL_THUNK1(void, Source, setPitch,, ALfloat)
1347 DECL_THUNK0(ALfloat, Source, getPitch, const)
1348 DECL_THUNK1(void, Source, setGain,, ALfloat)
1349 DECL_THUNK0(ALfloat, Source, getGain, const)
1350 DECL_THUNK2(void, Source, setGainRange,, ALfloat, ALfloat)
1351 DECL_THUNK0(ALfloatPair, Source, getGainRange, const)
1352 DECL_THUNK2(void, Source, setDistanceRange,, ALfloat, ALfloat)
1353 DECL_THUNK0(ALfloatPair, Source, getDistanceRange, const)
1354 DECL_THUNK3(void, Source, set3DParameters,, const Vector3&, const Vector3&, const Vector3&)
1355 DECL_THUNK3(void, Source, set3DParameters,, const Vector3&, const Vector3&, Vector3Pair)
1356 DECL_THUNK3(void, Source, setPosition,, ALfloat, ALfloat, ALfloat)
1357 DECL_THUNK1(void, Source, setPosition,, const ALfloat*)
1358 DECL_THUNK0(Vector3, Source, getPosition, const)
1359 DECL_THUNK3(void, Source, setVelocity,, ALfloat, ALfloat, ALfloat)
1360 DECL_THUNK1(void, Source, setVelocity,, const ALfloat*)
1361 DECL_THUNK0(Vector3, Source, getVelocity, const)
1362 DECL_THUNK3(void, Source, setDirection,, ALfloat, ALfloat, ALfloat)
1363 DECL_THUNK1(void, Source, setDirection,, const ALfloat*)
1364 DECL_THUNK0(Vector3, Source, getDirection, const)
1365 DECL_THUNK6(void, Source, setOrientation,, ALfloat, ALfloat, ALfloat, ALfloat, ALfloat, ALfloat)
1366 DECL_THUNK2(void, Source, setOrientation,, const ALfloat*, const ALfloat*)
1367 DECL_THUNK1(void, Source, setOrientation,, const ALfloat*)
1368 DECL_THUNK0(Vector3Pair, Source, getOrientation, const)
1369 DECL_THUNK2(void, Source, setConeAngles,, ALfloat, ALfloat)
1370 DECL_THUNK0(ALfloatPair, Source, getConeAngles, const)
1371 DECL_THUNK2(void, Source, setOuterConeGains,, ALfloat, ALfloat)
1372 DECL_THUNK0(ALfloatPair, Source, getOuterConeGains, const)
1373 DECL_THUNK2(void, Source, setRolloffFactors,, ALfloat, ALfloat)
1374 DECL_THUNK0(ALfloatPair, Source, getRolloffFactors, const)
1375 DECL_THUNK1(void, Source, setDopplerFactor,, ALfloat)
1376 DECL_THUNK0(ALfloat, Source, getDopplerFactor, const)
1377 DECL_THUNK1(void, Source, setRelative,, bool)
1378 DECL_THUNK0(bool, Source, getRelative, const)
1379 DECL_THUNK1(void, Source, setRadius,, ALfloat)
1380 DECL_THUNK0(ALfloat, Source, getRadius, const)
1381 DECL_THUNK2(void, Source, setStereoAngles,, ALfloat, ALfloat)
1382 DECL_THUNK0(ALfloatPair, Source, getStereoAngles, const)
1383 DECL_THUNK1(void, Source, set3DSpatialize,, Spatialize)
1384 DECL_THUNK0(Spatialize, Source, get3DSpatialize, const)
1385 DECL_THUNK1(void, Source, setResamplerIndex,, ALsizei)
1386 DECL_THUNK0(ALsizei, Source, getResamplerIndex, const)
1387 DECL_THUNK1(void, Source, setAirAbsorptionFactor,, ALfloat)
1388 DECL_THUNK0(ALfloat, Source, getAirAbsorptionFactor, const)
1389 DECL_THUNK3(void, Source, setGainAuto,, bool, bool, bool)
1390 DECL_THUNK0(BoolTriple, Source, getGainAuto, const)
1391 DECL_THUNK1(void, Source, setDirectFilter,, const FilterParams&)
1392 DECL_THUNK2(void, Source, setSendFilter,, ALuint, const FilterParams&)
1393 DECL_THUNK2(void, Source, setAuxiliarySend,, AuxiliaryEffectSlot, ALuint)
1394 DECL_THUNK3(void, Source, setAuxiliarySendFilter,, AuxiliaryEffectSlot, ALuint, const FilterParams&)
1395 void Source::release()
1397 pImpl->release();
1398 pImpl = nullptr;