Use std::fill instead of memset
[alure.git] / src / source.cpp
blob35a3794223251816693347120e44f5e3d25657e6
2 #include "config.h"
4 #include "source.h"
6 #include <cstring>
8 #include <stdexcept>
9 #include <memory>
10 #include <limits>
12 #include "al.h"
13 #include "alext.h"
15 #include "context.h"
16 #include "buffer.h"
17 #include "auxeffectslot.h"
18 #include "sourcegroup.h"
20 namespace alure
23 class ALBufferStream {
24 SharedPtr<Decoder> mDecoder;
26 ALuint mUpdateLen;
27 ALuint mNumUpdates;
29 ALenum mFormat;
30 ALuint mFrequency;
31 ALuint mFrameSize;
33 Vector<ALbyte> mData;
34 ALbyte mSilence;
36 Vector<ALuint> mBufferIds;
37 ALuint mCurrentIdx;
39 std::pair<uint64_t,uint64_t> mLoopPts;
40 volatile bool mHasLooped;
41 volatile bool mDone;
43 public:
44 ALBufferStream(SharedPtr<Decoder> decoder, ALuint updatelen, ALuint numupdates)
45 : mDecoder(decoder), mUpdateLen(updatelen), mNumUpdates(numupdates),
46 mFormat(AL_NONE), mFrequency(0), mFrameSize(0), mSilence(0),
47 mCurrentIdx(0), mLoopPts{0,0}, mHasLooped(false), mDone(false)
48 { }
49 virtual ~ALBufferStream()
51 if(!mBufferIds.empty())
53 alDeleteBuffers(mBufferIds.size(), &mBufferIds[0]);
54 mBufferIds.clear();
58 uint64_t getLength() const { return mDecoder->getLength(); }
59 uint64_t getPosition() const { return mDecoder->getPosition(); }
61 ALuint getNumUpdates() const { return mNumUpdates; }
62 ALuint getUpdateLength() const { return mUpdateLen; }
64 bool seek(uint64_t pos)
66 if(!mDecoder->seek(pos))
67 return false;
68 mHasLooped = false;
69 mDone = false;
70 return true;
73 void prepare()
75 ALuint srate = mDecoder->getFrequency();
76 ChannelConfig chans = mDecoder->getChannelConfig();
77 SampleType type = mDecoder->getSampleType();
79 mLoopPts = mDecoder->getLoopPoints();
80 if(mLoopPts.first >= mLoopPts.second)
82 mLoopPts.first = 0;
83 mLoopPts.second = std::numeric_limits<uint64_t>::max();
86 mFormat = GetFormat(chans, type);
87 mFrequency = srate;
88 mFrameSize = FramesToBytes(1, chans, type);
90 mData.resize(mUpdateLen * mFrameSize);
91 if(type == SampleType::UInt8) mSilence = 0x80;
92 else if(type == SampleType::Mulaw) mSilence = 0x7f;
93 else mSilence = 0x00;
95 mBufferIds.assign(mNumUpdates, 0);
96 alGenBuffers(mBufferIds.size(), &mBufferIds[0]);
99 uint64_t getLoopStart() const { return mLoopPts.first; }
100 uint64_t getLoopEnd() const { return mLoopPts.second; }
102 bool hasLooped() const { return mHasLooped; }
103 bool hasMoreData() const { return !mDone; }
104 bool streamMoreData(ALuint srcid, bool loop)
106 if(mDone) return false;
108 ALuint len = mUpdateLen;
109 uint64_t pos = mDecoder->getPosition();
110 if(loop)
112 if(pos <= mLoopPts.second)
113 len = std::min<uint64_t>(len, mLoopPts.second - pos);
114 else
115 loop = false;
118 ALuint frames = mDecoder->read(&mData[0], len);
119 if(loop && frames < mUpdateLen && pos+frames > 0)
121 if(pos+frames < mLoopPts.second)
123 mLoopPts.second = pos+frames;
124 mLoopPts.first = std::min(mLoopPts.first, mLoopPts.second-1);
127 do {
128 if(!mDecoder->seek(mLoopPts.first))
129 break;
130 mHasLooped = true;
132 len = std::min<uint64_t>(mUpdateLen-frames, mLoopPts.second-mLoopPts.first);
133 ALuint got = mDecoder->read(&mData[frames*mFrameSize], len);
134 if(got == 0) break;
135 frames += got;
136 } while(frames < mUpdateLen);
138 if(frames < mUpdateLen)
140 mDone = true;
141 if(frames == 0) return false;
142 std::fill(mData.begin() + frames*mFrameSize, mData.end(), mSilence);
145 alBufferData(mBufferIds[mCurrentIdx], mFormat, &mData[0], mData.size(), mFrequency);
146 alSourceQueueBuffers(srcid, 1, &mBufferIds[mCurrentIdx]);
147 mCurrentIdx = (mCurrentIdx+1) % mBufferIds.size();
148 return true;
153 ALSource::ALSource(ALContext *context)
154 : mContext(context), mId(0), mBuffer(0), mGroup(nullptr), mIsAsync(false),
155 mDirectFilter(AL_FILTER_NULL)
157 resetProperties();
160 ALSource::~ALSource()
165 void ALSource::resetProperties()
167 if(mGroup)
168 mGroup->removeSource(this);
169 mGroup = nullptr;
171 mPaused.store(false, std::memory_order_release);
172 mLooping = false;
173 mOffset = 0;
174 mPitch = 1.0f;
175 mGain = 1.0f;
176 mMinGain = 0.0f;
177 mMaxGain = 1.0f;
178 mRefDist = 1.0f;
179 mMaxDist = std::numeric_limits<float>::max();
180 mPosition = Vector3(0.0f);
181 mVelocity = Vector3(0.0f);
182 mDirection = Vector3(0.0f);
183 mOrientation[0] = Vector3(0.0f, 0.0f, -1.0f);
184 mOrientation[1] = Vector3(0.0f, 1.0f, 0.0f);
185 mConeInnerAngle = 360.0f;
186 mConeOuterAngle = 360.0f;
187 mConeOuterGain = 0.0f;
188 mConeOuterGainHF = 1.0f;
189 mRolloffFactor = 1.0f;
190 mRoomRolloffFactor = 0.0f;
191 mDopplerFactor = 1.0f;
192 mRelative = false;
193 mRadius = 0.0f;
194 mStereoAngles[0] = F_PI / 6.0f;
195 mStereoAngles[1] = -F_PI / 6.0f;
196 mAirAbsorptionFactor = 0.0f;
197 mDryGainHFAuto = true;
198 mWetGainAuto = true;
199 mWetGainHFAuto = true;
200 if(mDirectFilter)
201 mContext->alDeleteFilters(1, &mDirectFilter);
202 mDirectFilter = 0;
203 for(auto &i : mEffectSlots)
205 if(i.second.mSlot)
206 i.second.mSlot->removeSourceSend(this, i.first);
207 if(i.second.mFilter)
208 mContext->alDeleteFilters(1, &i.second.mFilter);
210 mEffectSlots.clear();
212 mPriority = 0;
215 void ALSource::applyProperties(bool looping, ALuint offset) const
217 alSourcei(mId, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
218 alSourcei(mId, AL_SAMPLE_OFFSET, offset);
219 if(mGroup)
221 alSourcef(mId, AL_PITCH, mPitch * mGroup->getAppliedPitch());
222 alSourcef(mId, AL_GAIN, mGain * mGroup->getAppliedGain());
224 else
226 alSourcef(mId, AL_PITCH, mPitch);
227 alSourcef(mId, AL_GAIN, mGain);
229 alSourcef(mId, AL_MIN_GAIN, mMinGain);
230 alSourcef(mId, AL_MAX_GAIN, mMaxGain);
231 alSourcef(mId, AL_REFERENCE_DISTANCE, mRefDist);
232 alSourcef(mId, AL_MAX_DISTANCE, mMaxDist);
233 alSourcefv(mId, AL_POSITION, mPosition.getPtr());
234 alSourcefv(mId, AL_VELOCITY, mVelocity.getPtr());
235 alSourcefv(mId, AL_DIRECTION, mDirection.getPtr());
236 if(mContext->hasExtension(EXT_BFORMAT))
237 alSourcefv(mId, AL_ORIENTATION, &mOrientation[0][0]);
238 alSourcef(mId, AL_CONE_INNER_ANGLE, mConeInnerAngle);
239 alSourcef(mId, AL_CONE_OUTER_ANGLE, mConeOuterAngle);
240 alSourcef(mId, AL_CONE_OUTER_GAIN, mConeOuterGain);
241 alSourcef(mId, AL_ROLLOFF_FACTOR, mRolloffFactor);
242 alSourcef(mId, AL_DOPPLER_FACTOR, mDopplerFactor);
243 if(mContext->hasExtension(EXT_SOURCE_RADIUS))
244 alSourcef(mId, AL_SOURCE_RADIUS, mRadius);
245 if(mContext->hasExtension(EXT_STEREO_ANGLES))
246 alSourcefv(mId, AL_STEREO_ANGLES, mStereoAngles);
247 alSourcei(mId, AL_SOURCE_RELATIVE, mRelative ? AL_TRUE : AL_FALSE);
248 if(mContext->hasExtension(EXT_EFX))
250 alSourcef(mId, AL_CONE_OUTER_GAINHF, mConeOuterGainHF);
251 alSourcef(mId, AL_ROOM_ROLLOFF_FACTOR, mRoomRolloffFactor);
252 alSourcef(mId, AL_AIR_ABSORPTION_FACTOR, mAirAbsorptionFactor);
253 alSourcei(mId, AL_DIRECT_FILTER_GAINHF_AUTO, mDryGainHFAuto ? AL_TRUE : AL_FALSE);
254 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, mWetGainAuto ? AL_TRUE : AL_FALSE);
255 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, mWetGainHFAuto ? AL_TRUE : AL_FALSE);
256 alSourcei(mId, AL_DIRECT_FILTER, mDirectFilter);
257 for(const auto &i : mEffectSlots)
259 ALuint slotid = (i.second.mSlot ? i.second.mSlot->getId() : 0);
260 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, i.first, i.second.mFilter);
266 void ALSource::setGroup(ALSourceGroup *group)
268 if(mGroup)
269 mGroup->removeSource(this);
270 mGroup = group;
271 groupUpdate();
274 void ALSource::unsetGroup()
276 mGroup = nullptr;
277 groupUpdate();
280 void ALSource::groupUpdate()
282 if(mId)
284 if(mGroup)
286 alSourcef(mId, AL_PITCH, mPitch * mGroup->getAppliedPitch());
287 alSourcef(mId, AL_GAIN, mGain * mGroup->getAppliedGain());
289 else
291 alSourcef(mId, AL_PITCH, mPitch);
292 alSourcef(mId, AL_GAIN, mGain);
297 void ALSource::groupPropUpdate(ALfloat gain, ALfloat pitch)
299 if(mId)
301 alSourcef(mId, AL_PITCH, mPitch * pitch);
302 alSourcef(mId, AL_GAIN, mGain * gain);
307 void ALSource::play(Buffer *buffer)
309 ALBuffer *albuf = cast<ALBuffer*>(buffer);
310 if(!albuf) throw std::runtime_error("Buffer is not valid");
311 CheckContext(mContext);
312 CheckContext(albuf->getContext());
314 if(!albuf->isReady())
315 throw std::runtime_error("Buffer is not ready");
317 if(mIsAsync.load(std::memory_order_acquire))
319 mContext->removeStream(this);
320 mIsAsync.store(false, std::memory_order_release);
323 if(mId == 0)
325 mId = mContext->getSourceId(mPriority);
326 applyProperties(mLooping, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
328 else
330 alSourceRewind(mId);
331 alSourcei(mId, AL_BUFFER, 0);
332 alSourcei(mId, AL_LOOPING, mLooping ? AL_TRUE : AL_FALSE);
333 alSourcei(mId, AL_SAMPLE_OFFSET, (ALuint)std::min<uint64_t>(mOffset, std::numeric_limits<ALint>::max()));
335 mOffset = 0;
337 mStream.reset();
339 if(mBuffer)
340 mBuffer->removeSource(this);
341 mBuffer = albuf;
342 mBuffer->addSource(this);
344 alSourcei(mId, AL_BUFFER, mBuffer->getId());
345 alSourcePlay(mId);
346 mPaused.store(false, std::memory_order_release);
349 void ALSource::play(SharedPtr<Decoder> decoder, ALuint updatelen, ALuint queuesize)
351 if(updatelen < 64)
352 throw std::runtime_error("Update length out of range");
353 if(queuesize < 2)
354 throw std::runtime_error("Queue size out of range");
355 CheckContext(mContext);
357 std::unique_ptr<ALBufferStream> stream(new ALBufferStream(decoder, updatelen, queuesize));
358 stream->prepare();
360 if(mIsAsync.load(std::memory_order_acquire))
362 mContext->removeStream(this);
363 mIsAsync.store(false, std::memory_order_release);
366 if(mId == 0)
368 mId = mContext->getSourceId(mPriority);
369 applyProperties(false, 0);
371 else
373 alSourceRewind(mId);
374 alSourcei(mId, AL_BUFFER, 0);
375 alSourcei(mId, AL_LOOPING, AL_FALSE);
376 alSourcei(mId, AL_SAMPLE_OFFSET, 0);
379 if(mBuffer)
380 mBuffer->removeSource(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);
401 void ALSource::makeStopped()
403 if(mIsAsync.load(std::memory_order_acquire))
405 mContext->removeStreamNoLock(this);
406 mIsAsync.store(false, std::memory_order_release);
409 if(mId != 0)
411 alSourcei(mId, AL_BUFFER, 0);
412 if(mContext->hasExtension(EXT_EFX))
414 alSourcei(mId, AL_DIRECT_FILTER, AL_FILTER_NULL);
415 for(auto &i : mEffectSlots)
416 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, 0, i.first, AL_FILTER_NULL);
418 mContext->insertSourceId(mId);
419 mId = 0;
422 if(mBuffer)
423 mBuffer->removeSource(this);
424 mBuffer = 0;
426 mStream.reset();
428 mPaused.store(false, std::memory_order_release);
430 mContext->send(&MessageHandler::sourceStopped, this, true);
433 void ALSource::stop()
435 CheckContext(mContext);
437 if(mIsAsync.load(std::memory_order_acquire))
439 mContext->removeStream(this);
440 mIsAsync.store(false, std::memory_order_release);
443 if(mId != 0)
445 alSourceRewind(mId);
446 alSourcei(mId, AL_BUFFER, 0);
447 if(mContext->hasExtension(EXT_EFX))
449 alSourcei(mId, AL_DIRECT_FILTER, AL_FILTER_NULL);
450 for(auto &i : mEffectSlots)
451 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, 0, i.first, AL_FILTER_NULL);
453 mContext->insertSourceId(mId);
454 mId = 0;
457 if(mBuffer)
458 mBuffer->removeSource(this);
459 mBuffer = 0;
461 mStream.reset();
463 mPaused.store(false, std::memory_order_release);
467 void ALSource::checkPaused()
469 if(mPaused.load(std::memory_order_acquire) || mId == 0)
470 return;
472 ALint state = -1;
473 alGetSourcei(mId, AL_SOURCE_STATE, &state);
474 // Streaming sources may be in a stopped state if underrun
475 mPaused.store((state == AL_PAUSED) ||
476 (state == AL_STOPPED && mStream && mStream->hasMoreData()),
477 std::memory_order_release);
480 void ALSource::pause()
482 CheckContext(mContext);
483 if(mPaused.load(std::memory_order_acquire))
484 return;
486 if(mId != 0)
488 std::lock_guard<std::mutex> lock(mMutex);
489 alSourcePause(mId);
490 ALint state = -1;
491 alGetSourcei(mId, AL_SOURCE_STATE, &state);
492 // Streaming sources may be in a stopped state if underrun
493 mPaused.store((state == AL_PAUSED) ||
494 (state == AL_STOPPED && mStream && mStream->hasMoreData()),
495 std::memory_order_release);
499 void ALSource::resume()
501 CheckContext(mContext);
502 if(!mPaused.load(std::memory_order_acquire))
503 return;
505 if(mId != 0)
506 alSourcePlay(mId);
507 mPaused.store(false, std::memory_order_release);
511 bool ALSource::isPlaying() const
513 CheckContext(mContext);
514 if(mId == 0) return false;
516 ALint state = -1;
517 alGetSourcei(mId, AL_SOURCE_STATE, &state);
518 if(state == -1)
519 throw std::runtime_error("Source state error");
521 return state == AL_PLAYING || (!mPaused.load(std::memory_order_acquire) &&
522 mStream && mStream->hasMoreData());
525 bool ALSource::isPaused() const
527 CheckContext(mContext);
528 if(mId == 0) return false;
530 ALint state = -1;
531 alGetSourcei(mId, AL_SOURCE_STATE, &state);
532 if(state == -1)
533 throw std::runtime_error("Source state error");
535 return state == AL_PAUSED || mPaused.load(std::memory_order_acquire);
539 ALint ALSource::refillBufferStream()
541 ALint processed;
542 alGetSourcei(mId, AL_BUFFERS_PROCESSED, &processed);
543 while(processed > 0)
545 ALuint buf;
546 alSourceUnqueueBuffers(mId, 1, &buf);
547 --processed;
550 ALint queued;
551 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
552 for(;(ALuint)queued < mStream->getNumUpdates();queued++)
554 if(!mStream->streamMoreData(mId, mLooping))
555 break;
558 return queued;
562 void ALSource::update()
564 CheckContext(mContext);
565 updateNoCtxCheck();
568 void ALSource::updateNoCtxCheck()
570 if(mId == 0)
571 return;
573 if(mStream)
575 if(!mIsAsync.load(std::memory_order_acquire))
577 stop();
578 mContext->send(&MessageHandler::sourceStopped, this, false);
581 else
583 ALint state = -1;
584 alGetSourcei(mId, AL_SOURCE_STATE, &state);
585 if(state != AL_PLAYING && state != AL_PAUSED)
587 stop();
588 mContext->send(&MessageHandler::sourceStopped, this, false);
593 bool ALSource::updateAsync()
595 std::lock_guard<std::mutex> lock(mMutex);
597 ALint queued = refillBufferStream();
598 if(queued == 0)
600 mIsAsync.store(false, std::memory_order_release);
601 return false;
603 if(!mPaused.load(std::memory_order_acquire))
605 ALint state = -1;
606 alGetSourcei(mId, AL_SOURCE_STATE, &state);
607 if(state != AL_PLAYING)
609 refillBufferStream();
610 alSourcePlay(mId);
613 return true;
617 void ALSource::setPriority(ALuint priority)
619 mPriority = priority;
623 void ALSource::setOffset(uint64_t offset)
625 CheckContext(mContext);
626 if(mId == 0)
628 mOffset = offset;
629 return;
632 if(!mStream)
634 if(offset >= std::numeric_limits<ALint>::max())
635 throw std::runtime_error("Offset out of range");
636 alGetError();
637 alSourcei(mId, AL_SAMPLE_OFFSET, (ALint)offset);
638 if(alGetError() != AL_NO_ERROR)
639 throw std::runtime_error("Offset out of range");
641 else
643 std::lock_guard<std::mutex> lock(mMutex);
644 if(!mStream->seek(offset))
645 throw std::runtime_error("Failed to seek to offset");
646 alSourceRewind(mId);
647 alSourcei(mId, AL_BUFFER, 0);
648 ALint queued = refillBufferStream();
649 if(queued > 0 && !mPaused)
650 alSourcePlay(mId);
654 uint64_t ALSource::getOffset(uint64_t *latency) const
656 CheckContext(mContext);
657 if(mId == 0)
659 if(latency)
660 *latency = 0;
661 return 0;
664 if(mStream)
666 std::lock_guard<std::mutex> lock(mMutex);
667 ALint queued = 0, state = -1, srcpos = 0;
668 alGetSourcei(mId, AL_BUFFERS_QUEUED, &queued);
669 if(latency && mContext->hasExtension(SOFT_source_latency))
671 ALint64SOFT val[2];
672 mContext->alGetSourcei64vSOFT(mId, AL_SAMPLE_OFFSET_LATENCY_SOFT, val);
673 srcpos = val[0]>>32;
674 *latency = val[1];
676 else
678 alGetSourcei(mId, AL_SAMPLE_OFFSET, &srcpos);
679 if(latency) *latency = 0;
681 alGetSourcei(mId, AL_SOURCE_STATE, &state);
683 uint64_t pos = mStream->getPosition();
684 if(state != AL_STOPPED)
686 // The amount of samples in the queue waiting to play
687 ALuint inqueue = queued*mStream->getUpdateLength() - srcpos;
689 if(pos >= inqueue)
691 pos -= inqueue;
692 if(pos < mStream->getLoopStart() && mStream->hasLooped())
694 uint64_t looplen = mStream->getLoopEnd() - mStream->getLoopStart();
695 do {
696 pos += looplen;
697 } while(pos < mStream->getLoopStart());
700 else if(!mStream->hasLooped())
702 // A non-looped stream should never have more samples queued
703 // than have been read...
704 pos = 0;
706 else
708 uint64_t looplen = mStream->getLoopEnd() - mStream->getLoopStart();
709 while(pos < mStream->getLoopStart())
710 pos += looplen;
714 return pos;
717 ALint srcpos = 0;
718 if(latency && mContext->hasExtension(SOFT_source_latency))
720 ALint64SOFT val[2];
721 mContext->alGetSourcei64vSOFT(mId, AL_SAMPLE_OFFSET_LATENCY_SOFT, val);
722 srcpos = val[0]>>32;
723 *latency = val[1];
725 else
727 alGetSourcei(mId, AL_SAMPLE_OFFSET, &srcpos);
728 if(latency) *latency = 0;
730 return srcpos;
734 void ALSource::setLooping(bool looping)
736 CheckContext(mContext);
738 if(mId && !mStream)
739 alSourcei(mId, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
740 mLooping = looping;
744 void ALSource::setPitch(ALfloat pitch)
746 if(!(pitch > 0.0f))
747 throw std::runtime_error("Pitch out of range");
748 CheckContext(mContext);
749 if(mId != 0)
750 alSourcef(mId, AL_PITCH, pitch * (mGroup ? mGroup->getAppliedPitch() : 1.0f));
751 mPitch = pitch;
755 void ALSource::setGain(ALfloat gain)
757 if(!(gain >= 0.0f))
758 throw std::runtime_error("Gain out of range");
759 CheckContext(mContext);
760 if(mId != 0)
761 alSourcef(mId, AL_GAIN, gain * (mGroup ? mGroup->getAppliedGain() : 1.0f));
762 mGain = gain;
765 void ALSource::setGainRange(ALfloat mingain, ALfloat maxgain)
767 if(!(mingain >= 0.0f && maxgain <= 1.0f && maxgain >= mingain))
768 throw std::runtime_error("Gain range out of range");
769 CheckContext(mContext);
770 if(mId != 0)
772 alSourcef(mId, AL_MIN_GAIN, mingain);
773 alSourcef(mId, AL_MAX_GAIN, maxgain);
775 mMinGain = mingain;
776 mMaxGain = maxgain;
780 void ALSource::setDistanceRange(ALfloat refdist, ALfloat maxdist)
782 if(!(refdist >= 0.0f && maxdist <= std::numeric_limits<float>::max() && refdist <= maxdist))
783 throw std::runtime_error("Distance range out of range");
784 CheckContext(mContext);
785 if(mId != 0)
787 alSourcef(mId, AL_REFERENCE_DISTANCE, refdist);
788 alSourcef(mId, AL_MAX_DISTANCE, maxdist);
790 mRefDist = refdist;
791 mMaxDist = maxdist;
795 void ALSource::setPosition(ALfloat x, ALfloat y, ALfloat z)
797 CheckContext(mContext);
798 if(mId != 0)
799 alSource3f(mId, AL_POSITION, x, y, z);
800 mPosition[0] = x;
801 mPosition[1] = y;
802 mPosition[2] = z;
805 void ALSource::setPosition(const ALfloat *pos)
807 CheckContext(mContext);
808 if(mId != 0)
809 alSourcefv(mId, AL_POSITION, pos);
810 mPosition[0] = pos[0];
811 mPosition[1] = pos[1];
812 mPosition[2] = pos[2];
815 void ALSource::setVelocity(ALfloat x, ALfloat y, ALfloat z)
817 CheckContext(mContext);
818 if(mId != 0)
819 alSource3f(mId, AL_VELOCITY, x, y, z);
820 mVelocity[0] = x;
821 mVelocity[1] = y;
822 mVelocity[2] = z;
825 void ALSource::setVelocity(const ALfloat *vel)
827 CheckContext(mContext);
828 if(mId != 0)
829 alSourcefv(mId, AL_VELOCITY, vel);
830 mVelocity[0] = vel[0];
831 mVelocity[1] = vel[1];
832 mVelocity[2] = vel[2];
835 void ALSource::setDirection(ALfloat x, ALfloat y, ALfloat z)
837 CheckContext(mContext);
838 if(mId != 0)
839 alSource3f(mId, AL_DIRECTION, x, y, z);
840 mDirection[0] = x;
841 mDirection[1] = y;
842 mDirection[2] = z;
845 void ALSource::setDirection(const ALfloat *dir)
847 CheckContext(mContext);
848 if(mId != 0)
849 alSourcefv(mId, AL_DIRECTION, dir);
850 mDirection[0] = dir[0];
851 mDirection[1] = dir[1];
852 mDirection[2] = dir[2];
855 void ALSource::setOrientation(ALfloat x1, ALfloat y1, ALfloat z1, ALfloat x2, ALfloat y2, ALfloat z2)
857 CheckContext(mContext);
858 if(mId != 0)
860 ALfloat ori[6] = { x1, y1, z1, x2, y2, z2 };
861 if(mContext->hasExtension(EXT_BFORMAT))
862 alSourcefv(mId, AL_ORIENTATION, ori);
863 alSourcefv(mId, AL_DIRECTION, ori);
865 mDirection[0] = mOrientation[0][0] = x1;
866 mDirection[1] = mOrientation[0][1] = y1;
867 mDirection[2] = mOrientation[0][2] = z1;
868 mOrientation[1][0] = x2;
869 mOrientation[1][1] = y2;
870 mOrientation[1][2] = z2;
873 void ALSource::setOrientation(const ALfloat *at, const ALfloat *up)
875 CheckContext(mContext);
876 if(mId != 0)
878 ALfloat ori[6] = { at[0], at[1], at[2], up[0], up[1], up[2] };
879 if(mContext->hasExtension(EXT_BFORMAT))
880 alSourcefv(mId, AL_ORIENTATION, ori);
881 alSourcefv(mId, AL_DIRECTION, ori);
883 mDirection[0] = mOrientation[0][0] = at[0];
884 mDirection[1] = mOrientation[0][1] = at[1];
885 mDirection[2] = mOrientation[0][2] = at[2];
886 mOrientation[1][0] = up[0];
887 mOrientation[1][1] = up[1];
888 mOrientation[1][2] = up[2];
891 void ALSource::setOrientation(const ALfloat *ori)
893 CheckContext(mContext);
894 if(mId != 0)
896 if(mContext->hasExtension(EXT_BFORMAT))
897 alSourcefv(mId, AL_ORIENTATION, ori);
898 alSourcefv(mId, AL_DIRECTION, ori);
900 mDirection[0] = mOrientation[0][0] = ori[0];
901 mDirection[1] = mOrientation[0][1] = ori[1];
902 mDirection[2] = mOrientation[0][2] = ori[2];
903 mOrientation[1][0] = ori[3];
904 mOrientation[1][1] = ori[4];
905 mOrientation[1][2] = ori[5];
909 void ALSource::setConeAngles(ALfloat inner, ALfloat outer)
911 if(!(inner >= 0.0f && outer <= 360.0f && outer >= inner))
912 throw std::runtime_error("Cone angles out of range");
913 CheckContext(mContext);
914 if(mId != 0)
916 alSourcef(mId, AL_CONE_INNER_ANGLE, inner);
917 alSourcef(mId, AL_CONE_OUTER_ANGLE, outer);
919 mConeInnerAngle = inner;
920 mConeOuterAngle = outer;
923 void ALSource::setOuterConeGains(ALfloat gain, ALfloat gainhf)
925 if(!(gain >= 0.0f && gain <= 1.0f && gainhf >= 0.0f && gainhf <= 1.0f))
926 throw std::runtime_error("Outer cone gain out of range");
927 CheckContext(mContext);
928 if(mId != 0)
930 alSourcef(mId, AL_CONE_OUTER_GAIN, gain);
931 if(mContext->hasExtension(EXT_EFX))
932 alSourcef(mId, AL_CONE_OUTER_GAINHF, gainhf);
934 mConeOuterGain = gain;
935 mConeOuterGainHF = gainhf;
939 void ALSource::setRolloffFactors(ALfloat factor, ALfloat roomfactor)
941 if(!(factor >= 0.0f && roomfactor >= 0.0f))
942 throw std::runtime_error("Rolloff factor out of range");
943 CheckContext(mContext);
944 if(mId != 0)
946 alSourcef(mId, AL_ROLLOFF_FACTOR, factor);
947 if(mContext->hasExtension(EXT_EFX))
948 alSourcef(mId, AL_ROOM_ROLLOFF_FACTOR, roomfactor);
950 mRolloffFactor = factor;
951 mRoomRolloffFactor = roomfactor;
954 void ALSource::setDopplerFactor(ALfloat factor)
956 if(!(factor >= 0.0f && factor <= 1.0f))
957 throw std::runtime_error("Doppler factor out of range");
958 CheckContext(mContext);
959 if(mId != 0)
960 alSourcef(mId, AL_DOPPLER_FACTOR, factor);
961 mDopplerFactor = factor;
964 void ALSource::setAirAbsorptionFactor(ALfloat factor)
966 if(!(factor >= 0.0f && factor <= 10.0f))
967 throw std::runtime_error("Absorption factor out of range");
968 CheckContext(mContext);
969 if(mId != 0 && mContext->hasExtension(EXT_EFX))
970 alSourcef(mId, AL_AIR_ABSORPTION_FACTOR, factor);
971 mAirAbsorptionFactor = factor;
974 void ALSource::setRadius(ALfloat radius)
976 if(!(mRadius >= 0.0f))
977 throw std::runtime_error("Radius out of range");
978 CheckContext(mContext);
979 if(mId != 0 && mContext->hasExtension(EXT_SOURCE_RADIUS))
980 alSourcef(mId, AL_SOURCE_RADIUS, radius);
981 mRadius = radius;
984 void ALSource::setStereoAngles(ALfloat leftAngle, ALfloat rightAngle)
986 CheckContext(mContext);
987 if(mId != 0 && mContext->hasExtension(EXT_STEREO_ANGLES))
989 ALfloat angles[2] = { leftAngle, rightAngle };
990 alSourcefv(mId, AL_STEREO_ANGLES, angles);
992 mStereoAngles[0] = leftAngle;
993 mStereoAngles[1] = rightAngle;
996 void ALSource::setRelative(bool relative)
998 CheckContext(mContext);
999 if(mId != 0)
1000 alSourcei(mId, AL_SOURCE_RELATIVE, relative ? AL_TRUE : AL_FALSE);
1001 mRelative = relative;
1004 void ALSource::setGainAuto(bool directhf, bool send, bool sendhf)
1006 CheckContext(mContext);
1007 if(mId != 0 && mContext->hasExtension(EXT_EFX))
1009 alSourcei(mId, AL_DIRECT_FILTER_GAINHF_AUTO, directhf ? AL_TRUE : AL_FALSE);
1010 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, send ? AL_TRUE : AL_FALSE);
1011 alSourcei(mId, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, sendhf ? AL_TRUE : AL_FALSE);
1013 mDryGainHFAuto = directhf;
1014 mWetGainAuto = send;
1015 mWetGainHFAuto = sendhf;
1019 void ALSource::setFilterParams(ALuint &filterid, const FilterParams &params)
1021 if(!mContext->hasExtension(EXT_EFX))
1022 return;
1024 if(!(params.mGain < 1.0f || params.mGainHF < 1.0f || params.mGainLF < 1.0f))
1026 if(filterid)
1027 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_NULL);
1028 return;
1031 alGetError();
1032 if(!filterid)
1034 mContext->alGenFilters(1, &filterid);
1035 if(alGetError() != AL_NO_ERROR)
1036 throw std::runtime_error("Failed to create Filter");
1038 bool filterset = false;
1039 if(params.mGainHF < 1.0f && params.mGainLF < 1.0f)
1041 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_BANDPASS);
1042 if(alGetError() == AL_NO_ERROR)
1044 mContext->alFilterf(filterid, AL_BANDPASS_GAIN, std::min<ALfloat>(params.mGain, 1.0f));
1045 mContext->alFilterf(filterid, AL_BANDPASS_GAINHF, std::min<ALfloat>(params.mGainHF, 1.0f));
1046 mContext->alFilterf(filterid, AL_BANDPASS_GAINLF, std::min<ALfloat>(params.mGainLF, 1.0f));
1047 filterset = true;
1050 if(!filterset && !(params.mGainHF < 1.0f) && params.mGainLF < 1.0f)
1052 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_HIGHPASS);
1053 if(alGetError() == AL_NO_ERROR)
1055 mContext->alFilterf(filterid, AL_HIGHPASS_GAIN, std::min<ALfloat>(params.mGain, 1.0f));
1056 mContext->alFilterf(filterid, AL_HIGHPASS_GAINLF, std::min<ALfloat>(params.mGainLF, 1.0f));
1057 filterset = true;
1060 if(!filterset)
1062 mContext->alFilteri(filterid, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1063 if(alGetError() == AL_NO_ERROR)
1065 mContext->alFilterf(filterid, AL_LOWPASS_GAIN, std::min<ALfloat>(params.mGain, 1.0f));
1066 mContext->alFilterf(filterid, AL_LOWPASS_GAINHF, std::min<ALfloat>(params.mGainHF, 1.0f));
1067 filterset = true;
1073 void ALSource::setDirectFilter(const FilterParams &filter)
1075 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1076 throw std::runtime_error("Gain value out of range");
1077 CheckContext(mContext);
1079 setFilterParams(mDirectFilter, filter);
1080 if(mId)
1081 alSourcei(mId, AL_DIRECT_FILTER, mDirectFilter);
1084 void ALSource::setSendFilter(ALuint send, const FilterParams &filter)
1086 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1087 throw std::runtime_error("Gain value out of range");
1088 CheckContext(mContext);
1090 SendPropMap::iterator siter = mEffectSlots.find(send);
1091 if(siter == mEffectSlots.end())
1093 ALuint filterid = 0;
1095 setFilterParams(filterid, filter);
1096 if(!filterid) return;
1098 siter = mEffectSlots.insert(std::make_pair(send, SendProps(filterid))).first;
1100 else
1101 setFilterParams(siter->second.mFilter, filter);
1103 if(mId)
1105 ALuint slotid = (siter->second.mSlot ? siter->second.mSlot->getId() : 0);
1106 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->second.mFilter);
1110 void ALSource::setAuxiliarySend(AuxiliaryEffectSlot *auxslot, ALuint send)
1112 ALAuxiliaryEffectSlot *slot = 0;
1113 if(auxslot)
1115 slot = cast<ALAuxiliaryEffectSlot*>(auxslot);
1116 if(!slot) throw std::runtime_error("Invalid AuxiliaryEffectSlot");
1117 CheckContext(slot->getContext());
1119 CheckContext(mContext);
1121 SendPropMap::iterator siter = mEffectSlots.find(send);
1122 if(siter == mEffectSlots.end())
1124 if(!slot) return;
1125 slot->addSourceSend(this, send);
1126 siter = mEffectSlots.insert(std::make_pair(send, SendProps(slot))).first;
1128 else if(siter->second.mSlot != slot)
1130 if(slot) slot->addSourceSend(this, send);
1131 if(siter->second.mSlot)
1132 siter->second.mSlot->removeSourceSend(this, send);
1133 siter->second.mSlot = slot;
1136 if(mId)
1138 ALuint slotid = (siter->second.mSlot ? siter->second.mSlot->getId() : 0);
1139 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->second.mFilter);
1143 void ALSource::setAuxiliarySendFilter(AuxiliaryEffectSlot *auxslot, ALuint send, const FilterParams &filter)
1145 if(!(filter.mGain >= 0.0f && filter.mGainHF >= 0.0f && filter.mGainLF >= 0.0f))
1146 throw std::runtime_error("Gain value out of range");
1147 ALAuxiliaryEffectSlot *slot = 0;
1148 if(auxslot)
1150 slot = cast<ALAuxiliaryEffectSlot*>(auxslot);
1151 if(!slot) throw std::runtime_error("Invalid AuxiliaryEffectSlot");
1152 CheckContext(slot->getContext());
1154 CheckContext(mContext);
1156 SendPropMap::iterator siter = mEffectSlots.find(send);
1157 if(siter == mEffectSlots.end())
1159 ALuint filterid = 0;
1161 setFilterParams(filterid, filter);
1162 if(!filterid && !slot)
1163 return;
1165 if(slot) slot->addSourceSend(this, send);
1166 siter = mEffectSlots.insert(std::make_pair(send, SendProps(slot, filterid))).first;
1168 else
1170 if(siter->second.mSlot != slot)
1172 if(slot) slot->addSourceSend(this, send);
1173 if(siter->second.mSlot)
1174 siter->second.mSlot->removeSourceSend(this, send);
1175 siter->second.mSlot = slot;
1177 setFilterParams(siter->second.mFilter, filter);
1180 if(mId)
1182 ALuint slotid = (siter->second.mSlot ? siter->second.mSlot->getId() : 0);
1183 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, slotid, send, siter->second.mFilter);
1188 void ALSource::release()
1190 CheckContext(mContext);
1192 if(mIsAsync.load(std::memory_order_acquire))
1194 mContext->removeStream(this);
1195 mIsAsync.store(false, std::memory_order_release);
1198 if(mId != 0)
1200 alSourceRewind(mId);
1201 alSourcei(mId, AL_BUFFER, 0);
1202 if(mContext->hasExtension(EXT_EFX))
1204 alSourcei(mId, AL_DIRECT_FILTER, AL_FILTER_NULL);
1205 for(auto &i : mEffectSlots)
1206 alSource3i(mId, AL_AUXILIARY_SEND_FILTER, 0, i.first, AL_FILTER_NULL);
1208 mContext->insertSourceId(mId);
1209 mId = 0;
1212 mContext->freeSource(this);
1214 if(mDirectFilter)
1215 mContext->alDeleteFilters(1, &mDirectFilter);
1216 mDirectFilter = AL_FILTER_NULL;
1218 for(auto &i : mEffectSlots)
1220 if(i.second.mSlot)
1221 i.second.mSlot->removeSourceSend(this, i.first);
1222 if(i.second.mFilter)
1223 mContext->alDeleteFilters(1, &i.second.mFilter);
1225 mEffectSlots.clear();
1227 if(mBuffer)
1228 mBuffer->removeSource(this);
1229 mBuffer = 0;
1231 mStream.reset();
1233 resetProperties();