Remove the source's public update method
[alure.git] / src / source.cpp
blobb81c970149c0ed90da164c2b14c6fdeaed2b306b
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 std::pair<uint64_t,uint64_t> mLoopPts;
41 std::atomic<bool> mHasLooped;
42 std::atomic<bool> mDone;
44 public:
45 ALBufferStream(SharedPtr<Decoder> decoder, ALuint updatelen, ALuint numupdates)
46 : mDecoder(decoder), mUpdateLen(updatelen), mNumUpdates(numupdates),
47 mFormat(AL_NONE), mFrequency(0), mFrameSize(0), mSilence(0),
48 mCurrentIdx(0), mLoopPts{0,0}, mHasLooped(false), mDone(false)
49 { }
50 ~ALBufferStream()
52 if(!mBufferIds.empty())
54 alDeleteBuffers(mBufferIds.size(), &mBufferIds[0]);
55 mBufferIds.clear();
59 uint64_t getLength() const { return mDecoder->getLength(); }
60 uint64_t getPosition() const { return mDecoder->getPosition(); }
62 ALuint getNumUpdates() const { return mNumUpdates; }
63 ALuint getUpdateLength() const { return mUpdateLen; }
65 ALuint getFrequency() const { return mFrequency; }
67 bool seek(uint64_t pos)
69 if(!mDecoder->seek(pos))
70 return false;
71 mHasLooped.store(false, std::memory_order_release);
72 mDone.store(false, std::memory_order_release);
73 return true;
76 void prepare()
78 ALuint srate = mDecoder->getFrequency();
79 ChannelConfig chans = mDecoder->getChannelConfig();
80 SampleType type = mDecoder->getSampleType();
82 mLoopPts = mDecoder->getLoopPoints();
83 if(mLoopPts.first >= mLoopPts.second)
85 mLoopPts.first = 0;
86 mLoopPts.second = std::numeric_limits<uint64_t>::max();
89 mFrequency = srate;
90 mFrameSize = FramesToBytes(1, chans, type);
91 mFormat = GetFormat(chans, type);
92 if(mFormat == AL_NONE)
94 std::stringstream sstr;
95 sstr<< "Format not supported ("<<GetSampleTypeName(type)<<", "<<GetChannelConfigName(chans)<<")";
96 throw std::runtime_error(sstr.str());
99 mData.resize(mUpdateLen * mFrameSize);
100 if(type == SampleType::UInt8) mSilence = 0x80;
101 else if(type == SampleType::Mulaw) mSilence = 0x7f;
102 else mSilence = 0x00;
104 mBufferIds.assign(mNumUpdates, 0);
105 alGenBuffers(mBufferIds.size(), &mBufferIds[0]);
108 int64_t getLoopStart() const { return mLoopPts.first; }
109 int64_t getLoopEnd() const { return mLoopPts.second; }
111 bool hasLooped() const { return mHasLooped.load(std::memory_order_acquire); }
112 bool hasMoreData() const { return !mDone.load(std::memory_order_acquire); }
113 bool streamMoreData(ALuint srcid, bool loop)
115 if(mDone.load(std::memory_order_acquire))
116 return false;
118 ALuint frames;
119 if(!loop)
120 frames = mDecoder->read(&mData[0], mUpdateLen);
121 else
123 ALuint len = mUpdateLen;
124 uint64_t pos = mDecoder->getPosition();
125 if(pos <= mLoopPts.second)
126 len = std::min<uint64_t>(len, mLoopPts.second - pos);
127 else
128 loop = false;
130 frames = mDecoder->read(&mData[0], len);
131 if(frames < mUpdateLen && loop && pos+frames > 0)
133 if(pos+frames < mLoopPts.second)
135 mLoopPts.second = pos+frames;
136 mLoopPts.first = std::min(mLoopPts.first, mLoopPts.second-1);
139 do {
140 if(!mDecoder->seek(mLoopPts.first))
141 break;
142 mHasLooped.store(true, std::memory_order_release);
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 frames += got;
148 } while(frames < mUpdateLen);
151 if(frames < mUpdateLen)
153 mDone.store(true, std::memory_order_release);
154 if(frames == 0) return false;
155 std::fill(mData.begin() + frames*mFrameSize, mData.end(), mSilence);
158 alBufferData(mBufferIds[mCurrentIdx], mFormat, &mData[0], mData.size(), mFrequency);
159 alSourceQueueBuffers(srcid, 1, &mBufferIds[mCurrentIdx]);
160 mCurrentIdx = (mCurrentIdx+1) % mBufferIds.size();
161 return true;
166 ALSource::ALSource(ALContext *context)
167 : mContext(context), mId(0), mBuffer(0), mGroup(nullptr), mIsAsync(false),
168 mDirectFilter(AL_FILTER_NULL)
170 resetProperties();
173 ALSource::~ALSource()
178 void ALSource::resetProperties()
180 if(mGroup)
181 mGroup->removeSource(Source(this));
182 mGroup = nullptr;
184 mPaused.store(false, std::memory_order_release);
185 mOffset = 0;
186 mPitch = 1.0f;
187 mGain = 1.0f;
188 mMinGain = 0.0f;
189 mMaxGain = 1.0f;
190 mRefDist = 1.0f;
191 mMaxDist = std::numeric_limits<float>::max();
192 mPosition = Vector3(0.0f);
193 mVelocity = Vector3(0.0f);
194 mDirection = Vector3(0.0f);
195 mOrientation[0] = Vector3(0.0f, 0.0f, -1.0f);
196 mOrientation[1] = Vector3(0.0f, 1.0f, 0.0f);
197 mConeInnerAngle = 360.0f;
198 mConeOuterAngle = 360.0f;
199 mConeOuterGain = 0.0f;
200 mConeOuterGainHF = 1.0f;
201 mRolloffFactor = 1.0f;
202 mRoomRolloffFactor = 0.0f;
203 mDopplerFactor = 1.0f;
204 mAirAbsorptionFactor = 0.0f;
205 mRadius = 0.0f;
206 mStereoAngles[0] = F_PI / 6.0f;
207 mStereoAngles[1] = -F_PI / 6.0f;
208 mSpatialize = Spatialize::Auto;
209 mResampler = mContext->hasExtension(SOFT_source_resampler) ?
210 alGetInteger(AL_DEFAULT_RESAMPLER_SOFT) : 0;
211 mLooping = false;
212 mRelative = false;
213 mDryGainHFAuto = true;
214 mWetGainAuto = true;
215 mWetGainHFAuto = true;
216 if(mDirectFilter)
217 mContext->alDeleteFilters(1, &mDirectFilter);
218 mDirectFilter = 0;
219 for(auto &i : mEffectSlots)
221 if(i.second.mSlot)
222 i.second.mSlot->removeSourceSend(Source(this), i.first);
223 if(i.second.mFilter)
224 mContext->alDeleteFilters(1, &i.second.mFilter);
226 mEffectSlots.clear();
228 mPriority = 0;
231 void ALSource::applyProperties(bool looping, ALuint offset) const
233 alSourcei(mId, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
234 alSourcei(mId, AL_SAMPLE_OFFSET, offset);
235 if(mGroup)
237 alSourcef(mId, AL_PITCH, mPitch * mGroup->getAppliedPitch());
238 alSourcef(mId, AL_GAIN, mGain * mGroup->getAppliedGain());
240 else
242 alSourcef(mId, AL_PITCH, mPitch);
243 alSourcef(mId, AL_GAIN, mGain);
245 alSourcef(mId, AL_MIN_GAIN, mMinGain);
246 alSourcef(mId, AL_MAX_GAIN, mMaxGain);
247 alSourcef(mId, AL_REFERENCE_DISTANCE, mRefDist);
248 alSourcef(mId, AL_MAX_DISTANCE, mMaxDist);
249 alSourcefv(mId, AL_POSITION, mPosition.getPtr());
250 alSourcefv(mId, AL_VELOCITY, mVelocity.getPtr());
251 alSourcefv(mId, AL_DIRECTION, mDirection.getPtr());
252 if(mContext->hasExtension(EXT_BFORMAT))
253 alSourcefv(mId, AL_ORIENTATION, &mOrientation[0][0]);
254 alSourcef(mId, AL_CONE_INNER_ANGLE, mConeInnerAngle);
255 alSourcef(mId, AL_CONE_OUTER_ANGLE, mConeOuterAngle);
256 alSourcef(mId, AL_CONE_OUTER_GAIN, mConeOuterGain);
257 alSourcef(mId, AL_ROLLOFF_FACTOR, mRolloffFactor);
258 alSourcef(mId, AL_DOPPLER_FACTOR, mDopplerFactor);
259 if(mContext->hasExtension(EXT_SOURCE_RADIUS))
260 alSourcef(mId, AL_SOURCE_RADIUS, mRadius);
261 if(mContext->hasExtension(EXT_STEREO_ANGLES))
262 alSourcefv(mId, AL_STEREO_ANGLES, mStereoAngles);
263 if(mContext->hasExtension(SOFT_source_spatialize))
264 alSourcei(mId, AL_SOURCE_SPATIALIZE_SOFT, (ALint)mSpatialize);
265 if(mContext->hasExtension(SOFT_source_resampler))
266 alSourcei(mId, AL_SOURCE_RESAMPLER_SOFT, mResampler);
267 alSourcei(mId, AL_SOURCE_RELATIVE, mRelative ? AL_TRUE : AL_FALSE);
268 if(mContext->hasExtension(EXT_EFX))
270 alSourcef(mId, AL_CONE_OUTER_GAINHF, mConeOuterGainHF);
271 alSourcef(mId, AL_ROOM_ROLLOFF_FACTOR, mRoomRolloffFactor);
272 alSourcef(mId, AL_AIR_ABSORPTION_FACTOR, mAirAbsorptionFactor);
273 alSourcei(mId, AL_DIRECT_FILTER_GAINHF_AUTO, mDryGainHFAuto ? AL_TRUE : AL_FALSE);
274 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, mWetGainAuto ? AL_TRUE : AL_FALSE);
275 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, mWetGainHFAuto ? AL_TRUE : AL_FALSE);
276 alSourcei(mId, AL_DIRECT_FILTER, mDirectFilter);
277 for(const auto &i : mEffectSlots)
279 ALuint slotid = (i.second.mSlot ? i.second.mSlot->getId() : 0);
280 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, i.first, i.second.mFilter);
286 void ALSource::setGroup(ALSourceGroup *group)
288 if(mGroup)
289 mGroup->removeSource(Source(this));
290 mGroup = group;
291 groupUpdate();
294 void ALSource::unsetGroup()
296 mGroup = nullptr;
297 groupUpdate();
300 void ALSource::groupUpdate()
302 if(mId)
304 if(mGroup)
306 alSourcef(mId, AL_PITCH, mPitch * mGroup->getAppliedPitch());
307 alSourcef(mId, AL_GAIN, mGain * mGroup->getAppliedGain());
309 else
311 alSourcef(mId, AL_PITCH, mPitch);
312 alSourcef(mId, AL_GAIN, mGain);
317 void ALSource::groupPropUpdate(ALfloat gain, ALfloat pitch)
319 if(mId)
321 alSourcef(mId, AL_PITCH, mPitch * pitch);
322 alSourcef(mId, AL_GAIN, mGain * gain);
327 void ALSource::play(Buffer buffer)
329 ALBuffer *albuf = buffer.getHandle();
330 if(!albuf) throw std::runtime_error("Buffer is not valid");
331 CheckContext(mContext);
332 CheckContext(albuf->getContext());
334 if(!albuf->isReady())
335 throw std::runtime_error("Buffer is not ready");
337 if(mIsAsync.load(std::memory_order_acquire))
339 mContext->removeStream(this);
340 mIsAsync.store(false, std::memory_order_release);
343 if(mId == 0)
345 mId = mContext->getSourceId(mPriority);
346 applyProperties(mLooping, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
348 else
350 alSourceRewind(mId);
351 alSourcei(mId, AL_BUFFER, 0);
352 alSourcei(mId, AL_LOOPING, mLooping ? AL_TRUE : AL_FALSE);
353 alSourcei(mId, AL_SAMPLE_OFFSET, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
355 mOffset = 0;
357 mStream.reset();
359 if(mBuffer)
360 mBuffer->removeSource(Source(this));
361 mBuffer = albuf;
362 mBuffer->addSource(Source(this));
364 alSourcei(mId, AL_BUFFER, mBuffer->getId());
365 alSourcePlay(mId);
366 mPaused.store(false, std::memory_order_release);
369 void ALSource::play(SharedPtr<Decoder> decoder, ALuint updatelen, ALuint queuesize)
371 if(updatelen < 64)
372 throw std::runtime_error("Update length out of range");
373 if(queuesize < 2)
374 throw std::runtime_error("Queue size out of range");
375 CheckContext(mContext);
377 auto stream = MakeUnique<ALBufferStream>(decoder, updatelen, queuesize);
378 stream->prepare();
380 if(mIsAsync.load(std::memory_order_acquire))
382 mContext->removeStream(this);
383 mIsAsync.store(false, std::memory_order_release);
386 if(mId == 0)
388 mId = mContext->getSourceId(mPriority);
389 applyProperties(false, 0);
391 else
393 alSourceRewind(mId);
394 alSourcei(mId, AL_BUFFER, 0);
395 alSourcei(mId, AL_LOOPING, AL_FALSE);
396 alSourcei(mId, AL_SAMPLE_OFFSET, 0);
399 if(mBuffer)
400 mBuffer->removeSource(Source(this));
401 mBuffer = 0;
403 mStream = std::move(stream);
405 mStream->seek(mOffset);
406 mOffset = 0;
408 for(ALuint i = 0;i < mStream->getNumUpdates();i++)
410 if(!mStream->streamMoreData(mId, mLooping))
411 break;
413 alSourcePlay(mId);
414 mPaused.store(false, std::memory_order_release);
416 mContext->addStream(this);
417 mIsAsync.store(true, std::memory_order_release);
421 void ALSource::makeStopped()
423 if(mIsAsync.load(std::memory_order_acquire))
425 mContext->removeStreamNoLock(this);
426 mIsAsync.store(false, std::memory_order_release);
429 if(mId != 0)
431 alSourceRewind(mId);
432 alSourcei(mId, AL_BUFFER, 0);
433 if(mContext->hasExtension(EXT_EFX))
435 alSourcei(mId, AL_DIRECT_FILTER, AL_FILTER_NULL);
436 for(auto &i : mEffectSlots)
437 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, 0, i.first, AL_FILTER_NULL);
439 mContext->insertSourceId(mId);
440 mId = 0;
443 if(mBuffer)
444 mBuffer->removeSource(Source(this));
445 mBuffer = 0;
447 mStream.reset();
449 mPaused.store(false, std::memory_order_release);
452 void ALSource::stop()
454 CheckContext(mContext);
455 makeStopped();
459 void ALSource::checkPaused()
461 if(mPaused.load(std::memory_order_acquire) || mId == 0)
462 return;
464 ALint state = -1;
465 alGetSourcei(mId, AL_SOURCE_STATE, &state);
466 // Streaming sources may be in a stopped state if underrun
467 mPaused.store((state == AL_PAUSED) ||
468 (state == AL_STOPPED && mStream && mStream->hasMoreData()),
469 std::memory_order_release);
472 void ALSource::pause()
474 CheckContext(mContext);
475 if(mPaused.load(std::memory_order_acquire))
476 return;
478 if(mId != 0)
480 std::lock_guard<std::mutex> lock(mMutex);
481 alSourcePause(mId);
482 ALint state = -1;
483 alGetSourcei(mId, AL_SOURCE_STATE, &state);
484 // Streaming sources may be in a stopped state if underrun
485 mPaused.store((state == AL_PAUSED) ||
486 (state == AL_STOPPED && mStream && mStream->hasMoreData()),
487 std::memory_order_release);
491 void ALSource::resume()
493 CheckContext(mContext);
494 if(!mPaused.load(std::memory_order_acquire))
495 return;
497 if(mId != 0)
498 alSourcePlay(mId);
499 mPaused.store(false, std::memory_order_release);
503 bool ALSource::isPlaying() const
505 CheckContext(mContext);
506 if(mId == 0) return false;
508 ALint state = -1;
509 alGetSourcei(mId, AL_SOURCE_STATE, &state);
510 if(state == -1)
511 throw std::runtime_error("Source state error");
513 return state == AL_PLAYING || (!mPaused.load(std::memory_order_acquire) &&
514 mStream && mStream->hasMoreData());
517 bool ALSource::isPaused() const
519 CheckContext(mContext);
520 if(mId == 0) return false;
522 ALint state = -1;
523 alGetSourcei(mId, AL_SOURCE_STATE, &state);
524 if(state == -1)
525 throw std::runtime_error("Source state error");
527 return state == AL_PAUSED || mPaused.load(std::memory_order_acquire);
531 ALint ALSource::refillBufferStream()
533 ALint processed;
534 alGetSourcei(mId, AL_BUFFERS_PROCESSED, &processed);
535 while(processed > 0)
537 ALuint buf;
538 alSourceUnqueueBuffers(mId, 1, &buf);
539 --processed;
542 ALint queued;
543 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
544 for(;(ALuint)queued < mStream->getNumUpdates();queued++)
546 if(!mStream->streamMoreData(mId, mLooping))
547 break;
550 return queued;
554 void ALSource::updateNoCtxCheck()
556 if(mId == 0)
557 return;
559 if(mStream)
561 if(!mIsAsync.load(std::memory_order_acquire))
563 stop();
564 mContext->send(&MessageHandler::sourceStopped, Source(this));
567 else
569 ALint state = -1;
570 alGetSourcei(mId, AL_SOURCE_STATE, &state);
571 if(state != AL_PLAYING && state != AL_PAUSED)
573 stop();
574 mContext->send(&MessageHandler::sourceStopped, Source(this));
579 bool ALSource::updateAsync()
581 std::lock_guard<std::mutex> lock(mMutex);
583 ALint queued = refillBufferStream();
584 if(queued == 0)
586 mIsAsync.store(false, std::memory_order_release);
587 return false;
589 if(!mPaused.load(std::memory_order_acquire))
591 ALint state = -1;
592 alGetSourcei(mId, AL_SOURCE_STATE, &state);
593 if(state != AL_PLAYING)
594 alSourcePlay(mId);
596 return true;
600 void ALSource::setPriority(ALuint priority)
602 mPriority = priority;
606 void ALSource::setOffset(uint64_t offset)
608 CheckContext(mContext);
609 if(mId == 0)
611 mOffset = offset;
612 return;
615 if(!mStream)
617 if(offset >= std::numeric_limits<ALint>::max())
618 throw std::runtime_error("Offset out of range");
619 alGetError();
620 alSourcei(mId, AL_SAMPLE_OFFSET, (ALint)offset);
621 if(alGetError() != AL_NO_ERROR)
622 throw std::runtime_error("Offset out of range");
624 else
626 std::lock_guard<std::mutex> lock(mMutex);
627 if(!mStream->seek(offset))
628 throw std::runtime_error("Failed to seek to offset");
629 alSourceRewind(mId);
630 alSourcei(mId, AL_BUFFER, 0);
631 ALint queued = refillBufferStream();
632 if(queued > 0 && !mPaused)
633 alSourcePlay(mId);
637 std::pair<uint64_t,std::chrono::nanoseconds> ALSource::getSampleOffsetLatency() const
639 CheckContext(mContext);
640 if(mId == 0)
641 return { 0, std::chrono::nanoseconds::zero() };
643 if(mStream)
645 std::lock_guard<std::mutex> lock(mMutex);
646 ALint queued = 0, state = -1, srcpos = 0;
647 std::chrono::nanoseconds latency(0);
649 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
650 if(mContext->hasExtension(SOFT_source_latency))
652 ALint64SOFT val[2];
653 mContext->alGetSourcei64vSOFT(mId, AL_SAMPLE_OFFSET_LATENCY_SOFT, val);
654 srcpos = val[0]>>32;
655 latency = std::chrono::nanoseconds(val[1]);
657 else
658 alGetSourcei(mId, AL_SAMPLE_OFFSET, &srcpos);
659 alGetSourcei(mId, AL_SOURCE_STATE, &state);
661 int64_t streampos = mStream->getPosition();
662 if(state != AL_STOPPED)
664 // The amount of samples in the queue waiting to play
665 ALuint inqueue = queued*mStream->getUpdateLength() - srcpos;
666 if(!mStream->hasLooped())
668 // A non-looped stream should never have more samples queued
669 // than have been read...
670 streampos = std::max<int64_t>(streampos, inqueue) - inqueue;
672 else
674 streampos -= inqueue;
675 int64_t looplen = mStream->getLoopEnd() - mStream->getLoopStart();
676 while(streampos < mStream->getLoopStart())
677 streampos += looplen;
681 return { streampos, latency };
684 std::chrono::nanoseconds latency(0);
685 ALint srcpos = 0;
686 if(mContext->hasExtension(SOFT_source_latency))
688 ALint64SOFT val[2];
689 mContext->alGetSourcei64vSOFT(mId, AL_SAMPLE_OFFSET_LATENCY_SOFT, val);
690 srcpos = val[0]>>32;
691 latency = std::chrono::nanoseconds(val[1]);
693 else
694 alGetSourcei(mId, AL_SAMPLE_OFFSET, &srcpos);
695 return { srcpos, latency };
698 std::pair<Seconds,Seconds> ALSource::getSecOffsetLatency() const
700 CheckContext(mContext);
701 if(mId == 0)
702 return { Seconds::zero(), Seconds::zero() };
704 if(mStream)
706 std::lock_guard<std::mutex> lock(mMutex);
707 ALint queued = 0, state = -1;
708 ALdouble srcpos = 0;
709 Seconds latency(0.0);
711 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
712 if(mContext->hasExtension(SOFT_source_latency))
714 ALdouble val[2];
715 mContext->alGetSourcedvSOFT(mId, AL_SEC_OFFSET_LATENCY_SOFT, val);
716 srcpos = val[0];
717 latency = Seconds(val[1]);
719 else
721 ALfloat f;
722 alGetSourcef(mId, AL_SEC_OFFSET, &f);
723 srcpos = f;
725 alGetSourcei(mId, AL_SOURCE_STATE, &state);
727 ALdouble frac = 0.0;
728 int64_t streampos = mStream->getPosition();
729 if(state != AL_STOPPED)
731 ALdouble ipos;
732 frac = std::modf(srcpos * mStream->getFrequency(), &ipos);
734 // The amount of samples in the queue waiting to play
735 ALuint inqueue = queued*mStream->getUpdateLength() - (ALuint)ipos;
736 if(!mStream->hasLooped())
738 // A non-looped stream should never have more samples queued
739 // than have been read...
740 streampos = std::max<int64_t>(streampos, inqueue) - inqueue;
742 else
744 streampos -= inqueue;
745 int64_t looplen = mStream->getLoopEnd() - mStream->getLoopStart();
746 while(streampos < mStream->getLoopStart())
747 streampos += looplen;
751 return { Seconds((streampos+frac) / mStream->getFrequency()), latency };
754 ALdouble srcpos = 0.0;
755 Seconds latency(0.0);
756 if(mContext->hasExtension(SOFT_source_latency))
758 ALdouble val[2];
759 mContext->alGetSourcedvSOFT(mId, AL_SAMPLE_OFFSET_LATENCY_SOFT, val);
760 srcpos = val[0];
761 latency = Seconds(val[1]);
763 else
765 ALfloat f;
766 alGetSourcef(mId, AL_SEC_OFFSET, &f);
767 srcpos = f;
769 return { Seconds(srcpos), latency };
773 void ALSource::setLooping(bool looping)
775 CheckContext(mContext);
777 if(mId && !mStream)
778 alSourcei(mId, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
779 mLooping = looping;
783 void ALSource::setPitch(ALfloat pitch)
785 if(!(pitch > 0.0f))
786 throw std::runtime_error("Pitch out of range");
787 CheckContext(mContext);
788 if(mId != 0)
789 alSourcef(mId, AL_PITCH, pitch * (mGroup ? mGroup->getAppliedPitch() : 1.0f));
790 mPitch = pitch;
794 void ALSource::setGain(ALfloat gain)
796 if(!(gain >= 0.0f))
797 throw std::runtime_error("Gain out of range");
798 CheckContext(mContext);
799 if(mId != 0)
800 alSourcef(mId, AL_GAIN, gain * (mGroup ? mGroup->getAppliedGain() : 1.0f));
801 mGain = gain;
804 void ALSource::setGainRange(ALfloat mingain, ALfloat maxgain)
806 if(!(mingain >= 0.0f && maxgain <= 1.0f && maxgain >= mingain))
807 throw std::runtime_error("Gain range out of range");
808 CheckContext(mContext);
809 if(mId != 0)
811 alSourcef(mId, AL_MIN_GAIN, mingain);
812 alSourcef(mId, AL_MAX_GAIN, maxgain);
814 mMinGain = mingain;
815 mMaxGain = maxgain;
819 void ALSource::setDistanceRange(ALfloat refdist, ALfloat maxdist)
821 if(!(refdist >= 0.0f && maxdist <= std::numeric_limits<float>::max() && refdist <= maxdist))
822 throw std::runtime_error("Distance range out of range");
823 CheckContext(mContext);
824 if(mId != 0)
826 alSourcef(mId, AL_REFERENCE_DISTANCE, refdist);
827 alSourcef(mId, AL_MAX_DISTANCE, maxdist);
829 mRefDist = refdist;
830 mMaxDist = maxdist;
834 void ALSource::set3DParameters(const Vector3 &position, const Vector3 &velocity, const Vector3 &direction)
836 CheckContext(mContext);
837 if(mId != 0)
839 Batcher batcher = mContext->getBatcher();
840 alSourcefv(mId, AL_POSITION, position.getPtr());
841 alSourcefv(mId, AL_VELOCITY, velocity.getPtr());
842 alSourcefv(mId, AL_DIRECTION, direction.getPtr());
844 mPosition = position;
845 mVelocity = velocity;
846 mDirection = direction;
849 void ALSource::set3DParameters(const Vector3 &position, const Vector3 &velocity, std::pair<Vector3,Vector3> orientation)
851 static_assert(sizeof(orientation) == sizeof(ALfloat[6]), "Invalid Vector3 pair size");
852 CheckContext(mContext);
853 if(mId != 0)
855 Batcher batcher = mContext->getBatcher();
856 alSourcefv(mId, AL_POSITION, position.getPtr());
857 alSourcefv(mId, AL_VELOCITY, velocity.getPtr());
858 if(mContext->hasExtension(EXT_BFORMAT))
859 alSourcefv(mId, AL_ORIENTATION, orientation.first.getPtr());
860 alSourcefv(mId, AL_DIRECTION, orientation.first.getPtr());
862 mPosition = position;
863 mVelocity = velocity;
864 mDirection = mOrientation[0] = orientation.first;
865 mOrientation[1] = orientation.second;
869 void ALSource::setPosition(ALfloat x, ALfloat y, ALfloat z)
871 CheckContext(mContext);
872 if(mId != 0)
873 alSource3f(mId, AL_POSITION, x, y, z);
874 mPosition[0] = x;
875 mPosition[1] = y;
876 mPosition[2] = z;
879 void ALSource::setPosition(const ALfloat *pos)
881 CheckContext(mContext);
882 if(mId != 0)
883 alSourcefv(mId, AL_POSITION, pos);
884 mPosition[0] = pos[0];
885 mPosition[1] = pos[1];
886 mPosition[2] = pos[2];
889 void ALSource::setVelocity(ALfloat x, ALfloat y, ALfloat z)
891 CheckContext(mContext);
892 if(mId != 0)
893 alSource3f(mId, AL_VELOCITY, x, y, z);
894 mVelocity[0] = x;
895 mVelocity[1] = y;
896 mVelocity[2] = z;
899 void ALSource::setVelocity(const ALfloat *vel)
901 CheckContext(mContext);
902 if(mId != 0)
903 alSourcefv(mId, AL_VELOCITY, vel);
904 mVelocity[0] = vel[0];
905 mVelocity[1] = vel[1];
906 mVelocity[2] = vel[2];
909 void ALSource::setDirection(ALfloat x, ALfloat y, ALfloat z)
911 CheckContext(mContext);
912 if(mId != 0)
913 alSource3f(mId, AL_DIRECTION, x, y, z);
914 mDirection[0] = x;
915 mDirection[1] = y;
916 mDirection[2] = z;
919 void ALSource::setDirection(const ALfloat *dir)
921 CheckContext(mContext);
922 if(mId != 0)
923 alSourcefv(mId, AL_DIRECTION, dir);
924 mDirection[0] = dir[0];
925 mDirection[1] = dir[1];
926 mDirection[2] = dir[2];
929 void ALSource::setOrientation(ALfloat x1, ALfloat y1, ALfloat z1, ALfloat x2, ALfloat y2, ALfloat z2)
931 CheckContext(mContext);
932 if(mId != 0)
934 ALfloat ori[6] = { x1, y1, z1, x2, y2, z2 };
935 if(mContext->hasExtension(EXT_BFORMAT))
936 alSourcefv(mId, AL_ORIENTATION, ori);
937 alSourcefv(mId, AL_DIRECTION, ori);
939 mDirection[0] = mOrientation[0][0] = x1;
940 mDirection[1] = mOrientation[0][1] = y1;
941 mDirection[2] = mOrientation[0][2] = z1;
942 mOrientation[1][0] = x2;
943 mOrientation[1][1] = y2;
944 mOrientation[1][2] = z2;
947 void ALSource::setOrientation(const ALfloat *at, const ALfloat *up)
949 CheckContext(mContext);
950 if(mId != 0)
952 ALfloat ori[6] = { at[0], at[1], at[2], up[0], up[1], up[2] };
953 if(mContext->hasExtension(EXT_BFORMAT))
954 alSourcefv(mId, AL_ORIENTATION, ori);
955 alSourcefv(mId, AL_DIRECTION, ori);
957 mDirection[0] = mOrientation[0][0] = at[0];
958 mDirection[1] = mOrientation[0][1] = at[1];
959 mDirection[2] = mOrientation[0][2] = at[2];
960 mOrientation[1][0] = up[0];
961 mOrientation[1][1] = up[1];
962 mOrientation[1][2] = up[2];
965 void ALSource::setOrientation(const ALfloat *ori)
967 CheckContext(mContext);
968 if(mId != 0)
970 if(mContext->hasExtension(EXT_BFORMAT))
971 alSourcefv(mId, AL_ORIENTATION, ori);
972 alSourcefv(mId, AL_DIRECTION, ori);
974 mDirection[0] = mOrientation[0][0] = ori[0];
975 mDirection[1] = mOrientation[0][1] = ori[1];
976 mDirection[2] = mOrientation[0][2] = ori[2];
977 mOrientation[1][0] = ori[3];
978 mOrientation[1][1] = ori[4];
979 mOrientation[1][2] = ori[5];
983 void ALSource::setConeAngles(ALfloat inner, ALfloat outer)
985 if(!(inner >= 0.0f && outer <= 360.0f && outer >= inner))
986 throw std::runtime_error("Cone angles out of range");
987 CheckContext(mContext);
988 if(mId != 0)
990 alSourcef(mId, AL_CONE_INNER_ANGLE, inner);
991 alSourcef(mId, AL_CONE_OUTER_ANGLE, outer);
993 mConeInnerAngle = inner;
994 mConeOuterAngle = outer;
997 void ALSource::setOuterConeGains(ALfloat gain, ALfloat gainhf)
999 if(!(gain >= 0.0f && gain <= 1.0f && gainhf >= 0.0f && gainhf <= 1.0f))
1000 throw std::runtime_error("Outer cone gain out of range");
1001 CheckContext(mContext);
1002 if(mId != 0)
1004 alSourcef(mId, AL_CONE_OUTER_GAIN, gain);
1005 if(mContext->hasExtension(EXT_EFX))
1006 alSourcef(mId, AL_CONE_OUTER_GAINHF, gainhf);
1008 mConeOuterGain = gain;
1009 mConeOuterGainHF = gainhf;
1013 void ALSource::setRolloffFactors(ALfloat factor, ALfloat roomfactor)
1015 if(!(factor >= 0.0f && roomfactor >= 0.0f))
1016 throw std::runtime_error("Rolloff factor out of range");
1017 CheckContext(mContext);
1018 if(mId != 0)
1020 alSourcef(mId, AL_ROLLOFF_FACTOR, factor);
1021 if(mContext->hasExtension(EXT_EFX))
1022 alSourcef(mId, AL_ROOM_ROLLOFF_FACTOR, roomfactor);
1024 mRolloffFactor = factor;
1025 mRoomRolloffFactor = roomfactor;
1028 void ALSource::setDopplerFactor(ALfloat factor)
1030 if(!(factor >= 0.0f && factor <= 1.0f))
1031 throw std::runtime_error("Doppler factor out of range");
1032 CheckContext(mContext);
1033 if(mId != 0)
1034 alSourcef(mId, AL_DOPPLER_FACTOR, factor);
1035 mDopplerFactor = factor;
1038 void ALSource::setAirAbsorptionFactor(ALfloat factor)
1040 if(!(factor >= 0.0f && factor <= 10.0f))
1041 throw std::runtime_error("Absorption factor out of range");
1042 CheckContext(mContext);
1043 if(mId != 0 && mContext->hasExtension(EXT_EFX))
1044 alSourcef(mId, AL_AIR_ABSORPTION_FACTOR, factor);
1045 mAirAbsorptionFactor = factor;
1048 void ALSource::setRadius(ALfloat radius)
1050 if(!(mRadius >= 0.0f))
1051 throw std::runtime_error("Radius out of range");
1052 CheckContext(mContext);
1053 if(mId != 0 && mContext->hasExtension(EXT_SOURCE_RADIUS))
1054 alSourcef(mId, AL_SOURCE_RADIUS, radius);
1055 mRadius = radius;
1058 void ALSource::setStereoAngles(ALfloat leftAngle, ALfloat rightAngle)
1060 CheckContext(mContext);
1061 if(mId != 0 && mContext->hasExtension(EXT_STEREO_ANGLES))
1063 ALfloat angles[2] = { leftAngle, rightAngle };
1064 alSourcefv(mId, AL_STEREO_ANGLES, angles);
1066 mStereoAngles[0] = leftAngle;
1067 mStereoAngles[1] = rightAngle;
1070 void ALSource::set3DSpatialize(Spatialize spatialize)
1072 CheckContext(mContext);
1073 if(mId != 0 && mContext->hasExtension(SOFT_source_spatialize))
1074 alSourcei(mId, AL_SOURCE_SPATIALIZE_SOFT, (ALint)spatialize);
1075 mSpatialize = spatialize;
1078 void ALSource::setResamplerIndex(ALsizei index)
1080 if(index < 0)
1081 throw std::runtime_error("Resampler index out of range");
1082 index = std::min<ALsizei>(index, mContext->getAvailableResamplers().size());
1083 if(mId != 0 && mContext->hasExtension(SOFT_source_resampler))
1084 alSourcei(mId, AL_SOURCE_RESAMPLER_SOFT, index);
1085 mResampler = index;
1088 void ALSource::setRelative(bool relative)
1090 CheckContext(mContext);
1091 if(mId != 0)
1092 alSourcei(mId, AL_SOURCE_RELATIVE, relative ? AL_TRUE : AL_FALSE);
1093 mRelative = relative;
1096 void ALSource::setGainAuto(bool directhf, bool send, bool sendhf)
1098 CheckContext(mContext);
1099 if(mId != 0 && mContext->hasExtension(EXT_EFX))
1101 alSourcei(mId, AL_DIRECT_FILTER_GAINHF_AUTO, directhf ? AL_TRUE : AL_FALSE);
1102 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, send ? AL_TRUE : AL_FALSE);
1103 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, sendhf ? AL_TRUE : AL_FALSE);
1105 mDryGainHFAuto = directhf;
1106 mWetGainAuto = send;
1107 mWetGainHFAuto = sendhf;
1111 void ALSource::setFilterParams(ALuint &filterid, const FilterParams &params)
1113 if(!mContext->hasExtension(EXT_EFX))
1114 return;
1116 if(!(params.mGain < 1.0f || params.mGainHF < 1.0f || params.mGainLF < 1.0f))
1118 if(filterid)
1119 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_NULL);
1120 return;
1123 alGetError();
1124 if(!filterid)
1126 mContext->alGenFilters(1, &filterid);
1127 if(alGetError() != AL_NO_ERROR)
1128 throw std::runtime_error("Failed to create Filter");
1130 bool filterset = false;
1131 if(params.mGainHF < 1.0f && params.mGainLF < 1.0f)
1133 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_BANDPASS);
1134 if(alGetError() == AL_NO_ERROR)
1136 mContext->alFilterf(filterid, AL_BANDPASS_GAIN, std::min(params.mGain, 1.0f));
1137 mContext->alFilterf(filterid, AL_BANDPASS_GAINHF, std::min(params.mGainHF, 1.0f));
1138 mContext->alFilterf(filterid, AL_BANDPASS_GAINLF, std::min(params.mGainLF, 1.0f));
1139 filterset = true;
1142 if(!filterset && !(params.mGainHF < 1.0f) && params.mGainLF < 1.0f)
1144 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_HIGHPASS);
1145 if(alGetError() == AL_NO_ERROR)
1147 mContext->alFilterf(filterid, AL_HIGHPASS_GAIN, std::min(params.mGain, 1.0f));
1148 mContext->alFilterf(filterid, AL_HIGHPASS_GAINLF, std::min(params.mGainLF, 1.0f));
1149 filterset = true;
1152 if(!filterset)
1154 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1155 if(alGetError() == AL_NO_ERROR)
1157 mContext->alFilterf(filterid, AL_LOWPASS_GAIN, std::min(params.mGain, 1.0f));
1158 mContext->alFilterf(filterid, AL_LOWPASS_GAINHF, std::min(params.mGainHF, 1.0f));
1159 filterset = true;
1165 void ALSource::setDirectFilter(const FilterParams &filter)
1167 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1168 throw std::runtime_error("Gain value out of range");
1169 CheckContext(mContext);
1171 setFilterParams(mDirectFilter, filter);
1172 if(mId)
1173 alSourcei(mId, AL_DIRECT_FILTER, mDirectFilter);
1176 void ALSource::setSendFilter(ALuint send, const FilterParams &filter)
1178 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1179 throw std::runtime_error("Gain value out of range");
1180 CheckContext(mContext);
1182 SendPropMap::iterator siter = mEffectSlots.find(send);
1183 if(siter == mEffectSlots.end())
1185 ALuint filterid = 0;
1187 setFilterParams(filterid, filter);
1188 if(!filterid) return;
1190 siter = mEffectSlots.insert(std::make_pair(send, SendProps(filterid))).first;
1192 else
1193 setFilterParams(siter->second.mFilter, filter);
1195 if(mId)
1197 ALuint slotid = (siter->second.mSlot ? siter->second.mSlot->getId() : 0);
1198 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->second.mFilter);
1202 void ALSource::setAuxiliarySend(AuxiliaryEffectSlot auxslot, ALuint send)
1204 ALAuxiliaryEffectSlot *slot = auxslot.getHandle();
1205 if(slot) CheckContext(slot->getContext());
1206 CheckContext(mContext);
1208 SendPropMap::iterator siter = mEffectSlots.find(send);
1209 if(siter == mEffectSlots.end())
1211 if(!slot) return;
1212 slot->addSourceSend(Source(this), send);
1213 siter = mEffectSlots.insert(std::make_pair(send, SendProps(slot))).first;
1215 else if(siter->second.mSlot != slot)
1217 if(slot) slot->addSourceSend(Source(this), send);
1218 if(siter->second.mSlot)
1219 siter->second.mSlot->removeSourceSend(Source(this), send);
1220 siter->second.mSlot = slot;
1223 if(mId)
1225 ALuint slotid = (siter->second.mSlot ? siter->second.mSlot->getId() : 0);
1226 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->second.mFilter);
1230 void ALSource::setAuxiliarySendFilter(AuxiliaryEffectSlot auxslot, ALuint send, const FilterParams &filter)
1232 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1233 throw std::runtime_error("Gain value out of range");
1234 ALAuxiliaryEffectSlot *slot = auxslot.getHandle();
1235 if(slot) CheckContext(slot->getContext());
1236 CheckContext(mContext);
1238 SendPropMap::iterator siter = mEffectSlots.find(send);
1239 if(siter == mEffectSlots.end())
1241 ALuint filterid = 0;
1243 setFilterParams(filterid, filter);
1244 if(!filterid && !slot)
1245 return;
1247 if(slot) slot->addSourceSend(Source(this), send);
1248 siter = mEffectSlots.insert(std::make_pair(send, SendProps(slot, filterid))).first;
1250 else
1252 if(siter->second.mSlot != slot)
1254 if(slot) slot->addSourceSend(Source(this), send);
1255 if(siter->second.mSlot)
1256 siter->second.mSlot->removeSourceSend(Source(this), send);
1257 siter->second.mSlot = slot;
1259 setFilterParams(siter->second.mFilter, filter);
1262 if(mId)
1264 ALuint slotid = (siter->second.mSlot ? siter->second.mSlot->getId() : 0);
1265 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->second.mFilter);
1270 void ALSource::release()
1272 CheckContext(mContext);
1274 if(mIsAsync.load(std::memory_order_acquire))
1276 mContext->removeStream(this);
1277 mIsAsync.store(false, std::memory_order_release);
1280 if(mId != 0)
1282 alSourceRewind(mId);
1283 alSourcei(mId, AL_BUFFER, 0);
1284 if(mContext->hasExtension(EXT_EFX))
1286 alSourcei(mId, AL_DIRECT_FILTER, AL_FILTER_NULL);
1287 for(auto &i : mEffectSlots)
1288 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, 0, i.first, AL_FILTER_NULL);
1290 mContext->insertSourceId(mId);
1291 mId = 0;
1294 mContext->freeSource(this);
1296 if(mDirectFilter)
1297 mContext->alDeleteFilters(1, &mDirectFilter);
1298 mDirectFilter = AL_FILTER_NULL;
1300 for(auto &i : mEffectSlots)
1302 if(i.second.mSlot)
1303 i.second.mSlot->removeSourceSend(Source(this), i.first);
1304 if(i.second.mFilter)
1305 mContext->alDeleteFilters(1, &i.second.mFilter);
1307 mEffectSlots.clear();
1309 if(mBuffer)
1310 mBuffer->removeSource(Source(this));
1311 mBuffer = 0;
1313 mStream.reset();
1315 resetProperties();
1319 // Need to use these to avoid extraneous commas in macro parameter lists
1320 using UInt64NSecPair = std::pair<uint64_t,std::chrono::nanoseconds>;
1321 using SecondsPair = std::pair<Seconds,Seconds>;
1322 using ALfloatPair = std::pair<ALfloat,ALfloat>;
1323 using Vector3Pair = std::pair<Vector3,Vector3>;
1324 using BoolTriple = std::tuple<bool,bool,bool>;
1326 DECL_THUNK1(void, Source, play,, Buffer)
1327 DECL_THUNK3(void, Source, play,, SharedPtr<Decoder>, ALuint, ALuint)
1328 DECL_THUNK0(void, Source, stop,)
1329 DECL_THUNK0(void, Source, pause,)
1330 DECL_THUNK0(void, Source, resume,)
1331 DECL_THUNK0(bool, Source, isPlaying, const)
1332 DECL_THUNK0(bool, Source, isPaused, const)
1333 DECL_THUNK1(void, Source, setPriority,, ALuint)
1334 DECL_THUNK0(ALuint, Source, getPriority, const)
1335 DECL_THUNK1(void, Source, setOffset,, uint64_t)
1336 DECL_THUNK0(UInt64NSecPair, Source, getSampleOffsetLatency, const)
1337 DECL_THUNK0(SecondsPair, Source, getSecOffsetLatency, const)
1338 DECL_THUNK1(void, Source, setLooping,, bool)
1339 DECL_THUNK0(bool, Source, getLooping, const)
1340 DECL_THUNK1(void, Source, setPitch,, ALfloat)
1341 DECL_THUNK0(ALfloat, Source, getPitch, const)
1342 DECL_THUNK1(void, Source, setGain,, ALfloat)
1343 DECL_THUNK0(ALfloat, Source, getGain, const)
1344 DECL_THUNK2(void, Source, setGainRange,, ALfloat, ALfloat)
1345 DECL_THUNK0(ALfloatPair, Source, getGainRange, const)
1346 DECL_THUNK2(void, Source, setDistanceRange,, ALfloat, ALfloat)
1347 DECL_THUNK0(ALfloatPair, Source, getDistanceRange, const)
1348 DECL_THUNK3(void, Source, set3DParameters,, const Vector3&, const Vector3&, const Vector3&)
1349 DECL_THUNK3(void, Source, set3DParameters,, const Vector3&, const Vector3&, Vector3Pair)
1350 DECL_THUNK3(void, Source, setPosition,, ALfloat, ALfloat, ALfloat)
1351 DECL_THUNK1(void, Source, setPosition,, const ALfloat*)
1352 DECL_THUNK0(Vector3, Source, getPosition, const)
1353 DECL_THUNK3(void, Source, setVelocity,, ALfloat, ALfloat, ALfloat)
1354 DECL_THUNK1(void, Source, setVelocity,, const ALfloat*)
1355 DECL_THUNK0(Vector3, Source, getVelocity, const)
1356 DECL_THUNK3(void, Source, setDirection,, ALfloat, ALfloat, ALfloat)
1357 DECL_THUNK1(void, Source, setDirection,, const ALfloat*)
1358 DECL_THUNK0(Vector3, Source, getDirection, const)
1359 DECL_THUNK6(void, Source, setOrientation,, ALfloat, ALfloat, ALfloat, ALfloat, ALfloat, ALfloat)
1360 DECL_THUNK2(void, Source, setOrientation,, const ALfloat*, const ALfloat*)
1361 DECL_THUNK1(void, Source, setOrientation,, const ALfloat*)
1362 DECL_THUNK0(Vector3Pair, Source, getOrientation, const)
1363 DECL_THUNK2(void, Source, setConeAngles,, ALfloat, ALfloat)
1364 DECL_THUNK0(ALfloatPair, Source, getConeAngles, const)
1365 DECL_THUNK2(void, Source, setOuterConeGains,, ALfloat, ALfloat)
1366 DECL_THUNK0(ALfloatPair, Source, getOuterConeGains, const)
1367 DECL_THUNK2(void, Source, setRolloffFactors,, ALfloat, ALfloat)
1368 DECL_THUNK0(ALfloatPair, Source, getRolloffFactors, const)
1369 DECL_THUNK1(void, Source, setDopplerFactor,, ALfloat)
1370 DECL_THUNK0(ALfloat, Source, getDopplerFactor, const)
1371 DECL_THUNK1(void, Source, setRelative,, bool)
1372 DECL_THUNK0(bool, Source, getRelative, const)
1373 DECL_THUNK1(void, Source, setRadius,, ALfloat)
1374 DECL_THUNK0(ALfloat, Source, getRadius, const)
1375 DECL_THUNK2(void, Source, setStereoAngles,, ALfloat, ALfloat)
1376 DECL_THUNK0(ALfloatPair, Source, getStereoAngles, const)
1377 DECL_THUNK1(void, Source, set3DSpatialize,, Spatialize)
1378 DECL_THUNK0(Spatialize, Source, get3DSpatialize, const)
1379 DECL_THUNK1(void, Source, setResamplerIndex,, ALsizei)
1380 DECL_THUNK0(ALsizei, Source, getResamplerIndex, const)
1381 DECL_THUNK1(void, Source, setAirAbsorptionFactor,, ALfloat)
1382 DECL_THUNK0(ALfloat, Source, getAirAbsorptionFactor, const)
1383 DECL_THUNK3(void, Source, setGainAuto,, bool, bool, bool)
1384 DECL_THUNK0(BoolTriple, Source, getGainAuto, const)
1385 DECL_THUNK1(void, Source, setDirectFilter,, const FilterParams&)
1386 DECL_THUNK2(void, Source, setSendFilter,, ALuint, const FilterParams&)
1387 DECL_THUNK2(void, Source, setAuxiliarySend,, AuxiliaryEffectSlot, ALuint)
1388 DECL_THUNK3(void, Source, setAuxiliarySendFilter,, AuxiliaryEffectSlot, ALuint, const FilterParams&)
1389 void Source::release()
1391 pImpl->release();
1392 pImpl = nullptr;