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
37 #include "alcontext.h"
42 #include "alAuxEffectSlot.h"
43 #include "ringbuffer.h"
45 #include "backends/base.h"
53 using namespace std::placeholders
;
55 inline ALvoice
*GetSourceVoice(ALsource
*source
, ALCcontext
*context
)
57 ALint idx
{source
->VoiceIdx
};
58 if(idx
>= 0 && idx
< context
->VoiceCount
.load(std::memory_order_relaxed
))
60 ALuint sid
{source
->id
};
61 ALvoice
*voice
{context
->Voices
[idx
]};
62 if(voice
->SourceID
.load(std::memory_order_acquire
) == sid
)
65 source
->VoiceIdx
= -1;
69 void UpdateSourceProps(const ALsource
*source
, ALvoice
*voice
, ALCcontext
*context
)
71 /* Get an unused property container, or allocate a new one as needed. */
72 ALvoiceProps
*props
{context
->FreeVoiceProps
.load(std::memory_order_acquire
)};
74 props
= new ALvoiceProps
{};
79 next
= props
->next
.load(std::memory_order_relaxed
);
80 } while(context
->FreeVoiceProps
.compare_exchange_weak(props
, next
,
81 std::memory_order_acq_rel
, std::memory_order_acquire
) == 0);
84 /* Copy in current property values. */
85 props
->Pitch
= source
->Pitch
;
86 props
->Gain
= source
->Gain
;
87 props
->OuterGain
= source
->OuterGain
;
88 props
->MinGain
= source
->MinGain
;
89 props
->MaxGain
= source
->MaxGain
;
90 props
->InnerAngle
= source
->InnerAngle
;
91 props
->OuterAngle
= source
->OuterAngle
;
92 props
->RefDistance
= source
->RefDistance
;
93 props
->MaxDistance
= source
->MaxDistance
;
94 props
->RolloffFactor
= source
->RolloffFactor
;
95 props
->Position
= source
->Position
;
96 props
->Velocity
= source
->Velocity
;
97 props
->Direction
= source
->Direction
;
98 props
->OrientAt
= source
->OrientAt
;
99 props
->OrientUp
= source
->OrientUp
;
100 props
->HeadRelative
= source
->HeadRelative
;
101 props
->mDistanceModel
= source
->mDistanceModel
;
102 props
->mResampler
= source
->mResampler
;
103 props
->DirectChannels
= source
->DirectChannels
;
104 props
->mSpatializeMode
= source
->mSpatialize
;
106 props
->DryGainHFAuto
= source
->DryGainHFAuto
;
107 props
->WetGainAuto
= source
->WetGainAuto
;
108 props
->WetGainHFAuto
= source
->WetGainHFAuto
;
109 props
->OuterGainHF
= source
->OuterGainHF
;
111 props
->AirAbsorptionFactor
= source
->AirAbsorptionFactor
;
112 props
->RoomRolloffFactor
= source
->RoomRolloffFactor
;
113 props
->DopplerFactor
= source
->DopplerFactor
;
115 props
->StereoPan
= source
->StereoPan
;
117 props
->Radius
= source
->Radius
;
119 props
->Direct
.Gain
= source
->Direct
.Gain
;
120 props
->Direct
.GainHF
= source
->Direct
.GainHF
;
121 props
->Direct
.HFReference
= source
->Direct
.HFReference
;
122 props
->Direct
.GainLF
= source
->Direct
.GainLF
;
123 props
->Direct
.LFReference
= source
->Direct
.LFReference
;
125 auto copy_send
= [](const ALsource::SendData
&srcsend
) noexcept
-> ALvoicePropsBase::SendData
127 ALvoicePropsBase::SendData ret
;
128 ret
.Slot
= srcsend
.Slot
;
129 ret
.Gain
= srcsend
.Gain
;
130 ret
.GainHF
= srcsend
.GainHF
;
131 ret
.HFReference
= srcsend
.HFReference
;
132 ret
.GainLF
= srcsend
.GainLF
;
133 ret
.LFReference
= srcsend
.LFReference
;
136 std::transform(source
->Send
.cbegin(), source
->Send
.cend(), props
->Send
, copy_send
);
138 /* Set the new container for updating internal parameters. */
139 props
= voice
->Update
.exchange(props
, std::memory_order_acq_rel
);
142 /* If there was an unused update container, put it back in the
145 AtomicReplaceHead(context
->FreeVoiceProps
, props
);
150 /* GetSourceSampleOffset
152 * Gets the current read offset for the given Source, in 32.32 fixed-point
153 * samples. The offset is relative to the start of the queue (not the start of
154 * the current buffer).
156 ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, std::chrono::nanoseconds
*clocktime
)
158 ALCdevice
*device
{context
->Device
};
159 const ALbufferlistitem
*Current
;
167 while(((refcount
=device
->MixCount
.load(std::memory_order_acquire
))&1))
168 std::this_thread::yield();
169 *clocktime
= GetDeviceClockTime(device
);
171 voice
= GetSourceVoice(Source
, context
);
174 Current
= voice
->current_buffer
.load(std::memory_order_relaxed
);
176 readPos
= static_cast<ALuint64
>(voice
->position
.load(std::memory_order_relaxed
)) << 32;
177 readPos
|= static_cast<ALuint64
>(voice
->position_fraction
.load(std::memory_order_relaxed
)) <<
180 std::atomic_thread_fence(std::memory_order_acquire
);
181 } while(refcount
!= device
->MixCount
.load(std::memory_order_relaxed
));
185 const ALbufferlistitem
*BufferList
{Source
->queue
};
186 while(BufferList
&& BufferList
!= Current
)
188 readPos
+= static_cast<ALuint64
>(BufferList
->max_samples
) << 32;
189 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
191 readPos
= minu64(readPos
, 0x7fffffffffffffff_u
64);
194 return static_cast<ALint64
>(readPos
);
197 /* GetSourceSecOffset
199 * Gets the current read offset for the given Source, in seconds. The offset is
200 * relative to the start of the queue (not the start of the current buffer).
202 ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, std::chrono::nanoseconds
*clocktime
)
204 ALCdevice
*device
{context
->Device
};
205 const ALbufferlistitem
*Current
;
213 while(((refcount
=device
->MixCount
.load(std::memory_order_acquire
))&1))
214 std::this_thread::yield();
215 *clocktime
= GetDeviceClockTime(device
);
217 voice
= GetSourceVoice(Source
, context
);
220 Current
= voice
->current_buffer
.load(std::memory_order_relaxed
);
222 readPos
= static_cast<ALuint64
>(voice
->position
.load(std::memory_order_relaxed
)) << FRACTIONBITS
;
223 readPos
|= voice
->position_fraction
.load(std::memory_order_relaxed
);
225 std::atomic_thread_fence(std::memory_order_acquire
);
226 } while(refcount
!= device
->MixCount
.load(std::memory_order_relaxed
));
228 ALdouble offset
{0.0};
231 const ALbufferlistitem
*BufferList
{Source
->queue
};
232 const ALbuffer
*BufferFmt
{nullptr};
233 while(BufferList
&& BufferList
!= Current
)
235 for(ALsizei i
{0};!BufferFmt
&& i
< BufferList
->num_buffers
;++i
)
236 BufferFmt
= BufferList
->buffers
[i
];
237 readPos
+= static_cast<ALuint64
>(BufferList
->max_samples
) << FRACTIONBITS
;
238 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
241 while(BufferList
&& !BufferFmt
)
243 for(ALsizei i
{0};!BufferFmt
&& i
< BufferList
->num_buffers
;++i
)
244 BufferFmt
= BufferList
->buffers
[i
];
245 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
247 assert(BufferFmt
!= nullptr);
249 offset
= static_cast<ALdouble
>(readPos
) / static_cast<ALdouble
>FRACTIONONE
/
250 static_cast<ALdouble
>(BufferFmt
->Frequency
);
258 * Gets the current read offset for the given Source, in the appropriate format
259 * (Bytes, Samples or Seconds). The offset is relative to the start of the
260 * queue (not the start of the current buffer).
262 ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
)
264 ALCdevice
*device
{context
->Device
};
265 const ALbufferlistitem
*Current
;
273 readPos
= readPosFrac
= 0;
274 while(((refcount
=device
->MixCount
.load(std::memory_order_acquire
))&1))
275 std::this_thread::yield();
276 voice
= GetSourceVoice(Source
, context
);
279 Current
= voice
->current_buffer
.load(std::memory_order_relaxed
);
281 readPos
= voice
->position
.load(std::memory_order_relaxed
);
282 readPosFrac
= voice
->position_fraction
.load(std::memory_order_relaxed
);
284 std::atomic_thread_fence(std::memory_order_acquire
);
285 } while(refcount
!= device
->MixCount
.load(std::memory_order_relaxed
));
287 ALdouble offset
{0.0};
290 const ALbufferlistitem
*BufferList
{Source
->queue
};
291 const ALbuffer
*BufferFmt
{nullptr};
292 ALboolean readFin
{AL_FALSE
};
293 ALuint totalBufferLen
{0u};
297 for(ALsizei i
{0};!BufferFmt
&& i
< BufferList
->num_buffers
;++i
)
298 BufferFmt
= BufferList
->buffers
[i
];
300 readFin
|= (BufferList
== Current
);
301 totalBufferLen
+= BufferList
->max_samples
;
302 if(!readFin
) readPos
+= BufferList
->max_samples
;
304 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
306 assert(BufferFmt
!= nullptr);
309 readPos
%= totalBufferLen
;
313 if(readPos
>= totalBufferLen
)
314 readPos
= readPosFrac
= 0;
321 offset
= (readPos
+ static_cast<ALdouble
>(readPosFrac
)/FRACTIONONE
) / BufferFmt
->Frequency
;
324 case AL_SAMPLE_OFFSET
:
325 offset
= readPos
+ static_cast<ALdouble
>(readPosFrac
)/FRACTIONONE
;
329 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
331 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
332 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->mFmtChannels
);
333 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
335 /* Round down to nearest ADPCM block */
336 offset
= static_cast<ALdouble
>(readPos
/ FrameBlockSize
* BlockSize
);
338 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
340 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
341 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->mFmtChannels
);
342 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
344 /* Round down to nearest ADPCM block */
345 offset
= static_cast<ALdouble
>(readPos
/ FrameBlockSize
* BlockSize
);
349 const ALsizei FrameSize
{FrameSizeFromFmt(BufferFmt
->mFmtChannels
,
350 BufferFmt
->mFmtType
)};
351 offset
= static_cast<ALdouble
>(readPos
* FrameSize
);
363 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
364 * or Second offset supplied by the application). This takes into account the
365 * fact that the buffer format may have been modifed since.
367 ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALsizei
*frac
)
369 const ALbuffer
*BufferFmt
{nullptr};
370 const ALbufferlistitem
*BufferList
;
372 /* Find the first valid Buffer in the Queue */
373 BufferList
= Source
->queue
;
376 for(ALsizei i
{0};i
< BufferList
->num_buffers
&& !BufferFmt
;i
++)
377 BufferFmt
= BufferList
->buffers
[i
];
379 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
383 Source
->OffsetType
= AL_NONE
;
384 Source
->Offset
= 0.0;
388 ALdouble dbloff
, dblfrac
;
389 switch(Source
->OffsetType
)
392 /* Determine the ByteOffset (and ensure it is block aligned) */
393 *offset
= static_cast<ALuint
>(Source
->Offset
);
394 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
396 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
397 *offset
/= align
* ChannelsFromFmt(BufferFmt
->mFmtChannels
);
398 *offset
*= BufferFmt
->OriginalAlign
;
400 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
402 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
403 *offset
/= align
* ChannelsFromFmt(BufferFmt
->mFmtChannels
);
404 *offset
*= BufferFmt
->OriginalAlign
;
407 *offset
/= FrameSizeFromFmt(BufferFmt
->mFmtChannels
, BufferFmt
->mFmtType
);
411 case AL_SAMPLE_OFFSET
:
412 dblfrac
= modf(Source
->Offset
, &dbloff
);
413 *offset
= static_cast<ALuint
>(mind(dbloff
, std::numeric_limits
<unsigned int>::max()));
414 *frac
= static_cast<ALsizei
>(mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0));
418 dblfrac
= modf(Source
->Offset
*BufferFmt
->Frequency
, &dbloff
);
419 *offset
= static_cast<ALuint
>(mind(dbloff
, std::numeric_limits
<unsigned int>::max()));
420 *frac
= static_cast<ALsizei
>(mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0));
423 Source
->OffsetType
= AL_NONE
;
424 Source
->Offset
= 0.0;
431 * Apply the stored playback offset to the Source. This function will update
432 * the number of buffers "played" given the stored offset.
434 ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
)
436 /* Get sample frame offset */
439 if(!GetSampleOffset(Source
, &offset
, &frac
))
442 ALuint totalBufferLen
{0u};
443 ALbufferlistitem
*BufferList
{Source
->queue
};
444 while(BufferList
&& totalBufferLen
<= offset
)
446 if(static_cast<ALuint
>(BufferList
->max_samples
) > offset
-totalBufferLen
)
448 /* Offset is in this buffer */
449 voice
->position
.store(offset
- totalBufferLen
, std::memory_order_relaxed
);
450 voice
->position_fraction
.store(frac
, std::memory_order_relaxed
);
451 voice
->current_buffer
.store(BufferList
, std::memory_order_release
);
454 totalBufferLen
+= BufferList
->max_samples
;
456 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
459 /* Offset is out of range of the queue */
464 ALsource
*AllocSource(ALCcontext
*context
)
466 ALCdevice
*device
{context
->Device
};
467 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
468 if(context
->NumSources
>= device
->SourcesMax
)
470 alSetError(context
, AL_OUT_OF_MEMORY
, "Exceeding %u source limit", device
->SourcesMax
);
473 auto sublist
= std::find_if(context
->SourceList
.begin(), context
->SourceList
.end(),
474 [](const SourceSubList
&entry
) noexcept
-> bool
475 { return entry
.FreeMask
!= 0; }
477 auto lidx
= static_cast<ALsizei
>(std::distance(context
->SourceList
.begin(), sublist
));
480 if(LIKELY(sublist
!= context
->SourceList
.end()))
482 slidx
= CTZ64(sublist
->FreeMask
);
483 source
= sublist
->Sources
+ slidx
;
487 /* Don't allocate so many list entries that the 32-bit ID could
490 if(UNLIKELY(context
->SourceList
.size() >= 1<<25))
492 alSetError(context
, AL_OUT_OF_MEMORY
, "Too many sources allocated");
495 context
->SourceList
.emplace_back();
496 sublist
= context
->SourceList
.end() - 1;
498 sublist
->FreeMask
= ~0_u64
;
499 sublist
->Sources
= static_cast<ALsource
*>(al_calloc(16, sizeof(ALsource
)*64));
500 if(UNLIKELY(!sublist
->Sources
))
502 context
->SourceList
.pop_back();
503 alSetError(context
, AL_OUT_OF_MEMORY
, "Failed to allocate source batch");
508 source
= sublist
->Sources
+ slidx
;
511 source
= new (source
) ALsource
{device
->NumAuxSends
};
513 /* Add 1 to avoid source ID 0. */
514 source
->id
= ((lidx
<<6) | slidx
) + 1;
516 context
->NumSources
+= 1;
517 sublist
->FreeMask
&= ~(1_u64
<< slidx
);
522 void FreeSource(ALCcontext
*context
, ALsource
*source
)
524 ALuint id
= source
->id
- 1;
525 ALsizei lidx
= id
>> 6;
526 ALsizei slidx
= id
& 0x3f;
528 ALCdevice
*device
{context
->Device
};
529 BackendUniqueLock backlock
{*device
->Backend
};
530 if(ALvoice
*voice
{GetSourceVoice(source
, context
)})
532 voice
->SourceID
.store(0u, std::memory_order_relaxed
);
533 voice
->Playing
.store(false, std::memory_order_release
);
539 context
->SourceList
[lidx
].FreeMask
|= 1_u64
<< slidx
;
540 context
->NumSources
--;
544 inline ALsource
*LookupSource(ALCcontext
*context
, ALuint id
) noexcept
546 ALuint lidx
= (id
-1) >> 6;
547 ALsizei slidx
= (id
-1) & 0x3f;
549 if(UNLIKELY(lidx
>= context
->SourceList
.size()))
551 SourceSubList
&sublist
{context
->SourceList
[lidx
]};
552 if(UNLIKELY(sublist
.FreeMask
& (1_u64
<< slidx
)))
554 return sublist
.Sources
+ slidx
;
557 inline ALbuffer
*LookupBuffer(ALCdevice
*device
, ALuint id
) noexcept
559 ALuint lidx
= (id
-1) >> 6;
560 ALsizei slidx
= (id
-1) & 0x3f;
562 if(UNLIKELY(lidx
>= device
->BufferList
.size()))
564 BufferSubList
&sublist
= device
->BufferList
[lidx
];
565 if(UNLIKELY(sublist
.FreeMask
& (1_u64
<< slidx
)))
567 return sublist
.Buffers
+ slidx
;
570 inline ALfilter
*LookupFilter(ALCdevice
*device
, ALuint id
) noexcept
572 ALuint lidx
= (id
-1) >> 6;
573 ALsizei slidx
= (id
-1) & 0x3f;
575 if(UNLIKELY(lidx
>= device
->FilterList
.size()))
577 FilterSubList
&sublist
= device
->FilterList
[lidx
];
578 if(UNLIKELY(sublist
.FreeMask
& (1_u64
<< slidx
)))
580 return sublist
.Filters
+ slidx
;
583 inline ALeffectslot
*LookupEffectSlot(ALCcontext
*context
, ALuint id
) noexcept
586 if(UNLIKELY(id
>= context
->EffectSlotList
.size()))
588 return context
->EffectSlotList
[id
].get();
592 enum SourceProp
: ALenum
{
595 srcMinGain
= AL_MIN_GAIN
,
596 srcMaxGain
= AL_MAX_GAIN
,
597 srcMaxDistance
= AL_MAX_DISTANCE
,
598 srcRolloffFactor
= AL_ROLLOFF_FACTOR
,
599 srcDopplerFactor
= AL_DOPPLER_FACTOR
,
600 srcConeOuterGain
= AL_CONE_OUTER_GAIN
,
601 srcSecOffset
= AL_SEC_OFFSET
,
602 srcSampleOffset
= AL_SAMPLE_OFFSET
,
603 srcByteOffset
= AL_BYTE_OFFSET
,
604 srcConeInnerAngle
= AL_CONE_INNER_ANGLE
,
605 srcConeOuterAngle
= AL_CONE_OUTER_ANGLE
,
606 srcRefDistance
= AL_REFERENCE_DISTANCE
,
608 srcPosition
= AL_POSITION
,
609 srcVelocity
= AL_VELOCITY
,
610 srcDirection
= AL_DIRECTION
,
612 srcSourceRelative
= AL_SOURCE_RELATIVE
,
613 srcLooping
= AL_LOOPING
,
614 srcBuffer
= AL_BUFFER
,
615 srcSourceState
= AL_SOURCE_STATE
,
616 srcBuffersQueued
= AL_BUFFERS_QUEUED
,
617 srcBuffersProcessed
= AL_BUFFERS_PROCESSED
,
618 srcSourceType
= AL_SOURCE_TYPE
,
621 srcConeOuterGainHF
= AL_CONE_OUTER_GAINHF
,
622 srcAirAbsorptionFactor
= AL_AIR_ABSORPTION_FACTOR
,
623 srcRoomRolloffFactor
= AL_ROOM_ROLLOFF_FACTOR
,
624 srcDirectFilterGainHFAuto
= AL_DIRECT_FILTER_GAINHF_AUTO
,
625 srcAuxSendFilterGainAuto
= AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
,
626 srcAuxSendFilterGainHFAuto
= AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
,
627 srcDirectFilter
= AL_DIRECT_FILTER
,
628 srcAuxSendFilter
= AL_AUXILIARY_SEND_FILTER
,
630 /* AL_SOFT_direct_channels */
631 srcDirectChannelsSOFT
= AL_DIRECT_CHANNELS_SOFT
,
633 /* AL_EXT_source_distance_model */
634 srcDistanceModel
= AL_DISTANCE_MODEL
,
636 /* AL_SOFT_source_latency */
637 srcSampleOffsetLatencySOFT
= AL_SAMPLE_OFFSET_LATENCY_SOFT
,
638 srcSecOffsetLatencySOFT
= AL_SEC_OFFSET_LATENCY_SOFT
,
640 /* AL_EXT_STEREO_ANGLES */
641 srcAngles
= AL_STEREO_ANGLES
,
643 /* AL_EXT_SOURCE_RADIUS */
644 srcRadius
= AL_SOURCE_RADIUS
,
647 srcOrientation
= AL_ORIENTATION
,
649 /* AL_SOFT_source_resampler */
650 srcResampler
= AL_SOURCE_RESAMPLER_SOFT
,
652 /* AL_SOFT_source_spatialize */
653 srcSpatialize
= AL_SOURCE_SPATIALIZE_SOFT
,
655 /* ALC_SOFT_device_clock */
656 srcSampleOffsetClockSOFT
= AL_SAMPLE_OFFSET_CLOCK_SOFT
,
657 srcSecOffsetClockSOFT
= AL_SEC_OFFSET_CLOCK_SOFT
,
661 * Returns if the last known state for the source was playing or paused. Does
662 * not sync with the mixer voice.
664 inline bool IsPlayingOrPaused(ALsource
*source
)
665 { return source
->state
== AL_PLAYING
|| source
->state
== AL_PAUSED
; }
668 * Returns an updated source state using the matching voice's status (or lack
671 inline ALenum
GetSourceState(ALsource
*source
, ALvoice
*voice
)
673 if(!voice
&& source
->state
== AL_PLAYING
)
674 source
->state
= AL_STOPPED
;
675 return source
->state
;
679 * Returns if the source should specify an update, given the context's
680 * deferring state and the source's last known state.
682 inline bool SourceShouldUpdate(ALsource
*source
, ALCcontext
*context
)
684 return !context
->DeferUpdates
.load(std::memory_order_acquire
) &&
685 IsPlayingOrPaused(source
);
689 /** Can only be called while the mixer is locked! */
690 void SendStateChangeEvent(ALCcontext
*context
, ALuint id
, ALenum state
)
692 ALbitfieldSOFT enabledevt
{context
->EnabledEvts
.load(std::memory_order_acquire
)};
693 if(!(enabledevt
&EventType_SourceStateChange
)) return;
695 /* The mixer may have queued a state change that's not yet been processed,
696 * and we don't want state change messages to occur out of order, so send
697 * it through the async queue to ensure proper ordering.
699 RingBuffer
*ring
{context
->AsyncEvents
.get()};
700 auto evt_vec
= ring
->getWriteVector();
701 if(evt_vec
.first
.len
< 1) return;
703 AsyncEvent
*evt
{new (evt_vec
.first
.buf
) AsyncEvent
{EventType_SourceStateChange
}};
704 evt
->u
.srcstate
.id
= id
;
705 evt
->u
.srcstate
.state
= state
;
706 ring
->writeAdvance(1);
707 context
->EventSem
.post();
711 ALint
FloatValsByProp(ALenum prop
)
713 switch(static_cast<SourceProp
>(prop
))
719 case AL_MAX_DISTANCE
:
720 case AL_ROLLOFF_FACTOR
:
721 case AL_DOPPLER_FACTOR
:
722 case AL_CONE_OUTER_GAIN
:
724 case AL_SAMPLE_OFFSET
:
726 case AL_CONE_INNER_ANGLE
:
727 case AL_CONE_OUTER_ANGLE
:
728 case AL_REFERENCE_DISTANCE
:
729 case AL_CONE_OUTER_GAINHF
:
730 case AL_AIR_ABSORPTION_FACTOR
:
731 case AL_ROOM_ROLLOFF_FACTOR
:
732 case AL_DIRECT_FILTER_GAINHF_AUTO
:
733 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
734 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
735 case AL_DIRECT_CHANNELS_SOFT
:
736 case AL_DISTANCE_MODEL
:
737 case AL_SOURCE_RELATIVE
:
739 case AL_SOURCE_STATE
:
740 case AL_BUFFERS_QUEUED
:
741 case AL_BUFFERS_PROCESSED
:
743 case AL_SOURCE_RADIUS
:
744 case AL_SOURCE_RESAMPLER_SOFT
:
745 case AL_SOURCE_SPATIALIZE_SOFT
:
748 case AL_STEREO_ANGLES
:
759 case AL_SEC_OFFSET_LATENCY_SOFT
:
760 case AL_SEC_OFFSET_CLOCK_SOFT
:
761 break; /* Double only */
764 case AL_DIRECT_FILTER
:
765 case AL_AUXILIARY_SEND_FILTER
:
766 break; /* i/i64 only */
767 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
768 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
769 break; /* i64 only */
773 ALint
DoubleValsByProp(ALenum prop
)
775 switch(static_cast<SourceProp
>(prop
))
781 case AL_MAX_DISTANCE
:
782 case AL_ROLLOFF_FACTOR
:
783 case AL_DOPPLER_FACTOR
:
784 case AL_CONE_OUTER_GAIN
:
786 case AL_SAMPLE_OFFSET
:
788 case AL_CONE_INNER_ANGLE
:
789 case AL_CONE_OUTER_ANGLE
:
790 case AL_REFERENCE_DISTANCE
:
791 case AL_CONE_OUTER_GAINHF
:
792 case AL_AIR_ABSORPTION_FACTOR
:
793 case AL_ROOM_ROLLOFF_FACTOR
:
794 case AL_DIRECT_FILTER_GAINHF_AUTO
:
795 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
796 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
797 case AL_DIRECT_CHANNELS_SOFT
:
798 case AL_DISTANCE_MODEL
:
799 case AL_SOURCE_RELATIVE
:
801 case AL_SOURCE_STATE
:
802 case AL_BUFFERS_QUEUED
:
803 case AL_BUFFERS_PROCESSED
:
805 case AL_SOURCE_RADIUS
:
806 case AL_SOURCE_RESAMPLER_SOFT
:
807 case AL_SOURCE_SPATIALIZE_SOFT
:
810 case AL_SEC_OFFSET_LATENCY_SOFT
:
811 case AL_SEC_OFFSET_CLOCK_SOFT
:
812 case AL_STEREO_ANGLES
:
824 case AL_DIRECT_FILTER
:
825 case AL_AUXILIARY_SEND_FILTER
:
826 break; /* i/i64 only */
827 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
828 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
829 break; /* i64 only */
834 ALint
IntValsByProp(ALenum prop
)
836 switch(static_cast<SourceProp
>(prop
))
842 case AL_MAX_DISTANCE
:
843 case AL_ROLLOFF_FACTOR
:
844 case AL_DOPPLER_FACTOR
:
845 case AL_CONE_OUTER_GAIN
:
847 case AL_SAMPLE_OFFSET
:
849 case AL_CONE_INNER_ANGLE
:
850 case AL_CONE_OUTER_ANGLE
:
851 case AL_REFERENCE_DISTANCE
:
852 case AL_CONE_OUTER_GAINHF
:
853 case AL_AIR_ABSORPTION_FACTOR
:
854 case AL_ROOM_ROLLOFF_FACTOR
:
855 case AL_DIRECT_FILTER_GAINHF_AUTO
:
856 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
857 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
858 case AL_DIRECT_CHANNELS_SOFT
:
859 case AL_DISTANCE_MODEL
:
860 case AL_SOURCE_RELATIVE
:
863 case AL_SOURCE_STATE
:
864 case AL_BUFFERS_QUEUED
:
865 case AL_BUFFERS_PROCESSED
:
867 case AL_DIRECT_FILTER
:
868 case AL_SOURCE_RADIUS
:
869 case AL_SOURCE_RESAMPLER_SOFT
:
870 case AL_SOURCE_SPATIALIZE_SOFT
:
876 case AL_AUXILIARY_SEND_FILTER
:
882 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
883 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
884 break; /* i64 only */
885 case AL_SEC_OFFSET_LATENCY_SOFT
:
886 case AL_SEC_OFFSET_CLOCK_SOFT
:
887 break; /* Double only */
888 case AL_STEREO_ANGLES
:
889 break; /* Float/double only */
893 ALint
Int64ValsByProp(ALenum prop
)
895 switch(static_cast<SourceProp
>(prop
))
901 case AL_MAX_DISTANCE
:
902 case AL_ROLLOFF_FACTOR
:
903 case AL_DOPPLER_FACTOR
:
904 case AL_CONE_OUTER_GAIN
:
906 case AL_SAMPLE_OFFSET
:
908 case AL_CONE_INNER_ANGLE
:
909 case AL_CONE_OUTER_ANGLE
:
910 case AL_REFERENCE_DISTANCE
:
911 case AL_CONE_OUTER_GAINHF
:
912 case AL_AIR_ABSORPTION_FACTOR
:
913 case AL_ROOM_ROLLOFF_FACTOR
:
914 case AL_DIRECT_FILTER_GAINHF_AUTO
:
915 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
916 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
917 case AL_DIRECT_CHANNELS_SOFT
:
918 case AL_DISTANCE_MODEL
:
919 case AL_SOURCE_RELATIVE
:
922 case AL_SOURCE_STATE
:
923 case AL_BUFFERS_QUEUED
:
924 case AL_BUFFERS_PROCESSED
:
926 case AL_DIRECT_FILTER
:
927 case AL_SOURCE_RADIUS
:
928 case AL_SOURCE_RESAMPLER_SOFT
:
929 case AL_SOURCE_SPATIALIZE_SOFT
:
932 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
933 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
939 case AL_AUXILIARY_SEND_FILTER
:
945 case AL_SEC_OFFSET_LATENCY_SOFT
:
946 case AL_SEC_OFFSET_CLOCK_SOFT
:
947 break; /* Double only */
948 case AL_STEREO_ANGLES
:
949 break; /* Float/double only */
955 ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
);
956 ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
);
957 ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
);
959 #define CHECKVAL(x) do { \
962 alSetError(Context, AL_INVALID_VALUE, "Value out of range"); \
967 #define DO_UPDATEPROPS() do { \
969 if(SourceShouldUpdate(Source, Context) && \
970 (voice=GetSourceVoice(Source, Context)) != nullptr) \
971 UpdateSourceProps(Source, voice, Context); \
973 Source->PropsClean.clear(std::memory_order_release); \
976 ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
)
982 case AL_SEC_OFFSET_LATENCY_SOFT
:
983 case AL_SEC_OFFSET_CLOCK_SOFT
:
985 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
986 "Setting read-only source property 0x%04x", prop
);
989 CHECKVAL(*values
>= 0.0f
);
991 Source
->Pitch
= *values
;
995 case AL_CONE_INNER_ANGLE
:
996 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
998 Source
->InnerAngle
= *values
;
1002 case AL_CONE_OUTER_ANGLE
:
1003 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
1005 Source
->OuterAngle
= *values
;
1010 CHECKVAL(*values
>= 0.0f
);
1012 Source
->Gain
= *values
;
1016 case AL_MAX_DISTANCE
:
1017 CHECKVAL(*values
>= 0.0f
);
1019 Source
->MaxDistance
= *values
;
1023 case AL_ROLLOFF_FACTOR
:
1024 CHECKVAL(*values
>= 0.0f
);
1026 Source
->RolloffFactor
= *values
;
1030 case AL_REFERENCE_DISTANCE
:
1031 CHECKVAL(*values
>= 0.0f
);
1033 Source
->RefDistance
= *values
;
1038 CHECKVAL(*values
>= 0.0f
);
1040 Source
->MinGain
= *values
;
1045 CHECKVAL(*values
>= 0.0f
);
1047 Source
->MaxGain
= *values
;
1051 case AL_CONE_OUTER_GAIN
:
1052 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
1054 Source
->OuterGain
= *values
;
1058 case AL_CONE_OUTER_GAINHF
:
1059 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
1061 Source
->OuterGainHF
= *values
;
1065 case AL_AIR_ABSORPTION_FACTOR
:
1066 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
1068 Source
->AirAbsorptionFactor
= *values
;
1072 case AL_ROOM_ROLLOFF_FACTOR
:
1073 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
1075 Source
->RoomRolloffFactor
= *values
;
1079 case AL_DOPPLER_FACTOR
:
1080 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
1082 Source
->DopplerFactor
= *values
;
1087 case AL_SAMPLE_OFFSET
:
1088 case AL_BYTE_OFFSET
:
1089 CHECKVAL(*values
>= 0.0f
);
1091 Source
->OffsetType
= prop
;
1092 Source
->Offset
= *values
;
1094 if(IsPlayingOrPaused(Source
))
1096 ALCdevice
*device
{Context
->Device
};
1097 BackendLockGuard _
{*device
->Backend
};
1098 /* Double-check that the source is still playing while we have
1101 if(ALvoice
*voice
{GetSourceVoice(Source
, Context
)})
1103 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
1104 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid offset");
1109 case AL_SOURCE_RADIUS
:
1110 CHECKVAL(*values
>= 0.0f
&& std::isfinite(*values
));
1112 Source
->Radius
= *values
;
1116 case AL_STEREO_ANGLES
:
1117 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]));
1119 Source
->StereoPan
[0] = values
[0];
1120 Source
->StereoPan
[1] = values
[1];
1126 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]));
1128 Source
->Position
[0] = values
[0];
1129 Source
->Position
[1] = values
[1];
1130 Source
->Position
[2] = values
[2];
1135 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]));
1137 Source
->Velocity
[0] = values
[0];
1138 Source
->Velocity
[1] = values
[1];
1139 Source
->Velocity
[2] = values
[2];
1144 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]));
1146 Source
->Direction
[0] = values
[0];
1147 Source
->Direction
[1] = values
[1];
1148 Source
->Direction
[2] = values
[2];
1152 case AL_ORIENTATION
:
1153 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]) &&
1154 std::isfinite(values
[3]) && std::isfinite(values
[4]) && std::isfinite(values
[5]));
1156 Source
->OrientAt
[0] = values
[0];
1157 Source
->OrientAt
[1] = values
[1];
1158 Source
->OrientAt
[2] = values
[2];
1159 Source
->OrientUp
[0] = values
[3];
1160 Source
->OrientUp
[1] = values
[4];
1161 Source
->OrientUp
[2] = values
[5];
1166 case AL_SOURCE_RELATIVE
:
1168 case AL_SOURCE_STATE
:
1169 case AL_SOURCE_TYPE
:
1170 case AL_DISTANCE_MODEL
:
1171 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1172 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1173 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1174 case AL_DIRECT_CHANNELS_SOFT
:
1175 case AL_SOURCE_RESAMPLER_SOFT
:
1176 case AL_SOURCE_SPATIALIZE_SOFT
:
1177 ival
= static_cast<ALint
>(values
[0]);
1178 return SetSourceiv(Source
, Context
, prop
, &ival
);
1180 case AL_BUFFERS_QUEUED
:
1181 case AL_BUFFERS_PROCESSED
:
1182 ival
= static_cast<ALint
>(static_cast<ALuint
>(values
[0]));
1183 return SetSourceiv(Source
, Context
, prop
, &ival
);
1186 case AL_DIRECT_FILTER
:
1187 case AL_AUXILIARY_SEND_FILTER
:
1188 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1189 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1193 ERR("Unexpected property: 0x%04x\n", prop
);
1194 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source float property 0x%04x", prop
);
1197 ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
)
1199 ALCdevice
*device
{Context
->Device
};
1200 ALbuffer
*buffer
{nullptr};
1201 ALfilter
*filter
{nullptr};
1202 ALeffectslot
*slot
{nullptr};
1203 ALbufferlistitem
*oldlist
{nullptr};
1204 std::unique_lock
<std::mutex
> slotlock
;
1205 std::unique_lock
<std::mutex
> filtlock
;
1206 std::unique_lock
<std::mutex
> buflock
;
1211 case AL_SOURCE_STATE
:
1212 case AL_SOURCE_TYPE
:
1213 case AL_BUFFERS_QUEUED
:
1214 case AL_BUFFERS_PROCESSED
:
1216 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
1217 "Setting read-only source property 0x%04x", prop
);
1219 case AL_SOURCE_RELATIVE
:
1220 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
1222 Source
->HeadRelative
= static_cast<ALboolean
>(*values
);
1227 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
1229 Source
->Looping
= static_cast<ALboolean
>(*values
);
1230 if(IsPlayingOrPaused(Source
))
1232 ALvoice
*voice
{GetSourceVoice(Source
, Context
)};
1236 voice
->loop_buffer
.store(Source
->queue
, std::memory_order_release
);
1238 voice
->loop_buffer
.store(nullptr, std::memory_order_release
);
1240 /* If the source is playing, wait for the current mix to finish
1241 * to ensure it isn't currently looping back or reaching the
1244 while((device
->MixCount
.load(std::memory_order_acquire
)&1))
1245 std::this_thread::yield();
1251 buflock
= std::unique_lock
<std::mutex
>{device
->BufferLock
};
1252 if(!(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != nullptr))
1253 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid buffer ID %u",
1256 if(buffer
&& buffer
->MappedAccess
!= 0 &&
1257 !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
1258 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
1259 "Setting non-persistently mapped buffer %u", buffer
->id
);
1262 ALenum state
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
1263 if(state
== AL_PLAYING
|| state
== AL_PAUSED
)
1264 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
1265 "Setting buffer on playing or paused source %u", Source
->id
);
1268 oldlist
= Source
->queue
;
1269 if(buffer
!= nullptr)
1271 /* Add the selected buffer to a one-item queue */
1272 auto newlist
= static_cast<ALbufferlistitem
*>(al_calloc(DEF_ALIGN
,
1273 FAM_SIZE(ALbufferlistitem
, buffers
, 1)));
1274 newlist
->next
.store(nullptr, std::memory_order_relaxed
);
1275 newlist
->max_samples
= buffer
->SampleLen
;
1276 newlist
->num_buffers
= 1;
1277 newlist
->buffers
[0] = buffer
;
1278 IncrementRef(&buffer
->ref
);
1280 /* Source is now Static */
1281 Source
->SourceType
= AL_STATIC
;
1282 Source
->queue
= newlist
;
1286 /* Source is now Undetermined */
1287 Source
->SourceType
= AL_UNDETERMINED
;
1288 Source
->queue
= nullptr;
1292 /* Delete all elements in the previous queue */
1293 while(oldlist
!= nullptr)
1295 ALbufferlistitem
*temp
{oldlist
};
1296 oldlist
= temp
->next
.load(std::memory_order_relaxed
);
1298 for(ALsizei i
{0};i
< temp
->num_buffers
;i
++)
1300 if(temp
->buffers
[i
])
1301 DecrementRef(&temp
->buffers
[i
]->ref
);
1308 case AL_SAMPLE_OFFSET
:
1309 case AL_BYTE_OFFSET
:
1310 CHECKVAL(*values
>= 0);
1312 Source
->OffsetType
= prop
;
1313 Source
->Offset
= *values
;
1315 if(IsPlayingOrPaused(Source
))
1317 ALCdevice
*device
{Context
->Device
};
1318 BackendLockGuard _
{*device
->Backend
};
1319 if(ALvoice
*voice
{GetSourceVoice(Source
, Context
)})
1321 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
1322 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
,
1323 "Invalid source offset");
1328 case AL_DIRECT_FILTER
:
1329 filtlock
= std::unique_lock
<std::mutex
>{device
->FilterLock
};
1330 if(!(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != nullptr))
1331 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid filter ID %u",
1336 Source
->Direct
.Gain
= 1.0f
;
1337 Source
->Direct
.GainHF
= 1.0f
;
1338 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
1339 Source
->Direct
.GainLF
= 1.0f
;
1340 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
1344 Source
->Direct
.Gain
= filter
->Gain
;
1345 Source
->Direct
.GainHF
= filter
->GainHF
;
1346 Source
->Direct
.HFReference
= filter
->HFReference
;
1347 Source
->Direct
.GainLF
= filter
->GainLF
;
1348 Source
->Direct
.LFReference
= filter
->LFReference
;
1354 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1355 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
1357 Source
->DryGainHFAuto
= *values
;
1361 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1362 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
1364 Source
->WetGainAuto
= *values
;
1368 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1369 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
1371 Source
->WetGainHFAuto
= *values
;
1375 case AL_DIRECT_CHANNELS_SOFT
:
1376 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
1378 Source
->DirectChannels
= *values
;
1382 case AL_DISTANCE_MODEL
:
1383 CHECKVAL(*values
== AL_NONE
||
1384 *values
== AL_INVERSE_DISTANCE
||
1385 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
1386 *values
== AL_LINEAR_DISTANCE
||
1387 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
1388 *values
== AL_EXPONENT_DISTANCE
||
1389 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
1391 Source
->mDistanceModel
= static_cast<DistanceModel
>(*values
);
1392 if(Context
->SourceDistanceModel
)
1396 case AL_SOURCE_RESAMPLER_SOFT
:
1397 CHECKVAL(*values
>= 0 && *values
<= ResamplerMax
);
1399 Source
->mResampler
= static_cast<Resampler
>(*values
);
1403 case AL_SOURCE_SPATIALIZE_SOFT
:
1404 CHECKVAL(*values
>= AL_FALSE
&& *values
<= AL_AUTO_SOFT
);
1406 Source
->mSpatialize
= static_cast<SpatializeMode
>(*values
);
1411 case AL_AUXILIARY_SEND_FILTER
:
1412 slotlock
= std::unique_lock
<std::mutex
>{Context
->EffectSlotLock
};
1413 if(!(values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != nullptr))
1414 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid effect ID %u",
1416 if(static_cast<ALuint
>(values
[1]) >= static_cast<ALuint
>(device
->NumAuxSends
))
1417 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid send %u", values
[1]);
1419 filtlock
= std::unique_lock
<std::mutex
>{device
->FilterLock
};
1420 if(!(values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != nullptr))
1421 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid filter ID %u",
1426 /* Disable filter */
1427 Source
->Send
[values
[1]].Gain
= 1.0f
;
1428 Source
->Send
[values
[1]].GainHF
= 1.0f
;
1429 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
1430 Source
->Send
[values
[1]].GainLF
= 1.0f
;
1431 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
1435 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
1436 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
1437 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
1438 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
1439 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
1443 if(slot
!= Source
->Send
[values
[1]].Slot
&& IsPlayingOrPaused(Source
))
1445 /* Add refcount on the new slot, and release the previous slot */
1446 if(slot
) IncrementRef(&slot
->ref
);
1447 if(Source
->Send
[values
[1]].Slot
)
1448 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
1449 Source
->Send
[values
[1]].Slot
= slot
;
1451 /* We must force an update if the auxiliary slot changed on an
1452 * active source, in case the slot is about to be deleted.
1454 ALvoice
*voice
{GetSourceVoice(Source
, Context
)};
1455 if(voice
) UpdateSourceProps(Source
, voice
, Context
);
1456 else Source
->PropsClean
.clear(std::memory_order_release
);
1460 if(slot
) IncrementRef(&slot
->ref
);
1461 if(Source
->Send
[values
[1]].Slot
)
1462 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
1463 Source
->Send
[values
[1]].Slot
= slot
;
1471 case AL_CONE_INNER_ANGLE
:
1472 case AL_CONE_OUTER_ANGLE
:
1477 case AL_REFERENCE_DISTANCE
:
1478 case AL_ROLLOFF_FACTOR
:
1479 case AL_CONE_OUTER_GAIN
:
1480 case AL_MAX_DISTANCE
:
1481 case AL_DOPPLER_FACTOR
:
1482 case AL_CONE_OUTER_GAINHF
:
1483 case AL_AIR_ABSORPTION_FACTOR
:
1484 case AL_ROOM_ROLLOFF_FACTOR
:
1485 case AL_SOURCE_RADIUS
:
1486 fvals
[0] = static_cast<ALfloat
>(*values
);
1487 return SetSourcefv(Source
, Context
, prop
, fvals
);
1493 fvals
[0] = static_cast<ALfloat
>(values
[0]);
1494 fvals
[1] = static_cast<ALfloat
>(values
[1]);
1495 fvals
[2] = static_cast<ALfloat
>(values
[2]);
1496 return SetSourcefv(Source
, Context
, prop
, fvals
);
1499 case AL_ORIENTATION
:
1500 fvals
[0] = static_cast<ALfloat
>(values
[0]);
1501 fvals
[1] = static_cast<ALfloat
>(values
[1]);
1502 fvals
[2] = static_cast<ALfloat
>(values
[2]);
1503 fvals
[3] = static_cast<ALfloat
>(values
[3]);
1504 fvals
[4] = static_cast<ALfloat
>(values
[4]);
1505 fvals
[5] = static_cast<ALfloat
>(values
[5]);
1506 return SetSourcefv(Source
, Context
, prop
, fvals
);
1508 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1509 case AL_SEC_OFFSET_LATENCY_SOFT
:
1510 case AL_SEC_OFFSET_CLOCK_SOFT
:
1511 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1512 case AL_STEREO_ANGLES
:
1516 ERR("Unexpected property: 0x%04x\n", prop
);
1517 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer property 0x%04x",
1521 ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
1528 case AL_SOURCE_TYPE
:
1529 case AL_BUFFERS_QUEUED
:
1530 case AL_BUFFERS_PROCESSED
:
1531 case AL_SOURCE_STATE
:
1532 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1533 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1535 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
1536 "Setting read-only source property 0x%04x", prop
);
1539 case AL_SOURCE_RELATIVE
:
1542 case AL_SAMPLE_OFFSET
:
1543 case AL_BYTE_OFFSET
:
1544 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1545 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1546 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1547 case AL_DIRECT_CHANNELS_SOFT
:
1548 case AL_DISTANCE_MODEL
:
1549 case AL_SOURCE_RESAMPLER_SOFT
:
1550 case AL_SOURCE_SPATIALIZE_SOFT
:
1551 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
1553 ivals
[0] = static_cast<ALint
>(*values
);
1554 return SetSourceiv(Source
, Context
, prop
, ivals
);
1558 case AL_DIRECT_FILTER
:
1559 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
1561 ivals
[0] = static_cast<ALuint
>(*values
);
1562 return SetSourceiv(Source
, Context
, prop
, ivals
);
1565 case AL_AUXILIARY_SEND_FILTER
:
1566 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
1567 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
1568 values
[2] <= UINT_MAX
&& values
[2] >= 0);
1570 ivals
[0] = static_cast<ALuint
>(values
[0]);
1571 ivals
[1] = static_cast<ALuint
>(values
[1]);
1572 ivals
[2] = static_cast<ALuint
>(values
[2]);
1573 return SetSourceiv(Source
, Context
, prop
, ivals
);
1576 case AL_CONE_INNER_ANGLE
:
1577 case AL_CONE_OUTER_ANGLE
:
1582 case AL_REFERENCE_DISTANCE
:
1583 case AL_ROLLOFF_FACTOR
:
1584 case AL_CONE_OUTER_GAIN
:
1585 case AL_MAX_DISTANCE
:
1586 case AL_DOPPLER_FACTOR
:
1587 case AL_CONE_OUTER_GAINHF
:
1588 case AL_AIR_ABSORPTION_FACTOR
:
1589 case AL_ROOM_ROLLOFF_FACTOR
:
1590 case AL_SOURCE_RADIUS
:
1591 fvals
[0] = static_cast<ALfloat
>(*values
);
1592 return SetSourcefv(Source
, Context
, prop
, fvals
);
1598 fvals
[0] = static_cast<ALfloat
>(values
[0]);
1599 fvals
[1] = static_cast<ALfloat
>(values
[1]);
1600 fvals
[2] = static_cast<ALfloat
>(values
[2]);
1601 return SetSourcefv(Source
, Context
, prop
, fvals
);
1604 case AL_ORIENTATION
:
1605 fvals
[0] = static_cast<ALfloat
>(values
[0]);
1606 fvals
[1] = static_cast<ALfloat
>(values
[1]);
1607 fvals
[2] = static_cast<ALfloat
>(values
[2]);
1608 fvals
[3] = static_cast<ALfloat
>(values
[3]);
1609 fvals
[4] = static_cast<ALfloat
>(values
[4]);
1610 fvals
[5] = static_cast<ALfloat
>(values
[5]);
1611 return SetSourcefv(Source
, Context
, prop
, fvals
);
1613 case AL_SEC_OFFSET_LATENCY_SOFT
:
1614 case AL_SEC_OFFSET_CLOCK_SOFT
:
1615 case AL_STEREO_ANGLES
:
1619 ERR("Unexpected property: 0x%04x\n", prop
);
1620 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer64 property 0x%04x",
1627 ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
);
1628 ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
);
1629 ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
);
1631 ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
1633 ALCdevice
*device
{Context
->Device
};
1634 ClockLatency clocktime
;
1635 std::chrono::nanoseconds srcclock
;
1642 *values
= Source
->Gain
;
1646 *values
= Source
->Pitch
;
1649 case AL_MAX_DISTANCE
:
1650 *values
= Source
->MaxDistance
;
1653 case AL_ROLLOFF_FACTOR
:
1654 *values
= Source
->RolloffFactor
;
1657 case AL_REFERENCE_DISTANCE
:
1658 *values
= Source
->RefDistance
;
1661 case AL_CONE_INNER_ANGLE
:
1662 *values
= Source
->InnerAngle
;
1665 case AL_CONE_OUTER_ANGLE
:
1666 *values
= Source
->OuterAngle
;
1670 *values
= Source
->MinGain
;
1674 *values
= Source
->MaxGain
;
1677 case AL_CONE_OUTER_GAIN
:
1678 *values
= Source
->OuterGain
;
1682 case AL_SAMPLE_OFFSET
:
1683 case AL_BYTE_OFFSET
:
1684 *values
= GetSourceOffset(Source
, prop
, Context
);
1687 case AL_CONE_OUTER_GAINHF
:
1688 *values
= Source
->OuterGainHF
;
1691 case AL_AIR_ABSORPTION_FACTOR
:
1692 *values
= Source
->AirAbsorptionFactor
;
1695 case AL_ROOM_ROLLOFF_FACTOR
:
1696 *values
= Source
->RoomRolloffFactor
;
1699 case AL_DOPPLER_FACTOR
:
1700 *values
= Source
->DopplerFactor
;
1703 case AL_SOURCE_RADIUS
:
1704 *values
= Source
->Radius
;
1707 case AL_STEREO_ANGLES
:
1708 values
[0] = Source
->StereoPan
[0];
1709 values
[1] = Source
->StereoPan
[1];
1712 case AL_SEC_OFFSET_LATENCY_SOFT
:
1713 /* Get the source offset with the clock time first. Then get the
1714 * clock time with the device latency. Order is important.
1716 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1717 { std::lock_guard
<std::mutex
> _
{device
->StateLock
};
1718 clocktime
= GetClockLatency(device
);
1720 if(srcclock
== clocktime
.ClockTime
)
1721 values
[1] = static_cast<ALdouble
>(clocktime
.Latency
.count()) / 1000000000.0;
1724 /* If the clock time incremented, reduce the latency by that
1725 * much since it's that much closer to the source offset it got
1728 std::chrono::nanoseconds diff
= clocktime
.ClockTime
- srcclock
;
1729 values
[1] = static_cast<ALdouble
>((clocktime
.Latency
- std::min(clocktime
.Latency
, diff
)).count()) /
1734 case AL_SEC_OFFSET_CLOCK_SOFT
:
1735 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1736 values
[1] = srcclock
.count() / 1000000000.0;
1740 values
[0] = Source
->Position
[0];
1741 values
[1] = Source
->Position
[1];
1742 values
[2] = Source
->Position
[2];
1746 values
[0] = Source
->Velocity
[0];
1747 values
[1] = Source
->Velocity
[1];
1748 values
[2] = Source
->Velocity
[2];
1752 values
[0] = Source
->Direction
[0];
1753 values
[1] = Source
->Direction
[1];
1754 values
[2] = Source
->Direction
[2];
1757 case AL_ORIENTATION
:
1758 values
[0] = Source
->OrientAt
[0];
1759 values
[1] = Source
->OrientAt
[1];
1760 values
[2] = Source
->OrientAt
[2];
1761 values
[3] = Source
->OrientUp
[0];
1762 values
[4] = Source
->OrientUp
[1];
1763 values
[5] = Source
->OrientUp
[2];
1767 case AL_SOURCE_RELATIVE
:
1769 case AL_SOURCE_STATE
:
1770 case AL_BUFFERS_QUEUED
:
1771 case AL_BUFFERS_PROCESSED
:
1772 case AL_SOURCE_TYPE
:
1773 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1774 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1775 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1776 case AL_DIRECT_CHANNELS_SOFT
:
1777 case AL_DISTANCE_MODEL
:
1778 case AL_SOURCE_RESAMPLER_SOFT
:
1779 case AL_SOURCE_SPATIALIZE_SOFT
:
1780 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1781 *values
= static_cast<ALdouble
>(ivals
[0]);
1785 case AL_DIRECT_FILTER
:
1786 case AL_AUXILIARY_SEND_FILTER
:
1787 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1788 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1792 ERR("Unexpected property: 0x%04x\n", prop
);
1793 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source double property 0x%04x",
1797 ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1799 ALbufferlistitem
*BufferList
;
1805 case AL_SOURCE_RELATIVE
:
1806 *values
= Source
->HeadRelative
;
1810 *values
= Source
->Looping
;
1814 BufferList
= (Source
->SourceType
== AL_STATIC
) ? Source
->queue
: nullptr;
1815 *values
= (BufferList
&& BufferList
->num_buffers
>= 1 && BufferList
->buffers
[0]) ?
1816 BufferList
->buffers
[0]->id
: 0;
1819 case AL_SOURCE_STATE
:
1820 *values
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
1823 case AL_BUFFERS_QUEUED
:
1824 if(!(BufferList
=Source
->queue
))
1830 count
+= BufferList
->num_buffers
;
1831 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
1832 } while(BufferList
!= nullptr);
1837 case AL_BUFFERS_PROCESSED
:
1838 if(Source
->Looping
|| Source
->SourceType
!= AL_STREAMING
)
1840 /* Buffers on a looping source are in a perpetual state of
1841 * PENDING, so don't report any as PROCESSED */
1846 const ALbufferlistitem
*BufferList
{Source
->queue
};
1847 const ALbufferlistitem
*Current
{nullptr};
1850 ALvoice
*voice
{GetSourceVoice(Source
, Context
)};
1851 if(voice
!= nullptr)
1852 Current
= voice
->current_buffer
.load(std::memory_order_relaxed
);
1853 else if(Source
->state
== AL_INITIAL
)
1854 Current
= BufferList
;
1856 while(BufferList
&& BufferList
!= Current
)
1858 played
+= BufferList
->num_buffers
;
1859 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
1865 case AL_SOURCE_TYPE
:
1866 *values
= Source
->SourceType
;
1869 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1870 *values
= Source
->DryGainHFAuto
;
1873 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1874 *values
= Source
->WetGainAuto
;
1877 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1878 *values
= Source
->WetGainHFAuto
;
1881 case AL_DIRECT_CHANNELS_SOFT
:
1882 *values
= Source
->DirectChannels
;
1885 case AL_DISTANCE_MODEL
:
1886 *values
= static_cast<int>(Source
->mDistanceModel
);
1889 case AL_SOURCE_RESAMPLER_SOFT
:
1890 *values
= Source
->mResampler
;
1893 case AL_SOURCE_SPATIALIZE_SOFT
:
1894 *values
= Source
->mSpatialize
;
1897 /* 1x float/double */
1898 case AL_CONE_INNER_ANGLE
:
1899 case AL_CONE_OUTER_ANGLE
:
1904 case AL_REFERENCE_DISTANCE
:
1905 case AL_ROLLOFF_FACTOR
:
1906 case AL_CONE_OUTER_GAIN
:
1907 case AL_MAX_DISTANCE
:
1909 case AL_SAMPLE_OFFSET
:
1910 case AL_BYTE_OFFSET
:
1911 case AL_DOPPLER_FACTOR
:
1912 case AL_AIR_ABSORPTION_FACTOR
:
1913 case AL_ROOM_ROLLOFF_FACTOR
:
1914 case AL_CONE_OUTER_GAINHF
:
1915 case AL_SOURCE_RADIUS
:
1916 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1917 *values
= static_cast<ALint
>(dvals
[0]);
1920 /* 3x float/double */
1924 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1926 values
[0] = static_cast<ALint
>(dvals
[0]);
1927 values
[1] = static_cast<ALint
>(dvals
[1]);
1928 values
[2] = static_cast<ALint
>(dvals
[2]);
1932 /* 6x float/double */
1933 case AL_ORIENTATION
:
1934 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1936 values
[0] = static_cast<ALint
>(dvals
[0]);
1937 values
[1] = static_cast<ALint
>(dvals
[1]);
1938 values
[2] = static_cast<ALint
>(dvals
[2]);
1939 values
[3] = static_cast<ALint
>(dvals
[3]);
1940 values
[4] = static_cast<ALint
>(dvals
[4]);
1941 values
[5] = static_cast<ALint
>(dvals
[5]);
1945 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1946 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1947 break; /* i64 only */
1948 case AL_SEC_OFFSET_LATENCY_SOFT
:
1949 case AL_SEC_OFFSET_CLOCK_SOFT
:
1950 break; /* Double only */
1951 case AL_STEREO_ANGLES
:
1952 break; /* Float/double only */
1954 case AL_DIRECT_FILTER
:
1955 case AL_AUXILIARY_SEND_FILTER
:
1959 ERR("Unexpected property: 0x%04x\n", prop
);
1960 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer property 0x%04x",
1964 ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1966 ALCdevice
*device
= Context
->Device
;
1967 ClockLatency clocktime
;
1968 std::chrono::nanoseconds srcclock
;
1975 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1976 /* Get the source offset with the clock time first. Then get the
1977 * clock time with the device latency. Order is important.
1979 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1980 { std::lock_guard
<std::mutex
> _
{device
->StateLock
};
1981 clocktime
= GetClockLatency(device
);
1983 if(srcclock
== clocktime
.ClockTime
)
1984 values
[1] = clocktime
.Latency
.count();
1987 /* If the clock time incremented, reduce the latency by that
1988 * much since it's that much closer to the source offset it got
1991 auto diff
= clocktime
.ClockTime
- srcclock
;
1992 values
[1] = (clocktime
.Latency
- std::min(clocktime
.Latency
, diff
)).count();
1996 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1997 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
1998 values
[1] = srcclock
.count();
2001 /* 1x float/double */
2002 case AL_CONE_INNER_ANGLE
:
2003 case AL_CONE_OUTER_ANGLE
:
2008 case AL_REFERENCE_DISTANCE
:
2009 case AL_ROLLOFF_FACTOR
:
2010 case AL_CONE_OUTER_GAIN
:
2011 case AL_MAX_DISTANCE
:
2013 case AL_SAMPLE_OFFSET
:
2014 case AL_BYTE_OFFSET
:
2015 case AL_DOPPLER_FACTOR
:
2016 case AL_AIR_ABSORPTION_FACTOR
:
2017 case AL_ROOM_ROLLOFF_FACTOR
:
2018 case AL_CONE_OUTER_GAINHF
:
2019 case AL_SOURCE_RADIUS
:
2020 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
2021 *values
= static_cast<ALint64
>(dvals
[0]);
2024 /* 3x float/double */
2028 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
2030 values
[0] = static_cast<ALint64
>(dvals
[0]);
2031 values
[1] = static_cast<ALint64
>(dvals
[1]);
2032 values
[2] = static_cast<ALint64
>(dvals
[2]);
2036 /* 6x float/double */
2037 case AL_ORIENTATION
:
2038 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
2040 values
[0] = static_cast<ALint64
>(dvals
[0]);
2041 values
[1] = static_cast<ALint64
>(dvals
[1]);
2042 values
[2] = static_cast<ALint64
>(dvals
[2]);
2043 values
[3] = static_cast<ALint64
>(dvals
[3]);
2044 values
[4] = static_cast<ALint64
>(dvals
[4]);
2045 values
[5] = static_cast<ALint64
>(dvals
[5]);
2050 case AL_SOURCE_RELATIVE
:
2052 case AL_SOURCE_STATE
:
2053 case AL_BUFFERS_QUEUED
:
2054 case AL_BUFFERS_PROCESSED
:
2055 case AL_SOURCE_TYPE
:
2056 case AL_DIRECT_FILTER_GAINHF_AUTO
:
2057 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
2058 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
2059 case AL_DIRECT_CHANNELS_SOFT
:
2060 case AL_DISTANCE_MODEL
:
2061 case AL_SOURCE_RESAMPLER_SOFT
:
2062 case AL_SOURCE_SPATIALIZE_SOFT
:
2063 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
2069 case AL_DIRECT_FILTER
:
2070 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
2071 *values
= static_cast<ALuint
>(ivals
[0]);
2075 case AL_AUXILIARY_SEND_FILTER
:
2076 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
2078 values
[0] = static_cast<ALuint
>(ivals
[0]);
2079 values
[1] = static_cast<ALuint
>(ivals
[1]);
2080 values
[2] = static_cast<ALuint
>(ivals
[2]);
2084 case AL_SEC_OFFSET_LATENCY_SOFT
:
2085 case AL_SEC_OFFSET_CLOCK_SOFT
:
2086 break; /* Double only */
2087 case AL_STEREO_ANGLES
:
2088 break; /* Float/double only */
2091 ERR("Unexpected property: 0x%04x\n", prop
);
2092 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer64 property 0x%04x",
2098 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
2100 ContextRef context
{GetContextRef()};
2101 if(UNLIKELY(!context
)) return;
2104 alSetError(context
.get(), AL_INVALID_VALUE
, "Generating %d sources", n
);
2107 ALsource
*source
= AllocSource(context
.get());
2108 if(source
) sources
[0] = source
->id
;
2112 al::vector
<ALuint
> tempids(n
);
2113 auto alloc_end
= std::find_if_not(tempids
.begin(), tempids
.end(),
2114 [&context
](ALuint
&id
) -> bool
2116 ALsource
*source
{AllocSource(context
.get())};
2117 if(!source
) return false;
2122 if(alloc_end
!= tempids
.end())
2123 alDeleteSources(static_cast<ALsizei
>(std::distance(tempids
.begin(), alloc_end
)),
2126 std::copy(tempids
.cbegin(), tempids
.cend(), sources
);
2131 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
2133 ContextRef context
{GetContextRef()};
2134 if(UNLIKELY(!context
)) return;
2137 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Deleting %d sources", n
);
2139 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2141 /* Check that all Sources are valid */
2142 const ALuint
*sources_end
= sources
+ n
;
2143 auto invsrc
= std::find_if_not(sources
, sources_end
,
2144 [&context
](ALuint sid
) -> bool
2146 if(!LookupSource(context
.get(), sid
))
2148 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", sid
);
2154 if(LIKELY(invsrc
== sources_end
))
2156 /* All good. Delete source IDs. */
2157 std::for_each(sources
, sources_end
,
2158 [&context
](ALuint sid
) -> void
2160 ALsource
*src
{LookupSource(context
.get(), sid
)};
2161 if(src
) FreeSource(context
.get(), src
);
2168 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
2170 ContextRef context
{GetContextRef()};
2173 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2174 if(LookupSource(context
.get(), source
) != nullptr)
2181 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
2183 ContextRef context
{GetContextRef()};
2184 if(UNLIKELY(!context
)) return;
2186 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
2187 std::lock_guard
<std::mutex
> __
{context
->SourceLock
};
2188 ALsource
*Source
= LookupSource(context
.get(), source
);
2189 if(UNLIKELY(!Source
))
2190 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2191 else if(FloatValsByProp(param
) != 1)
2192 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid float property 0x%04x", param
);
2194 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), &value
);
2197 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
2199 ContextRef context
{GetContextRef()};
2200 if(UNLIKELY(!context
)) return;
2202 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
2203 std::lock_guard
<std::mutex
> __
{context
->SourceLock
};
2204 ALsource
*Source
= LookupSource(context
.get(), source
);
2205 if(UNLIKELY(!Source
))
2206 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2207 else if(FloatValsByProp(param
) != 3)
2208 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid 3-float property 0x%04x", param
);
2211 ALfloat fvals
[3] = { value1
, value2
, value3
};
2212 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), fvals
);
2216 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
2218 ContextRef context
{GetContextRef()};
2219 if(UNLIKELY(!context
)) return;
2221 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
2222 std::lock_guard
<std::mutex
> __
{context
->SourceLock
};
2223 ALsource
*Source
= LookupSource(context
.get(), source
);
2224 if(UNLIKELY(!Source
))
2225 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2227 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2228 else if(FloatValsByProp(param
) < 1)
2229 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid float-vector property 0x%04x", param
);
2231 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), values
);
2235 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
2237 ContextRef context
{GetContextRef()};
2238 if(UNLIKELY(!context
)) return;
2240 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
2241 std::lock_guard
<std::mutex
> __
{context
->SourceLock
};
2242 ALsource
*Source
= LookupSource(context
.get(), source
);
2243 if(UNLIKELY(!Source
))
2244 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2245 else if(DoubleValsByProp(param
) != 1)
2246 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid double property 0x%04x", param
);
2249 ALfloat fval
= static_cast<ALfloat
>(value
);
2250 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), &fval
);
2254 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
2256 ContextRef context
{GetContextRef()};
2257 if(UNLIKELY(!context
)) return;
2259 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
2260 std::lock_guard
<std::mutex
> __
{context
->SourceLock
};
2261 ALsource
*Source
= LookupSource(context
.get(), source
);
2262 if(UNLIKELY(!Source
))
2263 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2264 else if(DoubleValsByProp(param
) != 3)
2265 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid 3-double property 0x%04x", param
);
2267 ALfloat fvals
[3] = {static_cast<ALfloat
>(value1
),
2268 static_cast<ALfloat
>(value2
),
2269 static_cast<ALfloat
>(value3
)};
2270 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), fvals
);
2274 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
2276 ContextRef context
{GetContextRef()};
2277 if(UNLIKELY(!context
)) return;
2279 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
2280 std::lock_guard
<std::mutex
> __
{context
->SourceLock
};
2281 ALsource
*Source
= LookupSource(context
.get(), source
);
2282 if(UNLIKELY(!Source
))
2283 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2285 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2288 ALint count
{DoubleValsByProp(param
)};
2289 if(count
< 1 || count
> 6)
2290 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid double-vector property 0x%04x", param
);
2296 for(i
= 0;i
< count
;i
++)
2297 fvals
[i
] = static_cast<ALfloat
>(values
[i
]);
2298 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), fvals
);
2304 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
2306 ContextRef context
{GetContextRef()};
2307 if(UNLIKELY(!context
)) return;
2309 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
2310 std::lock_guard
<std::mutex
> __
{context
->SourceLock
};
2311 ALsource
*Source
= LookupSource(context
.get(), source
);
2312 if(UNLIKELY(!Source
))
2313 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2314 else if(IntValsByProp(param
) != 1)
2315 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid integer property 0x%04x", param
);
2317 SetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), &value
);
2320 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
2322 ContextRef context
{GetContextRef()};
2323 if(UNLIKELY(!context
)) return;
2325 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
2326 std::lock_guard
<std::mutex
> __
{context
->SourceLock
};
2327 ALsource
*Source
= LookupSource(context
.get(), source
);
2328 if(UNLIKELY(!Source
))
2329 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2330 else if(IntValsByProp(param
) != 3)
2331 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid 3-integer property 0x%04x", param
);
2334 ALint ivals
[3] = { value1
, value2
, value3
};
2335 SetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), ivals
);
2339 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
2341 ContextRef context
{GetContextRef()};
2342 if(UNLIKELY(!context
)) return;
2344 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
2345 std::lock_guard
<std::mutex
> __
{context
->SourceLock
};
2346 ALsource
*Source
= LookupSource(context
.get(), source
);
2347 if(UNLIKELY(!Source
))
2348 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2350 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2351 else if(IntValsByProp(param
) < 1)
2352 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid integer-vector property 0x%04x", param
);
2354 SetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), values
);
2358 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
2360 ContextRef context
{GetContextRef()};
2361 if(UNLIKELY(!context
)) return;
2363 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
2364 std::lock_guard
<std::mutex
> __
{context
->SourceLock
};
2365 ALsource
*Source
{LookupSource(context
.get(), source
)};
2366 if(UNLIKELY(!Source
))
2367 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2368 else if(Int64ValsByProp(param
) != 1)
2369 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid integer64 property 0x%04x", param
);
2371 SetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), &value
);
2374 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
2376 ContextRef context
{GetContextRef()};
2377 if(UNLIKELY(!context
)) return;
2379 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
2380 std::lock_guard
<std::mutex
> __
{context
->SourceLock
};
2381 ALsource
*Source
{LookupSource(context
.get(), source
)};
2382 if(UNLIKELY(!Source
))
2383 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2384 else if(Int64ValsByProp(param
) != 3)
2385 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid 3-integer64 property 0x%04x", param
);
2388 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
2389 SetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), i64vals
);
2393 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
2395 ContextRef context
{GetContextRef()};
2396 if(UNLIKELY(!context
)) return;
2398 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
2399 std::lock_guard
<std::mutex
> __
{context
->SourceLock
};
2400 ALsource
*Source
{LookupSource(context
.get(), source
)};
2401 if(UNLIKELY(!Source
))
2402 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2404 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2405 else if(Int64ValsByProp(param
) < 1)
2406 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid integer64-vector property 0x%04x", param
);
2408 SetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), values
);
2412 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
2414 ContextRef context
{GetContextRef()};
2415 if(UNLIKELY(!context
)) return;
2417 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2418 ALsource
*Source
{LookupSource(context
.get(), source
)};
2419 if(UNLIKELY(!Source
))
2420 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2422 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2423 else if(FloatValsByProp(param
) != 1)
2424 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid float property 0x%04x", param
);
2428 if(GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), &dval
))
2429 *value
= static_cast<ALfloat
>(dval
);
2434 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
2436 ContextRef context
{GetContextRef()};
2437 if(UNLIKELY(!context
)) return;
2439 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2440 ALsource
*Source
{LookupSource(context
.get(), source
)};
2441 if(UNLIKELY(!Source
))
2442 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2443 else if(!(value1
&& value2
&& value3
))
2444 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2445 else if(FloatValsByProp(param
) != 3)
2446 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid 3-float property 0x%04x", param
);
2450 if(GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), dvals
))
2452 *value1
= static_cast<ALfloat
>(dvals
[0]);
2453 *value2
= static_cast<ALfloat
>(dvals
[1]);
2454 *value3
= static_cast<ALfloat
>(dvals
[2]);
2460 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2462 ContextRef context
{GetContextRef()};
2463 if(UNLIKELY(!context
)) return;
2465 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2466 ALsource
*Source
{LookupSource(context
.get(), source
)};
2467 if(UNLIKELY(!Source
))
2468 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2470 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2473 ALint count
{FloatValsByProp(param
)};
2474 if(count
< 1 && count
> 6)
2475 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid float-vector property 0x%04x", param
);
2479 if(GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), dvals
))
2481 for(ALint i
{0};i
< count
;i
++)
2482 values
[i
] = static_cast<ALfloat
>(dvals
[i
]);
2489 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2491 ContextRef context
{GetContextRef()};
2492 if(UNLIKELY(!context
)) return;
2494 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2495 ALsource
*Source
{LookupSource(context
.get(), source
)};
2496 if(UNLIKELY(!Source
))
2497 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2499 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2500 else if(DoubleValsByProp(param
) != 1)
2501 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid double property 0x%04x", param
);
2503 GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), value
);
2506 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2508 ContextRef context
{GetContextRef()};
2509 if(UNLIKELY(!context
)) return;
2511 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2512 ALsource
*Source
{LookupSource(context
.get(), source
)};
2513 if(UNLIKELY(!Source
))
2514 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2515 else if(!(value1
&& value2
&& value3
))
2516 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2517 else if(DoubleValsByProp(param
) != 3)
2518 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid 3-double property 0x%04x", param
);
2522 if(GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), dvals
))
2531 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2533 ContextRef context
{GetContextRef()};
2534 if(UNLIKELY(!context
)) return;
2536 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2537 ALsource
*Source
{LookupSource(context
.get(), source
)};
2538 if(UNLIKELY(!Source
))
2539 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2541 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2542 else if(DoubleValsByProp(param
) < 1)
2543 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid double-vector property 0x%04x", param
);
2545 GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), values
);
2549 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2551 ContextRef context
{GetContextRef()};
2552 if(UNLIKELY(!context
)) return;
2554 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2555 ALsource
*Source
{LookupSource(context
.get(), source
)};
2556 if(UNLIKELY(!Source
))
2557 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2559 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2560 else if(IntValsByProp(param
) != 1)
2561 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid integer property 0x%04x", param
);
2563 GetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), value
);
2567 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2569 ContextRef context
{GetContextRef()};
2570 if(UNLIKELY(!context
)) return;
2572 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2573 ALsource
*Source
{LookupSource(context
.get(), source
)};
2574 if(UNLIKELY(!Source
))
2575 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2576 else if(!(value1
&& value2
&& value3
))
2577 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2578 else if(IntValsByProp(param
) != 3)
2579 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid 3-integer property 0x%04x", param
);
2583 if(GetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), ivals
))
2593 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2595 ContextRef context
{GetContextRef()};
2596 if(UNLIKELY(!context
)) return;
2598 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2599 ALsource
*Source
{LookupSource(context
.get(), source
)};
2600 if(UNLIKELY(!Source
))
2601 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2603 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2604 else if(IntValsByProp(param
) < 1)
2605 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid integer-vector property 0x%04x", param
);
2607 GetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), values
);
2611 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2613 ContextRef context
{GetContextRef()};
2614 if(UNLIKELY(!context
)) return;
2616 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2617 ALsource
*Source
{LookupSource(context
.get(), source
)};
2618 if(UNLIKELY(!Source
))
2619 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2621 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2622 else if(Int64ValsByProp(param
) != 1)
2623 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid integer64 property 0x%04x", param
);
2625 GetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), value
);
2628 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2630 ContextRef context
{GetContextRef()};
2631 if(UNLIKELY(!context
)) return;
2633 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2634 ALsource
*Source
{LookupSource(context
.get(), source
)};
2635 if(UNLIKELY(!Source
))
2636 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2637 else if(!(value1
&& value2
&& value3
))
2638 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2639 else if(Int64ValsByProp(param
) != 3)
2640 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid 3-integer64 property 0x%04x", param
);
2644 if(GetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), i64vals
))
2646 *value1
= i64vals
[0];
2647 *value2
= i64vals
[1];
2648 *value3
= i64vals
[2];
2653 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2655 ContextRef context
{GetContextRef()};
2656 if(UNLIKELY(!context
)) return;
2658 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2659 ALsource
*Source
{LookupSource(context
.get(), source
)};
2660 if(UNLIKELY(!Source
))
2661 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2663 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2664 else if(Int64ValsByProp(param
) < 1)
2665 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid integer64-vector property 0x%04x", param
);
2667 GetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), values
);
2671 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2673 alSourcePlayv(1, &source
);
2675 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2677 ContextRef context
{GetContextRef()};
2678 if(UNLIKELY(!context
)) return;
2681 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Playing %d sources", n
);
2684 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2685 auto sources_end
= sources
+n
;
2686 auto bad_sid
= std::find_if_not(sources
, sources_end
,
2687 [&context
](ALuint sid
) -> bool
2689 ALsource
*source
{LookupSource(context
.get(), sid
)};
2690 return LIKELY(source
!= nullptr);
2693 if(UNLIKELY(bad_sid
!= sources
+n
))
2694 SETERR_RETURN(context
.get(), AL_INVALID_NAME
,, "Invalid source ID %u", *bad_sid
);
2696 ALCdevice
*device
{context
->Device
};
2697 BackendLockGuard __
{*device
->Backend
};
2698 /* If the device is disconnected, go right to stopped. */
2699 if(UNLIKELY(!device
->Connected
.load(std::memory_order_acquire
)))
2701 /* TODO: Send state change event? */
2702 std::for_each(sources
, sources_end
,
2703 [&context
](ALuint sid
) -> void
2705 ALsource
*source
{LookupSource(context
.get(), sid
)};
2706 source
->OffsetType
= AL_NONE
;
2707 source
->Offset
= 0.0;
2708 source
->state
= AL_STOPPED
;
2714 while(n
> context
->MaxVoices
-context
->VoiceCount
.load(std::memory_order_relaxed
))
2716 if(UNLIKELY(context
->MaxVoices
> std::numeric_limits
<ALsizei
>::max()>>1))
2717 SETERR_RETURN(context
.get(), AL_OUT_OF_MEMORY
,,
2718 "Overflow increasing voice count from %d", context
->MaxVoices
);
2719 ALsizei newcount
= context
->MaxVoices
<< 1;
2720 AllocateVoices(context
.get(), newcount
, device
->NumAuxSends
);
2723 auto start_source
= [&context
,device
](ALuint sid
) -> void
2725 ALsource
*source
{LookupSource(context
.get(), sid
)};
2726 /* Check that there is a queue containing at least one valid, non zero
2729 ALbufferlistitem
*BufferList
{source
->queue
};
2730 while(BufferList
&& BufferList
->max_samples
== 0)
2731 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
2733 /* If there's nothing to play, go right to stopped. */
2734 if(UNLIKELY(!BufferList
))
2736 /* NOTE: A source without any playable buffers should not have an
2737 * ALvoice since it shouldn't be in a playing or paused state. So
2738 * there's no need to look up its voice and clear the source.
2740 ALenum oldstate
{GetSourceState(source
, nullptr)};
2741 source
->OffsetType
= AL_NONE
;
2742 source
->Offset
= 0.0;
2743 if(oldstate
!= AL_STOPPED
)
2745 source
->state
= AL_STOPPED
;
2746 SendStateChangeEvent(context
.get(), source
->id
, AL_STOPPED
);
2751 ALvoice
*voice
{GetSourceVoice(source
, context
.get())};
2752 switch(GetSourceState(source
, voice
))
2755 assert(voice
!= nullptr);
2756 /* A source that's already playing is restarted from the beginning. */
2757 voice
->current_buffer
.store(BufferList
, std::memory_order_relaxed
);
2758 voice
->position
.store(0u, std::memory_order_relaxed
);
2759 voice
->position_fraction
.store(0, std::memory_order_release
);
2763 assert(voice
!= nullptr);
2764 /* A source that's paused simply resumes. */
2765 voice
->Playing
.store(true, std::memory_order_release
);
2766 source
->state
= AL_PLAYING
;
2767 SendStateChangeEvent(context
.get(), source
->id
, AL_PLAYING
);
2771 assert(voice
== nullptr);
2775 /* Look for an unused voice to play this source with. */
2776 auto voices_end
= context
->Voices
+ context
->VoiceCount
.load(std::memory_order_relaxed
);
2777 auto voice_iter
= std::find_if(context
->Voices
, voices_end
,
2778 [](const ALvoice
*voice
) noexcept
-> bool
2779 { return voice
->SourceID
.load(std::memory_order_relaxed
) == 0u; }
2781 auto vidx
= static_cast<ALint
>(std::distance(context
->Voices
, voice_iter
));
2782 voice
= *voice_iter
;
2783 voice
->Playing
.store(false, std::memory_order_release
);
2784 if(voice_iter
== voices_end
) context
->VoiceCount
.fetch_add(1, std::memory_order_acq_rel
);
2786 source
->PropsClean
.test_and_set(std::memory_order_acquire
);
2787 UpdateSourceProps(source
, voice
, context
.get());
2789 /* A source that's not playing or paused has any offset applied when it
2793 voice
->loop_buffer
.store(source
->queue
, std::memory_order_relaxed
);
2795 voice
->loop_buffer
.store(nullptr, std::memory_order_relaxed
);
2796 voice
->current_buffer
.store(BufferList
, std::memory_order_relaxed
);
2797 voice
->position
.store(0u, std::memory_order_relaxed
);
2798 voice
->position_fraction
.store(0, std::memory_order_relaxed
);
2799 bool start_fading
{false};
2800 if(ApplyOffset(source
, voice
) != AL_FALSE
)
2801 start_fading
= voice
->position
.load(std::memory_order_relaxed
) != 0 ||
2802 voice
->position_fraction
.load(std::memory_order_relaxed
) != 0 ||
2803 voice
->current_buffer
.load(std::memory_order_relaxed
) != BufferList
;
2805 auto buffers_end
= BufferList
->buffers
+ BufferList
->num_buffers
;
2806 auto buffer
= std::find_if(BufferList
->buffers
, buffers_end
,
2807 std::bind(std::not_equal_to
<const ALbuffer
*>{}, _1
, nullptr));
2808 if(buffer
!= buffers_end
)
2810 voice
->NumChannels
= ChannelsFromFmt((*buffer
)->mFmtChannels
);
2811 voice
->SampleSize
= BytesFromFmt((*buffer
)->mFmtType
);
2814 /* Clear previous samples. */
2815 for(auto &samples
: voice
->PrevSamples
)
2816 std::fill(std::begin(samples
), std::end(samples
), 0.0f
);
2818 /* Clear the stepping value so the mixer knows not to mix this until
2819 * the update gets applied.
2823 voice
->Flags
= start_fading
? VOICE_IS_FADING
: 0;
2824 if(source
->SourceType
== AL_STATIC
) voice
->Flags
|= VOICE_IS_STATIC
;
2826 std::fill_n(std::begin(voice
->Direct
.Params
), voice
->NumChannels
, DirectParams
{});
2827 std::for_each(voice
->Send
+0, voice
->Send
+source
->Send
.size(),
2828 [voice
](ALvoice::SendData
&send
) -> void
2829 { std::fill_n(std::begin(send
.Params
), voice
->NumChannels
, SendParams
{}); }
2832 if(device
->AvgSpeakerDist
> 0.0f
)
2834 ALfloat w1
= SPEEDOFSOUNDMETRESPERSEC
/
2835 (device
->AvgSpeakerDist
* device
->Frequency
);
2836 std::for_each(voice
->Direct
.Params
+0, voice
->Direct
.Params
+voice
->NumChannels
,
2837 [w1
](DirectParams
&parms
) noexcept
-> void
2838 { parms
.NFCtrlFilter
.init(0.0f
, w1
); }
2842 voice
->SourceID
.store(source
->id
, std::memory_order_relaxed
);
2843 voice
->Playing
.store(true, std::memory_order_release
);
2844 source
->state
= AL_PLAYING
;
2845 source
->VoiceIdx
= vidx
;
2847 SendStateChangeEvent(context
.get(), source
->id
, AL_PLAYING
);
2849 std::for_each(sources
, sources_end
, start_source
);
2852 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2854 alSourcePausev(1, &source
);
2856 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2858 ContextRef context
{GetContextRef()};
2859 if(UNLIKELY(!context
)) return;
2862 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Pausing %d sources", n
);
2865 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2866 for(ALsizei i
{0};i
< n
;i
++)
2868 if(!LookupSource(context
.get(), sources
[i
]))
2869 SETERR_RETURN(context
.get(), AL_INVALID_NAME
,, "Invalid source ID %u", sources
[i
]);
2872 ALCdevice
*device
{context
->Device
};
2873 BackendLockGuard __
{*device
->Backend
};
2874 for(ALsizei i
{0};i
< n
;i
++)
2876 ALsource
*source
{LookupSource(context
.get(), sources
[i
])};
2877 ALvoice
*voice
{GetSourceVoice(source
, context
.get())};
2878 if(voice
) voice
->Playing
.store(false, std::memory_order_release
);
2879 if(GetSourceState(source
, voice
) == AL_PLAYING
)
2881 source
->state
= AL_PAUSED
;
2882 SendStateChangeEvent(context
.get(), source
->id
, AL_PAUSED
);
2887 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2889 alSourceStopv(1, &source
);
2891 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2893 ContextRef context
{GetContextRef()};
2894 if(UNLIKELY(!context
)) return;
2897 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Stopping %d sources", n
);
2900 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2901 for(ALsizei i
{0};i
< n
;i
++)
2903 if(!LookupSource(context
.get(), sources
[i
]))
2904 SETERR_RETURN(context
.get(), AL_INVALID_NAME
,, "Invalid source ID %u", sources
[i
]);
2907 ALCdevice
*device
{context
->Device
};
2908 BackendLockGuard __
{*device
->Backend
};
2909 for(ALsizei i
{0};i
< n
;i
++)
2911 ALsource
*source
{LookupSource(context
.get(), sources
[i
])};
2912 ALvoice
*voice
{GetSourceVoice(source
, context
.get())};
2913 if(voice
!= nullptr)
2915 voice
->SourceID
.store(0u, std::memory_order_relaxed
);
2916 voice
->Playing
.store(false, std::memory_order_release
);
2919 ALenum oldstate
{GetSourceState(source
, voice
)};
2920 if(oldstate
!= AL_INITIAL
&& oldstate
!= AL_STOPPED
)
2922 source
->state
= AL_STOPPED
;
2923 SendStateChangeEvent(context
.get(), source
->id
, AL_STOPPED
);
2925 source
->OffsetType
= AL_NONE
;
2926 source
->Offset
= 0.0;
2930 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2932 alSourceRewindv(1, &source
);
2934 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2936 ContextRef context
{GetContextRef()};
2937 if(UNLIKELY(!context
)) return;
2940 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Rewinding %d sources", n
);
2943 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2944 for(ALsizei i
{0};i
< n
;i
++)
2946 if(!LookupSource(context
.get(), sources
[i
]))
2947 SETERR_RETURN(context
.get(), AL_INVALID_NAME
,, "Invalid source ID %u", sources
[i
]);
2950 ALCdevice
*device
{context
->Device
};
2951 BackendLockGuard __
{*device
->Backend
};
2952 for(ALsizei i
{0};i
< n
;i
++)
2954 ALsource
*source
{LookupSource(context
.get(), sources
[i
])};
2955 ALvoice
*voice
{GetSourceVoice(source
, context
.get())};
2956 if(voice
!= nullptr)
2958 voice
->SourceID
.store(0u, std::memory_order_relaxed
);
2959 voice
->Playing
.store(false, std::memory_order_release
);
2962 if(GetSourceState(source
, voice
) != AL_INITIAL
)
2964 source
->state
= AL_INITIAL
;
2965 SendStateChangeEvent(context
.get(), source
->id
, AL_INITIAL
);
2967 source
->OffsetType
= AL_NONE
;
2968 source
->Offset
= 0.0;
2973 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2975 ContextRef context
{GetContextRef()};
2976 if(UNLIKELY(!context
)) return;
2979 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Queueing %d buffers", nb
);
2982 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
2983 ALsource
*source
{LookupSource(context
.get(),src
)};
2984 if(UNLIKELY(!source
))
2985 SETERR_RETURN(context
.get(), AL_INVALID_NAME
,, "Invalid source ID %u", src
);
2987 /* Can't queue on a Static Source */
2988 if(UNLIKELY(source
->SourceType
== AL_STATIC
))
2989 SETERR_RETURN(context
.get(), AL_INVALID_OPERATION
,, "Queueing onto static source %u", src
);
2991 /* Check for a valid Buffer, for its frequency and format */
2992 ALCdevice
*device
{context
->Device
};
2993 ALbuffer
*BufferFmt
{nullptr};
2994 ALbufferlistitem
*BufferList
{source
->queue
};
2997 for(ALsizei i
{0};i
< BufferList
->num_buffers
;i
++)
2999 if((BufferFmt
=BufferList
->buffers
[i
]) != nullptr)
3002 if(BufferFmt
) break;
3003 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
3006 std::unique_lock
<std::mutex
> buflock
{device
->BufferLock
};
3007 ALbufferlistitem
*BufferListStart
{nullptr};
3008 BufferList
= nullptr;
3009 for(ALsizei i
{0};i
< nb
;i
++)
3011 ALbuffer
*buffer
{nullptr};
3012 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == nullptr)
3014 alSetError(context
.get(), AL_INVALID_NAME
, "Queueing invalid buffer ID %u",
3019 if(!BufferListStart
)
3021 BufferListStart
= static_cast<ALbufferlistitem
*>(al_calloc(DEF_ALIGN
,
3022 FAM_SIZE(ALbufferlistitem
, buffers
, 1)));
3023 BufferList
= BufferListStart
;
3027 auto item
= static_cast<ALbufferlistitem
*>(al_calloc(DEF_ALIGN
,
3028 FAM_SIZE(ALbufferlistitem
, buffers
, 1)));
3029 BufferList
->next
.store(item
, std::memory_order_relaxed
);
3032 BufferList
->next
.store(nullptr, std::memory_order_relaxed
);
3033 BufferList
->max_samples
= buffer
? buffer
->SampleLen
: 0;
3034 BufferList
->num_buffers
= 1;
3035 BufferList
->buffers
[0] = buffer
;
3036 if(!buffer
) continue;
3038 IncrementRef(&buffer
->ref
);
3040 if(buffer
->MappedAccess
!= 0 && !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
3042 alSetError(context
.get(), AL_INVALID_OPERATION
,
3043 "Queueing non-persistently mapped buffer %u", buffer
->id
);
3047 if(BufferFmt
== nullptr)
3049 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
3050 BufferFmt
->mFmtChannels
!= buffer
->mFmtChannels
||
3051 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
3053 alSetError(context
.get(), AL_INVALID_OPERATION
,
3054 "Queueing buffer with mismatched format");
3057 /* A buffer failed (invalid ID or format), so unlock and release
3058 * each buffer we had. */
3059 while(BufferListStart
)
3061 ALbufferlistitem
*next
= BufferListStart
->next
.load(std::memory_order_relaxed
);
3062 for(i
= 0;i
< BufferListStart
->num_buffers
;i
++)
3064 if((buffer
=BufferListStart
->buffers
[i
]) != nullptr)
3065 DecrementRef(&buffer
->ref
);
3067 al_free(BufferListStart
);
3068 BufferListStart
= next
;
3073 /* All buffers good. */
3076 /* Source is now streaming */
3077 source
->SourceType
= AL_STREAMING
;
3079 if(!(BufferList
=source
->queue
))
3080 source
->queue
= BufferListStart
;
3083 ALbufferlistitem
*next
;
3084 while((next
=BufferList
->next
.load(std::memory_order_relaxed
)) != nullptr)
3086 BufferList
->next
.store(BufferListStart
, std::memory_order_release
);
3090 AL_API
void AL_APIENTRY
alSourceQueueBufferLayersSOFT(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
3092 ContextRef context
{GetContextRef()};
3093 if(UNLIKELY(!context
)) return;
3096 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Queueing %d buffer layers", nb
);
3099 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
3100 ALsource
*source
{LookupSource(context
.get(),src
)};
3101 if(UNLIKELY(!source
))
3102 SETERR_RETURN(context
.get(), AL_INVALID_NAME
,, "Invalid source ID %u", src
);
3104 /* Can't queue on a Static Source */
3105 if(UNLIKELY(source
->SourceType
== AL_STATIC
))
3106 SETERR_RETURN(context
.get(), AL_INVALID_OPERATION
,, "Queueing onto static source %u", src
);
3108 /* Check for a valid Buffer, for its frequency and format */
3109 ALCdevice
*device
{context
->Device
};
3110 ALbuffer
*BufferFmt
{nullptr};
3111 ALbufferlistitem
*BufferList
{source
->queue
};
3114 for(ALsizei i
{0};i
< BufferList
->num_buffers
;i
++)
3116 if((BufferFmt
=BufferList
->buffers
[i
]) != nullptr)
3119 if(BufferFmt
) break;
3120 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
3123 std::unique_lock
<std::mutex
> buflock
{device
->BufferLock
};
3124 auto BufferListStart
= static_cast<ALbufferlistitem
*>(al_calloc(DEF_ALIGN
,
3125 FAM_SIZE(ALbufferlistitem
, buffers
, nb
)));
3126 BufferList
= BufferListStart
;
3127 BufferList
->next
.store(nullptr, std::memory_order_relaxed
);
3128 BufferList
->max_samples
= 0;
3129 BufferList
->num_buffers
= 0;
3131 for(ALsizei i
{0};i
< nb
;i
++)
3133 ALbuffer
*buffer
{nullptr};
3134 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == nullptr)
3136 alSetError(context
.get(), AL_INVALID_NAME
, "Queueing invalid buffer ID %u",
3141 BufferList
->buffers
[BufferList
->num_buffers
++] = buffer
;
3142 if(!buffer
) continue;
3144 IncrementRef(&buffer
->ref
);
3146 BufferList
->max_samples
= maxi(BufferList
->max_samples
, buffer
->SampleLen
);
3148 if(buffer
->MappedAccess
!= 0 && !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
3150 alSetError(context
.get(), AL_INVALID_OPERATION
,
3151 "Queueing non-persistently mapped buffer %u", buffer
->id
);
3155 if(BufferFmt
== nullptr)
3157 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
3158 BufferFmt
->mFmtChannels
!= buffer
->mFmtChannels
||
3159 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
3161 alSetError(context
.get(), AL_INVALID_OPERATION
,
3162 "Queueing buffer with mismatched format");
3165 /* A buffer failed (invalid ID or format), so unlock and release
3166 * each buffer we had. */
3167 while(BufferListStart
)
3169 ALbufferlistitem
*next
{BufferListStart
->next
.load(std::memory_order_relaxed
)};
3170 for(i
= 0;i
< BufferListStart
->num_buffers
;i
++)
3172 if((buffer
=BufferListStart
->buffers
[i
]) != nullptr)
3173 DecrementRef(&buffer
->ref
);
3175 al_free(BufferListStart
);
3176 BufferListStart
= next
;
3181 /* All buffers good. */
3184 /* Source is now streaming */
3185 source
->SourceType
= AL_STREAMING
;
3187 if(!(BufferList
=source
->queue
))
3188 source
->queue
= BufferListStart
;
3191 ALbufferlistitem
*next
;
3192 while((next
=BufferList
->next
.load(std::memory_order_relaxed
)) != nullptr)
3194 BufferList
->next
.store(BufferListStart
, std::memory_order_release
);
3198 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
3200 ContextRef context
{GetContextRef()};
3201 if(UNLIKELY(!context
)) return;
3204 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Unqueueing %d buffers", nb
);
3207 std::lock_guard
<std::mutex
> _
{context
->SourceLock
};
3208 ALsource
*source
{LookupSource(context
.get(),src
)};
3209 if(UNLIKELY(!source
))
3210 SETERR_RETURN(context
.get(), AL_INVALID_NAME
,, "Invalid source ID %u", src
);
3212 if(UNLIKELY(source
->Looping
))
3213 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Unqueueing from looping source %u", src
);
3214 if(UNLIKELY(source
->SourceType
!= AL_STREAMING
))
3215 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,,
3216 "Unqueueing from a non-streaming source %u", src
);
3218 /* Make sure enough buffers have been processed to unqueue. */
3219 ALbufferlistitem
*BufferList
{source
->queue
};
3220 ALvoice
*voice
{GetSourceVoice(source
, context
.get())};
3221 ALbufferlistitem
*Current
{nullptr};
3223 Current
= voice
->current_buffer
.load(std::memory_order_relaxed
);
3224 else if(source
->state
== AL_INITIAL
)
3225 Current
= BufferList
;
3226 if(UNLIKELY(BufferList
== Current
))
3227 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Unqueueing pending buffers");
3229 ALsizei i
{BufferList
->num_buffers
};
3232 /* If the next bufferlist to check is NULL or is the current one, it's
3233 * trying to unqueue pending buffers.
3235 ALbufferlistitem
*next
{BufferList
->next
.load(std::memory_order_relaxed
)};
3236 if(UNLIKELY(!next
) || UNLIKELY(next
== Current
))
3237 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Unqueueing pending buffers");
3240 i
+= BufferList
->num_buffers
;
3245 ALbufferlistitem
*head
{source
->queue
};
3246 ALbufferlistitem
*next
{head
->next
.load(std::memory_order_relaxed
)};
3247 for(i
= 0;i
< head
->num_buffers
&& nb
> 0;i
++,nb
--)
3249 ALbuffer
*buffer
{head
->buffers
[i
]};
3254 *(buffers
++) = buffer
->id
;
3255 DecrementRef(&buffer
->ref
);
3258 if(i
< head
->num_buffers
)
3260 /* This head has some buffers left over, so move them to the front
3261 * and update the sample and buffer count.
3263 ALsizei max_length
{0};
3265 while(i
< head
->num_buffers
)
3267 ALbuffer
*buffer
{head
->buffers
[i
++]};
3268 if(buffer
) max_length
= maxi(max_length
, buffer
->SampleLen
);
3269 head
->buffers
[j
++] = buffer
;
3271 head
->max_samples
= max_length
;
3272 head
->num_buffers
= j
;
3276 /* Otherwise, free this item and set the source queue head to the next
3280 source
->queue
= next
;
3285 ALsource::ALsource(ALsizei num_sends
)
3287 InnerAngle
= 360.0f
;
3288 OuterAngle
= 360.0f
;
3296 Direction
[0] = 0.0f
;
3297 Direction
[1] = 0.0f
;
3298 Direction
[2] = 0.0f
;
3301 OrientAt
[2] = -1.0f
;
3306 MaxDistance
= std::numeric_limits
<float>::max();
3307 RolloffFactor
= 1.0f
;
3314 DryGainHFAuto
= AL_TRUE
;
3315 WetGainAuto
= AL_TRUE
;
3316 WetGainHFAuto
= AL_TRUE
;
3317 AirAbsorptionFactor
= 0.0f
;
3318 RoomRolloffFactor
= 0.0f
;
3319 DopplerFactor
= 1.0f
;
3320 HeadRelative
= AL_FALSE
;
3322 mDistanceModel
= DistanceModel::Default
;
3323 mResampler
= ResamplerDefault
;
3324 DirectChannels
= AL_FALSE
;
3325 mSpatialize
= SpatializeAuto
;
3327 StereoPan
[0] = Deg2Rad( 30.0f
);
3328 StereoPan
[1] = Deg2Rad(-30.0f
);
3333 Direct
.GainHF
= 1.0f
;
3334 Direct
.HFReference
= LOWPASSFREQREF
;
3335 Direct
.GainLF
= 1.0f
;
3336 Direct
.LFReference
= HIGHPASSFREQREF
;
3337 Send
.resize(num_sends
);
3338 for(auto &send
: Send
)
3340 send
.Slot
= nullptr;
3343 send
.HFReference
= LOWPASSFREQREF
;
3345 send
.LFReference
= HIGHPASSFREQREF
;
3349 OffsetType
= AL_NONE
;
3350 SourceType
= AL_UNDETERMINED
;
3358 ALsource::~ALsource()
3360 ALbufferlistitem
*BufferList
{queue
};
3361 while(BufferList
!= nullptr)
3363 ALbufferlistitem
*next
{BufferList
->next
.load(std::memory_order_relaxed
)};
3364 for(ALsizei i
{0};i
< BufferList
->num_buffers
;i
++)
3366 if(BufferList
->buffers
[i
])
3367 DecrementRef(&BufferList
->buffers
[i
]->ref
);
3369 al_free(BufferList
);
3374 std::for_each(Send
.begin(), Send
.end(),
3375 [](ALsource::SendData
&send
) -> void
3378 DecrementRef(&send
.Slot
->ref
);
3379 send
.Slot
= nullptr;
3384 void UpdateAllSourceProps(ALCcontext
*context
)
3386 auto voices_end
= context
->Voices
+ context
->VoiceCount
.load(std::memory_order_relaxed
);
3387 std::for_each(context
->Voices
, voices_end
,
3388 [context
](ALvoice
*voice
) -> void
3390 ALuint sid
{voice
->SourceID
.load(std::memory_order_acquire
)};
3391 ALsource
*source
= sid
? LookupSource(context
, sid
) : nullptr;
3392 if(source
&& !source
->PropsClean
.test_and_set(std::memory_order_acq_rel
))
3393 UpdateSourceProps(source
, voice
, context
);
3398 SourceSubList::~SourceSubList()
3400 ALuint64 usemask
= ~FreeMask
;
3403 ALsizei idx
{CTZ64(usemask
)};
3404 Sources
[idx
].~ALsource();
3405 usemask
&= ~(1_u64
<< idx
);
3407 FreeMask
= ~usemask
;