Simplify calculating the source stream offset
[alure.git] / src / source.cpp
blob5ea0463368278c5a1ca12681235a4f7146f31803
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::update()
556 CheckContext(mContext);
557 updateNoCtxCheck();
560 void ALSource::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 ALSource::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 ALSource::setPriority(ALuint priority)
608 mPriority = priority;
612 void ALSource::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> ALSource::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> ALSource::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 srcpos *= mStream->getFrequency();
738 frac = srcpos - std::floor(srcpos);
740 // The amount of samples in the queue waiting to play
741 ALuint inqueue = queued*mStream->getUpdateLength() - (ALuint)std::ceil(srcpos);
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_SAMPLE_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 ALSource::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 ALSource::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 ALSource::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 ALSource::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 ALSource::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 ALSource::setPosition(ALfloat x, ALfloat y, ALfloat z)
842 CheckContext(mContext);
843 if(mId != 0)
844 alSource3f(mId, AL_POSITION, x, y, z);
845 mPosition[0] = x;
846 mPosition[1] = y;
847 mPosition[2] = z;
850 void ALSource::setPosition(const ALfloat *pos)
852 CheckContext(mContext);
853 if(mId != 0)
854 alSourcefv(mId, AL_POSITION, pos);
855 mPosition[0] = pos[0];
856 mPosition[1] = pos[1];
857 mPosition[2] = pos[2];
860 void ALSource::setVelocity(ALfloat x, ALfloat y, ALfloat z)
862 CheckContext(mContext);
863 if(mId != 0)
864 alSource3f(mId, AL_VELOCITY, x, y, z);
865 mVelocity[0] = x;
866 mVelocity[1] = y;
867 mVelocity[2] = z;
870 void ALSource::setVelocity(const ALfloat *vel)
872 CheckContext(mContext);
873 if(mId != 0)
874 alSourcefv(mId, AL_VELOCITY, vel);
875 mVelocity[0] = vel[0];
876 mVelocity[1] = vel[1];
877 mVelocity[2] = vel[2];
880 void ALSource::setDirection(ALfloat x, ALfloat y, ALfloat z)
882 CheckContext(mContext);
883 if(mId != 0)
884 alSource3f(mId, AL_DIRECTION, x, y, z);
885 mDirection[0] = x;
886 mDirection[1] = y;
887 mDirection[2] = z;
890 void ALSource::setDirection(const ALfloat *dir)
892 CheckContext(mContext);
893 if(mId != 0)
894 alSourcefv(mId, AL_DIRECTION, dir);
895 mDirection[0] = dir[0];
896 mDirection[1] = dir[1];
897 mDirection[2] = dir[2];
900 void ALSource::setOrientation(ALfloat x1, ALfloat y1, ALfloat z1, ALfloat x2, ALfloat y2, ALfloat z2)
902 CheckContext(mContext);
903 if(mId != 0)
905 ALfloat ori[6] = { x1, y1, z1, x2, y2, z2 };
906 if(mContext->hasExtension(EXT_BFORMAT))
907 alSourcefv(mId, AL_ORIENTATION, ori);
908 alSourcefv(mId, AL_DIRECTION, ori);
910 mDirection[0] = mOrientation[0][0] = x1;
911 mDirection[1] = mOrientation[0][1] = y1;
912 mDirection[2] = mOrientation[0][2] = z1;
913 mOrientation[1][0] = x2;
914 mOrientation[1][1] = y2;
915 mOrientation[1][2] = z2;
918 void ALSource::setOrientation(const ALfloat *at, const ALfloat *up)
920 CheckContext(mContext);
921 if(mId != 0)
923 ALfloat ori[6] = { at[0], at[1], at[2], up[0], up[1], up[2] };
924 if(mContext->hasExtension(EXT_BFORMAT))
925 alSourcefv(mId, AL_ORIENTATION, ori);
926 alSourcefv(mId, AL_DIRECTION, ori);
928 mDirection[0] = mOrientation[0][0] = at[0];
929 mDirection[1] = mOrientation[0][1] = at[1];
930 mDirection[2] = mOrientation[0][2] = at[2];
931 mOrientation[1][0] = up[0];
932 mOrientation[1][1] = up[1];
933 mOrientation[1][2] = up[2];
936 void ALSource::setOrientation(const ALfloat *ori)
938 CheckContext(mContext);
939 if(mId != 0)
941 if(mContext->hasExtension(EXT_BFORMAT))
942 alSourcefv(mId, AL_ORIENTATION, ori);
943 alSourcefv(mId, AL_DIRECTION, ori);
945 mDirection[0] = mOrientation[0][0] = ori[0];
946 mDirection[1] = mOrientation[0][1] = ori[1];
947 mDirection[2] = mOrientation[0][2] = ori[2];
948 mOrientation[1][0] = ori[3];
949 mOrientation[1][1] = ori[4];
950 mOrientation[1][2] = ori[5];
954 void ALSource::setConeAngles(ALfloat inner, ALfloat outer)
956 if(!(inner >= 0.0f && outer <= 360.0f && outer >= inner))
957 throw std::runtime_error("Cone angles out of range");
958 CheckContext(mContext);
959 if(mId != 0)
961 alSourcef(mId, AL_CONE_INNER_ANGLE, inner);
962 alSourcef(mId, AL_CONE_OUTER_ANGLE, outer);
964 mConeInnerAngle = inner;
965 mConeOuterAngle = outer;
968 void ALSource::setOuterConeGains(ALfloat gain, ALfloat gainhf)
970 if(!(gain >= 0.0f && gain <= 1.0f && gainhf >= 0.0f && gainhf <= 1.0f))
971 throw std::runtime_error("Outer cone gain out of range");
972 CheckContext(mContext);
973 if(mId != 0)
975 alSourcef(mId, AL_CONE_OUTER_GAIN, gain);
976 if(mContext->hasExtension(EXT_EFX))
977 alSourcef(mId, AL_CONE_OUTER_GAINHF, gainhf);
979 mConeOuterGain = gain;
980 mConeOuterGainHF = gainhf;
984 void ALSource::setRolloffFactors(ALfloat factor, ALfloat roomfactor)
986 if(!(factor >= 0.0f && roomfactor >= 0.0f))
987 throw std::runtime_error("Rolloff factor out of range");
988 CheckContext(mContext);
989 if(mId != 0)
991 alSourcef(mId, AL_ROLLOFF_FACTOR, factor);
992 if(mContext->hasExtension(EXT_EFX))
993 alSourcef(mId, AL_ROOM_ROLLOFF_FACTOR, roomfactor);
995 mRolloffFactor = factor;
996 mRoomRolloffFactor = roomfactor;
999 void ALSource::setDopplerFactor(ALfloat factor)
1001 if(!(factor >= 0.0f && factor <= 1.0f))
1002 throw std::runtime_error("Doppler factor out of range");
1003 CheckContext(mContext);
1004 if(mId != 0)
1005 alSourcef(mId, AL_DOPPLER_FACTOR, factor);
1006 mDopplerFactor = factor;
1009 void ALSource::setAirAbsorptionFactor(ALfloat factor)
1011 if(!(factor >= 0.0f && factor <= 10.0f))
1012 throw std::runtime_error("Absorption factor out of range");
1013 CheckContext(mContext);
1014 if(mId != 0 && mContext->hasExtension(EXT_EFX))
1015 alSourcef(mId, AL_AIR_ABSORPTION_FACTOR, factor);
1016 mAirAbsorptionFactor = factor;
1019 void ALSource::setRadius(ALfloat radius)
1021 if(!(mRadius >= 0.0f))
1022 throw std::runtime_error("Radius out of range");
1023 CheckContext(mContext);
1024 if(mId != 0 && mContext->hasExtension(EXT_SOURCE_RADIUS))
1025 alSourcef(mId, AL_SOURCE_RADIUS, radius);
1026 mRadius = radius;
1029 void ALSource::setStereoAngles(ALfloat leftAngle, ALfloat rightAngle)
1031 CheckContext(mContext);
1032 if(mId != 0 && mContext->hasExtension(EXT_STEREO_ANGLES))
1034 ALfloat angles[2] = { leftAngle, rightAngle };
1035 alSourcefv(mId, AL_STEREO_ANGLES, angles);
1037 mStereoAngles[0] = leftAngle;
1038 mStereoAngles[1] = rightAngle;
1041 void ALSource::set3DSpatialize(Spatialize spatialize)
1043 CheckContext(mContext);
1044 if(mId != 0 && mContext->hasExtension(SOFT_source_spatialize))
1045 alSourcei(mId, AL_SOURCE_SPATIALIZE_SOFT, (ALint)spatialize);
1046 mSpatialize = spatialize;
1049 void ALSource::setResamplerIndex(ALsizei index)
1051 if(index < 0)
1052 throw std::runtime_error("Resampler index out of range");
1053 index = std::min<ALsizei>(index, mContext->getAvailableResamplers().size());
1054 if(mId != 0 && mContext->hasExtension(SOFT_source_resampler))
1055 alSourcei(mId, AL_SOURCE_RESAMPLER_SOFT, index);
1056 mResampler = index;
1059 void ALSource::setRelative(bool relative)
1061 CheckContext(mContext);
1062 if(mId != 0)
1063 alSourcei(mId, AL_SOURCE_RELATIVE, relative ? AL_TRUE : AL_FALSE);
1064 mRelative = relative;
1067 void ALSource::setGainAuto(bool directhf, bool send, bool sendhf)
1069 CheckContext(mContext);
1070 if(mId != 0 && mContext->hasExtension(EXT_EFX))
1072 alSourcei(mId, AL_DIRECT_FILTER_GAINHF_AUTO, directhf ? AL_TRUE : AL_FALSE);
1073 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, send ? AL_TRUE : AL_FALSE);
1074 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, sendhf ? AL_TRUE : AL_FALSE);
1076 mDryGainHFAuto = directhf;
1077 mWetGainAuto = send;
1078 mWetGainHFAuto = sendhf;
1082 void ALSource::setFilterParams(ALuint &filterid, const FilterParams &params)
1084 if(!mContext->hasExtension(EXT_EFX))
1085 return;
1087 if(!(params.mGain < 1.0f || params.mGainHF < 1.0f || params.mGainLF < 1.0f))
1089 if(filterid)
1090 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_NULL);
1091 return;
1094 alGetError();
1095 if(!filterid)
1097 mContext->alGenFilters(1, &filterid);
1098 if(alGetError() != AL_NO_ERROR)
1099 throw std::runtime_error("Failed to create Filter");
1101 bool filterset = false;
1102 if(params.mGainHF < 1.0f && params.mGainLF < 1.0f)
1104 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_BANDPASS);
1105 if(alGetError() == AL_NO_ERROR)
1107 mContext->alFilterf(filterid, AL_BANDPASS_GAIN, std::min<ALfloat>(params.mGain, 1.0f));
1108 mContext->alFilterf(filterid, AL_BANDPASS_GAINHF, std::min<ALfloat>(params.mGainHF, 1.0f));
1109 mContext->alFilterf(filterid, AL_BANDPASS_GAINLF, std::min<ALfloat>(params.mGainLF, 1.0f));
1110 filterset = true;
1113 if(!filterset && !(params.mGainHF < 1.0f) && params.mGainLF < 1.0f)
1115 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_HIGHPASS);
1116 if(alGetError() == AL_NO_ERROR)
1118 mContext->alFilterf(filterid, AL_HIGHPASS_GAIN, std::min<ALfloat>(params.mGain, 1.0f));
1119 mContext->alFilterf(filterid, AL_HIGHPASS_GAINLF, std::min<ALfloat>(params.mGainLF, 1.0f));
1120 filterset = true;
1123 if(!filterset)
1125 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1126 if(alGetError() == AL_NO_ERROR)
1128 mContext->alFilterf(filterid, AL_LOWPASS_GAIN, std::min<ALfloat>(params.mGain, 1.0f));
1129 mContext->alFilterf(filterid, AL_LOWPASS_GAINHF, std::min<ALfloat>(params.mGainHF, 1.0f));
1130 filterset = true;
1136 void ALSource::setDirectFilter(const FilterParams &filter)
1138 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1139 throw std::runtime_error("Gain value out of range");
1140 CheckContext(mContext);
1142 setFilterParams(mDirectFilter, filter);
1143 if(mId)
1144 alSourcei(mId, AL_DIRECT_FILTER, mDirectFilter);
1147 void ALSource::setSendFilter(ALuint send, const FilterParams &filter)
1149 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1150 throw std::runtime_error("Gain value out of range");
1151 CheckContext(mContext);
1153 SendPropMap::iterator siter = mEffectSlots.find(send);
1154 if(siter == mEffectSlots.end())
1156 ALuint filterid = 0;
1158 setFilterParams(filterid, filter);
1159 if(!filterid) return;
1161 siter = mEffectSlots.insert(std::make_pair(send, SendProps(filterid))).first;
1163 else
1164 setFilterParams(siter->second.mFilter, filter);
1166 if(mId)
1168 ALuint slotid = (siter->second.mSlot ? siter->second.mSlot->getId() : 0);
1169 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->second.mFilter);
1173 void ALSource::setAuxiliarySend(AuxiliaryEffectSlot auxslot, ALuint send)
1175 ALAuxiliaryEffectSlot *slot = auxslot.getHandle();
1176 if(slot) CheckContext(slot->getContext());
1177 CheckContext(mContext);
1179 SendPropMap::iterator siter = mEffectSlots.find(send);
1180 if(siter == mEffectSlots.end())
1182 if(!slot) return;
1183 slot->addSourceSend(Source(this), send);
1184 siter = mEffectSlots.insert(std::make_pair(send, SendProps(slot))).first;
1186 else if(siter->second.mSlot != slot)
1188 if(slot) slot->addSourceSend(Source(this), send);
1189 if(siter->second.mSlot)
1190 siter->second.mSlot->removeSourceSend(Source(this), send);
1191 siter->second.mSlot = slot;
1194 if(mId)
1196 ALuint slotid = (siter->second.mSlot ? siter->second.mSlot->getId() : 0);
1197 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->second.mFilter);
1201 void ALSource::setAuxiliarySendFilter(AuxiliaryEffectSlot auxslot, ALuint send, const FilterParams &filter)
1203 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1204 throw std::runtime_error("Gain value out of range");
1205 ALAuxiliaryEffectSlot *slot = auxslot.getHandle();
1206 if(slot) CheckContext(slot->getContext());
1207 CheckContext(mContext);
1209 SendPropMap::iterator siter = mEffectSlots.find(send);
1210 if(siter == mEffectSlots.end())
1212 ALuint filterid = 0;
1214 setFilterParams(filterid, filter);
1215 if(!filterid && !slot)
1216 return;
1218 if(slot) slot->addSourceSend(Source(this), send);
1219 siter = mEffectSlots.insert(std::make_pair(send, SendProps(slot, filterid))).first;
1221 else
1223 if(siter->second.mSlot != slot)
1225 if(slot) slot->addSourceSend(Source(this), send);
1226 if(siter->second.mSlot)
1227 siter->second.mSlot->removeSourceSend(Source(this), send);
1228 siter->second.mSlot = slot;
1230 setFilterParams(siter->second.mFilter, filter);
1233 if(mId)
1235 ALuint slotid = (siter->second.mSlot ? siter->second.mSlot->getId() : 0);
1236 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->second.mFilter);
1241 void ALSource::release()
1243 CheckContext(mContext);
1245 if(mIsAsync.load(std::memory_order_acquire))
1247 mContext->removeStream(this);
1248 mIsAsync.store(false, std::memory_order_release);
1251 if(mId != 0)
1253 alSourceRewind(mId);
1254 alSourcei(mId, AL_BUFFER, 0);
1255 if(mContext->hasExtension(EXT_EFX))
1257 alSourcei(mId, AL_DIRECT_FILTER, AL_FILTER_NULL);
1258 for(auto &i : mEffectSlots)
1259 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, 0, i.first, AL_FILTER_NULL);
1261 mContext->insertSourceId(mId);
1262 mId = 0;
1265 mContext->freeSource(this);
1267 if(mDirectFilter)
1268 mContext->alDeleteFilters(1, &mDirectFilter);
1269 mDirectFilter = AL_FILTER_NULL;
1271 for(auto &i : mEffectSlots)
1273 if(i.second.mSlot)
1274 i.second.mSlot->removeSourceSend(Source(this), i.first);
1275 if(i.second.mFilter)
1276 mContext->alDeleteFilters(1, &i.second.mFilter);
1278 mEffectSlots.clear();
1280 if(mBuffer)
1281 mBuffer->removeSource(Source(this));
1282 mBuffer = 0;
1284 mStream.reset();
1286 resetProperties();
1290 // Need to use these to avoid extraneous commas in macro parameter lists
1291 using UInt64NSecPair = std::pair<uint64_t,std::chrono::nanoseconds>;
1292 using SecondsPair = std::pair<Seconds,Seconds>;
1293 using ALfloatPair = std::pair<ALfloat,ALfloat>;
1294 using Vector3Pair = std::pair<Vector3,Vector3>;
1295 using BoolTriple = std::tuple<bool,bool,bool>;
1297 DECL_THUNK1(void, Source, play,, Buffer)
1298 DECL_THUNK3(void, Source, play,, SharedPtr<Decoder>, ALuint, ALuint)
1299 DECL_THUNK0(void, Source, stop,)
1300 DECL_THUNK0(void, Source, pause,)
1301 DECL_THUNK0(void, Source, resume,)
1302 DECL_THUNK0(bool, Source, isPlaying, const)
1303 DECL_THUNK0(bool, Source, isPaused, const)
1304 DECL_THUNK1(void, Source, setPriority,, ALuint)
1305 DECL_THUNK0(ALuint, Source, getPriority, const)
1306 DECL_THUNK1(void, Source, setOffset,, uint64_t)
1307 DECL_THUNK0(UInt64NSecPair, Source, getSampleOffsetLatency, const)
1308 DECL_THUNK0(SecondsPair, Source, getSecOffsetLatency, const)
1309 DECL_THUNK1(void, Source, setLooping,, bool)
1310 DECL_THUNK0(bool, Source, getLooping, const)
1311 DECL_THUNK1(void, Source, setPitch,, ALfloat)
1312 DECL_THUNK0(ALfloat, Source, getPitch, const)
1313 DECL_THUNK1(void, Source, setGain,, ALfloat)
1314 DECL_THUNK0(ALfloat, Source, getGain, const)
1315 DECL_THUNK2(void, Source, setGainRange,, ALfloat, ALfloat)
1316 DECL_THUNK0(ALfloatPair, Source, getGainRange, const)
1317 DECL_THUNK2(void, Source, setDistanceRange,, ALfloat, ALfloat)
1318 DECL_THUNK0(ALfloatPair, Source, getDistanceRange, const)
1319 DECL_THUNK3(void, Source, setPosition,, ALfloat, ALfloat, ALfloat)
1320 DECL_THUNK1(void, Source, setPosition,, const ALfloat*)
1321 DECL_THUNK0(Vector3, Source, getPosition, const)
1322 DECL_THUNK3(void, Source, setVelocity,, ALfloat, ALfloat, ALfloat)
1323 DECL_THUNK1(void, Source, setVelocity,, const ALfloat*)
1324 DECL_THUNK0(Vector3, Source, getVelocity, const)
1325 DECL_THUNK3(void, Source, setDirection,, ALfloat, ALfloat, ALfloat)
1326 DECL_THUNK1(void, Source, setDirection,, const ALfloat*)
1327 DECL_THUNK0(Vector3, Source, getDirection, const)
1328 DECL_THUNK6(void, Source, setOrientation,, ALfloat, ALfloat, ALfloat, ALfloat, ALfloat, ALfloat)
1329 DECL_THUNK2(void, Source, setOrientation,, const ALfloat*, const ALfloat*)
1330 DECL_THUNK1(void, Source, setOrientation,, const ALfloat*)
1331 DECL_THUNK0(Vector3Pair, Source, getOrientation, const)
1332 DECL_THUNK2(void, Source, setConeAngles,, ALfloat, ALfloat)
1333 DECL_THUNK0(ALfloatPair, Source, getConeAngles, const)
1334 DECL_THUNK2(void, Source, setOuterConeGains,, ALfloat, ALfloat)
1335 DECL_THUNK0(ALfloatPair, Source, getOuterConeGains, const)
1336 DECL_THUNK2(void, Source, setRolloffFactors,, ALfloat, ALfloat)
1337 DECL_THUNK0(ALfloatPair, Source, getRolloffFactors, const)
1338 DECL_THUNK1(void, Source, setDopplerFactor,, ALfloat)
1339 DECL_THUNK0(ALfloat, Source, getDopplerFactor, const)
1340 DECL_THUNK1(void, Source, setRelative,, bool)
1341 DECL_THUNK0(bool, Source, getRelative, const)
1342 DECL_THUNK1(void, Source, setRadius,, ALfloat)
1343 DECL_THUNK0(ALfloat, Source, getRadius, const)
1344 DECL_THUNK2(void, Source, setStereoAngles,, ALfloat, ALfloat)
1345 DECL_THUNK0(ALfloatPair, Source, getStereoAngles, const)
1346 DECL_THUNK1(void, Source, set3DSpatialize,, Spatialize)
1347 DECL_THUNK0(Spatialize, Source, get3DSpatialize, const)
1348 DECL_THUNK1(void, Source, setResamplerIndex,, ALsizei)
1349 DECL_THUNK0(ALsizei, Source, getResamplerIndex, const)
1350 DECL_THUNK1(void, Source, setAirAbsorptionFactor,, ALfloat)
1351 DECL_THUNK0(ALfloat, Source, getAirAbsorptionFactor, const)
1352 DECL_THUNK3(void, Source, setGainAuto,, bool, bool, bool)
1353 DECL_THUNK0(BoolTriple, Source, getGainAuto, const)
1354 DECL_THUNK1(void, Source, setDirectFilter,, const FilterParams&)
1355 DECL_THUNK2(void, Source, setSendFilter,, ALuint, const FilterParams&)
1356 DECL_THUNK2(void, Source, setAuxiliarySend,, AuxiliaryEffectSlot, ALuint)
1357 DECL_THUNK3(void, Source, setAuxiliarySendFilter,, AuxiliaryEffectSlot, ALuint, const FilterParams&)
1358 DECL_THUNK0(void, Source, update,)
1359 void Source::release()
1361 pImpl->release();
1362 pImpl = nullptr;