Make sources and source groups specify their parent
[alure.git] / src / source.cpp
blob29652c6fd990e2c01f2c76014f4f3c662568fa1f
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->eraseSource(this);
183 mGroup = nullptr;
184 mGroupPitch = 1.0f;
185 mGroupGain = 1.0f;
187 mFadeGainTarget = 1.0f;
188 mFadeGain = 1.0f;
190 mPaused.store(false, std::memory_order_release);
191 mOffset = 0;
192 mPitch = 1.0f;
193 mGain = 1.0f;
194 mMinGain = 0.0f;
195 mMaxGain = 1.0f;
196 mRefDist = 1.0f;
197 mMaxDist = std::numeric_limits<float>::max();
198 mPosition = Vector3(0.0f);
199 mVelocity = Vector3(0.0f);
200 mDirection = Vector3(0.0f);
201 mOrientation[0] = Vector3(0.0f, 0.0f, -1.0f);
202 mOrientation[1] = Vector3(0.0f, 1.0f, 0.0f);
203 mConeInnerAngle = 360.0f;
204 mConeOuterAngle = 360.0f;
205 mConeOuterGain = 0.0f;
206 mConeOuterGainHF = 1.0f;
207 mRolloffFactor = 1.0f;
208 mRoomRolloffFactor = 0.0f;
209 mDopplerFactor = 1.0f;
210 mAirAbsorptionFactor = 0.0f;
211 mRadius = 0.0f;
212 mStereoAngles[0] = F_PI / 6.0f;
213 mStereoAngles[1] = -F_PI / 6.0f;
214 mSpatialize = Spatialize::Auto;
215 mResampler = mContext->hasExtension(AL::SOFT_source_resampler) ?
216 alGetInteger(AL_DEFAULT_RESAMPLER_SOFT) : 0;
217 mLooping = false;
218 mRelative = false;
219 mDryGainHFAuto = true;
220 mWetGainAuto = true;
221 mWetGainHFAuto = true;
222 if(mDirectFilter)
223 mContext->alDeleteFilters(1, &mDirectFilter);
224 mDirectFilter = 0;
225 for(auto &i : mEffectSlots)
227 if(i.second.mSlot)
228 i.second.mSlot->removeSourceSend({Source(this), i.first});
229 if(i.second.mFilter)
230 mContext->alDeleteFilters(1, &i.second.mFilter);
232 mEffectSlots.clear();
234 mPriority = 0;
237 void SourceImpl::applyProperties(bool looping, ALuint offset) const
239 alSourcei(mId, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
240 alSourcei(mId, AL_SAMPLE_OFFSET, offset);
241 alSourcef(mId, AL_PITCH, mPitch * mGroupPitch);
242 alSourcef(mId, AL_GAIN, mGain * mGroupGain * mFadeGain);
243 alSourcef(mId, AL_MIN_GAIN, mMinGain);
244 alSourcef(mId, AL_MAX_GAIN, mMaxGain);
245 alSourcef(mId, AL_REFERENCE_DISTANCE, mRefDist);
246 alSourcef(mId, AL_MAX_DISTANCE, mMaxDist);
247 alSourcefv(mId, AL_POSITION, mPosition.getPtr());
248 alSourcefv(mId, AL_VELOCITY, mVelocity.getPtr());
249 alSourcefv(mId, AL_DIRECTION, mDirection.getPtr());
250 if(mContext->hasExtension(AL::EXT_BFORMAT))
251 alSourcefv(mId, AL_ORIENTATION, &mOrientation[0][0]);
252 alSourcef(mId, AL_CONE_INNER_ANGLE, mConeInnerAngle);
253 alSourcef(mId, AL_CONE_OUTER_ANGLE, mConeOuterAngle);
254 alSourcef(mId, AL_CONE_OUTER_GAIN, mConeOuterGain);
255 alSourcef(mId, AL_ROLLOFF_FACTOR, mRolloffFactor);
256 alSourcef(mId, AL_DOPPLER_FACTOR, mDopplerFactor);
257 if(mContext->hasExtension(AL::EXT_SOURCE_RADIUS))
258 alSourcef(mId, AL_SOURCE_RADIUS, mRadius);
259 if(mContext->hasExtension(AL::EXT_STEREO_ANGLES))
260 alSourcefv(mId, AL_STEREO_ANGLES, mStereoAngles);
261 if(mContext->hasExtension(AL::SOFT_source_spatialize))
262 alSourcei(mId, AL_SOURCE_SPATIALIZE_SOFT, (ALint)mSpatialize);
263 if(mContext->hasExtension(AL::SOFT_source_resampler))
264 alSourcei(mId, AL_SOURCE_RESAMPLER_SOFT, mResampler);
265 alSourcei(mId, AL_SOURCE_RELATIVE, mRelative ? AL_TRUE : AL_FALSE);
266 if(mContext->hasExtension(AL::EXT_EFX))
268 alSourcef(mId, AL_CONE_OUTER_GAINHF, mConeOuterGainHF);
269 alSourcef(mId, AL_ROOM_ROLLOFF_FACTOR, mRoomRolloffFactor);
270 alSourcef(mId, AL_AIR_ABSORPTION_FACTOR, mAirAbsorptionFactor);
271 alSourcei(mId, AL_DIRECT_FILTER_GAINHF_AUTO, mDryGainHFAuto ? AL_TRUE : AL_FALSE);
272 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, mWetGainAuto ? AL_TRUE : AL_FALSE);
273 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, mWetGainHFAuto ? AL_TRUE : AL_FALSE);
274 alSourcei(mId, AL_DIRECT_FILTER, mDirectFilter);
275 for(const auto &i : mEffectSlots)
277 ALuint slotid = (i.second.mSlot ? i.second.mSlot->getId() : 0);
278 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, i.first, i.second.mFilter);
284 void SourceImpl::unsetGroup()
286 mGroup = nullptr;
287 groupPropUpdate(1.0f, 1.0f);
290 void SourceImpl::groupPropUpdate(ALfloat gain, ALfloat pitch)
292 if(mId)
294 alSourcef(mId, AL_PITCH, mPitch * pitch);
295 alSourcef(mId, AL_GAIN, mGain * gain * mFadeGain);
297 mGroupPitch = pitch;
298 mGroupGain = gain;
302 void SourceImpl::play(Buffer buffer)
304 BufferImpl *albuf = buffer.getHandle();
305 if(!albuf) throw std::runtime_error("Buffer is not valid");
306 CheckContext(mContext);
307 CheckContext(albuf->getContext());
309 if(mStream)
310 mContext->removeStream(this);
311 mIsAsync.store(false, std::memory_order_release);
313 mFadeGainTarget = mFadeGain = 1.0f;
314 mFadeTimeTarget = mLastFadeTime = std::chrono::steady_clock::now();
316 if(mId == 0)
318 mId = mContext->getSourceId(mPriority);
319 applyProperties(mLooping, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
321 else
323 mContext->removeFadingSource(this);
324 mContext->removePlayingSource(this);
325 alSourceRewind(mId);
326 alSourcei(mId, AL_BUFFER, 0);
327 alSourcei(mId, AL_LOOPING, mLooping ? AL_TRUE : AL_FALSE);
328 alSourcei(mId, AL_SAMPLE_OFFSET, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
330 mOffset = 0;
332 mStream.reset();
333 if(mBuffer)
334 mBuffer->removeSource(Source(this));
335 mBuffer = albuf;
336 mBuffer->addSource(Source(this));
338 alSourcei(mId, AL_BUFFER, mBuffer->getId());
339 alSourcePlay(mId);
340 mPaused.store(false, std::memory_order_release);
341 mContext->removePendingSource(this);
342 mContext->addPlayingSource(this, mId);
345 void SourceImpl::play(SharedPtr<Decoder> decoder, ALuint chunk_len, ALuint queue_size)
347 if(chunk_len < 64)
348 throw std::runtime_error("Update length out of range");
349 if(queue_size < 2)
350 throw std::runtime_error("Queue size out of range");
351 CheckContext(mContext);
353 auto stream = MakeUnique<ALBufferStream>(decoder, chunk_len, queue_size);
354 stream->prepare();
356 if(mStream)
357 mContext->removeStream(this);
358 mIsAsync.store(false, std::memory_order_release);
360 mFadeGainTarget = mFadeGain = 1.0f;
361 mFadeTimeTarget = mLastFadeTime = std::chrono::steady_clock::now();
363 if(mId == 0)
365 mId = mContext->getSourceId(mPriority);
366 applyProperties(false, 0);
368 else
370 mContext->removeFadingSource(this);
371 mContext->removePlayingSource(this);
372 alSourceRewind(mId);
373 alSourcei(mId, AL_BUFFER, 0);
374 alSourcei(mId, AL_LOOPING, AL_FALSE);
375 alSourcei(mId, AL_SAMPLE_OFFSET, 0);
378 mStream.reset();
379 if(mBuffer)
380 mBuffer->removeSource(Source(this));
381 mBuffer = 0;
383 mStream = std::move(stream);
385 mStream->seek(mOffset);
386 mOffset = 0;
388 for(ALuint i = 0;i < mStream->getNumUpdates();i++)
390 if(!mStream->streamMoreData(mId, mLooping))
391 break;
393 alSourcePlay(mId);
394 mPaused.store(false, std::memory_order_release);
396 mContext->addStream(this);
397 mIsAsync.store(true, std::memory_order_release);
398 mContext->removePendingSource(this);
399 mContext->addPlayingSource(this);
402 void SourceImpl::play(SharedFuture<Buffer> future_buffer)
404 if(!future_buffer.valid())
405 throw std::runtime_error("Invalid future buffer");
406 if(future_buffer.wait_for(std::chrono::milliseconds::zero()) == std::future_status::ready)
408 play(future_buffer.get());
409 return;
412 CheckContext(mContext);
414 mContext->removeFadingSource(this);
415 mContext->removePlayingSource(this);
416 makeStopped(true);
418 mFadeGainTarget = mFadeGain = 1.0f;
419 mFadeTimeTarget = mLastFadeTime = std::chrono::steady_clock::now();
421 mContext->addPendingSource(this, std::move(future_buffer));
425 void SourceImpl::makeStopped(bool dolock)
427 if(mStream)
429 if(dolock)
430 mContext->removeStream(this);
431 else
432 mContext->removeStreamNoLock(this);
434 mIsAsync.store(false, std::memory_order_release);
436 if(mId != 0)
438 alSourceRewind(mId);
439 alSourcei(mId, AL_BUFFER, 0);
440 if(mContext->hasExtension(AL::EXT_EFX))
442 alSourcei(mId, AL_DIRECT_FILTER, AL_FILTER_NULL);
443 for(auto &i : mEffectSlots)
444 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, 0, i.first, AL_FILTER_NULL);
446 mContext->insertSourceId(mId);
447 mId = 0;
450 mStream.reset();
451 if(mBuffer)
452 mBuffer->removeSource(Source(this));
453 mBuffer = 0;
455 mPaused.store(false, std::memory_order_release);
458 void SourceImpl::stop()
460 CheckContext(mContext);
461 mContext->removePendingSource(this);
462 mContext->removeFadingSource(this);
463 mContext->removePlayingSource(this);
464 makeStopped();
468 void SourceImpl::fadeOutToStop(ALfloat gain, std::chrono::milliseconds duration)
470 if(!(gain < 1.0f && gain >= 0.0f))
471 throw std::runtime_error("Fade gain target out of range");
472 if(duration.count() <= 0)
473 throw std::runtime_error("Fade duration out of range");
474 CheckContext(mContext);
476 mFadeGainTarget = std::max<ALfloat>(gain, 0.0001f);
477 mLastFadeTime = std::chrono::steady_clock::now();
478 mFadeTimeTarget = mLastFadeTime + duration;
480 mContext->addFadingSource(this);
484 void SourceImpl::checkPaused()
486 if(mPaused.load(std::memory_order_acquire) || mId == 0)
487 return;
489 ALint state = -1;
490 alGetSourcei(mId, AL_SOURCE_STATE, &state);
491 // Streaming sources may be in a stopped or initial state if underrun
492 mPaused.store(state == AL_PAUSED || (mStream && mStream->hasMoreData()),
493 std::memory_order_release);
496 void SourceImpl::pause()
498 CheckContext(mContext);
499 if(mPaused.load(std::memory_order_acquire))
500 return;
502 if(mId != 0)
504 std::lock_guard<std::mutex> lock(mMutex);
505 alSourcePause(mId);
506 ALint state = -1;
507 alGetSourcei(mId, AL_SOURCE_STATE, &state);
508 // Streaming sources may be in a stopped or initial state if underrun
509 mPaused.store(state == AL_PAUSED || (mStream && mStream->hasMoreData()),
510 std::memory_order_release);
514 void SourceImpl::resume()
516 CheckContext(mContext);
517 if(!mPaused.load(std::memory_order_acquire))
518 return;
520 if(mId != 0)
521 alSourcePlay(mId);
522 mPaused.store(false, std::memory_order_release);
526 bool SourceImpl::isPending() const
528 CheckContext(mContext);
529 return mContext->isPendingSource(this);
532 bool SourceImpl::isPlaying() const
534 CheckContext(mContext);
535 if(mId == 0) return false;
537 ALint state = -1;
538 alGetSourcei(mId, AL_SOURCE_STATE, &state);
539 if(state == -1)
540 throw std::runtime_error("Source state error");
542 return state == AL_PLAYING || (!mPaused.load(std::memory_order_acquire) &&
543 mStream && mStream->hasMoreData());
546 bool SourceImpl::isPaused() const
548 CheckContext(mContext);
549 return mId != 0 && mPaused.load(std::memory_order_acquire);
553 void SourceImpl::setGroup(SourceGroup group)
555 CheckContext(mContext);
557 SourceGroupImpl *parent = group.getHandle();
558 if(parent == mGroup) return;
560 if(mGroup)
561 mGroup->eraseSource(this);
562 mGroup = parent;
563 if(mGroup)
565 mGroup->insertSource(this);
566 mGroupPitch = mGroup->getAppliedPitch();
567 mGroupGain = mGroup->getAppliedGain();
569 else
571 mGroupPitch = 1.0f;
572 mGroupGain = 1.0f;
575 if(mId)
577 alSourcef(mId, AL_PITCH, mPitch * mGroupPitch);
578 alSourcef(mId, AL_GAIN, mGain * mGroupGain * mFadeGain);
583 bool SourceImpl::checkPending(SharedFuture<Buffer> &future)
585 if(future.wait_for(std::chrono::milliseconds::zero()) != std::future_status::ready)
586 return true;
588 BufferImpl *buffer = future.get().getHandle();
589 if(Expect<false>(buffer->getContext() != mContext))
590 return false;
592 if(mId == 0)
594 mId = mContext->getSourceId(mPriority);
595 applyProperties(mLooping, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
597 else
599 alSourceRewind(mId);
600 alSourcei(mId, AL_BUFFER, 0);
601 alSourcei(mId, AL_LOOPING, mLooping ? AL_TRUE : AL_FALSE);
602 alSourcei(mId, AL_SAMPLE_OFFSET, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
604 mOffset = 0;
606 mBuffer = buffer;
607 mBuffer->addSource(Source(this));
609 alSourcei(mId, AL_BUFFER, mBuffer->getId());
610 alSourcePlay(mId);
611 mPaused.store(false, std::memory_order_release);
612 mContext->addPlayingSource(this, mId);
613 return false;
616 bool SourceImpl::fadeUpdate(std::chrono::steady_clock::time_point cur_fade_time)
618 if((cur_fade_time - mFadeTimeTarget).count() >= 0)
620 mLastFadeTime = mFadeTimeTarget;
621 mFadeGain = 1.0f;
622 if(mFadeGainTarget >= 1.0f)
624 if(mId != 0)
625 alSourcef(mId, AL_GAIN, mGain * mGroupGain);
626 return false;
628 mContext->removePendingSource(this);
629 mContext->removePlayingSource(this);
630 makeStopped(true);
631 return false;
634 float mult = std::pow(mFadeGainTarget/mFadeGain,
635 float(1.0/Seconds(mFadeTimeTarget-mLastFadeTime).count())
638 std::chrono::steady_clock::duration duration = cur_fade_time - mLastFadeTime;
639 mLastFadeTime = cur_fade_time;
641 float gain = mFadeGain * std::pow(mult, (float)Seconds(duration).count());
642 if(Expect<false>(gain == mFadeGain))
644 // Ensure the gain keeps moving toward its target, in case precision
645 // loss results in no change with small steps.
646 gain = std::nextafter(gain, mFadeGainTarget);
648 mFadeGain = gain;
650 if(mId != 0)
651 alSourcef(mId, AL_GAIN, mGain * mGroupGain * mFadeGain);
652 return true;
655 bool SourceImpl::playUpdate(ALuint id)
657 ALint state = -1;
658 alGetSourcei(id, AL_SOURCE_STATE, &state);
659 if(Expect<true>(state == AL_PLAYING || state == AL_PAUSED))
660 return true;
662 makeStopped();
663 mContext->send(&MessageHandler::sourceStopped, Source(this));
664 return false;
667 bool SourceImpl::playUpdate()
669 if(Expect<true>(mIsAsync.load(std::memory_order_acquire)))
670 return true;
672 makeStopped();
673 mContext->send(&MessageHandler::sourceStopped, Source(this));
674 return false;
678 ALint SourceImpl::refillBufferStream()
680 ALint processed;
681 alGetSourcei(mId, AL_BUFFERS_PROCESSED, &processed);
682 while(processed > 0)
684 ALuint buf;
685 alSourceUnqueueBuffers(mId, 1, &buf);
686 --processed;
689 ALint queued;
690 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
691 for(;(ALuint)queued < mStream->getNumUpdates();queued++)
693 if(!mStream->streamMoreData(mId, mLooping))
694 break;
697 return queued;
700 bool SourceImpl::updateAsync()
702 std::lock_guard<std::mutex> lock(mMutex);
704 ALint queued = refillBufferStream();
705 if(queued == 0)
707 mIsAsync.store(false, std::memory_order_release);
708 return false;
711 ALint state = -1;
712 alGetSourcei(mId, AL_SOURCE_STATE, &state);
713 if(!mPaused.load(std::memory_order_acquire))
715 // Make sure the source is still playing if it's not paused.
716 if(state != AL_PLAYING)
717 alSourcePlay(mId);
719 else
721 // Rewind the source to an initial state if it underrun as it was
722 // paused.
723 if(state == AL_STOPPED)
724 alSourceRewind(mId);
726 return true;
730 void SourceImpl::setPriority(ALuint priority)
732 mPriority = priority;
736 void SourceImpl::setOffset(uint64_t offset)
738 CheckContext(mContext);
739 if(mId == 0)
741 mOffset = offset;
742 return;
745 if(!mStream)
747 if(offset >= std::numeric_limits<ALint>::max())
748 throw std::runtime_error("Offset out of range");
749 alGetError();
750 alSourcei(mId, AL_SAMPLE_OFFSET, (ALint)offset);
751 if(alGetError() != AL_NO_ERROR)
752 throw std::runtime_error("Offset out of range");
754 else
756 std::lock_guard<std::mutex> lock(mMutex);
757 if(!mStream->seek(offset))
758 throw std::runtime_error("Failed to seek to offset");
759 alSourceRewind(mId);
760 alSourcei(mId, AL_BUFFER, 0);
761 ALint queued = refillBufferStream();
762 if(queued > 0 && !mPaused.load(std::memory_order_acquire))
763 alSourcePlay(mId);
767 std::pair<uint64_t,std::chrono::nanoseconds> SourceImpl::getSampleOffsetLatency() const
769 std::pair<uint64_t,std::chrono::nanoseconds> ret{0, std::chrono::nanoseconds::zero()};
770 CheckContext(mContext);
771 if(mId == 0) return ret;
773 if(mStream)
775 std::lock_guard<std::mutex> lock(mMutex);
776 ALint queued = 0, state = -1, srcpos = 0;
778 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
779 if(mContext->hasExtension(AL::SOFT_source_latency))
781 ALint64SOFT val[2];
782 mContext->alGetSourcei64vSOFT(mId, AL_SAMPLE_OFFSET_LATENCY_SOFT, val);
783 srcpos = val[0]>>32;
784 ret.second = std::chrono::nanoseconds(val[1]);
786 else
787 alGetSourcei(mId, AL_SAMPLE_OFFSET, &srcpos);
788 alGetSourcei(mId, AL_SOURCE_STATE, &state);
790 int64_t streampos = mStream->getPosition();
791 if(state != AL_STOPPED)
793 // The amount of samples in the queue waiting to play
794 ALuint inqueue = queued*mStream->getUpdateLength() - srcpos;
795 if(!mStream->hasLooped())
797 // A non-looped stream should never have more samples queued
798 // than have been read...
799 streampos = std::max<int64_t>(streampos, inqueue) - inqueue;
801 else
803 streampos -= inqueue;
804 int64_t looplen = mStream->getLoopEnd() - mStream->getLoopStart();
805 while(streampos < mStream->getLoopStart())
806 streampos += looplen;
810 ret.first = streampos;
811 return ret;
814 ALint srcpos = 0;
815 if(mContext->hasExtension(AL::SOFT_source_latency))
817 ALint64SOFT val[2];
818 mContext->alGetSourcei64vSOFT(mId, AL_SAMPLE_OFFSET_LATENCY_SOFT, val);
819 srcpos = val[0]>>32;
820 ret.second = std::chrono::nanoseconds(val[1]);
822 else
823 alGetSourcei(mId, AL_SAMPLE_OFFSET, &srcpos);
824 ret.first = srcpos;
825 return ret;
828 std::pair<Seconds,Seconds> SourceImpl::getSecOffsetLatency() const
830 std::pair<Seconds,Seconds> ret{Seconds::zero(), Seconds::zero()};
831 CheckContext(mContext);
832 if(mId == 0) return ret;
834 if(mStream)
836 std::lock_guard<std::mutex> lock(mMutex);
837 ALint queued = 0, state = -1;
838 ALdouble srcpos = 0;
840 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
841 if(mContext->hasExtension(AL::SOFT_source_latency))
843 ALdouble val[2];
844 mContext->alGetSourcedvSOFT(mId, AL_SEC_OFFSET_LATENCY_SOFT, val);
845 srcpos = val[0];
846 ret.second = Seconds(val[1]);
848 else
850 ALfloat f;
851 alGetSourcef(mId, AL_SEC_OFFSET, &f);
852 srcpos = f;
854 alGetSourcei(mId, AL_SOURCE_STATE, &state);
856 ALdouble frac = 0.0;
857 int64_t streampos = mStream->getPosition();
858 if(state != AL_STOPPED)
860 ALdouble ipos;
861 frac = std::modf(srcpos * mStream->getFrequency(), &ipos);
863 // The amount of samples in the queue waiting to play
864 ALuint inqueue = queued*mStream->getUpdateLength() - (ALuint)ipos;
865 if(!mStream->hasLooped())
867 // A non-looped stream should never have more samples queued
868 // than have been read...
869 streampos = std::max<int64_t>(streampos, inqueue) - inqueue;
871 else
873 streampos -= inqueue;
874 int64_t looplen = mStream->getLoopEnd() - mStream->getLoopStart();
875 while(streampos < mStream->getLoopStart())
876 streampos += looplen;
880 ret.first = Seconds((streampos+frac) / mStream->getFrequency());
881 return ret;
884 if(mContext->hasExtension(AL::SOFT_source_latency))
886 ALdouble val[2];
887 mContext->alGetSourcedvSOFT(mId, AL_SEC_OFFSET_LATENCY_SOFT, val);
888 ret.first = Seconds(val[0]);
889 ret.second = Seconds(val[1]);
891 else
893 ALfloat f;
894 alGetSourcef(mId, AL_SEC_OFFSET, &f);
895 ret.first = Seconds(f);
897 return ret;
901 void SourceImpl::setLooping(bool looping)
903 CheckContext(mContext);
905 if(mId && !mStream)
906 alSourcei(mId, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
907 mLooping = looping;
911 void SourceImpl::setPitch(ALfloat pitch)
913 if(!(pitch > 0.0f))
914 throw std::runtime_error("Pitch out of range");
915 CheckContext(mContext);
916 if(mId != 0)
917 alSourcef(mId, AL_PITCH, pitch * mGroupPitch);
918 mPitch = pitch;
922 void SourceImpl::setGain(ALfloat gain)
924 if(!(gain >= 0.0f))
925 throw std::runtime_error("Gain out of range");
926 CheckContext(mContext);
927 if(mId != 0)
928 alSourcef(mId, AL_GAIN, gain * mGroupGain * mFadeGain);
929 mGain = gain;
932 void SourceImpl::setGainRange(ALfloat mingain, ALfloat maxgain)
934 if(!(mingain >= 0.0f && maxgain <= 1.0f && maxgain >= mingain))
935 throw std::runtime_error("Gain range out of range");
936 CheckContext(mContext);
937 if(mId != 0)
939 alSourcef(mId, AL_MIN_GAIN, mingain);
940 alSourcef(mId, AL_MAX_GAIN, maxgain);
942 mMinGain = mingain;
943 mMaxGain = maxgain;
947 void SourceImpl::setDistanceRange(ALfloat refdist, ALfloat maxdist)
949 if(!(refdist >= 0.0f && maxdist <= std::numeric_limits<float>::max() && refdist <= maxdist))
950 throw std::runtime_error("Distance range out of range");
951 CheckContext(mContext);
952 if(mId != 0)
954 alSourcef(mId, AL_REFERENCE_DISTANCE, refdist);
955 alSourcef(mId, AL_MAX_DISTANCE, maxdist);
957 mRefDist = refdist;
958 mMaxDist = maxdist;
962 void SourceImpl::set3DParameters(const Vector3 &position, const Vector3 &velocity, const Vector3 &direction)
964 CheckContext(mContext);
965 if(mId != 0)
967 Batcher batcher = mContext->getBatcher();
968 alSourcefv(mId, AL_POSITION, position.getPtr());
969 alSourcefv(mId, AL_VELOCITY, velocity.getPtr());
970 alSourcefv(mId, AL_DIRECTION, direction.getPtr());
972 mPosition = position;
973 mVelocity = velocity;
974 mDirection = direction;
977 void SourceImpl::set3DParameters(const Vector3 &position, const Vector3 &velocity, std::pair<Vector3,Vector3> orientation)
979 static_assert(sizeof(orientation) == sizeof(ALfloat[6]), "Invalid Vector3 pair size");
980 CheckContext(mContext);
981 if(mId != 0)
983 Batcher batcher = mContext->getBatcher();
984 alSourcefv(mId, AL_POSITION, position.getPtr());
985 alSourcefv(mId, AL_VELOCITY, velocity.getPtr());
986 if(mContext->hasExtension(AL::EXT_BFORMAT))
987 alSourcefv(mId, AL_ORIENTATION, orientation.first.getPtr());
988 alSourcefv(mId, AL_DIRECTION, orientation.first.getPtr());
990 mPosition = position;
991 mVelocity = velocity;
992 mDirection = mOrientation[0] = orientation.first;
993 mOrientation[1] = orientation.second;
997 void SourceImpl::setPosition(ALfloat x, ALfloat y, ALfloat z)
999 CheckContext(mContext);
1000 if(mId != 0)
1001 alSource3f(mId, AL_POSITION, x, y, z);
1002 mPosition[0] = x;
1003 mPosition[1] = y;
1004 mPosition[2] = z;
1007 void SourceImpl::setPosition(const ALfloat *pos)
1009 CheckContext(mContext);
1010 if(mId != 0)
1011 alSourcefv(mId, AL_POSITION, pos);
1012 mPosition[0] = pos[0];
1013 mPosition[1] = pos[1];
1014 mPosition[2] = pos[2];
1017 void SourceImpl::setVelocity(ALfloat x, ALfloat y, ALfloat z)
1019 CheckContext(mContext);
1020 if(mId != 0)
1021 alSource3f(mId, AL_VELOCITY, x, y, z);
1022 mVelocity[0] = x;
1023 mVelocity[1] = y;
1024 mVelocity[2] = z;
1027 void SourceImpl::setVelocity(const ALfloat *vel)
1029 CheckContext(mContext);
1030 if(mId != 0)
1031 alSourcefv(mId, AL_VELOCITY, vel);
1032 mVelocity[0] = vel[0];
1033 mVelocity[1] = vel[1];
1034 mVelocity[2] = vel[2];
1037 void SourceImpl::setDirection(ALfloat x, ALfloat y, ALfloat z)
1039 CheckContext(mContext);
1040 if(mId != 0)
1041 alSource3f(mId, AL_DIRECTION, x, y, z);
1042 mDirection[0] = x;
1043 mDirection[1] = y;
1044 mDirection[2] = z;
1047 void SourceImpl::setDirection(const ALfloat *dir)
1049 CheckContext(mContext);
1050 if(mId != 0)
1051 alSourcefv(mId, AL_DIRECTION, dir);
1052 mDirection[0] = dir[0];
1053 mDirection[1] = dir[1];
1054 mDirection[2] = dir[2];
1057 void SourceImpl::setOrientation(ALfloat x1, ALfloat y1, ALfloat z1, ALfloat x2, ALfloat y2, ALfloat z2)
1059 CheckContext(mContext);
1060 if(mId != 0)
1062 ALfloat ori[6] = { x1, y1, z1, x2, y2, z2 };
1063 if(mContext->hasExtension(AL::EXT_BFORMAT))
1064 alSourcefv(mId, AL_ORIENTATION, ori);
1065 alSourcefv(mId, AL_DIRECTION, ori);
1067 mDirection[0] = mOrientation[0][0] = x1;
1068 mDirection[1] = mOrientation[0][1] = y1;
1069 mDirection[2] = mOrientation[0][2] = z1;
1070 mOrientation[1][0] = x2;
1071 mOrientation[1][1] = y2;
1072 mOrientation[1][2] = z2;
1075 void SourceImpl::setOrientation(const ALfloat *at, const ALfloat *up)
1077 CheckContext(mContext);
1078 if(mId != 0)
1080 ALfloat ori[6] = { at[0], at[1], at[2], up[0], up[1], up[2] };
1081 if(mContext->hasExtension(AL::EXT_BFORMAT))
1082 alSourcefv(mId, AL_ORIENTATION, ori);
1083 alSourcefv(mId, AL_DIRECTION, ori);
1085 mDirection[0] = mOrientation[0][0] = at[0];
1086 mDirection[1] = mOrientation[0][1] = at[1];
1087 mDirection[2] = mOrientation[0][2] = at[2];
1088 mOrientation[1][0] = up[0];
1089 mOrientation[1][1] = up[1];
1090 mOrientation[1][2] = up[2];
1093 void SourceImpl::setOrientation(const ALfloat *ori)
1095 CheckContext(mContext);
1096 if(mId != 0)
1098 if(mContext->hasExtension(AL::EXT_BFORMAT))
1099 alSourcefv(mId, AL_ORIENTATION, ori);
1100 alSourcefv(mId, AL_DIRECTION, ori);
1102 mDirection[0] = mOrientation[0][0] = ori[0];
1103 mDirection[1] = mOrientation[0][1] = ori[1];
1104 mDirection[2] = mOrientation[0][2] = ori[2];
1105 mOrientation[1][0] = ori[3];
1106 mOrientation[1][1] = ori[4];
1107 mOrientation[1][2] = ori[5];
1111 void SourceImpl::setConeAngles(ALfloat inner, ALfloat outer)
1113 if(!(inner >= 0.0f && outer <= 360.0f && outer >= inner))
1114 throw std::runtime_error("Cone angles out of range");
1115 CheckContext(mContext);
1116 if(mId != 0)
1118 alSourcef(mId, AL_CONE_INNER_ANGLE, inner);
1119 alSourcef(mId, AL_CONE_OUTER_ANGLE, outer);
1121 mConeInnerAngle = inner;
1122 mConeOuterAngle = outer;
1125 void SourceImpl::setOuterConeGains(ALfloat gain, ALfloat gainhf)
1127 if(!(gain >= 0.0f && gain <= 1.0f && gainhf >= 0.0f && gainhf <= 1.0f))
1128 throw std::runtime_error("Outer cone gain out of range");
1129 CheckContext(mContext);
1130 if(mId != 0)
1132 alSourcef(mId, AL_CONE_OUTER_GAIN, gain);
1133 if(mContext->hasExtension(AL::EXT_EFX))
1134 alSourcef(mId, AL_CONE_OUTER_GAINHF, gainhf);
1136 mConeOuterGain = gain;
1137 mConeOuterGainHF = gainhf;
1141 void SourceImpl::setRolloffFactors(ALfloat factor, ALfloat roomfactor)
1143 if(!(factor >= 0.0f && roomfactor >= 0.0f))
1144 throw std::runtime_error("Rolloff factor out of range");
1145 CheckContext(mContext);
1146 if(mId != 0)
1148 alSourcef(mId, AL_ROLLOFF_FACTOR, factor);
1149 if(mContext->hasExtension(AL::EXT_EFX))
1150 alSourcef(mId, AL_ROOM_ROLLOFF_FACTOR, roomfactor);
1152 mRolloffFactor = factor;
1153 mRoomRolloffFactor = roomfactor;
1156 void SourceImpl::setDopplerFactor(ALfloat factor)
1158 if(!(factor >= 0.0f && factor <= 1.0f))
1159 throw std::runtime_error("Doppler factor out of range");
1160 CheckContext(mContext);
1161 if(mId != 0)
1162 alSourcef(mId, AL_DOPPLER_FACTOR, factor);
1163 mDopplerFactor = factor;
1166 void SourceImpl::setAirAbsorptionFactor(ALfloat factor)
1168 if(!(factor >= 0.0f && factor <= 10.0f))
1169 throw std::runtime_error("Absorption factor out of range");
1170 CheckContext(mContext);
1171 if(mId != 0 && mContext->hasExtension(AL::EXT_EFX))
1172 alSourcef(mId, AL_AIR_ABSORPTION_FACTOR, factor);
1173 mAirAbsorptionFactor = factor;
1176 void SourceImpl::setRadius(ALfloat radius)
1178 if(!(mRadius >= 0.0f))
1179 throw std::runtime_error("Radius out of range");
1180 CheckContext(mContext);
1181 if(mId != 0 && mContext->hasExtension(AL::EXT_SOURCE_RADIUS))
1182 alSourcef(mId, AL_SOURCE_RADIUS, radius);
1183 mRadius = radius;
1186 void SourceImpl::setStereoAngles(ALfloat leftAngle, ALfloat rightAngle)
1188 CheckContext(mContext);
1189 if(mId != 0 && mContext->hasExtension(AL::EXT_STEREO_ANGLES))
1191 ALfloat angles[2] = { leftAngle, rightAngle };
1192 alSourcefv(mId, AL_STEREO_ANGLES, angles);
1194 mStereoAngles[0] = leftAngle;
1195 mStereoAngles[1] = rightAngle;
1198 void SourceImpl::set3DSpatialize(Spatialize spatialize)
1200 CheckContext(mContext);
1201 if(mId != 0 && mContext->hasExtension(AL::SOFT_source_spatialize))
1202 alSourcei(mId, AL_SOURCE_SPATIALIZE_SOFT, (ALint)spatialize);
1203 mSpatialize = spatialize;
1206 void SourceImpl::setResamplerIndex(ALsizei index)
1208 if(index < 0)
1209 throw std::runtime_error("Resampler index out of range");
1210 index = std::min<ALsizei>(index, mContext->getAvailableResamplers().size());
1211 if(mId != 0 && mContext->hasExtension(AL::SOFT_source_resampler))
1212 alSourcei(mId, AL_SOURCE_RESAMPLER_SOFT, index);
1213 mResampler = index;
1216 void SourceImpl::setRelative(bool relative)
1218 CheckContext(mContext);
1219 if(mId != 0)
1220 alSourcei(mId, AL_SOURCE_RELATIVE, relative ? AL_TRUE : AL_FALSE);
1221 mRelative = relative;
1224 void SourceImpl::setGainAuto(bool directhf, bool send, bool sendhf)
1226 CheckContext(mContext);
1227 if(mId != 0 && mContext->hasExtension(AL::EXT_EFX))
1229 alSourcei(mId, AL_DIRECT_FILTER_GAINHF_AUTO, directhf ? AL_TRUE : AL_FALSE);
1230 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, send ? AL_TRUE : AL_FALSE);
1231 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, sendhf ? AL_TRUE : AL_FALSE);
1233 mDryGainHFAuto = directhf;
1234 mWetGainAuto = send;
1235 mWetGainHFAuto = sendhf;
1239 void SourceImpl::setFilterParams(ALuint &filterid, const FilterParams &params)
1241 if(!mContext->hasExtension(AL::EXT_EFX))
1242 return;
1244 if(!(params.mGain < 1.0f || params.mGainHF < 1.0f || params.mGainLF < 1.0f))
1246 if(filterid)
1247 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_NULL);
1248 return;
1251 alGetError();
1252 if(!filterid)
1254 mContext->alGenFilters(1, &filterid);
1255 if(alGetError() != AL_NO_ERROR)
1256 throw std::runtime_error("Failed to create Filter");
1258 bool filterset = false;
1259 if(params.mGainHF < 1.0f && params.mGainLF < 1.0f)
1261 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_BANDPASS);
1262 if(alGetError() == AL_NO_ERROR)
1264 mContext->alFilterf(filterid, AL_BANDPASS_GAIN, std::min(params.mGain, 1.0f));
1265 mContext->alFilterf(filterid, AL_BANDPASS_GAINHF, std::min(params.mGainHF, 1.0f));
1266 mContext->alFilterf(filterid, AL_BANDPASS_GAINLF, std::min(params.mGainLF, 1.0f));
1267 filterset = true;
1270 if(!filterset && !(params.mGainHF < 1.0f) && params.mGainLF < 1.0f)
1272 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_HIGHPASS);
1273 if(alGetError() == AL_NO_ERROR)
1275 mContext->alFilterf(filterid, AL_HIGHPASS_GAIN, std::min(params.mGain, 1.0f));
1276 mContext->alFilterf(filterid, AL_HIGHPASS_GAINLF, std::min(params.mGainLF, 1.0f));
1277 filterset = true;
1280 if(!filterset)
1282 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1283 if(alGetError() == AL_NO_ERROR)
1285 mContext->alFilterf(filterid, AL_LOWPASS_GAIN, std::min(params.mGain, 1.0f));
1286 mContext->alFilterf(filterid, AL_LOWPASS_GAINHF, std::min(params.mGainHF, 1.0f));
1287 filterset = true;
1293 void SourceImpl::setDirectFilter(const FilterParams &filter)
1295 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1296 throw std::runtime_error("Gain value out of range");
1297 CheckContext(mContext);
1299 setFilterParams(mDirectFilter, filter);
1300 if(mId)
1301 alSourcei(mId, AL_DIRECT_FILTER, mDirectFilter);
1304 void SourceImpl::setSendFilter(ALuint send, const FilterParams &filter)
1306 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1307 throw std::runtime_error("Gain value out of range");
1308 CheckContext(mContext);
1310 SendPropMap::iterator siter = mEffectSlots.find(send);
1311 if(siter == mEffectSlots.end())
1313 ALuint filterid = 0;
1315 setFilterParams(filterid, filter);
1316 if(!filterid) return;
1318 siter = mEffectSlots.insert(std::make_pair(send, SendProps(filterid))).first;
1320 else
1321 setFilterParams(siter->second.mFilter, filter);
1323 if(mId)
1325 ALuint slotid = (siter->second.mSlot ? siter->second.mSlot->getId() : 0);
1326 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->second.mFilter);
1330 void SourceImpl::setAuxiliarySend(AuxiliaryEffectSlot auxslot, ALuint send)
1332 AuxiliaryEffectSlotImpl *slot = auxslot.getHandle();
1333 if(slot) CheckContext(slot->getContext());
1334 CheckContext(mContext);
1336 SendPropMap::iterator siter = mEffectSlots.find(send);
1337 if(siter == mEffectSlots.end())
1339 if(!slot) return;
1340 slot->addSourceSend({Source(this), send});
1341 siter = mEffectSlots.insert(std::make_pair(send, SendProps(slot))).first;
1343 else if(siter->second.mSlot != slot)
1345 if(slot) slot->addSourceSend({Source(this), send});
1346 if(siter->second.mSlot)
1347 siter->second.mSlot->removeSourceSend({Source(this), send});
1348 siter->second.mSlot = slot;
1351 if(mId)
1353 ALuint slotid = (siter->second.mSlot ? siter->second.mSlot->getId() : 0);
1354 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->second.mFilter);
1358 void SourceImpl::setAuxiliarySendFilter(AuxiliaryEffectSlot auxslot, ALuint send, const FilterParams &filter)
1360 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1361 throw std::runtime_error("Gain value out of range");
1362 AuxiliaryEffectSlotImpl *slot = auxslot.getHandle();
1363 if(slot) CheckContext(slot->getContext());
1364 CheckContext(mContext);
1366 SendPropMap::iterator siter = mEffectSlots.find(send);
1367 if(siter == mEffectSlots.end())
1369 ALuint filterid = 0;
1371 setFilterParams(filterid, filter);
1372 if(!filterid && !slot)
1373 return;
1375 if(slot) slot->addSourceSend({Source(this), send});
1376 siter = mEffectSlots.insert(std::make_pair(send, SendProps(slot, filterid))).first;
1378 else
1380 if(siter->second.mSlot != slot)
1382 if(slot) slot->addSourceSend({Source(this), send});
1383 if(siter->second.mSlot)
1384 siter->second.mSlot->removeSourceSend({Source(this), send});
1385 siter->second.mSlot = slot;
1387 setFilterParams(siter->second.mFilter, filter);
1390 if(mId)
1392 ALuint slotid = (siter->second.mSlot ? siter->second.mSlot->getId() : 0);
1393 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->second.mFilter);
1398 void SourceImpl::release()
1400 stop();
1402 resetProperties();
1403 mContext->freeSource(this);
1407 // Need to use these to avoid extraneous commas in macro parameter lists
1408 using UInt64NSecPair = std::pair<uint64_t,std::chrono::nanoseconds>;
1409 using SecondsPair = std::pair<Seconds,Seconds>;
1410 using ALfloatPair = std::pair<ALfloat,ALfloat>;
1411 using Vector3Pair = std::pair<Vector3,Vector3>;
1412 using BoolTriple = std::tuple<bool,bool,bool>;
1414 DECL_THUNK1(void, Source, play,, Buffer)
1415 DECL_THUNK3(void, Source, play,, SharedPtr<Decoder>, ALuint, ALuint)
1416 DECL_THUNK1(void, Source, play,, SharedFuture<Buffer>)
1417 DECL_THUNK0(void, Source, stop,)
1418 DECL_THUNK2(void, Source, fadeOutToStop,, ALfloat, std::chrono::milliseconds)
1419 DECL_THUNK0(void, Source, pause,)
1420 DECL_THUNK0(void, Source, resume,)
1421 DECL_THUNK0(bool, Source, isPending, const)
1422 DECL_THUNK0(bool, Source, isPlaying, const)
1423 DECL_THUNK0(bool, Source, isPaused, const)
1424 DECL_THUNK1(void, Source, setGroup,, SourceGroup)
1425 DECL_THUNK1(void, Source, setPriority,, ALuint)
1426 DECL_THUNK0(ALuint, Source, getPriority, const)
1427 DECL_THUNK1(void, Source, setOffset,, uint64_t)
1428 DECL_THUNK0(UInt64NSecPair, Source, getSampleOffsetLatency, const)
1429 DECL_THUNK0(SecondsPair, Source, getSecOffsetLatency, const)
1430 DECL_THUNK1(void, Source, setLooping,, bool)
1431 DECL_THUNK0(bool, Source, getLooping, const)
1432 DECL_THUNK1(void, Source, setPitch,, ALfloat)
1433 DECL_THUNK0(ALfloat, Source, getPitch, const)
1434 DECL_THUNK1(void, Source, setGain,, ALfloat)
1435 DECL_THUNK0(ALfloat, Source, getGain, const)
1436 DECL_THUNK2(void, Source, setGainRange,, ALfloat, ALfloat)
1437 DECL_THUNK0(ALfloatPair, Source, getGainRange, const)
1438 DECL_THUNK2(void, Source, setDistanceRange,, ALfloat, ALfloat)
1439 DECL_THUNK0(ALfloatPair, Source, getDistanceRange, const)
1440 DECL_THUNK3(void, Source, set3DParameters,, const Vector3&, const Vector3&, const Vector3&)
1441 DECL_THUNK3(void, Source, set3DParameters,, const Vector3&, const Vector3&, Vector3Pair)
1442 DECL_THUNK3(void, Source, setPosition,, ALfloat, ALfloat, ALfloat)
1443 DECL_THUNK1(void, Source, setPosition,, const ALfloat*)
1444 DECL_THUNK0(Vector3, Source, getPosition, const)
1445 DECL_THUNK3(void, Source, setVelocity,, ALfloat, ALfloat, ALfloat)
1446 DECL_THUNK1(void, Source, setVelocity,, const ALfloat*)
1447 DECL_THUNK0(Vector3, Source, getVelocity, const)
1448 DECL_THUNK3(void, Source, setDirection,, ALfloat, ALfloat, ALfloat)
1449 DECL_THUNK1(void, Source, setDirection,, const ALfloat*)
1450 DECL_THUNK0(Vector3, Source, getDirection, const)
1451 DECL_THUNK6(void, Source, setOrientation,, ALfloat, ALfloat, ALfloat, ALfloat, ALfloat, ALfloat)
1452 DECL_THUNK2(void, Source, setOrientation,, const ALfloat*, const ALfloat*)
1453 DECL_THUNK1(void, Source, setOrientation,, const ALfloat*)
1454 DECL_THUNK0(Vector3Pair, Source, getOrientation, const)
1455 DECL_THUNK2(void, Source, setConeAngles,, ALfloat, ALfloat)
1456 DECL_THUNK0(ALfloatPair, Source, getConeAngles, const)
1457 DECL_THUNK2(void, Source, setOuterConeGains,, ALfloat, ALfloat)
1458 DECL_THUNK0(ALfloatPair, Source, getOuterConeGains, const)
1459 DECL_THUNK2(void, Source, setRolloffFactors,, ALfloat, ALfloat)
1460 DECL_THUNK0(ALfloatPair, Source, getRolloffFactors, const)
1461 DECL_THUNK1(void, Source, setDopplerFactor,, ALfloat)
1462 DECL_THUNK0(ALfloat, Source, getDopplerFactor, const)
1463 DECL_THUNK1(void, Source, setRelative,, bool)
1464 DECL_THUNK0(bool, Source, getRelative, const)
1465 DECL_THUNK1(void, Source, setRadius,, ALfloat)
1466 DECL_THUNK0(ALfloat, Source, getRadius, const)
1467 DECL_THUNK2(void, Source, setStereoAngles,, ALfloat, ALfloat)
1468 DECL_THUNK0(ALfloatPair, Source, getStereoAngles, const)
1469 DECL_THUNK1(void, Source, set3DSpatialize,, Spatialize)
1470 DECL_THUNK0(Spatialize, Source, get3DSpatialize, const)
1471 DECL_THUNK1(void, Source, setResamplerIndex,, ALsizei)
1472 DECL_THUNK0(ALsizei, Source, getResamplerIndex, const)
1473 DECL_THUNK1(void, Source, setAirAbsorptionFactor,, ALfloat)
1474 DECL_THUNK0(ALfloat, Source, getAirAbsorptionFactor, const)
1475 DECL_THUNK3(void, Source, setGainAuto,, bool, bool, bool)
1476 DECL_THUNK0(BoolTriple, Source, getGainAuto, const)
1477 DECL_THUNK1(void, Source, setDirectFilter,, const FilterParams&)
1478 DECL_THUNK2(void, Source, setSendFilter,, ALuint, const FilterParams&)
1479 DECL_THUNK2(void, Source, setAuxiliarySend,, AuxiliaryEffectSlot, ALuint)
1480 DECL_THUNK3(void, Source, setAuxiliarySendFilter,, AuxiliaryEffectSlot, ALuint, const FilterParams&)
1481 void Source::release()
1483 pImpl->release();
1484 pImpl = nullptr;