Use rvalue or const lvalue references for some parameters
[alure.git] / src / source.cpp
blob0c1e32bee0cfe86bd55b9ce5452bd0fcfdcb0d50
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();
172 mEffectSlots.reserve(mContext->getDevice().getMaxAuxiliarySends());
175 SourceImpl::~SourceImpl()
180 void SourceImpl::resetProperties()
182 if(mGroup)
183 mGroup->eraseSource(this);
184 mGroup = nullptr;
185 mGroupPitch = 1.0f;
186 mGroupGain = 1.0f;
188 mFadeGainTarget = 1.0f;
189 mFadeGain = 1.0f;
191 mPaused.store(false, std::memory_order_release);
192 mOffset = 0;
193 mPitch = 1.0f;
194 mGain = 1.0f;
195 mMinGain = 0.0f;
196 mMaxGain = 1.0f;
197 mRefDist = 1.0f;
198 mMaxDist = std::numeric_limits<float>::max();
199 mPosition = Vector3(0.0f);
200 mVelocity = Vector3(0.0f);
201 mDirection = Vector3(0.0f);
202 mOrientation[0] = Vector3(0.0f, 0.0f, -1.0f);
203 mOrientation[1] = Vector3(0.0f, 1.0f, 0.0f);
204 mConeInnerAngle = 360.0f;
205 mConeOuterAngle = 360.0f;
206 mConeOuterGain = 0.0f;
207 mConeOuterGainHF = 1.0f;
208 mRolloffFactor = 1.0f;
209 mRoomRolloffFactor = 0.0f;
210 mDopplerFactor = 1.0f;
211 mAirAbsorptionFactor = 0.0f;
212 mRadius = 0.0f;
213 mStereoAngles[0] = F_PI / 6.0f;
214 mStereoAngles[1] = -F_PI / 6.0f;
215 mSpatialize = Spatialize::Auto;
216 mResampler = mContext->hasExtension(AL::SOFT_source_resampler) ?
217 alGetInteger(AL_DEFAULT_RESAMPLER_SOFT) : 0;
218 mLooping = false;
219 mRelative = false;
220 mDryGainHFAuto = true;
221 mWetGainAuto = true;
222 mWetGainHFAuto = true;
223 if(mDirectFilter)
224 mContext->alDeleteFilters(1, &mDirectFilter);
225 mDirectFilter = 0;
226 for(auto &i : mEffectSlots)
228 if(i.mSlot)
229 i.mSlot->removeSourceSend({Source(this), i.mSendIdx});
230 if(i.mFilter)
231 mContext->alDeleteFilters(1, &i.mFilter);
233 mEffectSlots.clear();
235 mPriority = 0;
238 void SourceImpl::applyProperties(bool looping, ALuint offset) const
240 alSourcei(mId, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
241 alSourcei(mId, AL_SAMPLE_OFFSET, offset);
242 alSourcef(mId, AL_PITCH, mPitch * mGroupPitch);
243 alSourcef(mId, AL_GAIN, mGain * mGroupGain * mFadeGain);
244 alSourcef(mId, AL_MIN_GAIN, mMinGain);
245 alSourcef(mId, AL_MAX_GAIN, mMaxGain);
246 alSourcef(mId, AL_REFERENCE_DISTANCE, mRefDist);
247 alSourcef(mId, AL_MAX_DISTANCE, mMaxDist);
248 alSourcefv(mId, AL_POSITION, mPosition.getPtr());
249 alSourcefv(mId, AL_VELOCITY, mVelocity.getPtr());
250 alSourcefv(mId, AL_DIRECTION, mDirection.getPtr());
251 if(mContext->hasExtension(AL::EXT_BFORMAT))
252 alSourcefv(mId, AL_ORIENTATION, &mOrientation[0][0]);
253 alSourcef(mId, AL_CONE_INNER_ANGLE, mConeInnerAngle);
254 alSourcef(mId, AL_CONE_OUTER_ANGLE, mConeOuterAngle);
255 alSourcef(mId, AL_CONE_OUTER_GAIN, mConeOuterGain);
256 alSourcef(mId, AL_ROLLOFF_FACTOR, mRolloffFactor);
257 alSourcef(mId, AL_DOPPLER_FACTOR, mDopplerFactor);
258 if(mContext->hasExtension(AL::EXT_SOURCE_RADIUS))
259 alSourcef(mId, AL_SOURCE_RADIUS, mRadius);
260 if(mContext->hasExtension(AL::EXT_STEREO_ANGLES))
261 alSourcefv(mId, AL_STEREO_ANGLES, mStereoAngles);
262 if(mContext->hasExtension(AL::SOFT_source_spatialize))
263 alSourcei(mId, AL_SOURCE_SPATIALIZE_SOFT, (ALint)mSpatialize);
264 if(mContext->hasExtension(AL::SOFT_source_resampler))
265 alSourcei(mId, AL_SOURCE_RESAMPLER_SOFT, mResampler);
266 alSourcei(mId, AL_SOURCE_RELATIVE, mRelative ? AL_TRUE : AL_FALSE);
267 if(mContext->hasExtension(AL::EXT_EFX))
269 alSourcef(mId, AL_CONE_OUTER_GAINHF, mConeOuterGainHF);
270 alSourcef(mId, AL_ROOM_ROLLOFF_FACTOR, mRoomRolloffFactor);
271 alSourcef(mId, AL_AIR_ABSORPTION_FACTOR, mAirAbsorptionFactor);
272 alSourcei(mId, AL_DIRECT_FILTER_GAINHF_AUTO, mDryGainHFAuto ? AL_TRUE : AL_FALSE);
273 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, mWetGainAuto ? AL_TRUE : AL_FALSE);
274 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, mWetGainHFAuto ? AL_TRUE : AL_FALSE);
275 alSourcei(mId, AL_DIRECT_FILTER, mDirectFilter);
276 for(const auto &i : mEffectSlots)
278 ALuint slotid = (i.mSlot ? i.mSlot->getId() : 0);
279 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, i.mSendIdx, i.mFilter);
285 void SourceImpl::unsetGroup()
287 mGroup = nullptr;
288 groupPropUpdate(1.0f, 1.0f);
291 void SourceImpl::groupPropUpdate(ALfloat gain, ALfloat pitch)
293 if(mId)
295 alSourcef(mId, AL_PITCH, mPitch * pitch);
296 alSourcef(mId, AL_GAIN, mGain * gain * mFadeGain);
298 mGroupPitch = pitch;
299 mGroupGain = gain;
303 void SourceImpl::play(Buffer buffer)
305 BufferImpl *albuf = buffer.getHandle();
306 if(!albuf) throw std::runtime_error("Buffer is not valid");
307 CheckContext(mContext);
308 CheckContext(albuf->getContext());
310 if(mStream)
311 mContext->removeStream(this);
312 mIsAsync.store(false, std::memory_order_release);
314 mFadeGainTarget = mFadeGain = 1.0f;
315 mFadeTimeTarget = mLastFadeTime = std::chrono::steady_clock::now();
317 if(mId == 0)
319 mId = mContext->getSourceId(mPriority);
320 applyProperties(mLooping, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
322 else
324 mContext->removeFadingSource(this);
325 mContext->removePlayingSource(this);
326 alSourceRewind(mId);
327 alSourcei(mId, AL_BUFFER, 0);
328 alSourcei(mId, AL_LOOPING, mLooping ? AL_TRUE : AL_FALSE);
329 alSourcei(mId, AL_SAMPLE_OFFSET, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
331 mOffset = 0;
333 mStream.reset();
334 if(mBuffer)
335 mBuffer->removeSource(Source(this));
336 mBuffer = albuf;
337 mBuffer->addSource(Source(this));
339 alSourcei(mId, AL_BUFFER, mBuffer->getId());
340 alSourcePlay(mId);
341 mPaused.store(false, std::memory_order_release);
342 mContext->removePendingSource(this);
343 mContext->addPlayingSource(this, mId);
346 void SourceImpl::play(SharedPtr<Decoder>&& decoder, ALuint chunk_len, ALuint queue_size)
348 if(chunk_len < 64)
349 throw std::runtime_error("Update length out of range");
350 if(queue_size < 2)
351 throw std::runtime_error("Queue size out of range");
352 CheckContext(mContext);
354 auto stream = MakeUnique<ALBufferStream>(decoder, chunk_len, queue_size);
355 stream->prepare();
357 if(mStream)
358 mContext->removeStream(this);
359 mIsAsync.store(false, std::memory_order_release);
361 mFadeGainTarget = mFadeGain = 1.0f;
362 mFadeTimeTarget = mLastFadeTime = std::chrono::steady_clock::now();
364 if(mId == 0)
366 mId = mContext->getSourceId(mPriority);
367 applyProperties(false, 0);
369 else
371 mContext->removeFadingSource(this);
372 mContext->removePlayingSource(this);
373 alSourceRewind(mId);
374 alSourcei(mId, AL_BUFFER, 0);
375 alSourcei(mId, AL_LOOPING, AL_FALSE);
376 alSourcei(mId, AL_SAMPLE_OFFSET, 0);
379 mStream.reset();
380 if(mBuffer)
381 mBuffer->removeSource(Source(this));
382 mBuffer = 0;
384 mStream = std::move(stream);
386 mStream->seek(mOffset);
387 mOffset = 0;
389 for(ALuint i = 0;i < mStream->getNumUpdates();i++)
391 if(!mStream->streamMoreData(mId, mLooping))
392 break;
394 alSourcePlay(mId);
395 mPaused.store(false, std::memory_order_release);
397 mContext->addStream(this);
398 mIsAsync.store(true, std::memory_order_release);
399 mContext->removePendingSource(this);
400 mContext->addPlayingSource(this);
403 void SourceImpl::play(SharedFuture<Buffer>&& future_buffer)
405 if(!future_buffer.valid())
406 throw std::runtime_error("Invalid future buffer");
407 if(future_buffer.wait_for(std::chrono::milliseconds::zero()) == std::future_status::ready)
409 play(future_buffer.get());
410 return;
413 CheckContext(mContext);
415 mContext->removeFadingSource(this);
416 mContext->removePlayingSource(this);
417 makeStopped(true);
419 mFadeGainTarget = mFadeGain = 1.0f;
420 mFadeTimeTarget = mLastFadeTime = std::chrono::steady_clock::now();
422 mContext->addPendingSource(this, std::move(future_buffer));
426 void SourceImpl::makeStopped(bool dolock)
428 if(mStream)
430 if(dolock)
431 mContext->removeStream(this);
432 else
433 mContext->removeStreamNoLock(this);
435 mIsAsync.store(false, std::memory_order_release);
437 if(mId != 0)
439 alSourceRewind(mId);
440 alSourcei(mId, AL_BUFFER, 0);
441 if(mContext->hasExtension(AL::EXT_EFX))
443 alSourcei(mId, AL_DIRECT_FILTER, AL_FILTER_NULL);
444 for(auto &i : mEffectSlots)
445 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, 0, i.mSendIdx, AL_FILTER_NULL);
447 mContext->insertSourceId(mId);
448 mId = 0;
451 mStream.reset();
452 if(mBuffer)
453 mBuffer->removeSource(Source(this));
454 mBuffer = 0;
456 mPaused.store(false, std::memory_order_release);
459 void SourceImpl::stop()
461 CheckContext(mContext);
462 mContext->removePendingSource(this);
463 mContext->removeFadingSource(this);
464 mContext->removePlayingSource(this);
465 makeStopped();
469 void SourceImpl::fadeOutToStop(ALfloat gain, std::chrono::milliseconds duration)
471 if(!(gain < 1.0f && gain >= 0.0f))
472 throw std::runtime_error("Fade gain target out of range");
473 if(duration.count() <= 0)
474 throw std::runtime_error("Fade duration out of range");
475 CheckContext(mContext);
477 mFadeGainTarget = std::max<ALfloat>(gain, 0.0001f);
478 mLastFadeTime = std::chrono::steady_clock::now();
479 mFadeTimeTarget = mLastFadeTime + duration;
481 mContext->addFadingSource(this);
485 void SourceImpl::checkPaused()
487 if(mPaused.load(std::memory_order_acquire) || mId == 0)
488 return;
490 ALint state = -1;
491 alGetSourcei(mId, AL_SOURCE_STATE, &state);
492 // Streaming sources may be in a stopped or initial state if underrun
493 mPaused.store(state == AL_PAUSED || (mStream && mStream->hasMoreData()),
494 std::memory_order_release);
497 void SourceImpl::pause()
499 CheckContext(mContext);
500 if(mPaused.load(std::memory_order_acquire))
501 return;
503 if(mId != 0)
505 std::lock_guard<std::mutex> lock(mMutex);
506 alSourcePause(mId);
507 ALint state = -1;
508 alGetSourcei(mId, AL_SOURCE_STATE, &state);
509 // Streaming sources may be in a stopped or initial state if underrun
510 mPaused.store(state == AL_PAUSED || (mStream && mStream->hasMoreData()),
511 std::memory_order_release);
515 void SourceImpl::resume()
517 CheckContext(mContext);
518 if(!mPaused.load(std::memory_order_acquire))
519 return;
521 if(mId != 0)
522 alSourcePlay(mId);
523 mPaused.store(false, std::memory_order_release);
527 bool SourceImpl::isPending() const
529 CheckContext(mContext);
530 return mContext->isPendingSource(this);
533 bool SourceImpl::isPlaying() const
535 CheckContext(mContext);
536 if(mId == 0) return false;
538 ALint state = -1;
539 alGetSourcei(mId, AL_SOURCE_STATE, &state);
540 if(state == -1)
541 throw std::runtime_error("Source state error");
543 return state == AL_PLAYING || (!mPaused.load(std::memory_order_acquire) &&
544 mStream && mStream->hasMoreData());
547 bool SourceImpl::isPaused() const
549 CheckContext(mContext);
550 return mId != 0 && mPaused.load(std::memory_order_acquire);
554 void SourceImpl::setGroup(SourceGroup group)
556 CheckContext(mContext);
558 SourceGroupImpl *parent = group.getHandle();
559 if(parent == mGroup) return;
561 if(mGroup)
562 mGroup->eraseSource(this);
563 mGroup = parent;
564 if(mGroup)
566 mGroup->insertSource(this);
567 mGroupPitch = mGroup->getAppliedPitch();
568 mGroupGain = mGroup->getAppliedGain();
570 else
572 mGroupPitch = 1.0f;
573 mGroupGain = 1.0f;
576 if(mId)
578 alSourcef(mId, AL_PITCH, mPitch * mGroupPitch);
579 alSourcef(mId, AL_GAIN, mGain * mGroupGain * mFadeGain);
584 bool SourceImpl::checkPending(SharedFuture<Buffer> &future)
586 if(future.wait_for(std::chrono::milliseconds::zero()) != std::future_status::ready)
587 return true;
589 BufferImpl *buffer = future.get().getHandle();
590 if(Expect<false>(buffer->getContext() != mContext))
591 return false;
593 if(mId == 0)
595 mId = mContext->getSourceId(mPriority);
596 applyProperties(mLooping, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
598 else
600 alSourceRewind(mId);
601 alSourcei(mId, AL_BUFFER, 0);
602 alSourcei(mId, AL_LOOPING, mLooping ? AL_TRUE : AL_FALSE);
603 alSourcei(mId, AL_SAMPLE_OFFSET, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
605 mOffset = 0;
607 mBuffer = buffer;
608 mBuffer->addSource(Source(this));
610 alSourcei(mId, AL_BUFFER, mBuffer->getId());
611 alSourcePlay(mId);
612 mPaused.store(false, std::memory_order_release);
613 mContext->addPlayingSource(this, mId);
614 return false;
617 bool SourceImpl::fadeUpdate(std::chrono::steady_clock::time_point cur_fade_time)
619 if((cur_fade_time - mFadeTimeTarget).count() >= 0)
621 mLastFadeTime = mFadeTimeTarget;
622 mFadeGain = 1.0f;
623 if(mFadeGainTarget >= 1.0f)
625 if(mId != 0)
626 alSourcef(mId, AL_GAIN, mGain * mGroupGain);
627 return false;
629 mContext->removePendingSource(this);
630 mContext->removePlayingSource(this);
631 makeStopped(true);
632 return false;
635 float mult = std::pow(mFadeGainTarget/mFadeGain,
636 float(1.0/Seconds(mFadeTimeTarget-mLastFadeTime).count())
639 std::chrono::steady_clock::duration duration = cur_fade_time - mLastFadeTime;
640 mLastFadeTime = cur_fade_time;
642 float gain = mFadeGain * std::pow(mult, (float)Seconds(duration).count());
643 if(Expect<false>(gain == mFadeGain))
645 // Ensure the gain keeps moving toward its target, in case precision
646 // loss results in no change with small steps.
647 gain = std::nextafter(gain, mFadeGainTarget);
649 mFadeGain = gain;
651 if(mId != 0)
652 alSourcef(mId, AL_GAIN, mGain * mGroupGain * mFadeGain);
653 return true;
656 bool SourceImpl::playUpdate(ALuint id)
658 ALint state = -1;
659 alGetSourcei(id, AL_SOURCE_STATE, &state);
660 if(Expect<true>(state == AL_PLAYING || state == AL_PAUSED))
661 return true;
663 makeStopped();
664 mContext->send(&MessageHandler::sourceStopped, Source(this));
665 return false;
668 bool SourceImpl::playUpdate()
670 if(Expect<true>(mIsAsync.load(std::memory_order_acquire)))
671 return true;
673 makeStopped();
674 mContext->send(&MessageHandler::sourceStopped, Source(this));
675 return false;
679 ALint SourceImpl::refillBufferStream()
681 ALint processed;
682 alGetSourcei(mId, AL_BUFFERS_PROCESSED, &processed);
683 while(processed > 0)
685 ALuint buf;
686 alSourceUnqueueBuffers(mId, 1, &buf);
687 --processed;
690 ALint queued;
691 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
692 for(;(ALuint)queued < mStream->getNumUpdates();queued++)
694 if(!mStream->streamMoreData(mId, mLooping))
695 break;
698 return queued;
701 bool SourceImpl::updateAsync()
703 std::lock_guard<std::mutex> lock(mMutex);
705 ALint queued = refillBufferStream();
706 if(queued == 0)
708 mIsAsync.store(false, std::memory_order_release);
709 return false;
712 ALint state = -1;
713 alGetSourcei(mId, AL_SOURCE_STATE, &state);
714 if(!mPaused.load(std::memory_order_acquire))
716 // Make sure the source is still playing if it's not paused.
717 if(state != AL_PLAYING)
718 alSourcePlay(mId);
720 else
722 // Rewind the source to an initial state if it underrun as it was
723 // paused.
724 if(state == AL_STOPPED)
725 alSourceRewind(mId);
727 return true;
731 void SourceImpl::setPriority(ALuint priority)
733 mPriority = priority;
737 void SourceImpl::setOffset(uint64_t offset)
739 CheckContext(mContext);
740 if(mId == 0)
742 mOffset = offset;
743 return;
746 if(!mStream)
748 if(offset >= std::numeric_limits<ALint>::max())
749 throw std::runtime_error("Offset out of range");
750 alGetError();
751 alSourcei(mId, AL_SAMPLE_OFFSET, (ALint)offset);
752 if(alGetError() != AL_NO_ERROR)
753 throw std::runtime_error("Offset out of range");
755 else
757 std::lock_guard<std::mutex> lock(mMutex);
758 if(!mStream->seek(offset))
759 throw std::runtime_error("Failed to seek to offset");
760 alSourceRewind(mId);
761 alSourcei(mId, AL_BUFFER, 0);
762 ALint queued = refillBufferStream();
763 if(queued > 0 && !mPaused.load(std::memory_order_acquire))
764 alSourcePlay(mId);
768 std::pair<uint64_t,std::chrono::nanoseconds> SourceImpl::getSampleOffsetLatency() const
770 std::pair<uint64_t,std::chrono::nanoseconds> ret{0, std::chrono::nanoseconds::zero()};
771 CheckContext(mContext);
772 if(mId == 0) return ret;
774 if(mStream)
776 std::lock_guard<std::mutex> lock(mMutex);
777 ALint queued = 0, state = -1, srcpos = 0;
779 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
780 if(mContext->hasExtension(AL::SOFT_source_latency))
782 ALint64SOFT val[2];
783 mContext->alGetSourcei64vSOFT(mId, AL_SAMPLE_OFFSET_LATENCY_SOFT, val);
784 srcpos = val[0]>>32;
785 ret.second = std::chrono::nanoseconds(val[1]);
787 else
788 alGetSourcei(mId, AL_SAMPLE_OFFSET, &srcpos);
789 alGetSourcei(mId, AL_SOURCE_STATE, &state);
791 int64_t streampos = mStream->getPosition();
792 if(state != AL_STOPPED)
794 // The amount of samples in the queue waiting to play
795 ALuint inqueue = queued*mStream->getUpdateLength() - srcpos;
796 if(!mStream->hasLooped())
798 // A non-looped stream should never have more samples queued
799 // than have been read...
800 streampos = std::max<int64_t>(streampos, inqueue) - inqueue;
802 else
804 streampos -= inqueue;
805 int64_t looplen = mStream->getLoopEnd() - mStream->getLoopStart();
806 while(streampos < mStream->getLoopStart())
807 streampos += looplen;
811 ret.first = streampos;
812 return ret;
815 ALint srcpos = 0;
816 if(mContext->hasExtension(AL::SOFT_source_latency))
818 ALint64SOFT val[2];
819 mContext->alGetSourcei64vSOFT(mId, AL_SAMPLE_OFFSET_LATENCY_SOFT, val);
820 srcpos = val[0]>>32;
821 ret.second = std::chrono::nanoseconds(val[1]);
823 else
824 alGetSourcei(mId, AL_SAMPLE_OFFSET, &srcpos);
825 ret.first = srcpos;
826 return ret;
829 std::pair<Seconds,Seconds> SourceImpl::getSecOffsetLatency() const
831 std::pair<Seconds,Seconds> ret{Seconds::zero(), Seconds::zero()};
832 CheckContext(mContext);
833 if(mId == 0) return ret;
835 if(mStream)
837 std::lock_guard<std::mutex> lock(mMutex);
838 ALint queued = 0, state = -1;
839 ALdouble srcpos = 0;
841 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
842 if(mContext->hasExtension(AL::SOFT_source_latency))
844 ALdouble val[2];
845 mContext->alGetSourcedvSOFT(mId, AL_SEC_OFFSET_LATENCY_SOFT, val);
846 srcpos = val[0];
847 ret.second = Seconds(val[1]);
849 else
851 ALfloat f;
852 alGetSourcef(mId, AL_SEC_OFFSET, &f);
853 srcpos = f;
855 alGetSourcei(mId, AL_SOURCE_STATE, &state);
857 ALdouble frac = 0.0;
858 int64_t streampos = mStream->getPosition();
859 if(state != AL_STOPPED)
861 ALdouble ipos;
862 frac = std::modf(srcpos * mStream->getFrequency(), &ipos);
864 // The amount of samples in the queue waiting to play
865 ALuint inqueue = queued*mStream->getUpdateLength() - (ALuint)ipos;
866 if(!mStream->hasLooped())
868 // A non-looped stream should never have more samples queued
869 // than have been read...
870 streampos = std::max<int64_t>(streampos, inqueue) - inqueue;
872 else
874 streampos -= inqueue;
875 int64_t looplen = mStream->getLoopEnd() - mStream->getLoopStart();
876 while(streampos < mStream->getLoopStart())
877 streampos += looplen;
881 ret.first = Seconds((streampos+frac) / mStream->getFrequency());
882 return ret;
885 if(mContext->hasExtension(AL::SOFT_source_latency))
887 ALdouble val[2];
888 mContext->alGetSourcedvSOFT(mId, AL_SEC_OFFSET_LATENCY_SOFT, val);
889 ret.first = Seconds(val[0]);
890 ret.second = Seconds(val[1]);
892 else
894 ALfloat f;
895 alGetSourcef(mId, AL_SEC_OFFSET, &f);
896 ret.first = Seconds(f);
898 return ret;
902 void SourceImpl::setLooping(bool looping)
904 CheckContext(mContext);
906 if(mId && !mStream)
907 alSourcei(mId, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
908 mLooping = looping;
912 void SourceImpl::setPitch(ALfloat pitch)
914 if(!(pitch > 0.0f))
915 throw std::runtime_error("Pitch out of range");
916 CheckContext(mContext);
917 if(mId != 0)
918 alSourcef(mId, AL_PITCH, pitch * mGroupPitch);
919 mPitch = pitch;
923 void SourceImpl::setGain(ALfloat gain)
925 if(!(gain >= 0.0f))
926 throw std::runtime_error("Gain out of range");
927 CheckContext(mContext);
928 if(mId != 0)
929 alSourcef(mId, AL_GAIN, gain * mGroupGain * mFadeGain);
930 mGain = gain;
933 void SourceImpl::setGainRange(ALfloat mingain, ALfloat maxgain)
935 if(!(mingain >= 0.0f && maxgain <= 1.0f && maxgain >= mingain))
936 throw std::runtime_error("Gain range out of range");
937 CheckContext(mContext);
938 if(mId != 0)
940 alSourcef(mId, AL_MIN_GAIN, mingain);
941 alSourcef(mId, AL_MAX_GAIN, maxgain);
943 mMinGain = mingain;
944 mMaxGain = maxgain;
948 void SourceImpl::setDistanceRange(ALfloat refdist, ALfloat maxdist)
950 if(!(refdist >= 0.0f && maxdist <= std::numeric_limits<float>::max() && refdist <= maxdist))
951 throw std::runtime_error("Distance range out of range");
952 CheckContext(mContext);
953 if(mId != 0)
955 alSourcef(mId, AL_REFERENCE_DISTANCE, refdist);
956 alSourcef(mId, AL_MAX_DISTANCE, maxdist);
958 mRefDist = refdist;
959 mMaxDist = maxdist;
963 void SourceImpl::set3DParameters(const Vector3 &position, const Vector3 &velocity, const Vector3 &direction)
965 CheckContext(mContext);
966 if(mId != 0)
968 Batcher batcher = mContext->getBatcher();
969 alSourcefv(mId, AL_POSITION, position.getPtr());
970 alSourcefv(mId, AL_VELOCITY, velocity.getPtr());
971 alSourcefv(mId, AL_DIRECTION, direction.getPtr());
973 mPosition = position;
974 mVelocity = velocity;
975 mDirection = direction;
978 void SourceImpl::set3DParameters(const Vector3 &position, const Vector3 &velocity, const std::pair<Vector3,Vector3> &orientation)
980 static_assert(sizeof(orientation) == sizeof(ALfloat[6]), "Invalid Vector3 pair size");
981 CheckContext(mContext);
982 if(mId != 0)
984 Batcher batcher = mContext->getBatcher();
985 alSourcefv(mId, AL_POSITION, position.getPtr());
986 alSourcefv(mId, AL_VELOCITY, velocity.getPtr());
987 if(mContext->hasExtension(AL::EXT_BFORMAT))
988 alSourcefv(mId, AL_ORIENTATION, orientation.first.getPtr());
989 alSourcefv(mId, AL_DIRECTION, orientation.first.getPtr());
991 mPosition = position;
992 mVelocity = velocity;
993 mDirection = mOrientation[0] = orientation.first;
994 mOrientation[1] = orientation.second;
998 void SourceImpl::setPosition(ALfloat x, ALfloat y, ALfloat z)
1000 CheckContext(mContext);
1001 if(mId != 0)
1002 alSource3f(mId, AL_POSITION, x, y, z);
1003 mPosition[0] = x;
1004 mPosition[1] = y;
1005 mPosition[2] = z;
1008 void SourceImpl::setPosition(const ALfloat *pos)
1010 CheckContext(mContext);
1011 if(mId != 0)
1012 alSourcefv(mId, AL_POSITION, pos);
1013 mPosition[0] = pos[0];
1014 mPosition[1] = pos[1];
1015 mPosition[2] = pos[2];
1018 void SourceImpl::setVelocity(ALfloat x, ALfloat y, ALfloat z)
1020 CheckContext(mContext);
1021 if(mId != 0)
1022 alSource3f(mId, AL_VELOCITY, x, y, z);
1023 mVelocity[0] = x;
1024 mVelocity[1] = y;
1025 mVelocity[2] = z;
1028 void SourceImpl::setVelocity(const ALfloat *vel)
1030 CheckContext(mContext);
1031 if(mId != 0)
1032 alSourcefv(mId, AL_VELOCITY, vel);
1033 mVelocity[0] = vel[0];
1034 mVelocity[1] = vel[1];
1035 mVelocity[2] = vel[2];
1038 void SourceImpl::setDirection(ALfloat x, ALfloat y, ALfloat z)
1040 CheckContext(mContext);
1041 if(mId != 0)
1042 alSource3f(mId, AL_DIRECTION, x, y, z);
1043 mDirection[0] = x;
1044 mDirection[1] = y;
1045 mDirection[2] = z;
1048 void SourceImpl::setDirection(const ALfloat *dir)
1050 CheckContext(mContext);
1051 if(mId != 0)
1052 alSourcefv(mId, AL_DIRECTION, dir);
1053 mDirection[0] = dir[0];
1054 mDirection[1] = dir[1];
1055 mDirection[2] = dir[2];
1058 void SourceImpl::setOrientation(ALfloat x1, ALfloat y1, ALfloat z1, ALfloat x2, ALfloat y2, ALfloat z2)
1060 CheckContext(mContext);
1061 if(mId != 0)
1063 ALfloat ori[6] = { x1, y1, z1, x2, y2, z2 };
1064 if(mContext->hasExtension(AL::EXT_BFORMAT))
1065 alSourcefv(mId, AL_ORIENTATION, ori);
1066 alSourcefv(mId, AL_DIRECTION, ori);
1068 mDirection[0] = mOrientation[0][0] = x1;
1069 mDirection[1] = mOrientation[0][1] = y1;
1070 mDirection[2] = mOrientation[0][2] = z1;
1071 mOrientation[1][0] = x2;
1072 mOrientation[1][1] = y2;
1073 mOrientation[1][2] = z2;
1076 void SourceImpl::setOrientation(const ALfloat *at, const ALfloat *up)
1078 CheckContext(mContext);
1079 if(mId != 0)
1081 ALfloat ori[6] = { at[0], at[1], at[2], up[0], up[1], up[2] };
1082 if(mContext->hasExtension(AL::EXT_BFORMAT))
1083 alSourcefv(mId, AL_ORIENTATION, ori);
1084 alSourcefv(mId, AL_DIRECTION, ori);
1086 mDirection[0] = mOrientation[0][0] = at[0];
1087 mDirection[1] = mOrientation[0][1] = at[1];
1088 mDirection[2] = mOrientation[0][2] = at[2];
1089 mOrientation[1][0] = up[0];
1090 mOrientation[1][1] = up[1];
1091 mOrientation[1][2] = up[2];
1094 void SourceImpl::setOrientation(const ALfloat *ori)
1096 CheckContext(mContext);
1097 if(mId != 0)
1099 if(mContext->hasExtension(AL::EXT_BFORMAT))
1100 alSourcefv(mId, AL_ORIENTATION, ori);
1101 alSourcefv(mId, AL_DIRECTION, ori);
1103 mDirection[0] = mOrientation[0][0] = ori[0];
1104 mDirection[1] = mOrientation[0][1] = ori[1];
1105 mDirection[2] = mOrientation[0][2] = ori[2];
1106 mOrientation[1][0] = ori[3];
1107 mOrientation[1][1] = ori[4];
1108 mOrientation[1][2] = ori[5];
1112 void SourceImpl::setConeAngles(ALfloat inner, ALfloat outer)
1114 if(!(inner >= 0.0f && outer <= 360.0f && outer >= inner))
1115 throw std::runtime_error("Cone angles out of range");
1116 CheckContext(mContext);
1117 if(mId != 0)
1119 alSourcef(mId, AL_CONE_INNER_ANGLE, inner);
1120 alSourcef(mId, AL_CONE_OUTER_ANGLE, outer);
1122 mConeInnerAngle = inner;
1123 mConeOuterAngle = outer;
1126 void SourceImpl::setOuterConeGains(ALfloat gain, ALfloat gainhf)
1128 if(!(gain >= 0.0f && gain <= 1.0f && gainhf >= 0.0f && gainhf <= 1.0f))
1129 throw std::runtime_error("Outer cone gain out of range");
1130 CheckContext(mContext);
1131 if(mId != 0)
1133 alSourcef(mId, AL_CONE_OUTER_GAIN, gain);
1134 if(mContext->hasExtension(AL::EXT_EFX))
1135 alSourcef(mId, AL_CONE_OUTER_GAINHF, gainhf);
1137 mConeOuterGain = gain;
1138 mConeOuterGainHF = gainhf;
1142 void SourceImpl::setRolloffFactors(ALfloat factor, ALfloat roomfactor)
1144 if(!(factor >= 0.0f && roomfactor >= 0.0f))
1145 throw std::runtime_error("Rolloff factor out of range");
1146 CheckContext(mContext);
1147 if(mId != 0)
1149 alSourcef(mId, AL_ROLLOFF_FACTOR, factor);
1150 if(mContext->hasExtension(AL::EXT_EFX))
1151 alSourcef(mId, AL_ROOM_ROLLOFF_FACTOR, roomfactor);
1153 mRolloffFactor = factor;
1154 mRoomRolloffFactor = roomfactor;
1157 void SourceImpl::setDopplerFactor(ALfloat factor)
1159 if(!(factor >= 0.0f && factor <= 1.0f))
1160 throw std::runtime_error("Doppler factor out of range");
1161 CheckContext(mContext);
1162 if(mId != 0)
1163 alSourcef(mId, AL_DOPPLER_FACTOR, factor);
1164 mDopplerFactor = factor;
1167 void SourceImpl::setAirAbsorptionFactor(ALfloat factor)
1169 if(!(factor >= 0.0f && factor <= 10.0f))
1170 throw std::runtime_error("Absorption factor out of range");
1171 CheckContext(mContext);
1172 if(mId != 0 && mContext->hasExtension(AL::EXT_EFX))
1173 alSourcef(mId, AL_AIR_ABSORPTION_FACTOR, factor);
1174 mAirAbsorptionFactor = factor;
1177 void SourceImpl::setRadius(ALfloat radius)
1179 if(!(mRadius >= 0.0f))
1180 throw std::runtime_error("Radius out of range");
1181 CheckContext(mContext);
1182 if(mId != 0 && mContext->hasExtension(AL::EXT_SOURCE_RADIUS))
1183 alSourcef(mId, AL_SOURCE_RADIUS, radius);
1184 mRadius = radius;
1187 void SourceImpl::setStereoAngles(ALfloat leftAngle, ALfloat rightAngle)
1189 CheckContext(mContext);
1190 if(mId != 0 && mContext->hasExtension(AL::EXT_STEREO_ANGLES))
1192 ALfloat angles[2] = { leftAngle, rightAngle };
1193 alSourcefv(mId, AL_STEREO_ANGLES, angles);
1195 mStereoAngles[0] = leftAngle;
1196 mStereoAngles[1] = rightAngle;
1199 void SourceImpl::set3DSpatialize(Spatialize spatialize)
1201 CheckContext(mContext);
1202 if(mId != 0 && mContext->hasExtension(AL::SOFT_source_spatialize))
1203 alSourcei(mId, AL_SOURCE_SPATIALIZE_SOFT, (ALint)spatialize);
1204 mSpatialize = spatialize;
1207 void SourceImpl::setResamplerIndex(ALsizei index)
1209 if(index < 0)
1210 throw std::runtime_error("Resampler index out of range");
1211 index = std::min<ALsizei>(index, mContext->getAvailableResamplers().size());
1212 if(mId != 0 && mContext->hasExtension(AL::SOFT_source_resampler))
1213 alSourcei(mId, AL_SOURCE_RESAMPLER_SOFT, index);
1214 mResampler = index;
1217 void SourceImpl::setRelative(bool relative)
1219 CheckContext(mContext);
1220 if(mId != 0)
1221 alSourcei(mId, AL_SOURCE_RELATIVE, relative ? AL_TRUE : AL_FALSE);
1222 mRelative = relative;
1225 void SourceImpl::setGainAuto(bool directhf, bool send, bool sendhf)
1227 CheckContext(mContext);
1228 if(mId != 0 && mContext->hasExtension(AL::EXT_EFX))
1230 alSourcei(mId, AL_DIRECT_FILTER_GAINHF_AUTO, directhf ? AL_TRUE : AL_FALSE);
1231 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, send ? AL_TRUE : AL_FALSE);
1232 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, sendhf ? AL_TRUE : AL_FALSE);
1234 mDryGainHFAuto = directhf;
1235 mWetGainAuto = send;
1236 mWetGainHFAuto = sendhf;
1240 void SourceImpl::setFilterParams(ALuint &filterid, const FilterParams &params)
1242 if(!mContext->hasExtension(AL::EXT_EFX))
1243 return;
1245 if(!(params.mGain < 1.0f || params.mGainHF < 1.0f || params.mGainLF < 1.0f))
1247 if(filterid)
1248 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_NULL);
1249 return;
1252 alGetError();
1253 if(!filterid)
1255 mContext->alGenFilters(1, &filterid);
1256 if(alGetError() != AL_NO_ERROR)
1257 throw std::runtime_error("Failed to create Filter");
1259 bool filterset = false;
1260 if(params.mGainHF < 1.0f && params.mGainLF < 1.0f)
1262 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_BANDPASS);
1263 if(alGetError() == AL_NO_ERROR)
1265 mContext->alFilterf(filterid, AL_BANDPASS_GAIN, std::min(params.mGain, 1.0f));
1266 mContext->alFilterf(filterid, AL_BANDPASS_GAINHF, std::min(params.mGainHF, 1.0f));
1267 mContext->alFilterf(filterid, AL_BANDPASS_GAINLF, std::min(params.mGainLF, 1.0f));
1268 filterset = true;
1271 if(!filterset && !(params.mGainHF < 1.0f) && params.mGainLF < 1.0f)
1273 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_HIGHPASS);
1274 if(alGetError() == AL_NO_ERROR)
1276 mContext->alFilterf(filterid, AL_HIGHPASS_GAIN, std::min(params.mGain, 1.0f));
1277 mContext->alFilterf(filterid, AL_HIGHPASS_GAINLF, std::min(params.mGainLF, 1.0f));
1278 filterset = true;
1281 if(!filterset)
1283 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1284 if(alGetError() == AL_NO_ERROR)
1286 mContext->alFilterf(filterid, AL_LOWPASS_GAIN, std::min(params.mGain, 1.0f));
1287 mContext->alFilterf(filterid, AL_LOWPASS_GAINHF, std::min(params.mGainHF, 1.0f));
1288 filterset = true;
1294 void SourceImpl::setDirectFilter(const FilterParams &filter)
1296 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1297 throw std::runtime_error("Gain value out of range");
1298 CheckContext(mContext);
1300 setFilterParams(mDirectFilter, filter);
1301 if(mId)
1302 alSourcei(mId, AL_DIRECT_FILTER, mDirectFilter);
1305 void SourceImpl::setSendFilter(ALuint send, const FilterParams &filter)
1307 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1308 throw std::runtime_error("Gain value out of range");
1309 CheckContext(mContext);
1311 auto siter = std::lower_bound(mEffectSlots.begin(), mEffectSlots.end(), send,
1312 [](const SendProps &prop, ALuint send) -> bool
1313 { return prop.mSendIdx < send; }
1315 if(siter == mEffectSlots.end() || siter->mSendIdx != send)
1317 ALuint filterid = 0;
1319 setFilterParams(filterid, filter);
1320 if(!filterid) return;
1322 siter = mEffectSlots.emplace(siter, send, filterid);
1324 else
1325 setFilterParams(siter->mFilter, filter);
1327 if(mId)
1329 ALuint slotid = (siter->mSlot ? siter->mSlot->getId() : 0);
1330 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->mFilter);
1334 void SourceImpl::setAuxiliarySend(AuxiliaryEffectSlot auxslot, ALuint send)
1336 AuxiliaryEffectSlotImpl *slot = auxslot.getHandle();
1337 if(slot) CheckContext(slot->getContext());
1338 CheckContext(mContext);
1340 auto siter = std::lower_bound(mEffectSlots.begin(), mEffectSlots.end(), send,
1341 [](const SendProps &prop, ALuint send) -> bool
1342 { return prop.mSendIdx < send; }
1344 if(siter == mEffectSlots.end() || siter->mSendIdx != send)
1346 if(!slot) return;
1347 slot->addSourceSend({Source(this), send});
1348 siter = mEffectSlots.emplace(siter, send, slot);
1350 else if(siter->mSlot != slot)
1352 if(slot) slot->addSourceSend({Source(this), send});
1353 if(siter->mSlot)
1354 siter->mSlot->removeSourceSend({Source(this), send});
1355 siter->mSlot = slot;
1358 if(mId)
1360 ALuint slotid = (siter->mSlot ? siter->mSlot->getId() : 0);
1361 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->mFilter);
1365 void SourceImpl::setAuxiliarySendFilter(AuxiliaryEffectSlot auxslot, ALuint send, const FilterParams &filter)
1367 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1368 throw std::runtime_error("Gain value out of range");
1369 AuxiliaryEffectSlotImpl *slot = auxslot.getHandle();
1370 if(slot) CheckContext(slot->getContext());
1371 CheckContext(mContext);
1373 auto siter = std::lower_bound(mEffectSlots.begin(), mEffectSlots.end(), send,
1374 [](const SendProps &prop, ALuint send) -> bool
1375 { return prop.mSendIdx < send; }
1377 if(siter == mEffectSlots.end() || siter->mSendIdx != send)
1379 ALuint filterid = 0;
1381 setFilterParams(filterid, filter);
1382 if(!filterid && !slot)
1383 return;
1385 if(slot) slot->addSourceSend({Source(this), send});
1386 siter = mEffectSlots.emplace(siter, send, slot, filterid);
1388 else
1390 if(siter->mSlot != slot)
1392 if(slot) slot->addSourceSend({Source(this), send});
1393 if(siter->mSlot)
1394 siter->mSlot->removeSourceSend({Source(this), send});
1395 siter->mSlot = slot;
1397 setFilterParams(siter->mFilter, filter);
1400 if(mId)
1402 ALuint slotid = (siter->mSlot ? siter->mSlot->getId() : 0);
1403 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->mFilter);
1408 void SourceImpl::release()
1410 stop();
1412 resetProperties();
1413 mContext->freeSource(this);
1417 // Need to use these to avoid extraneous commas in macro parameter lists
1418 using UInt64NSecPair = std::pair<uint64_t,std::chrono::nanoseconds>;
1419 using SecondsPair = std::pair<Seconds,Seconds>;
1420 using ALfloatPair = std::pair<ALfloat,ALfloat>;
1421 using Vector3Pair = std::pair<Vector3,Vector3>;
1422 using BoolTriple = std::tuple<bool,bool,bool>;
1424 DECL_THUNK1(void, Source, play,, Buffer)
1425 DECL_THUNK3(void, Source, play,, SharedPtr<Decoder>, ALuint, ALuint)
1426 DECL_THUNK1(void, Source, play,, SharedFuture<Buffer>)
1427 DECL_THUNK0(void, Source, stop,)
1428 DECL_THUNK2(void, Source, fadeOutToStop,, ALfloat, std::chrono::milliseconds)
1429 DECL_THUNK0(void, Source, pause,)
1430 DECL_THUNK0(void, Source, resume,)
1431 DECL_THUNK0(bool, Source, isPending, const)
1432 DECL_THUNK0(bool, Source, isPlaying, const)
1433 DECL_THUNK0(bool, Source, isPaused, const)
1434 DECL_THUNK1(void, Source, setGroup,, SourceGroup)
1435 DECL_THUNK0(SourceGroup, Source, getGroup, const)
1436 DECL_THUNK1(void, Source, setPriority,, ALuint)
1437 DECL_THUNK0(ALuint, Source, getPriority, const)
1438 DECL_THUNK1(void, Source, setOffset,, uint64_t)
1439 DECL_THUNK0(UInt64NSecPair, Source, getSampleOffsetLatency, const)
1440 DECL_THUNK0(SecondsPair, Source, getSecOffsetLatency, const)
1441 DECL_THUNK1(void, Source, setLooping,, bool)
1442 DECL_THUNK0(bool, Source, getLooping, const)
1443 DECL_THUNK1(void, Source, setPitch,, ALfloat)
1444 DECL_THUNK0(ALfloat, Source, getPitch, const)
1445 DECL_THUNK1(void, Source, setGain,, ALfloat)
1446 DECL_THUNK0(ALfloat, Source, getGain, const)
1447 DECL_THUNK2(void, Source, setGainRange,, ALfloat, ALfloat)
1448 DECL_THUNK0(ALfloatPair, Source, getGainRange, const)
1449 DECL_THUNK2(void, Source, setDistanceRange,, ALfloat, ALfloat)
1450 DECL_THUNK0(ALfloatPair, Source, getDistanceRange, const)
1451 DECL_THUNK3(void, Source, set3DParameters,, const Vector3&, const Vector3&, const Vector3&)
1452 DECL_THUNK3(void, Source, set3DParameters,, const Vector3&, const Vector3&, const Vector3Pair&)
1453 DECL_THUNK3(void, Source, setPosition,, ALfloat, ALfloat, ALfloat)
1454 DECL_THUNK1(void, Source, setPosition,, const ALfloat*)
1455 DECL_THUNK0(Vector3, Source, getPosition, const)
1456 DECL_THUNK3(void, Source, setVelocity,, ALfloat, ALfloat, ALfloat)
1457 DECL_THUNK1(void, Source, setVelocity,, const ALfloat*)
1458 DECL_THUNK0(Vector3, Source, getVelocity, const)
1459 DECL_THUNK3(void, Source, setDirection,, ALfloat, ALfloat, ALfloat)
1460 DECL_THUNK1(void, Source, setDirection,, const ALfloat*)
1461 DECL_THUNK0(Vector3, Source, getDirection, const)
1462 DECL_THUNK6(void, Source, setOrientation,, ALfloat, ALfloat, ALfloat, ALfloat, ALfloat, ALfloat)
1463 DECL_THUNK2(void, Source, setOrientation,, const ALfloat*, const ALfloat*)
1464 DECL_THUNK1(void, Source, setOrientation,, const ALfloat*)
1465 DECL_THUNK0(Vector3Pair, Source, getOrientation, const)
1466 DECL_THUNK2(void, Source, setConeAngles,, ALfloat, ALfloat)
1467 DECL_THUNK0(ALfloatPair, Source, getConeAngles, const)
1468 DECL_THUNK2(void, Source, setOuterConeGains,, ALfloat, ALfloat)
1469 DECL_THUNK0(ALfloatPair, Source, getOuterConeGains, const)
1470 DECL_THUNK2(void, Source, setRolloffFactors,, ALfloat, ALfloat)
1471 DECL_THUNK0(ALfloatPair, Source, getRolloffFactors, const)
1472 DECL_THUNK1(void, Source, setDopplerFactor,, ALfloat)
1473 DECL_THUNK0(ALfloat, Source, getDopplerFactor, const)
1474 DECL_THUNK1(void, Source, setRelative,, bool)
1475 DECL_THUNK0(bool, Source, getRelative, const)
1476 DECL_THUNK1(void, Source, setRadius,, ALfloat)
1477 DECL_THUNK0(ALfloat, Source, getRadius, const)
1478 DECL_THUNK2(void, Source, setStereoAngles,, ALfloat, ALfloat)
1479 DECL_THUNK0(ALfloatPair, Source, getStereoAngles, const)
1480 DECL_THUNK1(void, Source, set3DSpatialize,, Spatialize)
1481 DECL_THUNK0(Spatialize, Source, get3DSpatialize, const)
1482 DECL_THUNK1(void, Source, setResamplerIndex,, ALsizei)
1483 DECL_THUNK0(ALsizei, Source, getResamplerIndex, const)
1484 DECL_THUNK1(void, Source, setAirAbsorptionFactor,, ALfloat)
1485 DECL_THUNK0(ALfloat, Source, getAirAbsorptionFactor, const)
1486 DECL_THUNK3(void, Source, setGainAuto,, bool, bool, bool)
1487 DECL_THUNK0(BoolTriple, Source, getGainAuto, const)
1488 DECL_THUNK1(void, Source, setDirectFilter,, const FilterParams&)
1489 DECL_THUNK2(void, Source, setSendFilter,, ALuint, const FilterParams&)
1490 DECL_THUNK2(void, Source, setAuxiliarySend,, AuxiliaryEffectSlot, ALuint)
1491 DECL_THUNK3(void, Source, setAuxiliarySendFilter,, AuxiliaryEffectSlot, ALuint, const FilterParams&)
1492 void Source::release()
1494 pImpl->release();
1495 pImpl = nullptr;