2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
49 #include "alcontext.h"
52 #include "alnumeric.h"
53 #include "aloptional.h"
58 #include "auxeffectslot.h"
59 #include "backends/base.h"
60 #include "bformatdec.h"
64 #include "filters/nfc.h"
65 #include "filters/splitter.h"
66 #include "inprogext.h"
68 #include "math_defs.h"
69 #include "opthelpers.h"
70 #include "ringbuffer.h"
76 using namespace std::placeholders
;
77 using std::chrono::nanoseconds
;
79 ALvoice
*GetSourceVoice(ALsource
*source
, ALCcontext
*context
)
81 ALuint idx
{source
->VoiceIdx
};
82 if(idx
< context
->mVoices
.size())
84 ALuint sid
{source
->id
};
85 ALvoice
&voice
= context
->mVoices
[idx
];
86 if(voice
.mSourceID
.load(std::memory_order_acquire
) == sid
)
89 source
->VoiceIdx
= INVALID_VOICE_IDX
;
93 void UpdateSourceProps(const ALsource
*source
, ALvoice
*voice
, ALCcontext
*context
)
95 /* Get an unused property container, or allocate a new one as needed. */
96 ALvoiceProps
*props
{context
->mFreeVoiceProps
.load(std::memory_order_acquire
)};
98 props
= new ALvoiceProps
{};
103 next
= props
->next
.load(std::memory_order_relaxed
);
104 } while(context
->mFreeVoiceProps
.compare_exchange_weak(props
, next
,
105 std::memory_order_acq_rel
, std::memory_order_acquire
) == 0);
108 /* Copy in current property values. */
109 props
->Pitch
= source
->Pitch
;
110 props
->Gain
= source
->Gain
;
111 props
->OuterGain
= source
->OuterGain
;
112 props
->MinGain
= source
->MinGain
;
113 props
->MaxGain
= source
->MaxGain
;
114 props
->InnerAngle
= source
->InnerAngle
;
115 props
->OuterAngle
= source
->OuterAngle
;
116 props
->RefDistance
= source
->RefDistance
;
117 props
->MaxDistance
= source
->MaxDistance
;
118 props
->RolloffFactor
= source
->RolloffFactor
;
119 props
->Position
= source
->Position
;
120 props
->Velocity
= source
->Velocity
;
121 props
->Direction
= source
->Direction
;
122 props
->OrientAt
= source
->OrientAt
;
123 props
->OrientUp
= source
->OrientUp
;
124 props
->HeadRelative
= source
->HeadRelative
;
125 props
->mDistanceModel
= source
->mDistanceModel
;
126 props
->mResampler
= source
->mResampler
;
127 props
->DirectChannels
= source
->DirectChannels
;
128 props
->mSpatializeMode
= source
->mSpatialize
;
130 props
->DryGainHFAuto
= source
->DryGainHFAuto
;
131 props
->WetGainAuto
= source
->WetGainAuto
;
132 props
->WetGainHFAuto
= source
->WetGainHFAuto
;
133 props
->OuterGainHF
= source
->OuterGainHF
;
135 props
->AirAbsorptionFactor
= source
->AirAbsorptionFactor
;
136 props
->RoomRolloffFactor
= source
->RoomRolloffFactor
;
137 props
->DopplerFactor
= source
->DopplerFactor
;
139 props
->StereoPan
= source
->StereoPan
;
141 props
->Radius
= source
->Radius
;
143 props
->Direct
.Gain
= source
->Direct
.Gain
;
144 props
->Direct
.GainHF
= source
->Direct
.GainHF
;
145 props
->Direct
.HFReference
= source
->Direct
.HFReference
;
146 props
->Direct
.GainLF
= source
->Direct
.GainLF
;
147 props
->Direct
.LFReference
= source
->Direct
.LFReference
;
149 auto copy_send
= [](const ALsource::SendData
&srcsend
) noexcept
-> ALvoicePropsBase::SendData
151 ALvoicePropsBase::SendData ret
;
152 ret
.Slot
= srcsend
.Slot
;
153 ret
.Gain
= srcsend
.Gain
;
154 ret
.GainHF
= srcsend
.GainHF
;
155 ret
.HFReference
= srcsend
.HFReference
;
156 ret
.GainLF
= srcsend
.GainLF
;
157 ret
.LFReference
= srcsend
.LFReference
;
160 std::transform(source
->Send
.cbegin(), source
->Send
.cend(), props
->Send
, copy_send
);
162 /* Set the new container for updating internal parameters. */
163 props
= voice
->mUpdate
.exchange(props
, std::memory_order_acq_rel
);
166 /* If there was an unused update container, put it back in the
169 AtomicReplaceHead(context
->mFreeVoiceProps
, props
);
173 /* GetSourceSampleOffset
175 * Gets the current read offset for the given Source, in 32.32 fixed-point
176 * samples. The offset is relative to the start of the queue (not the start of
177 * the current buffer).
179 int64_t GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, nanoseconds
*clocktime
)
181 ALCdevice
*device
{context
->mDevice
.get()};
182 const ALbufferlistitem
*Current
;
190 while(((refcount
=device
->MixCount
.load(std::memory_order_acquire
))&1))
191 std::this_thread::yield();
192 *clocktime
= GetDeviceClockTime(device
);
194 voice
= GetSourceVoice(Source
, context
);
197 Current
= voice
->mCurrentBuffer
.load(std::memory_order_relaxed
);
199 readPos
= uint64_t{voice
->mPosition
.load(std::memory_order_relaxed
)} << 32;
200 readPos
|= uint64_t{voice
->mPositionFrac
.load(std::memory_order_relaxed
)} <<
203 std::atomic_thread_fence(std::memory_order_acquire
);
204 } while(refcount
!= device
->MixCount
.load(std::memory_order_relaxed
));
208 const ALbufferlistitem
*BufferList
{Source
->queue
};
209 while(BufferList
&& BufferList
!= Current
)
211 readPos
+= uint64_t{BufferList
->mSampleLen
} << 32;
212 BufferList
= BufferList
->mNext
.load(std::memory_order_relaxed
);
214 readPos
= minu64(readPos
, 0x7fffffffffffffff_u
64);
217 return static_cast<int64_t>(readPos
);
220 /* GetSourceSecOffset
222 * Gets the current read offset for the given Source, in seconds. The offset is
223 * relative to the start of the queue (not the start of the current buffer).
225 ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, nanoseconds
*clocktime
)
227 ALCdevice
*device
{context
->mDevice
.get()};
228 const ALbufferlistitem
*Current
;
236 while(((refcount
=device
->MixCount
.load(std::memory_order_acquire
))&1))
237 std::this_thread::yield();
238 *clocktime
= GetDeviceClockTime(device
);
240 voice
= GetSourceVoice(Source
, context
);
243 Current
= voice
->mCurrentBuffer
.load(std::memory_order_relaxed
);
245 readPos
= uint64_t{voice
->mPosition
.load(std::memory_order_relaxed
)} << FRACTIONBITS
;
246 readPos
|= voice
->mPositionFrac
.load(std::memory_order_relaxed
);
248 std::atomic_thread_fence(std::memory_order_acquire
);
249 } while(refcount
!= device
->MixCount
.load(std::memory_order_relaxed
));
251 ALdouble offset
{0.0};
254 const ALbufferlistitem
*BufferList
{Source
->queue
};
255 const ALbuffer
*BufferFmt
{nullptr};
256 while(BufferList
&& BufferList
!= Current
)
258 if(!BufferFmt
) BufferFmt
= BufferList
->mBuffer
;
259 readPos
+= uint64_t{BufferList
->mSampleLen
} << FRACTIONBITS
;
260 BufferList
= BufferList
->mNext
.load(std::memory_order_relaxed
);
263 while(BufferList
&& !BufferFmt
)
265 BufferFmt
= BufferList
->mBuffer
;
266 BufferList
= BufferList
->mNext
.load(std::memory_order_relaxed
);
268 assert(BufferFmt
!= nullptr);
270 offset
= static_cast<ALdouble
>(readPos
) / ALdouble
{FRACTIONONE
} / BufferFmt
->Frequency
;
278 * Gets the current read offset for the given Source, in the appropriate format
279 * (Bytes, Samples or Seconds). The offset is relative to the start of the
280 * queue (not the start of the current buffer).
282 ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
)
284 ALCdevice
*device
{context
->mDevice
.get()};
285 const ALbufferlistitem
*Current
;
293 readPos
= readPosFrac
= 0;
294 while(((refcount
=device
->MixCount
.load(std::memory_order_acquire
))&1))
295 std::this_thread::yield();
296 voice
= GetSourceVoice(Source
, context
);
299 Current
= voice
->mCurrentBuffer
.load(std::memory_order_relaxed
);
301 readPos
= voice
->mPosition
.load(std::memory_order_relaxed
);
302 readPosFrac
= voice
->mPositionFrac
.load(std::memory_order_relaxed
);
304 std::atomic_thread_fence(std::memory_order_acquire
);
305 } while(refcount
!= device
->MixCount
.load(std::memory_order_relaxed
));
307 ALdouble offset
{0.0};
308 if(!voice
) return offset
;
310 const ALbufferlistitem
*BufferList
{Source
->queue
};
311 const ALbuffer
*BufferFmt
{nullptr};
312 ALuint totalBufferLen
{0u};
317 if(!BufferFmt
) BufferFmt
= BufferList
->mBuffer
;
319 readFin
|= (BufferList
== Current
);
320 totalBufferLen
+= BufferList
->mSampleLen
;
321 if(!readFin
) readPos
+= BufferList
->mSampleLen
;
323 BufferList
= BufferList
->mNext
.load(std::memory_order_relaxed
);
325 assert(BufferFmt
!= nullptr);
328 readPos
%= totalBufferLen
;
332 if(readPos
>= totalBufferLen
)
333 readPos
= readPosFrac
= 0;
339 offset
= (readPos
+ static_cast<ALdouble
>(readPosFrac
)/FRACTIONONE
) / BufferFmt
->Frequency
;
342 case AL_SAMPLE_OFFSET
:
343 offset
= readPos
+ static_cast<ALdouble
>(readPosFrac
)/FRACTIONONE
;
347 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
349 ALuint FrameBlockSize
{BufferFmt
->OriginalAlign
};
350 ALuint align
{(BufferFmt
->OriginalAlign
-1)/2 + 4};
351 ALuint BlockSize
{align
* ChannelsFromFmt(BufferFmt
->mFmtChannels
)};
353 /* Round down to nearest ADPCM block */
354 offset
= static_cast<ALdouble
>(readPos
/ FrameBlockSize
* BlockSize
);
356 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
358 ALuint FrameBlockSize
{BufferFmt
->OriginalAlign
};
359 ALuint align
{(FrameBlockSize
-2)/2 + 7};
360 ALuint BlockSize
{align
* ChannelsFromFmt(BufferFmt
->mFmtChannels
)};
362 /* Round down to nearest ADPCM block */
363 offset
= static_cast<ALdouble
>(readPos
/ FrameBlockSize
* BlockSize
);
367 const ALuint FrameSize
{FrameSizeFromFmt(BufferFmt
->mFmtChannels
, BufferFmt
->mFmtType
)};
368 offset
= static_cast<ALdouble
>(readPos
* FrameSize
);
379 ALbufferlistitem
*bufferitem
;
385 * Retrieves the voice position, fixed-point fraction, and bufferlist item
386 * using the source's stored offset and offset type. If the source has no
387 * stored offset, or the offset is out of range, returns an empty optional.
389 al::optional
<VoicePos
> GetSampleOffset(ALsource
*Source
)
391 al::optional
<VoicePos
> ret
;
393 /* Find the first valid Buffer in the Queue */
394 const ALbuffer
*BufferFmt
{nullptr};
395 ALbufferlistitem
*BufferList
{Source
->queue
};
398 if((BufferFmt
=BufferList
->mBuffer
) != nullptr) break;
399 BufferList
= BufferList
->mNext
.load(std::memory_order_relaxed
);
403 Source
->OffsetType
= AL_NONE
;
404 Source
->Offset
= 0.0;
408 /* Get sample frame offset */
409 ALuint offset
{0u}, frac
{0u};
410 ALdouble dbloff
, dblfrac
;
411 switch(Source
->OffsetType
)
414 /* Determine the ByteOffset (and ensure it is block aligned) */
415 offset
= static_cast<ALuint
>(Source
->Offset
);
416 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
418 const ALuint align
{(BufferFmt
->OriginalAlign
-1)/2 + 4};
419 offset
/= align
* ChannelsFromFmt(BufferFmt
->mFmtChannels
);
420 offset
*= BufferFmt
->OriginalAlign
;
422 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
424 const ALuint align
{(BufferFmt
->OriginalAlign
-2)/2 + 7};
425 offset
/= align
* ChannelsFromFmt(BufferFmt
->mFmtChannels
);
426 offset
*= BufferFmt
->OriginalAlign
;
429 offset
/= FrameSizeFromFmt(BufferFmt
->mFmtChannels
, BufferFmt
->mFmtType
);
433 case AL_SAMPLE_OFFSET
:
434 dblfrac
= std::modf(Source
->Offset
, &dbloff
);
435 offset
= static_cast<ALuint
>(mind(dbloff
, std::numeric_limits
<ALuint
>::max()));
436 frac
= static_cast<ALuint
>(mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0));
440 dblfrac
= std::modf(Source
->Offset
*BufferFmt
->Frequency
, &dbloff
);
441 offset
= static_cast<ALuint
>(mind(dbloff
, std::numeric_limits
<ALuint
>::max()));
442 frac
= static_cast<ALuint
>(mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0));
445 Source
->OffsetType
= AL_NONE
;
446 Source
->Offset
= 0.0;
448 /* Find the bufferlist item this offset belongs to. */
449 ALuint totalBufferLen
{0u};
450 while(BufferList
&& totalBufferLen
<= offset
)
452 if(BufferList
->mSampleLen
> offset
-totalBufferLen
)
454 /* Offset is in this buffer */
455 ret
= {offset
-totalBufferLen
, frac
, BufferList
};
458 totalBufferLen
+= BufferList
->mSampleLen
;
460 BufferList
= BufferList
->mNext
.load(std::memory_order_relaxed
);
463 /* Offset is out of range of the queue */
469 * Returns if the last known state for the source was playing or paused. Does
470 * not sync with the mixer voice.
472 inline bool IsPlayingOrPaused(ALsource
*source
)
473 { return source
->state
== AL_PLAYING
|| source
->state
== AL_PAUSED
; }
476 * Returns an updated source state using the matching voice's status (or lack
479 inline ALenum
GetSourceState(ALsource
*source
, ALvoice
*voice
)
481 if(!voice
&& source
->state
== AL_PLAYING
)
482 source
->state
= AL_STOPPED
;
483 return source
->state
;
487 * Returns if the source should specify an update, given the context's
488 * deferring state and the source's last known state.
490 inline bool SourceShouldUpdate(ALsource
*source
, ALCcontext
*context
)
492 return !context
->mDeferUpdates
.load(std::memory_order_acquire
) &&
493 IsPlayingOrPaused(source
);
497 bool EnsureSources(ALCcontext
*context
, size_t needed
)
499 size_t count
{std::accumulate(context
->mSourceList
.cbegin(), context
->mSourceList
.cend(),
501 [](size_t cur
, const SourceSubList
&sublist
) noexcept
-> size_t
502 { return cur
+ static_cast<ALuint
>(POPCNT64(sublist
.FreeMask
)); }
505 while(needed
> count
)
507 if UNLIKELY(context
->mSourceList
.size() >= 1<<25)
510 context
->mSourceList
.emplace_back();
511 auto sublist
= context
->mSourceList
.end() - 1;
512 sublist
->FreeMask
= ~0_u64
;
513 sublist
->Sources
= static_cast<ALsource
*>(al_calloc(alignof(ALsource
), sizeof(ALsource
)*64));
514 if UNLIKELY(!sublist
->Sources
)
516 context
->mSourceList
.pop_back();
524 ALsource
*AllocSource(ALCcontext
*context
, ALuint num_sends
)
526 auto sublist
= std::find_if(context
->mSourceList
.begin(), context
->mSourceList
.end(),
527 [](const SourceSubList
&entry
) noexcept
-> bool
528 { return entry
.FreeMask
!= 0; }
530 auto lidx
= static_cast<ALuint
>(std::distance(context
->mSourceList
.begin(), sublist
));
531 auto slidx
= static_cast<ALuint
>(CTZ64(sublist
->FreeMask
));
533 ALsource
*source
{::new (sublist
->Sources
+ slidx
) ALsource
{num_sends
}};
535 /* Add 1 to avoid source ID 0. */
536 source
->id
= ((lidx
<<6) | slidx
) + 1;
538 context
->mNumSources
+= 1;
539 sublist
->FreeMask
&= ~(1_u64
<< slidx
);
544 void FreeSource(ALCcontext
*context
, ALsource
*source
)
546 const ALuint id
{source
->id
- 1};
547 const size_t lidx
{id
>> 6};
548 const ALuint slidx
{id
& 0x3f};
550 if(IsPlayingOrPaused(source
))
552 ALCdevice
*device
{context
->mDevice
.get()};
553 BackendLockGuard _
{*device
->Backend
};
554 if(ALvoice
*voice
{GetSourceVoice(source
, context
)})
556 voice
->mCurrentBuffer
.store(nullptr, std::memory_order_relaxed
);
557 voice
->mLoopBuffer
.store(nullptr, std::memory_order_relaxed
);
558 voice
->mSourceID
.store(0u, std::memory_order_relaxed
);
559 std::atomic_thread_fence(std::memory_order_release
);
560 /* Don't set the voice to stopping if it was already stopped or
563 ALvoice::State oldvstate
{ALvoice::Playing
};
564 voice
->mPlayState
.compare_exchange_strong(oldvstate
, ALvoice::Stopping
,
565 std::memory_order_acq_rel
, std::memory_order_acquire
);
569 al::destroy_at(source
);
571 context
->mSourceList
[lidx
].FreeMask
|= 1_u64
<< slidx
;
572 context
->mNumSources
--;
576 inline ALsource
*LookupSource(ALCcontext
*context
, ALuint id
) noexcept
578 const size_t lidx
{(id
-1) >> 6};
579 const ALuint slidx
{(id
-1) & 0x3f};
581 if UNLIKELY(lidx
>= context
->mSourceList
.size())
583 SourceSubList
&sublist
{context
->mSourceList
[lidx
]};
584 if UNLIKELY(sublist
.FreeMask
& (1_u64
<< slidx
))
586 return sublist
.Sources
+ slidx
;
589 inline ALbuffer
*LookupBuffer(ALCdevice
*device
, ALuint id
) noexcept
591 const size_t lidx
{(id
-1) >> 6};
592 const ALuint slidx
{(id
-1) & 0x3f};
594 if UNLIKELY(lidx
>= device
->BufferList
.size())
596 BufferSubList
&sublist
= device
->BufferList
[lidx
];
597 if UNLIKELY(sublist
.FreeMask
& (1_u64
<< slidx
))
599 return sublist
.Buffers
+ slidx
;
602 inline ALfilter
*LookupFilter(ALCdevice
*device
, ALuint id
) noexcept
604 const size_t lidx
{(id
-1) >> 6};
605 const ALuint slidx
{(id
-1) & 0x3f};
607 if UNLIKELY(lidx
>= device
->FilterList
.size())
609 FilterSubList
&sublist
= device
->FilterList
[lidx
];
610 if UNLIKELY(sublist
.FreeMask
& (1_u64
<< slidx
))
612 return sublist
.Filters
+ slidx
;
615 inline ALeffectslot
*LookupEffectSlot(ALCcontext
*context
, ALuint id
) noexcept
617 const size_t lidx
{(id
-1) >> 6};
618 const ALuint slidx
{(id
-1) & 0x3f};
620 if UNLIKELY(lidx
>= context
->mEffectSlotList
.size())
622 EffectSlotSubList
&sublist
{context
->mEffectSlotList
[lidx
]};
623 if UNLIKELY(sublist
.FreeMask
& (1_u64
<< slidx
))
625 return sublist
.EffectSlots
+ slidx
;
629 enum SourceProp
: ALenum
{
632 srcMinGain
= AL_MIN_GAIN
,
633 srcMaxGain
= AL_MAX_GAIN
,
634 srcMaxDistance
= AL_MAX_DISTANCE
,
635 srcRolloffFactor
= AL_ROLLOFF_FACTOR
,
636 srcDopplerFactor
= AL_DOPPLER_FACTOR
,
637 srcConeOuterGain
= AL_CONE_OUTER_GAIN
,
638 srcSecOffset
= AL_SEC_OFFSET
,
639 srcSampleOffset
= AL_SAMPLE_OFFSET
,
640 srcByteOffset
= AL_BYTE_OFFSET
,
641 srcConeInnerAngle
= AL_CONE_INNER_ANGLE
,
642 srcConeOuterAngle
= AL_CONE_OUTER_ANGLE
,
643 srcRefDistance
= AL_REFERENCE_DISTANCE
,
645 srcPosition
= AL_POSITION
,
646 srcVelocity
= AL_VELOCITY
,
647 srcDirection
= AL_DIRECTION
,
649 srcSourceRelative
= AL_SOURCE_RELATIVE
,
650 srcLooping
= AL_LOOPING
,
651 srcBuffer
= AL_BUFFER
,
652 srcSourceState
= AL_SOURCE_STATE
,
653 srcBuffersQueued
= AL_BUFFERS_QUEUED
,
654 srcBuffersProcessed
= AL_BUFFERS_PROCESSED
,
655 srcSourceType
= AL_SOURCE_TYPE
,
658 srcConeOuterGainHF
= AL_CONE_OUTER_GAINHF
,
659 srcAirAbsorptionFactor
= AL_AIR_ABSORPTION_FACTOR
,
660 srcRoomRolloffFactor
= AL_ROOM_ROLLOFF_FACTOR
,
661 srcDirectFilterGainHFAuto
= AL_DIRECT_FILTER_GAINHF_AUTO
,
662 srcAuxSendFilterGainAuto
= AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
,
663 srcAuxSendFilterGainHFAuto
= AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
,
664 srcDirectFilter
= AL_DIRECT_FILTER
,
665 srcAuxSendFilter
= AL_AUXILIARY_SEND_FILTER
,
667 /* AL_SOFT_direct_channels */
668 srcDirectChannelsSOFT
= AL_DIRECT_CHANNELS_SOFT
,
670 /* AL_EXT_source_distance_model */
671 srcDistanceModel
= AL_DISTANCE_MODEL
,
673 /* AL_SOFT_source_latency */
674 srcSampleOffsetLatencySOFT
= AL_SAMPLE_OFFSET_LATENCY_SOFT
,
675 srcSecOffsetLatencySOFT
= AL_SEC_OFFSET_LATENCY_SOFT
,
677 /* AL_EXT_STEREO_ANGLES */
678 srcAngles
= AL_STEREO_ANGLES
,
680 /* AL_EXT_SOURCE_RADIUS */
681 srcRadius
= AL_SOURCE_RADIUS
,
684 srcOrientation
= AL_ORIENTATION
,
686 /* AL_SOFT_source_resampler */
687 srcResampler
= AL_SOURCE_RESAMPLER_SOFT
,
689 /* AL_SOFT_source_spatialize */
690 srcSpatialize
= AL_SOURCE_SPATIALIZE_SOFT
,
692 /* ALC_SOFT_device_clock */
693 srcSampleOffsetClockSOFT
= AL_SAMPLE_OFFSET_CLOCK_SOFT
,
694 srcSecOffsetClockSOFT
= AL_SEC_OFFSET_CLOCK_SOFT
,
698 /** Can only be called while the mixer is locked! */
699 void SendStateChangeEvent(ALCcontext
*context
, ALuint id
, ALenum state
)
701 ALbitfieldSOFT enabledevt
{context
->mEnabledEvts
.load(std::memory_order_acquire
)};
702 if(!(enabledevt
&EventType_SourceStateChange
)) return;
704 /* The mixer may have queued a state change that's not yet been processed,
705 * and we don't want state change messages to occur out of order, so send
706 * it through the async queue to ensure proper ordering.
708 RingBuffer
*ring
{context
->mAsyncEvents
.get()};
709 auto evt_vec
= ring
->getWriteVector();
710 if(evt_vec
.first
.len
< 1) return;
712 AsyncEvent
*evt
{::new (evt_vec
.first
.buf
) AsyncEvent
{EventType_SourceStateChange
}};
713 evt
->u
.srcstate
.id
= id
;
714 evt
->u
.srcstate
.state
= state
;
715 ring
->writeAdvance(1);
716 context
->mEventSem
.post();
720 constexpr size_t MaxValues
{6u};
722 ALuint
FloatValsByProp(ALenum prop
)
724 switch(static_cast<SourceProp
>(prop
))
730 case AL_MAX_DISTANCE
:
731 case AL_ROLLOFF_FACTOR
:
732 case AL_DOPPLER_FACTOR
:
733 case AL_CONE_OUTER_GAIN
:
735 case AL_SAMPLE_OFFSET
:
737 case AL_CONE_INNER_ANGLE
:
738 case AL_CONE_OUTER_ANGLE
:
739 case AL_REFERENCE_DISTANCE
:
740 case AL_CONE_OUTER_GAINHF
:
741 case AL_AIR_ABSORPTION_FACTOR
:
742 case AL_ROOM_ROLLOFF_FACTOR
:
743 case AL_DIRECT_FILTER_GAINHF_AUTO
:
744 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
745 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
746 case AL_DIRECT_CHANNELS_SOFT
:
747 case AL_DISTANCE_MODEL
:
748 case AL_SOURCE_RELATIVE
:
750 case AL_SOURCE_STATE
:
751 case AL_BUFFERS_QUEUED
:
752 case AL_BUFFERS_PROCESSED
:
754 case AL_SOURCE_RADIUS
:
755 case AL_SOURCE_RESAMPLER_SOFT
:
756 case AL_SOURCE_SPATIALIZE_SOFT
:
759 case AL_STEREO_ANGLES
:
770 case AL_SEC_OFFSET_LATENCY_SOFT
:
771 case AL_SEC_OFFSET_CLOCK_SOFT
:
772 break; /* Double only */
775 case AL_DIRECT_FILTER
:
776 case AL_AUXILIARY_SEND_FILTER
:
777 break; /* i/i64 only */
778 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
779 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
780 break; /* i64 only */
784 ALuint
DoubleValsByProp(ALenum prop
)
786 switch(static_cast<SourceProp
>(prop
))
792 case AL_MAX_DISTANCE
:
793 case AL_ROLLOFF_FACTOR
:
794 case AL_DOPPLER_FACTOR
:
795 case AL_CONE_OUTER_GAIN
:
797 case AL_SAMPLE_OFFSET
:
799 case AL_CONE_INNER_ANGLE
:
800 case AL_CONE_OUTER_ANGLE
:
801 case AL_REFERENCE_DISTANCE
:
802 case AL_CONE_OUTER_GAINHF
:
803 case AL_AIR_ABSORPTION_FACTOR
:
804 case AL_ROOM_ROLLOFF_FACTOR
:
805 case AL_DIRECT_FILTER_GAINHF_AUTO
:
806 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
807 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
808 case AL_DIRECT_CHANNELS_SOFT
:
809 case AL_DISTANCE_MODEL
:
810 case AL_SOURCE_RELATIVE
:
812 case AL_SOURCE_STATE
:
813 case AL_BUFFERS_QUEUED
:
814 case AL_BUFFERS_PROCESSED
:
816 case AL_SOURCE_RADIUS
:
817 case AL_SOURCE_RESAMPLER_SOFT
:
818 case AL_SOURCE_SPATIALIZE_SOFT
:
821 case AL_SEC_OFFSET_LATENCY_SOFT
:
822 case AL_SEC_OFFSET_CLOCK_SOFT
:
823 case AL_STEREO_ANGLES
:
835 case AL_DIRECT_FILTER
:
836 case AL_AUXILIARY_SEND_FILTER
:
837 break; /* i/i64 only */
838 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
839 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
840 break; /* i64 only */
846 bool SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const al::span
<const ALfloat
> values
);
847 bool SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const al::span
<const ALint
> values
);
848 bool SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const al::span
<const ALint64SOFT
> values
);
850 #define CHECKSIZE(v, s) do { \
851 if LIKELY((v).size() == (s) || (v).size() == MaxValues) break; \
852 Context->setError(AL_INVALID_ENUM, \
853 "Property 0x%04x expects %d value(s), got %zu", prop, (s), \
857 #define CHECKVAL(x) do { \
858 if LIKELY(x) break; \
859 Context->setError(AL_INVALID_VALUE, "Value out of range"); \
863 bool UpdateSourceProps(ALsource
*source
, ALCcontext
*context
)
866 if(SourceShouldUpdate(source
, context
) && (voice
=GetSourceVoice(source
, context
)) != nullptr)
867 UpdateSourceProps(source
, voice
, context
);
869 source
->PropsClean
.clear(std::memory_order_release
);
873 bool SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const al::span
<const ALfloat
> values
)
879 case AL_SEC_OFFSET_LATENCY_SOFT
:
880 case AL_SEC_OFFSET_CLOCK_SOFT
:
882 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, false,
883 "Setting read-only source property 0x%04x", prop
);
886 CHECKSIZE(values
, 1);
887 CHECKVAL(values
[0] >= 0.0f
);
889 Source
->Pitch
= values
[0];
890 return UpdateSourceProps(Source
, Context
);
892 case AL_CONE_INNER_ANGLE
:
893 CHECKSIZE(values
, 1);
894 CHECKVAL(values
[0] >= 0.0f
&& values
[0] <= 360.0f
);
896 Source
->InnerAngle
= values
[0];
897 return UpdateSourceProps(Source
, Context
);
899 case AL_CONE_OUTER_ANGLE
:
900 CHECKSIZE(values
, 1);
901 CHECKVAL(values
[0] >= 0.0f
&& values
[0] <= 360.0f
);
903 Source
->OuterAngle
= values
[0];
904 return UpdateSourceProps(Source
, Context
);
907 CHECKSIZE(values
, 1);
908 CHECKVAL(values
[0] >= 0.0f
);
910 Source
->Gain
= values
[0];
911 return UpdateSourceProps(Source
, Context
);
913 case AL_MAX_DISTANCE
:
914 CHECKSIZE(values
, 1);
915 CHECKVAL(values
[0] >= 0.0f
);
917 Source
->MaxDistance
= values
[0];
918 return UpdateSourceProps(Source
, Context
);
920 case AL_ROLLOFF_FACTOR
:
921 CHECKSIZE(values
, 1);
922 CHECKVAL(values
[0] >= 0.0f
);
924 Source
->RolloffFactor
= values
[0];
925 return UpdateSourceProps(Source
, Context
);
927 case AL_REFERENCE_DISTANCE
:
928 CHECKSIZE(values
, 1);
929 CHECKVAL(values
[0] >= 0.0f
);
931 Source
->RefDistance
= values
[0];
932 return UpdateSourceProps(Source
, Context
);
935 CHECKSIZE(values
, 1);
936 CHECKVAL(values
[0] >= 0.0f
);
938 Source
->MinGain
= values
[0];
939 return UpdateSourceProps(Source
, Context
);
942 CHECKSIZE(values
, 1);
943 CHECKVAL(values
[0] >= 0.0f
);
945 Source
->MaxGain
= values
[0];
946 return UpdateSourceProps(Source
, Context
);
948 case AL_CONE_OUTER_GAIN
:
949 CHECKSIZE(values
, 1);
950 CHECKVAL(values
[0] >= 0.0f
&& values
[0] <= 1.0f
);
952 Source
->OuterGain
= values
[0];
953 return UpdateSourceProps(Source
, Context
);
955 case AL_CONE_OUTER_GAINHF
:
956 CHECKSIZE(values
, 1);
957 CHECKVAL(values
[0] >= 0.0f
&& values
[0] <= 1.0f
);
959 Source
->OuterGainHF
= values
[0];
960 return UpdateSourceProps(Source
, Context
);
962 case AL_AIR_ABSORPTION_FACTOR
:
963 CHECKSIZE(values
, 1);
964 CHECKVAL(values
[0] >= 0.0f
&& values
[0] <= 10.0f
);
966 Source
->AirAbsorptionFactor
= values
[0];
967 return UpdateSourceProps(Source
, Context
);
969 case AL_ROOM_ROLLOFF_FACTOR
:
970 CHECKSIZE(values
, 1);
971 CHECKVAL(values
[0] >= 0.0f
&& values
[0] <= 10.0f
);
973 Source
->RoomRolloffFactor
= values
[0];
974 return UpdateSourceProps(Source
, Context
);
976 case AL_DOPPLER_FACTOR
:
977 CHECKSIZE(values
, 1);
978 CHECKVAL(values
[0] >= 0.0f
&& values
[0] <= 1.0f
);
980 Source
->DopplerFactor
= values
[0];
981 return UpdateSourceProps(Source
, Context
);
984 case AL_SAMPLE_OFFSET
:
986 CHECKSIZE(values
, 1);
987 CHECKVAL(values
[0] >= 0.0f
);
989 Source
->OffsetType
= prop
;
990 Source
->Offset
= values
[0];
992 if(IsPlayingOrPaused(Source
))
994 ALCdevice
*device
{Context
->mDevice
.get()};
995 BackendLockGuard _
{*device
->Backend
};
996 /* Double-check that the source is still playing while we have the
999 if(ALvoice
*voice
{GetSourceVoice(Source
, Context
)})
1001 auto vpos
= GetSampleOffset(Source
);
1002 if(!vpos
) SETERR_RETURN(Context
, AL_INVALID_VALUE
, false, "Invalid offset");
1004 voice
->mPosition
.store(vpos
->pos
, std::memory_order_relaxed
);
1005 voice
->mPositionFrac
.store(vpos
->frac
, std::memory_order_relaxed
);
1006 voice
->mCurrentBuffer
.store(vpos
->bufferitem
, std::memory_order_release
);
1011 case AL_SOURCE_RADIUS
:
1012 CHECKSIZE(values
, 1);
1013 CHECKVAL(values
[0] >= 0.0f
&& std::isfinite(values
[0]));
1015 Source
->Radius
= values
[0];
1016 return UpdateSourceProps(Source
, Context
);
1018 case AL_STEREO_ANGLES
:
1019 CHECKSIZE(values
, 2);
1020 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]));
1022 Source
->StereoPan
[0] = values
[0];
1023 Source
->StereoPan
[1] = values
[1];
1024 return UpdateSourceProps(Source
, Context
);
1028 CHECKSIZE(values
, 3);
1029 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]));
1031 Source
->Position
[0] = values
[0];
1032 Source
->Position
[1] = values
[1];
1033 Source
->Position
[2] = values
[2];
1034 return UpdateSourceProps(Source
, Context
);
1037 CHECKSIZE(values
, 3);
1038 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]));
1040 Source
->Velocity
[0] = values
[0];
1041 Source
->Velocity
[1] = values
[1];
1042 Source
->Velocity
[2] = values
[2];
1043 return UpdateSourceProps(Source
, Context
);
1046 CHECKSIZE(values
, 3);
1047 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]));
1049 Source
->Direction
[0] = values
[0];
1050 Source
->Direction
[1] = values
[1];
1051 Source
->Direction
[2] = values
[2];
1052 return UpdateSourceProps(Source
, Context
);
1054 case AL_ORIENTATION
:
1055 CHECKSIZE(values
, 6);
1056 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2])
1057 && std::isfinite(values
[3]) && std::isfinite(values
[4]) && std::isfinite(values
[5]));
1059 Source
->OrientAt
[0] = values
[0];
1060 Source
->OrientAt
[1] = values
[1];
1061 Source
->OrientAt
[2] = values
[2];
1062 Source
->OrientUp
[0] = values
[3];
1063 Source
->OrientUp
[1] = values
[4];
1064 Source
->OrientUp
[2] = values
[5];
1065 return UpdateSourceProps(Source
, Context
);
1068 case AL_SOURCE_RELATIVE
:
1070 case AL_SOURCE_STATE
:
1071 case AL_SOURCE_TYPE
:
1072 case AL_DISTANCE_MODEL
:
1073 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1074 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1075 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1076 case AL_DIRECT_CHANNELS_SOFT
:
1077 case AL_SOURCE_RESAMPLER_SOFT
:
1078 case AL_SOURCE_SPATIALIZE_SOFT
:
1079 CHECKSIZE(values
, 1);
1080 ival
= static_cast<ALint
>(values
[0]);
1081 return SetSourceiv(Source
, Context
, prop
, {&ival
, 1u});
1083 case AL_BUFFERS_QUEUED
:
1084 case AL_BUFFERS_PROCESSED
:
1085 CHECKSIZE(values
, 1);
1086 ival
= static_cast<ALint
>(static_cast<ALuint
>(values
[0]));
1087 return SetSourceiv(Source
, Context
, prop
, {&ival
, 1u});
1090 case AL_DIRECT_FILTER
:
1091 case AL_AUXILIARY_SEND_FILTER
:
1092 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1093 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1097 ERR("Unexpected property: 0x%04x\n", prop
);
1098 Context
->setError(AL_INVALID_ENUM
, "Invalid source float property 0x%04x", prop
);
1102 bool SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const al::span
<const ALint
> values
)
1104 ALCdevice
*device
{Context
->mDevice
.get()};
1105 ALbuffer
*buffer
{nullptr};
1106 ALfilter
*filter
{nullptr};
1107 ALeffectslot
*slot
{nullptr};
1108 ALbufferlistitem
*oldlist
{nullptr};
1109 std::unique_lock
<std::mutex
> slotlock
;
1110 std::unique_lock
<std::mutex
> filtlock
;
1111 std::unique_lock
<std::mutex
> buflock
;
1116 case AL_SOURCE_STATE
:
1117 case AL_SOURCE_TYPE
:
1118 case AL_BUFFERS_QUEUED
:
1119 case AL_BUFFERS_PROCESSED
:
1121 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, false,
1122 "Setting read-only source property 0x%04x", prop
);
1124 case AL_SOURCE_RELATIVE
:
1125 CHECKSIZE(values
, 1);
1126 CHECKVAL(values
[0] == AL_FALSE
|| values
[0] == AL_TRUE
);
1128 Source
->HeadRelative
= values
[0] != AL_FALSE
;
1129 return UpdateSourceProps(Source
, Context
);
1132 CHECKSIZE(values
, 1);
1133 CHECKVAL(values
[0] == AL_FALSE
|| values
[0] == AL_TRUE
);
1135 Source
->Looping
= values
[0] != AL_FALSE
;
1136 if(IsPlayingOrPaused(Source
))
1138 if(ALvoice
*voice
{GetSourceVoice(Source
, Context
)})
1141 voice
->mLoopBuffer
.store(Source
->queue
, std::memory_order_release
);
1143 voice
->mLoopBuffer
.store(nullptr, std::memory_order_release
);
1145 /* If the source is playing, wait for the current mix to finish
1146 * to ensure it isn't currently looping back or reaching the
1149 while((device
->MixCount
.load(std::memory_order_acquire
)&1))
1150 std::this_thread::yield();
1156 CHECKSIZE(values
, 1);
1157 buflock
= std::unique_lock
<std::mutex
>{device
->BufferLock
};
1158 if(values
[0] && (buffer
=LookupBuffer(device
, static_cast<ALuint
>(values
[0]))) == nullptr)
1159 SETERR_RETURN(Context
, AL_INVALID_VALUE
, false, "Invalid buffer ID %u",
1160 static_cast<ALuint
>(values
[0]));
1162 if(buffer
&& buffer
->MappedAccess
!= 0 &&
1163 !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
1164 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, false,
1165 "Setting non-persistently mapped buffer %u", buffer
->id
);
1168 ALenum state
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
1169 if(state
== AL_PLAYING
|| state
== AL_PAUSED
)
1170 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, false,
1171 "Setting buffer on playing or paused source %u", Source
->id
);
1174 oldlist
= Source
->queue
;
1175 if(buffer
!= nullptr)
1177 /* Add the selected buffer to a one-item queue */
1178 auto newlist
= new ALbufferlistitem
{};
1179 newlist
->mSampleLen
= buffer
->SampleLen
;
1180 newlist
->mBuffer
= buffer
;
1181 IncrementRef(buffer
->ref
);
1183 /* Source is now Static */
1184 Source
->SourceType
= AL_STATIC
;
1185 Source
->queue
= newlist
;
1189 /* Source is now Undetermined */
1190 Source
->SourceType
= AL_UNDETERMINED
;
1191 Source
->queue
= nullptr;
1195 /* Delete all elements in the previous queue */
1196 while(oldlist
!= nullptr)
1198 std::unique_ptr
<ALbufferlistitem
> temp
{oldlist
};
1199 oldlist
= temp
->mNext
.load(std::memory_order_relaxed
);
1201 if((buffer
=temp
->mBuffer
) != nullptr)
1202 DecrementRef(buffer
->ref
);
1207 case AL_SAMPLE_OFFSET
:
1208 case AL_BYTE_OFFSET
:
1209 CHECKSIZE(values
, 1);
1210 CHECKVAL(values
[0] >= 0);
1212 Source
->OffsetType
= prop
;
1213 Source
->Offset
= values
[0];
1215 if(IsPlayingOrPaused(Source
))
1217 BackendLockGuard _
{*device
->Backend
};
1218 if(ALvoice
*voice
{GetSourceVoice(Source
, Context
)})
1220 auto vpos
= GetSampleOffset(Source
);
1221 if(!vpos
) SETERR_RETURN(Context
, AL_INVALID_VALUE
, false, "Invalid source offset");
1223 voice
->mPosition
.store(vpos
->pos
, std::memory_order_relaxed
);
1224 voice
->mPositionFrac
.store(vpos
->frac
, std::memory_order_relaxed
);
1225 voice
->mCurrentBuffer
.store(vpos
->bufferitem
, std::memory_order_release
);
1230 case AL_DIRECT_FILTER
:
1231 CHECKSIZE(values
, 1);
1232 filtlock
= std::unique_lock
<std::mutex
>{device
->FilterLock
};
1233 if(values
[0] && (filter
=LookupFilter(device
, static_cast<ALuint
>(values
[0]))) == nullptr)
1234 SETERR_RETURN(Context
, AL_INVALID_VALUE
, false, "Invalid filter ID %u",
1235 static_cast<ALuint
>(values
[0]));
1239 Source
->Direct
.Gain
= 1.0f
;
1240 Source
->Direct
.GainHF
= 1.0f
;
1241 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
1242 Source
->Direct
.GainLF
= 1.0f
;
1243 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
1247 Source
->Direct
.Gain
= filter
->Gain
;
1248 Source
->Direct
.GainHF
= filter
->GainHF
;
1249 Source
->Direct
.HFReference
= filter
->HFReference
;
1250 Source
->Direct
.GainLF
= filter
->GainLF
;
1251 Source
->Direct
.LFReference
= filter
->LFReference
;
1254 return UpdateSourceProps(Source
, Context
);
1256 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1257 CHECKSIZE(values
, 1);
1258 CHECKVAL(values
[0] == AL_FALSE
|| values
[0] == AL_TRUE
);
1260 Source
->DryGainHFAuto
= values
[0] != AL_FALSE
;
1261 return UpdateSourceProps(Source
, Context
);
1263 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1264 CHECKSIZE(values
, 1);
1265 CHECKVAL(values
[0] == AL_FALSE
|| values
[0] == AL_TRUE
);
1267 Source
->WetGainAuto
= values
[0] != AL_FALSE
;
1268 return UpdateSourceProps(Source
, Context
);
1270 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1271 CHECKSIZE(values
, 1);
1272 CHECKVAL(values
[0] == AL_FALSE
|| values
[0] == AL_TRUE
);
1274 Source
->WetGainHFAuto
= values
[0] != AL_FALSE
;
1275 return UpdateSourceProps(Source
, Context
);
1277 case AL_DIRECT_CHANNELS_SOFT
:
1278 CHECKSIZE(values
, 1);
1279 CHECKVAL(values
[0] == AL_FALSE
|| values
[0] == AL_TRUE
);
1281 Source
->DirectChannels
= values
[0] != AL_FALSE
;
1282 return UpdateSourceProps(Source
, Context
);
1284 case AL_DISTANCE_MODEL
:
1285 CHECKSIZE(values
, 1);
1286 CHECKVAL(values
[0] == AL_NONE
||
1287 values
[0] == AL_INVERSE_DISTANCE
|| values
[0] == AL_INVERSE_DISTANCE_CLAMPED
||
1288 values
[0] == AL_LINEAR_DISTANCE
|| values
[0] == AL_LINEAR_DISTANCE_CLAMPED
||
1289 values
[0] == AL_EXPONENT_DISTANCE
|| values
[0] == AL_EXPONENT_DISTANCE_CLAMPED
);
1291 Source
->mDistanceModel
= static_cast<DistanceModel
>(values
[0]);
1292 if(Context
->mSourceDistanceModel
)
1293 return UpdateSourceProps(Source
, Context
);
1296 case AL_SOURCE_RESAMPLER_SOFT
:
1297 CHECKSIZE(values
, 1);
1298 CHECKVAL(values
[0] >= 0 && values
[0] <= static_cast<int>(Resampler::Max
));
1300 Source
->mResampler
= static_cast<Resampler
>(values
[0]);
1301 return UpdateSourceProps(Source
, Context
);
1303 case AL_SOURCE_SPATIALIZE_SOFT
:
1304 CHECKSIZE(values
, 1);
1305 CHECKVAL(values
[0] >= AL_FALSE
&& values
[0] <= AL_AUTO_SOFT
);
1307 Source
->mSpatialize
= static_cast<SpatializeMode
>(values
[0]);
1308 return UpdateSourceProps(Source
, Context
);
1311 case AL_AUXILIARY_SEND_FILTER
:
1312 CHECKSIZE(values
, 3);
1313 slotlock
= std::unique_lock
<std::mutex
>{Context
->mEffectSlotLock
};
1314 if(values
[0] && (slot
=LookupEffectSlot(Context
, static_cast<ALuint
>(values
[0]))) == nullptr)
1315 SETERR_RETURN(Context
, AL_INVALID_VALUE
, false, "Invalid effect ID %u", values
[0]);
1316 if(static_cast<ALuint
>(values
[1]) >= device
->NumAuxSends
)
1317 SETERR_RETURN(Context
, AL_INVALID_VALUE
, false, "Invalid send %u", values
[1]);
1319 filtlock
= std::unique_lock
<std::mutex
>{device
->FilterLock
};
1320 if(values
[2] && (filter
=LookupFilter(device
, static_cast<ALuint
>(values
[2]))) == nullptr)
1321 SETERR_RETURN(Context
, AL_INVALID_VALUE
, false, "Invalid filter ID %u", values
[2]);
1325 /* Disable filter */
1326 auto &send
= Source
->Send
[static_cast<ALuint
>(values
[1])];
1329 send
.HFReference
= LOWPASSFREQREF
;
1331 send
.LFReference
= HIGHPASSFREQREF
;
1335 auto &send
= Source
->Send
[static_cast<ALuint
>(values
[1])];
1336 send
.Gain
= filter
->Gain
;
1337 send
.GainHF
= filter
->GainHF
;
1338 send
.HFReference
= filter
->HFReference
;
1339 send
.GainLF
= filter
->GainLF
;
1340 send
.LFReference
= filter
->LFReference
;
1344 if(slot
!= Source
->Send
[static_cast<ALuint
>(values
[1])].Slot
&& IsPlayingOrPaused(Source
))
1346 /* Add refcount on the new slot, and release the previous slot */
1347 if(slot
) IncrementRef(slot
->ref
);
1348 if(auto *oldslot
= Source
->Send
[static_cast<ALuint
>(values
[1])].Slot
)
1349 DecrementRef(oldslot
->ref
);
1350 Source
->Send
[static_cast<ALuint
>(values
[1])].Slot
= slot
;
1352 /* We must force an update if the auxiliary slot changed on an
1353 * active source, in case the slot is about to be deleted.
1355 ALvoice
*voice
{GetSourceVoice(Source
, Context
)};
1356 if(voice
) UpdateSourceProps(Source
, voice
, Context
);
1357 else Source
->PropsClean
.clear(std::memory_order_release
);
1361 if(slot
) IncrementRef(slot
->ref
);
1362 if(auto *oldslot
= Source
->Send
[static_cast<ALuint
>(values
[1])].Slot
)
1363 DecrementRef(oldslot
->ref
);
1364 Source
->Send
[static_cast<ALuint
>(values
[1])].Slot
= slot
;
1365 UpdateSourceProps(Source
, Context
);
1371 case AL_CONE_INNER_ANGLE
:
1372 case AL_CONE_OUTER_ANGLE
:
1377 case AL_REFERENCE_DISTANCE
:
1378 case AL_ROLLOFF_FACTOR
:
1379 case AL_CONE_OUTER_GAIN
:
1380 case AL_MAX_DISTANCE
:
1381 case AL_DOPPLER_FACTOR
:
1382 case AL_CONE_OUTER_GAINHF
:
1383 case AL_AIR_ABSORPTION_FACTOR
:
1384 case AL_ROOM_ROLLOFF_FACTOR
:
1385 case AL_SOURCE_RADIUS
:
1386 CHECKSIZE(values
, 1);
1387 fvals
[0] = static_cast<ALfloat
>(values
[0]);
1388 return SetSourcefv(Source
, Context
, prop
, {fvals
, 1u});
1394 CHECKSIZE(values
, 3);
1395 fvals
[0] = static_cast<ALfloat
>(values
[0]);
1396 fvals
[1] = static_cast<ALfloat
>(values
[1]);
1397 fvals
[2] = static_cast<ALfloat
>(values
[2]);
1398 return SetSourcefv(Source
, Context
, prop
, {fvals
, 3u});
1401 case AL_ORIENTATION
:
1402 CHECKSIZE(values
, 6);
1403 fvals
[0] = static_cast<ALfloat
>(values
[0]);
1404 fvals
[1] = static_cast<ALfloat
>(values
[1]);
1405 fvals
[2] = static_cast<ALfloat
>(values
[2]);
1406 fvals
[3] = static_cast<ALfloat
>(values
[3]);
1407 fvals
[4] = static_cast<ALfloat
>(values
[4]);
1408 fvals
[5] = static_cast<ALfloat
>(values
[5]);
1409 return SetSourcefv(Source
, Context
, prop
, {fvals
, 6u});
1411 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1412 case AL_SEC_OFFSET_LATENCY_SOFT
:
1413 case AL_SEC_OFFSET_CLOCK_SOFT
:
1414 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1415 case AL_STEREO_ANGLES
:
1419 ERR("Unexpected property: 0x%04x\n", prop
);
1420 Context
->setError(AL_INVALID_ENUM
, "Invalid source integer property 0x%04x", prop
);
1424 bool SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const al::span
<const ALint64SOFT
> values
)
1426 ALfloat fvals
[MaxValues
];
1427 ALint ivals
[MaxValues
];
1431 case AL_SOURCE_TYPE
:
1432 case AL_BUFFERS_QUEUED
:
1433 case AL_BUFFERS_PROCESSED
:
1434 case AL_SOURCE_STATE
:
1435 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1436 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1438 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, false,
1439 "Setting read-only source property 0x%04x", prop
);
1442 case AL_SOURCE_RELATIVE
:
1445 case AL_SAMPLE_OFFSET
:
1446 case AL_BYTE_OFFSET
:
1447 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1448 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1449 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1450 case AL_DIRECT_CHANNELS_SOFT
:
1451 case AL_DISTANCE_MODEL
:
1452 case AL_SOURCE_RESAMPLER_SOFT
:
1453 case AL_SOURCE_SPATIALIZE_SOFT
:
1454 CHECKSIZE(values
, 1);
1455 CHECKVAL(values
[0] <= INT_MAX
&& values
[0] >= INT_MIN
);
1457 ivals
[0] = static_cast<ALint
>(values
[0]);
1458 return SetSourceiv(Source
, Context
, prop
, {ivals
, 1u});
1462 case AL_DIRECT_FILTER
:
1463 CHECKSIZE(values
, 1);
1464 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0);
1466 ivals
[0] = static_cast<ALint
>(values
[0]);
1467 return SetSourceiv(Source
, Context
, prop
, {ivals
, 1u});
1470 case AL_AUXILIARY_SEND_FILTER
:
1471 CHECKSIZE(values
, 3);
1472 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 && values
[1] <= UINT_MAX
&& values
[1] >= 0
1473 && values
[2] <= UINT_MAX
&& values
[2] >= 0);
1475 ivals
[0] = static_cast<ALint
>(values
[0]);
1476 ivals
[1] = static_cast<ALint
>(values
[1]);
1477 ivals
[2] = static_cast<ALint
>(values
[2]);
1478 return SetSourceiv(Source
, Context
, prop
, {ivals
, 3u});
1481 case AL_CONE_INNER_ANGLE
:
1482 case AL_CONE_OUTER_ANGLE
:
1487 case AL_REFERENCE_DISTANCE
:
1488 case AL_ROLLOFF_FACTOR
:
1489 case AL_CONE_OUTER_GAIN
:
1490 case AL_MAX_DISTANCE
:
1491 case AL_DOPPLER_FACTOR
:
1492 case AL_CONE_OUTER_GAINHF
:
1493 case AL_AIR_ABSORPTION_FACTOR
:
1494 case AL_ROOM_ROLLOFF_FACTOR
:
1495 case AL_SOURCE_RADIUS
:
1496 CHECKSIZE(values
, 1);
1497 fvals
[0] = static_cast<ALfloat
>(values
[0]);
1498 return SetSourcefv(Source
, Context
, prop
, {fvals
, 1u});
1504 CHECKSIZE(values
, 3);
1505 fvals
[0] = static_cast<ALfloat
>(values
[0]);
1506 fvals
[1] = static_cast<ALfloat
>(values
[1]);
1507 fvals
[2] = static_cast<ALfloat
>(values
[2]);
1508 return SetSourcefv(Source
, Context
, prop
, {fvals
, 3u});
1511 case AL_ORIENTATION
:
1512 CHECKSIZE(values
, 6);
1513 fvals
[0] = static_cast<ALfloat
>(values
[0]);
1514 fvals
[1] = static_cast<ALfloat
>(values
[1]);
1515 fvals
[2] = static_cast<ALfloat
>(values
[2]);
1516 fvals
[3] = static_cast<ALfloat
>(values
[3]);
1517 fvals
[4] = static_cast<ALfloat
>(values
[4]);
1518 fvals
[5] = static_cast<ALfloat
>(values
[5]);
1519 return SetSourcefv(Source
, Context
, prop
, {fvals
, 6u});
1521 case AL_SEC_OFFSET_LATENCY_SOFT
:
1522 case AL_SEC_OFFSET_CLOCK_SOFT
:
1523 case AL_STEREO_ANGLES
:
1527 ERR("Unexpected property: 0x%04x\n", prop
);
1528 Context
->setError(AL_INVALID_ENUM
, "Invalid source integer64 property 0x%04x", prop
);
1535 bool GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const al::span
<ALdouble
> values
);
1536 bool GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const al::span
<ALint
> values
);
1537 bool GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const al::span
<ALint64SOFT
> values
);
1539 bool GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const al::span
<ALdouble
> values
)
1541 ALCdevice
*device
{Context
->mDevice
.get()};
1542 ClockLatency clocktime
;
1543 nanoseconds srcclock
;
1544 ALint ivals
[MaxValues
];
1550 CHECKSIZE(values
, 1);
1551 values
[0] = Source
->Gain
;
1555 CHECKSIZE(values
, 1);
1556 values
[0] = Source
->Pitch
;
1559 case AL_MAX_DISTANCE
:
1560 CHECKSIZE(values
, 1);
1561 values
[0] = Source
->MaxDistance
;
1564 case AL_ROLLOFF_FACTOR
:
1565 CHECKSIZE(values
, 1);
1566 values
[0] = Source
->RolloffFactor
;
1569 case AL_REFERENCE_DISTANCE
:
1570 CHECKSIZE(values
, 1);
1571 values
[0] = Source
->RefDistance
;
1574 case AL_CONE_INNER_ANGLE
:
1575 CHECKSIZE(values
, 1);
1576 values
[0] = Source
->InnerAngle
;
1579 case AL_CONE_OUTER_ANGLE
:
1580 CHECKSIZE(values
, 1);
1581 values
[0] = Source
->OuterAngle
;
1585 CHECKSIZE(values
, 1);
1586 values
[0] = Source
->MinGain
;
1590 CHECKSIZE(values
, 1);
1591 values
[0] = Source
->MaxGain
;
1594 case AL_CONE_OUTER_GAIN
:
1595 CHECKSIZE(values
, 1);
1596 values
[0] = Source
->OuterGain
;
1600 case AL_SAMPLE_OFFSET
:
1601 case AL_BYTE_OFFSET
:
1602 CHECKSIZE(values
, 1);
1603 values
[0] = GetSourceOffset(Source
, prop
, Context
);
1606 case AL_CONE_OUTER_GAINHF
:
1607 CHECKSIZE(values
, 1);
1608 values
[0] = Source
->OuterGainHF
;
1611 case AL_AIR_ABSORPTION_FACTOR
:
1612 CHECKSIZE(values
, 1);
1613 values
[0] = Source
->AirAbsorptionFactor
;
1616 case AL_ROOM_ROLLOFF_FACTOR
:
1617 CHECKSIZE(values
, 1);
1618 values
[0] = Source
->RoomRolloffFactor
;
1621 case AL_DOPPLER_FACTOR
:
1622 CHECKSIZE(values
, 1);
1623 values
[0] = Source
->DopplerFactor
;
1626 case AL_SOURCE_RADIUS
:
1627 CHECKSIZE(values
, 1);
1628 values
[0] = Source
->Radius
;
1631 case AL_STEREO_ANGLES
:
1632 CHECKSIZE(values
, 2);
1633 values
[0] = Source
->StereoPan
[0];
1634 values
[1] = Source
->StereoPan
[1];
1637 case AL_SEC_OFFSET_LATENCY_SOFT
:
1638 CHECKSIZE(values
, 2);
1639 /* Get the source offset with the clock time first. Then get the clock
1640 * time with the device latency. Order is important.
1642 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1644 std::lock_guard
<std::mutex
> _
{device
->StateLock
};
1645 clocktime
= GetClockLatency(device
);
1647 if(srcclock
== clocktime
.ClockTime
)
1648 values
[1] = static_cast<ALdouble
>(clocktime
.Latency
.count()) / 1000000000.0;
1651 /* If the clock time incremented, reduce the latency by that much
1652 * since it's that much closer to the source offset it got earlier.
1654 const nanoseconds diff
{clocktime
.ClockTime
- srcclock
};
1655 const nanoseconds latency
{clocktime
.Latency
- std::min(clocktime
.Latency
, diff
)};
1656 values
[1] = static_cast<ALdouble
>(latency
.count()) / 1000000000.0;
1660 case AL_SEC_OFFSET_CLOCK_SOFT
:
1661 CHECKSIZE(values
, 2);
1662 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1663 values
[1] = static_cast<ALdouble
>(srcclock
.count()) / 1000000000.0;
1667 CHECKSIZE(values
, 3);
1668 values
[0] = Source
->Position
[0];
1669 values
[1] = Source
->Position
[1];
1670 values
[2] = Source
->Position
[2];
1674 CHECKSIZE(values
, 3);
1675 values
[0] = Source
->Velocity
[0];
1676 values
[1] = Source
->Velocity
[1];
1677 values
[2] = Source
->Velocity
[2];
1681 CHECKSIZE(values
, 3);
1682 values
[0] = Source
->Direction
[0];
1683 values
[1] = Source
->Direction
[1];
1684 values
[2] = Source
->Direction
[2];
1687 case AL_ORIENTATION
:
1688 CHECKSIZE(values
, 6);
1689 values
[0] = Source
->OrientAt
[0];
1690 values
[1] = Source
->OrientAt
[1];
1691 values
[2] = Source
->OrientAt
[2];
1692 values
[3] = Source
->OrientUp
[0];
1693 values
[4] = Source
->OrientUp
[1];
1694 values
[5] = Source
->OrientUp
[2];
1698 case AL_SOURCE_RELATIVE
:
1700 case AL_SOURCE_STATE
:
1701 case AL_BUFFERS_QUEUED
:
1702 case AL_BUFFERS_PROCESSED
:
1703 case AL_SOURCE_TYPE
:
1704 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1705 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1706 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1707 case AL_DIRECT_CHANNELS_SOFT
:
1708 case AL_DISTANCE_MODEL
:
1709 case AL_SOURCE_RESAMPLER_SOFT
:
1710 case AL_SOURCE_SPATIALIZE_SOFT
:
1711 CHECKSIZE(values
, 1);
1712 if((err
=GetSourceiv(Source
, Context
, prop
, {ivals
, 1u})) != false)
1713 values
[0] = static_cast<ALdouble
>(ivals
[0]);
1717 case AL_DIRECT_FILTER
:
1718 case AL_AUXILIARY_SEND_FILTER
:
1719 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1720 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1724 ERR("Unexpected property: 0x%04x\n", prop
);
1725 Context
->setError(AL_INVALID_ENUM
, "Invalid source double property 0x%04x", prop
);
1729 bool GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const al::span
<ALint
> values
)
1731 ALdouble dvals
[MaxValues
];
1736 case AL_SOURCE_RELATIVE
:
1737 CHECKSIZE(values
, 1);
1738 values
[0] = Source
->HeadRelative
;
1742 CHECKSIZE(values
, 1);
1743 values
[0] = Source
->Looping
;
1747 CHECKSIZE(values
, 1);
1749 ALbufferlistitem
*BufferList
{nullptr};
1750 if(Source
->SourceType
== AL_STATIC
) BufferList
= Source
->queue
;
1751 ALbuffer
*buffer
{nullptr};
1752 if(BufferList
) buffer
= BufferList
->mBuffer
;
1753 values
[0] = buffer
? static_cast<ALint
>(buffer
->id
) : 0;
1757 case AL_SOURCE_STATE
:
1758 CHECKSIZE(values
, 1);
1759 values
[0] = GetSourceState(Source
, GetSourceVoice(Source
, Context
));
1762 case AL_BUFFERS_QUEUED
:
1763 CHECKSIZE(values
, 1);
1764 if(ALbufferlistitem
*BufferList
{Source
->queue
})
1769 BufferList
= BufferList
->mNext
.load(std::memory_order_relaxed
);
1770 } while(BufferList
!= nullptr);
1777 case AL_BUFFERS_PROCESSED
:
1778 CHECKSIZE(values
, 1);
1779 if(Source
->Looping
|| Source
->SourceType
!= AL_STREAMING
)
1781 /* Buffers on a looping source are in a perpetual state of PENDING,
1782 * so don't report any as PROCESSED
1788 const ALbufferlistitem
*BufferList
{Source
->queue
};
1789 const ALbufferlistitem
*Current
{nullptr};
1792 ALvoice
*voice
{GetSourceVoice(Source
, Context
)};
1793 if(voice
!= nullptr)
1794 Current
= voice
->mCurrentBuffer
.load(std::memory_order_relaxed
);
1795 else if(Source
->state
== AL_INITIAL
)
1796 Current
= BufferList
;
1798 while(BufferList
&& BufferList
!= Current
)
1801 BufferList
= BufferList
->mNext
.load(std::memory_order_relaxed
);
1807 case AL_SOURCE_TYPE
:
1808 CHECKSIZE(values
, 1);
1809 values
[0] = Source
->SourceType
;
1812 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1813 CHECKSIZE(values
, 1);
1814 values
[0] = Source
->DryGainHFAuto
;
1817 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1818 CHECKSIZE(values
, 1);
1819 values
[0] = Source
->WetGainAuto
;
1822 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1823 CHECKSIZE(values
, 1);
1824 values
[0] = Source
->WetGainHFAuto
;
1827 case AL_DIRECT_CHANNELS_SOFT
:
1828 CHECKSIZE(values
, 1);
1829 values
[0] = Source
->DirectChannels
;
1832 case AL_DISTANCE_MODEL
:
1833 CHECKSIZE(values
, 1);
1834 values
[0] = static_cast<int>(Source
->mDistanceModel
);
1837 case AL_SOURCE_RESAMPLER_SOFT
:
1838 CHECKSIZE(values
, 1);
1839 values
[0] = static_cast<int>(Source
->mResampler
);
1842 case AL_SOURCE_SPATIALIZE_SOFT
:
1843 CHECKSIZE(values
, 1);
1844 values
[0] = Source
->mSpatialize
;
1847 /* 1x float/double */
1848 case AL_CONE_INNER_ANGLE
:
1849 case AL_CONE_OUTER_ANGLE
:
1854 case AL_REFERENCE_DISTANCE
:
1855 case AL_ROLLOFF_FACTOR
:
1856 case AL_CONE_OUTER_GAIN
:
1857 case AL_MAX_DISTANCE
:
1859 case AL_SAMPLE_OFFSET
:
1860 case AL_BYTE_OFFSET
:
1861 case AL_DOPPLER_FACTOR
:
1862 case AL_AIR_ABSORPTION_FACTOR
:
1863 case AL_ROOM_ROLLOFF_FACTOR
:
1864 case AL_CONE_OUTER_GAINHF
:
1865 case AL_SOURCE_RADIUS
:
1866 CHECKSIZE(values
, 1);
1867 if((err
=GetSourcedv(Source
, Context
, prop
, {dvals
, 1u})) != false)
1868 values
[0] = static_cast<ALint
>(dvals
[0]);
1871 /* 3x float/double */
1875 CHECKSIZE(values
, 3);
1876 if((err
=GetSourcedv(Source
, Context
, prop
, {dvals
, 3u})) != false)
1878 values
[0] = static_cast<ALint
>(dvals
[0]);
1879 values
[1] = static_cast<ALint
>(dvals
[1]);
1880 values
[2] = static_cast<ALint
>(dvals
[2]);
1884 /* 6x float/double */
1885 case AL_ORIENTATION
:
1886 CHECKSIZE(values
, 6);
1887 if((err
=GetSourcedv(Source
, Context
, prop
, {dvals
, 6u})) != false)
1889 values
[0] = static_cast<ALint
>(dvals
[0]);
1890 values
[1] = static_cast<ALint
>(dvals
[1]);
1891 values
[2] = static_cast<ALint
>(dvals
[2]);
1892 values
[3] = static_cast<ALint
>(dvals
[3]);
1893 values
[4] = static_cast<ALint
>(dvals
[4]);
1894 values
[5] = static_cast<ALint
>(dvals
[5]);
1898 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1899 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1900 break; /* i64 only */
1901 case AL_SEC_OFFSET_LATENCY_SOFT
:
1902 case AL_SEC_OFFSET_CLOCK_SOFT
:
1903 break; /* Double only */
1904 case AL_STEREO_ANGLES
:
1905 break; /* Float/double only */
1907 case AL_DIRECT_FILTER
:
1908 case AL_AUXILIARY_SEND_FILTER
:
1912 ERR("Unexpected property: 0x%04x\n", prop
);
1913 Context
->setError(AL_INVALID_ENUM
, "Invalid source integer property 0x%04x", prop
);
1917 bool GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const al::span
<ALint64SOFT
> values
)
1919 ALCdevice
*device
= Context
->mDevice
.get();
1920 ClockLatency clocktime
;
1921 nanoseconds srcclock
;
1922 ALdouble dvals
[MaxValues
];
1923 ALint ivals
[MaxValues
];
1928 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1929 CHECKSIZE(values
, 2);
1930 /* Get the source offset with the clock time first. Then get the clock
1931 * time with the device latency. Order is important.
1933 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1935 std::lock_guard
<std::mutex
> _
{device
->StateLock
};
1936 clocktime
= GetClockLatency(device
);
1938 if(srcclock
== clocktime
.ClockTime
)
1939 values
[1] = clocktime
.Latency
.count();
1942 /* If the clock time incremented, reduce the latency by that much
1943 * since it's that much closer to the source offset it got earlier.
1945 const nanoseconds diff
{clocktime
.ClockTime
- srcclock
};
1946 values
[1] = nanoseconds
{clocktime
.Latency
- std::min(clocktime
.Latency
, diff
)}.count();
1950 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1951 CHECKSIZE(values
, 2);
1952 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1953 values
[1] = srcclock
.count();
1956 /* 1x float/double */
1957 case AL_CONE_INNER_ANGLE
:
1958 case AL_CONE_OUTER_ANGLE
:
1963 case AL_REFERENCE_DISTANCE
:
1964 case AL_ROLLOFF_FACTOR
:
1965 case AL_CONE_OUTER_GAIN
:
1966 case AL_MAX_DISTANCE
:
1968 case AL_SAMPLE_OFFSET
:
1969 case AL_BYTE_OFFSET
:
1970 case AL_DOPPLER_FACTOR
:
1971 case AL_AIR_ABSORPTION_FACTOR
:
1972 case AL_ROOM_ROLLOFF_FACTOR
:
1973 case AL_CONE_OUTER_GAINHF
:
1974 case AL_SOURCE_RADIUS
:
1975 CHECKSIZE(values
, 1);
1976 if((err
=GetSourcedv(Source
, Context
, prop
, {dvals
, 1u})) != false)
1977 values
[0] = static_cast<int64_t>(dvals
[0]);
1980 /* 3x float/double */
1984 CHECKSIZE(values
, 3);
1985 if((err
=GetSourcedv(Source
, Context
, prop
, {dvals
, 3u})) != false)
1987 values
[0] = static_cast<int64_t>(dvals
[0]);
1988 values
[1] = static_cast<int64_t>(dvals
[1]);
1989 values
[2] = static_cast<int64_t>(dvals
[2]);
1993 /* 6x float/double */
1994 case AL_ORIENTATION
:
1995 CHECKSIZE(values
, 6);
1996 if((err
=GetSourcedv(Source
, Context
, prop
, {dvals
, 6u})) != false)
1998 values
[0] = static_cast<int64_t>(dvals
[0]);
1999 values
[1] = static_cast<int64_t>(dvals
[1]);
2000 values
[2] = static_cast<int64_t>(dvals
[2]);
2001 values
[3] = static_cast<int64_t>(dvals
[3]);
2002 values
[4] = static_cast<int64_t>(dvals
[4]);
2003 values
[5] = static_cast<int64_t>(dvals
[5]);
2008 case AL_SOURCE_RELATIVE
:
2010 case AL_SOURCE_STATE
:
2011 case AL_BUFFERS_QUEUED
:
2012 case AL_BUFFERS_PROCESSED
:
2013 case AL_SOURCE_TYPE
:
2014 case AL_DIRECT_FILTER_GAINHF_AUTO
:
2015 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
2016 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
2017 case AL_DIRECT_CHANNELS_SOFT
:
2018 case AL_DISTANCE_MODEL
:
2019 case AL_SOURCE_RESAMPLER_SOFT
:
2020 case AL_SOURCE_SPATIALIZE_SOFT
:
2021 CHECKSIZE(values
, 1);
2022 if((err
=GetSourceiv(Source
, Context
, prop
, {ivals
, 1u})) != false)
2023 values
[0] = ivals
[0];
2028 case AL_DIRECT_FILTER
:
2029 CHECKSIZE(values
, 1);
2030 if((err
=GetSourceiv(Source
, Context
, prop
, {ivals
, 1u})) != false)
2031 values
[0] = static_cast<ALuint
>(ivals
[0]);
2035 case AL_AUXILIARY_SEND_FILTER
:
2036 CHECKSIZE(values
, 3);
2037 if((err
=GetSourceiv(Source
, Context
, prop
, {ivals
, 3u})) != false)
2039 values
[0] = static_cast<ALuint
>(ivals
[0]);
2040 values
[1] = static_cast<ALuint
>(ivals
[1]);
2041 values
[2] = static_cast<ALuint
>(ivals
[2]);
2045 case AL_SEC_OFFSET_LATENCY_SOFT
:
2046 case AL_SEC_OFFSET_CLOCK_SOFT
:
2047 break; /* Double only */
2048 case AL_STEREO_ANGLES
:
2049 break; /* Float/double only */
2052 ERR("Unexpected property: 0x%04x\n", prop
);
2053 Context
->setError(AL_INVALID_ENUM
, "Invalid source integer64 property 0x%04x", prop
);
2059 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
2062 ContextRef context
{GetContextRef()};
2063 if UNLIKELY(!context
) return;
2066 context
->setError(AL_INVALID_VALUE
, "Generating %d sources", n
);
2067 if UNLIKELY(n
<= 0) return;
2069 std::unique_lock
<std::mutex
> srclock
{context
->mSourceLock
};
2070 ALCdevice
*device
{context
->mDevice
.get()};
2071 if(static_cast<ALuint
>(n
) > device
->SourcesMax
-context
->mNumSources
)
2073 context
->setError(AL_OUT_OF_MEMORY
, "Exceeding %u source limit (%u + %d)",
2074 device
->SourcesMax
, context
->mNumSources
, n
);
2077 if(!EnsureSources(context
.get(), static_cast<ALuint
>(n
)))
2079 context
->setError(AL_OUT_OF_MEMORY
, "Failed to allocate %d source%s", n
, (n
==1)?"":"s");
2085 ALsource
*source
{AllocSource(context
.get(), device
->NumAuxSends
)};
2086 sources
[0] = source
->id
;
2090 const ALuint num_sends
{device
->NumAuxSends
};
2091 al::vector
<ALuint
> ids
;
2092 ids
.reserve(static_cast<ALuint
>(n
));
2094 ALsource
*source
{AllocSource(context
.get(), num_sends
)};
2095 ids
.emplace_back(source
->id
);
2097 std::copy(ids
.cbegin(), ids
.cend(), sources
);
2102 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
2105 ContextRef context
{GetContextRef()};
2106 if UNLIKELY(!context
) return;
2109 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Deleting %d sources", n
);
2111 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
2113 /* Check that all Sources are valid */
2114 auto validate_source
= [&context
](const ALuint sid
) -> bool
2115 { return LookupSource(context
.get(), sid
) != nullptr; };
2117 const ALuint
*sources_end
= sources
+ n
;
2118 auto invsrc
= std::find_if_not(sources
, sources_end
, validate_source
);
2119 if UNLIKELY(invsrc
!= sources_end
)
2121 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", *invsrc
);
2125 /* All good. Delete source IDs. */
2126 auto delete_source
= [&context
](const ALuint sid
) -> void
2128 ALsource
*src
{LookupSource(context
.get(), sid
)};
2129 if(src
) FreeSource(context
.get(), src
);
2131 std::for_each(sources
, sources_end
, delete_source
);
2135 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
2138 ContextRef context
{GetContextRef()};
2141 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
2142 if(LookupSource(context
.get(), source
) != nullptr)
2150 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
2153 ContextRef context
{GetContextRef()};
2154 if UNLIKELY(!context
) return;
2156 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
2157 std::lock_guard
<std::mutex
> __
{context
->mSourceLock
};
2158 ALsource
*Source
= LookupSource(context
.get(), source
);
2159 if UNLIKELY(!Source
)
2160 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2162 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), {&value
, 1u});
2166 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
2169 ContextRef context
{GetContextRef()};
2170 if UNLIKELY(!context
) return;
2172 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
2173 std::lock_guard
<std::mutex
> __
{context
->mSourceLock
};
2174 ALsource
*Source
= LookupSource(context
.get(), source
);
2175 if UNLIKELY(!Source
)
2176 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2179 const ALfloat fvals
[3]{ value1
, value2
, value3
};
2180 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), fvals
);
2185 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
2188 ContextRef context
{GetContextRef()};
2189 if UNLIKELY(!context
) return;
2191 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
2192 std::lock_guard
<std::mutex
> __
{context
->mSourceLock
};
2193 ALsource
*Source
= LookupSource(context
.get(), source
);
2194 if UNLIKELY(!Source
)
2195 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2196 else if UNLIKELY(!values
)
2197 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
2199 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), {values
, MaxValues
});
2204 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
2207 ContextRef context
{GetContextRef()};
2208 if UNLIKELY(!context
) return;
2210 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
2211 std::lock_guard
<std::mutex
> __
{context
->mSourceLock
};
2212 ALsource
*Source
= LookupSource(context
.get(), source
);
2213 if UNLIKELY(!Source
)
2214 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2217 const ALfloat fval
[1]{static_cast<ALfloat
>(value
)};
2218 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), fval
);
2223 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
2226 ContextRef context
{GetContextRef()};
2227 if UNLIKELY(!context
) return;
2229 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
2230 std::lock_guard
<std::mutex
> __
{context
->mSourceLock
};
2231 ALsource
*Source
= LookupSource(context
.get(), source
);
2232 if UNLIKELY(!Source
)
2233 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2236 const ALfloat fvals
[3]{static_cast<ALfloat
>(value1
), static_cast<ALfloat
>(value2
),
2237 static_cast<ALfloat
>(value3
)};
2238 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), fvals
);
2243 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
2246 ContextRef context
{GetContextRef()};
2247 if UNLIKELY(!context
) return;
2249 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
2250 std::lock_guard
<std::mutex
> __
{context
->mSourceLock
};
2251 ALsource
*Source
= LookupSource(context
.get(), source
);
2252 if UNLIKELY(!Source
)
2253 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2254 else if UNLIKELY(!values
)
2255 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
2258 const ALuint count
{DoubleValsByProp(param
)};
2259 ALfloat fvals
[MaxValues
];
2260 for(ALuint i
{0};i
< count
;i
++)
2261 fvals
[i
] = static_cast<ALfloat
>(values
[i
]);
2262 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), {fvals
, count
});
2268 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
2271 ContextRef context
{GetContextRef()};
2272 if UNLIKELY(!context
) return;
2274 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
2275 std::lock_guard
<std::mutex
> __
{context
->mSourceLock
};
2276 ALsource
*Source
= LookupSource(context
.get(), source
);
2277 if UNLIKELY(!Source
)
2278 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2280 SetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), {&value
, 1u});
2284 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
2287 ContextRef context
{GetContextRef()};
2288 if UNLIKELY(!context
) return;
2290 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
2291 std::lock_guard
<std::mutex
> __
{context
->mSourceLock
};
2292 ALsource
*Source
= LookupSource(context
.get(), source
);
2293 if UNLIKELY(!Source
)
2294 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2297 const ALint ivals
[3]{ value1
, value2
, value3
};
2298 SetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), ivals
);
2303 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
2306 ContextRef context
{GetContextRef()};
2307 if UNLIKELY(!context
) return;
2309 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
2310 std::lock_guard
<std::mutex
> __
{context
->mSourceLock
};
2311 ALsource
*Source
= LookupSource(context
.get(), source
);
2312 if UNLIKELY(!Source
)
2313 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2314 else if UNLIKELY(!values
)
2315 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
2317 SetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), {values
, MaxValues
});
2322 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
2325 ContextRef context
{GetContextRef()};
2326 if UNLIKELY(!context
) return;
2328 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
2329 std::lock_guard
<std::mutex
> __
{context
->mSourceLock
};
2330 ALsource
*Source
{LookupSource(context
.get(), source
)};
2331 if UNLIKELY(!Source
)
2332 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2334 SetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), {&value
, 1u});
2338 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
2341 ContextRef context
{GetContextRef()};
2342 if UNLIKELY(!context
) return;
2344 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
2345 std::lock_guard
<std::mutex
> __
{context
->mSourceLock
};
2346 ALsource
*Source
{LookupSource(context
.get(), source
)};
2347 if UNLIKELY(!Source
)
2348 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2351 const ALint64SOFT i64vals
[3]{ value1
, value2
, value3
};
2352 SetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), i64vals
);
2357 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
2360 ContextRef context
{GetContextRef()};
2361 if UNLIKELY(!context
) return;
2363 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
2364 std::lock_guard
<std::mutex
> __
{context
->mSourceLock
};
2365 ALsource
*Source
{LookupSource(context
.get(), source
)};
2366 if UNLIKELY(!Source
)
2367 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2368 else if UNLIKELY(!values
)
2369 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
2371 SetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), {values
, MaxValues
});
2376 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
2379 ContextRef context
{GetContextRef()};
2380 if UNLIKELY(!context
) return;
2382 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
2383 ALsource
*Source
{LookupSource(context
.get(), source
)};
2384 if UNLIKELY(!Source
)
2385 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2386 else if UNLIKELY(!value
)
2387 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
2391 if(GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), dval
))
2392 *value
= static_cast<ALfloat
>(dval
[0]);
2397 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
2400 ContextRef context
{GetContextRef()};
2401 if UNLIKELY(!context
) return;
2403 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
2404 ALsource
*Source
{LookupSource(context
.get(), source
)};
2405 if UNLIKELY(!Source
)
2406 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2407 else if UNLIKELY(!(value1
&& value2
&& value3
))
2408 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
2412 if(GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), dvals
))
2414 *value1
= static_cast<ALfloat
>(dvals
[0]);
2415 *value2
= static_cast<ALfloat
>(dvals
[1]);
2416 *value3
= static_cast<ALfloat
>(dvals
[2]);
2422 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2425 ContextRef context
{GetContextRef()};
2426 if UNLIKELY(!context
) return;
2428 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
2429 ALsource
*Source
{LookupSource(context
.get(), source
)};
2430 if UNLIKELY(!Source
)
2431 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2432 else if UNLIKELY(!values
)
2433 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
2436 const ALuint count
{FloatValsByProp(param
)};
2437 ALdouble dvals
[MaxValues
];
2438 if(GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), {dvals
, count
}))
2440 for(ALuint i
{0};i
< count
;i
++)
2441 values
[i
] = static_cast<ALfloat
>(dvals
[i
]);
2448 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2451 ContextRef context
{GetContextRef()};
2452 if UNLIKELY(!context
) return;
2454 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
2455 ALsource
*Source
{LookupSource(context
.get(), source
)};
2456 if UNLIKELY(!Source
)
2457 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2458 else if UNLIKELY(!value
)
2459 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
2461 GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), {value
, 1u});
2465 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2468 ContextRef context
{GetContextRef()};
2469 if UNLIKELY(!context
) return;
2471 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
2472 ALsource
*Source
{LookupSource(context
.get(), source
)};
2473 if UNLIKELY(!Source
)
2474 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2475 else if UNLIKELY(!(value1
&& value2
&& value3
))
2476 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
2480 if(GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), dvals
))
2490 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2493 ContextRef context
{GetContextRef()};
2494 if UNLIKELY(!context
) return;
2496 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
2497 ALsource
*Source
{LookupSource(context
.get(), source
)};
2498 if UNLIKELY(!Source
)
2499 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2500 else if UNLIKELY(!values
)
2501 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
2503 GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), {values
, MaxValues
});
2508 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2511 ContextRef context
{GetContextRef()};
2512 if UNLIKELY(!context
) return;
2514 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
2515 ALsource
*Source
{LookupSource(context
.get(), source
)};
2516 if UNLIKELY(!Source
)
2517 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2518 else if UNLIKELY(!value
)
2519 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
2521 GetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), {value
, 1u});
2525 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2528 ContextRef context
{GetContextRef()};
2529 if UNLIKELY(!context
) return;
2531 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
2532 ALsource
*Source
{LookupSource(context
.get(), source
)};
2533 if UNLIKELY(!Source
)
2534 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2535 else if UNLIKELY(!(value1
&& value2
&& value3
))
2536 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
2540 if(GetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), ivals
))
2550 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2553 ContextRef context
{GetContextRef()};
2554 if UNLIKELY(!context
) return;
2556 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
2557 ALsource
*Source
{LookupSource(context
.get(), source
)};
2558 if UNLIKELY(!Source
)
2559 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2560 else if UNLIKELY(!values
)
2561 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
2563 GetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), {values
, MaxValues
});
2568 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2571 ContextRef context
{GetContextRef()};
2572 if UNLIKELY(!context
) return;
2574 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
2575 ALsource
*Source
{LookupSource(context
.get(), source
)};
2576 if UNLIKELY(!Source
)
2577 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2578 else if UNLIKELY(!value
)
2579 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
2581 GetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), {value
, 1u});
2585 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2588 ContextRef context
{GetContextRef()};
2589 if UNLIKELY(!context
) return;
2591 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
2592 ALsource
*Source
{LookupSource(context
.get(), source
)};
2593 if UNLIKELY(!Source
)
2594 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2595 else if UNLIKELY(!(value1
&& value2
&& value3
))
2596 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
2599 ALint64SOFT i64vals
[3];
2600 if(GetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), i64vals
))
2602 *value1
= i64vals
[0];
2603 *value2
= i64vals
[1];
2604 *value3
= i64vals
[2];
2610 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2613 ContextRef context
{GetContextRef()};
2614 if UNLIKELY(!context
) return;
2616 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
2617 ALsource
*Source
{LookupSource(context
.get(), source
)};
2618 if UNLIKELY(!Source
)
2619 context
->setError(AL_INVALID_NAME
, "Invalid source ID %u", source
);
2620 else if UNLIKELY(!values
)
2621 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
2623 GetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), {values
, MaxValues
});
2628 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2630 { alSourcePlayv(1, &source
); }
2633 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2636 ContextRef context
{GetContextRef()};
2637 if UNLIKELY(!context
) return;
2640 context
->setError(AL_INVALID_VALUE
, "Playing %d sources", n
);
2641 if UNLIKELY(n
<= 0) return;
2643 al::vector
<ALsource
*> extra_sources
;
2644 std::array
<ALsource
*,8> source_storage
;
2645 al::span
<ALsource
*> srchandles
;
2646 if LIKELY(static_cast<ALuint
>(n
) <= source_storage
.size())
2647 srchandles
= {source_storage
.data(), static_cast<ALuint
>(n
)};
2650 extra_sources
.resize(static_cast<ALuint
>(n
));
2651 srchandles
= {extra_sources
.data(), extra_sources
.size()};
2654 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
2655 for(auto &srchdl
: srchandles
)
2657 srchdl
= LookupSource(context
.get(), *sources
);
2659 SETERR_RETURN(context
, AL_INVALID_NAME
,, "Invalid source ID %u", *sources
);
2663 ALCdevice
*device
{context
->mDevice
.get()};
2664 BackendLockGuard __
{*device
->Backend
};
2665 /* If the device is disconnected, go right to stopped. */
2666 if UNLIKELY(!device
->Connected
.load(std::memory_order_acquire
))
2668 /* TODO: Send state change event? */
2669 std::for_each(srchandles
.begin(), srchandles
.end(),
2670 [](ALsource
*source
) -> void
2672 source
->OffsetType
= AL_NONE
;
2673 source
->Offset
= 0.0;
2674 source
->state
= AL_STOPPED
;
2680 /* Count the number of reusable voices. */
2681 auto count_free_voices
= [](const ALuint count
, const ALvoice
&voice
) noexcept
-> ALuint
2683 if(voice
.mPlayState
.load(std::memory_order_acquire
) == ALvoice::Stopped
2684 && voice
.mSourceID
.load(std::memory_order_relaxed
) == 0u)
2688 auto free_voices
= std::accumulate(context
->mVoices
.begin(), context
->mVoices
.end(),
2689 ALuint
{0}, count_free_voices
);
2690 if UNLIKELY(srchandles
.size() > free_voices
)
2692 /* Increase the number of voices to handle the request. */
2693 const size_t need_voices
{srchandles
.size() - free_voices
};
2694 context
->mVoices
.resize(context
->mVoices
.size() + need_voices
);
2697 auto start_source
= [&context
,device
](ALsource
*source
) -> void
2699 /* Check that there is a queue containing at least one valid, non zero
2702 ALbufferlistitem
*BufferList
{source
->queue
};
2703 while(BufferList
&& BufferList
->mSampleLen
== 0)
2704 BufferList
= BufferList
->mNext
.load(std::memory_order_relaxed
);
2706 /* If there's nothing to play, go right to stopped. */
2707 if UNLIKELY(!BufferList
)
2709 /* NOTE: A source without any playable buffers should not have an
2710 * ALvoice since it shouldn't be in a playing or paused state. So
2711 * there's no need to look up its voice and clear the source.
2713 ALenum oldstate
{GetSourceState(source
, nullptr)};
2714 source
->OffsetType
= AL_NONE
;
2715 source
->Offset
= 0.0;
2716 if(oldstate
!= AL_STOPPED
)
2718 source
->state
= AL_STOPPED
;
2719 SendStateChangeEvent(context
.get(), source
->id
, AL_STOPPED
);
2724 ALvoice
*voice
{GetSourceVoice(source
, context
.get())};
2725 switch(GetSourceState(source
, voice
))
2728 assert(voice
!= nullptr);
2729 /* A source that's paused simply resumes. */
2730 voice
->mPlayState
.store(ALvoice::Playing
, std::memory_order_release
);
2731 source
->state
= AL_PLAYING
;
2732 SendStateChangeEvent(context
.get(), source
->id
, AL_PLAYING
);
2736 assert(voice
!= nullptr);
2737 /* A source that's already playing is restarted from the beginning.
2738 * Stop the current voice and start a new one so it properly cross-
2739 * fades back to the beginning.
2741 voice
->mCurrentBuffer
.store(nullptr, std::memory_order_relaxed
);
2742 voice
->mLoopBuffer
.store(nullptr, std::memory_order_relaxed
);
2743 voice
->mSourceID
.store(0u, std::memory_order_release
);
2744 voice
->mPlayState
.store(ALvoice::Stopping
, std::memory_order_release
);
2749 assert(voice
== nullptr);
2753 /* Look for an unused voice to play this source with. */
2754 auto find_voice
= [](const ALvoice
&v
) noexcept
-> bool
2756 return v
.mPlayState
.load(std::memory_order_acquire
) == ALvoice::Stopped
2757 && v
.mSourceID
.load(std::memory_order_relaxed
) == 0u;
2759 auto voices_end
= context
->mVoices
.data() + context
->mVoices
.size();
2760 voice
= std::find_if(context
->mVoices
.data(), voices_end
, find_voice
);
2761 assert(voice
!= voices_end
);
2763 auto vidx
= static_cast<ALuint
>(std::distance(context
->mVoices
.data(), voice
));
2764 voice
->mPlayState
.store(ALvoice::Stopped
, std::memory_order_release
);
2766 source
->PropsClean
.test_and_set(std::memory_order_acquire
);
2767 UpdateSourceProps(source
, voice
, context
.get());
2769 /* A source that's not playing or paused has any offset applied when it
2773 voice
->mLoopBuffer
.store(source
->queue
, std::memory_order_relaxed
);
2775 voice
->mLoopBuffer
.store(nullptr, std::memory_order_relaxed
);
2776 voice
->mCurrentBuffer
.store(BufferList
, std::memory_order_relaxed
);
2777 voice
->mPosition
.store(0u, std::memory_order_relaxed
);
2778 voice
->mPositionFrac
.store(0, std::memory_order_relaxed
);
2779 bool start_fading
{false};
2780 if(auto vpos
= GetSampleOffset(source
))
2782 start_fading
= vpos
->pos
!= 0 || vpos
->frac
!= 0 || vpos
->bufferitem
!= BufferList
;
2783 voice
->mPosition
.store(vpos
->pos
, std::memory_order_relaxed
);
2784 voice
->mPositionFrac
.store(vpos
->frac
, std::memory_order_relaxed
);
2785 voice
->mCurrentBuffer
.store(vpos
->bufferitem
, std::memory_order_relaxed
);
2788 ALbuffer
*buffer
{BufferList
->mBuffer
};
2789 voice
->mFrequency
= buffer
->Frequency
;
2790 voice
->mFmtChannels
= buffer
->mFmtChannels
;
2791 voice
->mNumChannels
= ChannelsFromFmt(buffer
->mFmtChannels
);
2792 voice
->mSampleSize
= BytesFromFmt(buffer
->mFmtType
);
2793 voice
->mAmbiLayout
= static_cast<AmbiLayout
>(buffer
->AmbiLayout
);
2794 voice
->mAmbiScaling
= static_cast<AmbiNorm
>(buffer
->AmbiScaling
);
2795 voice
->mAmbiOrder
= 1;
2797 /* Clear the stepping value so the mixer knows not to mix this until
2798 * the update gets applied.
2802 voice
->mFlags
= start_fading
? VOICE_IS_FADING
: 0;
2803 if(source
->SourceType
== AL_STATIC
) voice
->mFlags
|= VOICE_IS_STATIC
;
2805 /* Don't need to set the VOICE_IS_AMBISONIC flag if the device is not
2806 * higher order than the voice. No HF scaling is necessary to mix it.
2808 if((voice
->mFmtChannels
== FmtBFormat2D
|| voice
->mFmtChannels
== FmtBFormat3D
)
2809 && device
->mAmbiOrder
> voice
->mAmbiOrder
)
2811 const ALuint
*OrderFromChan
;
2812 if(voice
->mFmtChannels
== FmtBFormat2D
)
2814 static const ALuint Order2DFromChan
[MAX_AMBI2D_CHANNELS
]{
2816 OrderFromChan
= Order2DFromChan
;
2820 static const ALuint Order3DFromChan
[MAX_AMBI_CHANNELS
]{
2821 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3,};
2822 OrderFromChan
= Order3DFromChan
;
2825 const BandSplitter splitter
{400.0f
/ static_cast<float>(device
->Frequency
)};
2827 const auto scales
= BFormatDec::GetHFOrderScales(voice
->mAmbiOrder
,
2828 device
->mAmbiOrder
);
2829 auto init_ambi
= [device
,&scales
,&OrderFromChan
,splitter
](ALvoice::ChannelData
&chandata
) -> void
2831 chandata
.mPrevSamples
.fill(0.0f
);
2832 chandata
.mAmbiScale
= scales
[*(OrderFromChan
++)];
2833 chandata
.mAmbiSplitter
= splitter
;
2834 chandata
.mDryParams
= DirectParams
{};
2835 std::fill_n(chandata
.mWetParams
.begin(), device
->NumAuxSends
, SendParams
{});
2837 std::for_each(voice
->mChans
.begin(), voice
->mChans
.begin()+voice
->mNumChannels
,
2840 voice
->mFlags
|= VOICE_IS_AMBISONIC
;
2844 /* Clear previous samples. */
2845 auto clear_prevs
= [device
](ALvoice::ChannelData
&chandata
) -> void
2847 chandata
.mPrevSamples
.fill(0.0f
);
2848 chandata
.mDryParams
= DirectParams
{};
2849 std::fill_n(chandata
.mWetParams
.begin(), device
->NumAuxSends
, SendParams
{});
2851 std::for_each(voice
->mChans
.begin(), voice
->mChans
.begin()+voice
->mNumChannels
,
2855 if(device
->AvgSpeakerDist
> 0.0f
)
2857 const ALfloat w1
{SPEEDOFSOUNDMETRESPERSEC
/
2858 (device
->AvgSpeakerDist
* static_cast<float>(device
->Frequency
))};
2859 auto init_nfc
= [w1
](ALvoice::ChannelData
&chandata
) -> void
2860 { chandata
.mDryParams
.NFCtrlFilter
.init(w1
); };
2861 std::for_each(voice
->mChans
.begin(), voice
->mChans
.begin()+voice
->mNumChannels
,
2865 voice
->mSourceID
.store(source
->id
, std::memory_order_relaxed
);
2866 voice
->mPlayState
.store(ALvoice::Playing
, std::memory_order_release
);
2867 source
->VoiceIdx
= vidx
;
2869 if(source
->state
!= AL_PLAYING
)
2871 source
->state
= AL_PLAYING
;
2872 SendStateChangeEvent(context
.get(), source
->id
, AL_PLAYING
);
2875 std::for_each(srchandles
.begin(), srchandles
.end(), start_source
);
2880 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2882 { alSourcePausev(1, &source
); }
2885 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2888 ContextRef context
{GetContextRef()};
2889 if UNLIKELY(!context
) return;
2892 context
->setError(AL_INVALID_VALUE
, "Pausing %d sources", n
);
2893 if UNLIKELY(n
<= 0) return;
2895 al::vector
<ALsource
*> extra_sources
;
2896 std::array
<ALsource
*,8> source_storage
;
2897 al::span
<ALsource
*> srchandles
;
2898 if LIKELY(static_cast<ALuint
>(n
) <= source_storage
.size())
2899 srchandles
= {source_storage
.data(), static_cast<ALuint
>(n
)};
2902 extra_sources
.resize(static_cast<ALuint
>(n
));
2903 srchandles
= {extra_sources
.data(), extra_sources
.size()};
2906 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
2907 for(auto &srchdl
: srchandles
)
2909 srchdl
= LookupSource(context
.get(), *sources
);
2911 SETERR_RETURN(context
, AL_INVALID_NAME
,, "Invalid source ID %u", *sources
);
2915 ALCdevice
*device
{context
->mDevice
.get()};
2916 BackendLockGuard __
{*device
->Backend
};
2917 auto pause_source
= [&context
](ALsource
*source
) -> void
2919 ALvoice
*voice
{GetSourceVoice(source
, context
.get())};
2922 std::atomic_thread_fence(std::memory_order_release
);
2923 ALvoice::State oldvstate
{ALvoice::Playing
};
2924 voice
->mPlayState
.compare_exchange_strong(oldvstate
, ALvoice::Stopping
,
2925 std::memory_order_acq_rel
, std::memory_order_acquire
);
2927 if(GetSourceState(source
, voice
) == AL_PLAYING
)
2929 source
->state
= AL_PAUSED
;
2930 SendStateChangeEvent(context
.get(), source
->id
, AL_PAUSED
);
2933 std::for_each(srchandles
.begin(), srchandles
.end(), pause_source
);
2938 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2940 { alSourceStopv(1, &source
); }
2943 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2946 ContextRef context
{GetContextRef()};
2947 if UNLIKELY(!context
) return;
2950 context
->setError(AL_INVALID_VALUE
, "Stopping %d sources", n
);
2951 if UNLIKELY(n
<= 0) return;
2953 al::vector
<ALsource
*> extra_sources
;
2954 std::array
<ALsource
*,8> source_storage
;
2955 al::span
<ALsource
*> srchandles
;
2956 if LIKELY(static_cast<ALuint
>(n
) <= source_storage
.size())
2957 srchandles
= {source_storage
.data(), static_cast<ALuint
>(n
)};
2960 extra_sources
.resize(static_cast<ALuint
>(n
));
2961 srchandles
= {extra_sources
.data(), extra_sources
.size()};
2964 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
2965 for(auto &srchdl
: srchandles
)
2967 srchdl
= LookupSource(context
.get(), *sources
);
2969 SETERR_RETURN(context
, AL_INVALID_NAME
,, "Invalid source ID %u", *sources
);
2973 ALCdevice
*device
{context
->mDevice
.get()};
2974 BackendLockGuard __
{*device
->Backend
};
2975 auto stop_source
= [&context
](ALsource
*source
) -> void
2977 /* Get the source state before clearing from the voice, so we know what
2978 * state the source+voice was actually in.
2980 ALvoice
*voice
{GetSourceVoice(source
, context
.get())};
2981 const ALenum oldstate
{GetSourceState(source
, voice
)};
2982 if(voice
!= nullptr)
2984 voice
->mCurrentBuffer
.store(nullptr, std::memory_order_relaxed
);
2985 voice
->mLoopBuffer
.store(nullptr, std::memory_order_relaxed
);
2986 voice
->mSourceID
.store(0u, std::memory_order_relaxed
);
2987 std::atomic_thread_fence(std::memory_order_release
);
2988 ALvoice::State oldvstate
{ALvoice::Playing
};
2989 voice
->mPlayState
.compare_exchange_strong(oldvstate
, ALvoice::Stopping
,
2990 std::memory_order_acq_rel
, std::memory_order_acquire
);
2993 if(oldstate
!= AL_INITIAL
&& oldstate
!= AL_STOPPED
)
2995 source
->state
= AL_STOPPED
;
2996 SendStateChangeEvent(context
.get(), source
->id
, AL_STOPPED
);
2998 source
->OffsetType
= AL_NONE
;
2999 source
->Offset
= 0.0;
3001 std::for_each(srchandles
.begin(), srchandles
.end(), stop_source
);
3006 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
3008 { alSourceRewindv(1, &source
); }
3011 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
3014 ContextRef context
{GetContextRef()};
3015 if UNLIKELY(!context
) return;
3018 context
->setError(AL_INVALID_VALUE
, "Rewinding %d sources", n
);
3019 if UNLIKELY(n
<= 0) return;
3021 al::vector
<ALsource
*> extra_sources
;
3022 std::array
<ALsource
*,8> source_storage
;
3023 al::span
<ALsource
*> srchandles
;
3024 if LIKELY(static_cast<ALuint
>(n
) <= source_storage
.size())
3025 srchandles
= {source_storage
.data(), static_cast<ALuint
>(n
)};
3028 extra_sources
.resize(static_cast<ALuint
>(n
));
3029 srchandles
= {extra_sources
.data(), extra_sources
.size()};
3032 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
3033 for(auto &srchdl
: srchandles
)
3035 srchdl
= LookupSource(context
.get(), *sources
);
3037 SETERR_RETURN(context
, AL_INVALID_NAME
,, "Invalid source ID %u", *sources
);
3041 ALCdevice
*device
{context
->mDevice
.get()};
3042 BackendLockGuard __
{*device
->Backend
};
3043 auto rewind_source
= [&context
](ALsource
*source
) -> void
3045 ALvoice
*voice
{GetSourceVoice(source
, context
.get())};
3046 if(voice
!= nullptr)
3048 voice
->mCurrentBuffer
.store(nullptr, std::memory_order_relaxed
);
3049 voice
->mLoopBuffer
.store(nullptr, std::memory_order_relaxed
);
3050 voice
->mSourceID
.store(0u, std::memory_order_relaxed
);
3051 std::atomic_thread_fence(std::memory_order_release
);
3052 ALvoice::State oldvstate
{ALvoice::Playing
};
3053 voice
->mPlayState
.compare_exchange_strong(oldvstate
, ALvoice::Stopping
,
3054 std::memory_order_acq_rel
, std::memory_order_acquire
);
3057 if(source
->state
!= AL_INITIAL
)
3059 source
->state
= AL_INITIAL
;
3060 SendStateChangeEvent(context
.get(), source
->id
, AL_INITIAL
);
3062 source
->OffsetType
= AL_NONE
;
3063 source
->Offset
= 0.0;
3065 std::for_each(srchandles
.begin(), srchandles
.end(), rewind_source
);
3070 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
3073 ContextRef context
{GetContextRef()};
3074 if UNLIKELY(!context
) return;
3077 context
->setError(AL_INVALID_VALUE
, "Queueing %d buffers", nb
);
3078 if UNLIKELY(nb
<= 0) return;
3080 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
3081 ALsource
*source
{LookupSource(context
.get(),src
)};
3082 if UNLIKELY(!source
)
3083 SETERR_RETURN(context
, AL_INVALID_NAME
,, "Invalid source ID %u", src
);
3085 /* Can't queue on a Static Source */
3086 if UNLIKELY(source
->SourceType
== AL_STATIC
)
3087 SETERR_RETURN(context
, AL_INVALID_OPERATION
,, "Queueing onto static source %u", src
);
3089 /* Check for a valid Buffer, for its frequency and format */
3090 ALCdevice
*device
{context
->mDevice
.get()};
3091 ALbuffer
*BufferFmt
{nullptr};
3092 ALbufferlistitem
*BufferList
{source
->queue
};
3093 while(BufferList
&& !BufferFmt
)
3095 BufferFmt
= BufferList
->mBuffer
;
3096 BufferList
= BufferList
->mNext
.load(std::memory_order_relaxed
);
3099 std::unique_lock
<std::mutex
> buflock
{device
->BufferLock
};
3100 ALbufferlistitem
*BufferListStart
{nullptr};
3101 BufferList
= nullptr;
3102 for(ALsizei i
{0};i
< nb
;i
++)
3104 ALbuffer
*buffer
{nullptr};
3105 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == nullptr)
3107 context
->setError(AL_INVALID_NAME
, "Queueing invalid buffer ID %u", buffers
[i
]);
3111 if(!BufferListStart
)
3113 BufferListStart
= new ALbufferlistitem
{};
3114 BufferList
= BufferListStart
;
3118 auto item
= new ALbufferlistitem
{};
3119 BufferList
->mNext
.store(item
, std::memory_order_relaxed
);
3122 BufferList
->mNext
.store(nullptr, std::memory_order_relaxed
);
3123 BufferList
->mSampleLen
= buffer
? buffer
->SampleLen
: 0;
3124 BufferList
->mBuffer
= buffer
;
3125 if(!buffer
) continue;
3127 IncrementRef(buffer
->ref
);
3129 if(buffer
->MappedAccess
!= 0 && !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
3131 context
->setError(AL_INVALID_OPERATION
, "Queueing non-persistently mapped buffer %u",
3136 if(BufferFmt
== nullptr)
3138 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
3139 BufferFmt
->mFmtChannels
!= buffer
->mFmtChannels
||
3140 ((BufferFmt
->mFmtChannels
== FmtBFormat2D
||
3141 BufferFmt
->mFmtChannels
== FmtBFormat3D
) &&
3142 (BufferFmt
->AmbiLayout
!= buffer
->AmbiLayout
||
3143 BufferFmt
->AmbiScaling
!= buffer
->AmbiScaling
)) ||
3144 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
3146 context
->setError(AL_INVALID_OPERATION
, "Queueing buffer with mismatched format");
3149 /* A buffer failed (invalid ID or format), so unlock and release
3150 * each buffer we had. */
3151 while(BufferListStart
)
3153 std::unique_ptr
<ALbufferlistitem
> head
{BufferListStart
};
3154 BufferListStart
= head
->mNext
.load(std::memory_order_relaxed
);
3155 if((buffer
=head
->mBuffer
) != nullptr) DecrementRef(buffer
->ref
);
3160 /* All buffers good. */
3163 /* Source is now streaming */
3164 source
->SourceType
= AL_STREAMING
;
3166 BufferList
= source
->queue
;
3168 source
->queue
= BufferListStart
;
3171 ALbufferlistitem
*next
;
3172 while((next
=BufferList
->mNext
.load(std::memory_order_relaxed
)) != nullptr)
3174 BufferList
->mNext
.store(BufferListStart
, std::memory_order_release
);
3179 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
3182 ContextRef context
{GetContextRef()};
3183 if UNLIKELY(!context
) return;
3186 context
->setError(AL_INVALID_VALUE
, "Unqueueing %d buffers", nb
);
3187 if UNLIKELY(nb
<= 0) return;
3189 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
3190 ALsource
*source
{LookupSource(context
.get(),src
)};
3191 if UNLIKELY(!source
)
3192 SETERR_RETURN(context
, AL_INVALID_NAME
,, "Invalid source ID %u", src
);
3194 if UNLIKELY(source
->Looping
)
3195 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Unqueueing from looping source %u", src
);
3196 if UNLIKELY(source
->SourceType
!= AL_STREAMING
)
3197 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Unqueueing from a non-streaming source %u",
3200 /* Make sure enough buffers have been processed to unqueue. */
3201 ALbufferlistitem
*BufferList
{source
->queue
};
3202 ALvoice
*voice
{GetSourceVoice(source
, context
.get())};
3203 ALbufferlistitem
*Current
{nullptr};
3205 Current
= voice
->mCurrentBuffer
.load(std::memory_order_relaxed
);
3206 else if(source
->state
== AL_INITIAL
)
3207 Current
= BufferList
;
3208 if UNLIKELY(BufferList
== Current
)
3209 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Unqueueing pending buffers");
3212 while(i
< static_cast<ALuint
>(nb
))
3214 /* If the next bufferlist to check is NULL or is the current one, it's
3215 * trying to unqueue pending buffers.
3217 ALbufferlistitem
*next
{BufferList
->mNext
.load(std::memory_order_relaxed
)};
3218 if UNLIKELY(!next
|| next
== Current
)
3219 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Unqueueing pending buffers");
3226 std::unique_ptr
<ALbufferlistitem
> head
{source
->queue
};
3227 source
->queue
= head
->mNext
.load(std::memory_order_relaxed
);
3229 if(ALbuffer
*buffer
{head
->mBuffer
})
3231 *(buffers
++) = buffer
->id
;
3232 DecrementRef(buffer
->ref
);
3241 ALsource::ALsource(ALuint num_sends
)
3243 InnerAngle
= 360.0f
;
3244 OuterAngle
= 360.0f
;
3252 Direction
[0] = 0.0f
;
3253 Direction
[1] = 0.0f
;
3254 Direction
[2] = 0.0f
;
3257 OrientAt
[2] = -1.0f
;
3262 MaxDistance
= std::numeric_limits
<float>::max();
3263 RolloffFactor
= 1.0f
;
3270 DryGainHFAuto
= AL_TRUE
;
3271 WetGainAuto
= AL_TRUE
;
3272 WetGainHFAuto
= AL_TRUE
;
3273 AirAbsorptionFactor
= 0.0f
;
3274 RoomRolloffFactor
= 0.0f
;
3275 DopplerFactor
= 1.0f
;
3276 HeadRelative
= AL_FALSE
;
3278 mDistanceModel
= DistanceModel::Default
;
3279 mResampler
= ResamplerDefault
;
3280 DirectChannels
= AL_FALSE
;
3281 mSpatialize
= SpatializeAuto
;
3283 StereoPan
[0] = Deg2Rad( 30.0f
);
3284 StereoPan
[1] = Deg2Rad(-30.0f
);
3289 Direct
.GainHF
= 1.0f
;
3290 Direct
.HFReference
= LOWPASSFREQREF
;
3291 Direct
.GainLF
= 1.0f
;
3292 Direct
.LFReference
= HIGHPASSFREQREF
;
3293 Send
.resize(num_sends
);
3294 for(auto &send
: Send
)
3296 send
.Slot
= nullptr;
3299 send
.HFReference
= LOWPASSFREQREF
;
3301 send
.LFReference
= HIGHPASSFREQREF
;
3304 PropsClean
.test_and_set(std::memory_order_relaxed
);
3307 ALsource::~ALsource()
3309 ALbufferlistitem
*BufferList
{queue
};
3310 while(BufferList
!= nullptr)
3312 std::unique_ptr
<ALbufferlistitem
> head
{BufferList
};
3313 BufferList
= head
->mNext
.load(std::memory_order_relaxed
);
3314 if(ALbuffer
*buffer
{head
->mBuffer
}) DecrementRef(buffer
->ref
);
3318 std::for_each(Send
.begin(), Send
.end(),
3319 [](ALsource::SendData
&send
) -> void
3322 DecrementRef(send
.Slot
->ref
);
3323 send
.Slot
= nullptr;
3328 void UpdateAllSourceProps(ALCcontext
*context
)
3330 std::lock_guard
<std::mutex
> _
{context
->mSourceLock
};
3331 std::for_each(context
->mVoices
.begin(), context
->mVoices
.end(),
3332 [context
](ALvoice
&voice
) -> void
3334 ALuint sid
{voice
.mSourceID
.load(std::memory_order_acquire
)};
3335 ALsource
*source
= sid
? LookupSource(context
, sid
) : nullptr;
3336 if(source
&& !source
->PropsClean
.test_and_set(std::memory_order_acq_rel
))
3337 UpdateSourceProps(source
, &voice
, context
);
3342 SourceSubList::~SourceSubList()
3344 uint64_t usemask
{~FreeMask
};
3347 ALsizei idx
{CTZ64(usemask
)};
3348 al::destroy_at(Sources
+idx
);
3349 usemask
&= ~(1_u64
<< idx
);
3351 FreeMask
= ~usemask
;