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
35 #include "alcontext.h"
40 #include "alAuxEffectSlot.h"
41 #include "ringbuffer.h"
43 #include "backends/base.h"
51 inline ALvoice
*GetSourceVoice(ALsource
*source
, ALCcontext
*context
)
53 ALint idx
{source
->VoiceIdx
};
54 if(idx
>= 0 && idx
< context
->VoiceCount
.load(std::memory_order_relaxed
))
56 ALvoice
*voice
{context
->Voices
[idx
]};
57 if(voice
->Source
.load(std::memory_order_acquire
) == source
)
60 source
->VoiceIdx
= -1;
64 void UpdateSourceProps(ALsource
*source
, ALvoice
*voice
, ALCcontext
*context
)
66 /* Get an unused property container, or allocate a new one as needed. */
67 ALvoiceProps
*props
{context
->FreeVoiceProps
.load(std::memory_order_acquire
)};
69 props
= static_cast<ALvoiceProps
*>(al_calloc(16,
70 FAM_SIZE(ALvoiceProps
, Send
, source
->Send
.size()))
76 next
= props
->next
.load(std::memory_order_relaxed
);
77 } while(context
->FreeVoiceProps
.compare_exchange_weak(props
, next
,
78 std::memory_order_acq_rel
, std::memory_order_acquire
) == 0);
81 /* Copy in current property values. */
82 props
->Pitch
= source
->Pitch
;
83 props
->Gain
= source
->Gain
;
84 props
->OuterGain
= source
->OuterGain
;
85 props
->MinGain
= source
->MinGain
;
86 props
->MaxGain
= source
->MaxGain
;
87 props
->InnerAngle
= source
->InnerAngle
;
88 props
->OuterAngle
= source
->OuterAngle
;
89 props
->RefDistance
= source
->RefDistance
;
90 props
->MaxDistance
= source
->MaxDistance
;
91 props
->RolloffFactor
= source
->RolloffFactor
;
92 std::copy_n(source
->Position
, 3, props
->Position
);
93 std::copy_n(source
->Velocity
, 3, props
->Velocity
);
94 std::copy_n(source
->Direction
, 3, props
->Direction
);
95 for(ALsizei i
{0};i
< 2;i
++)
96 std::copy_n(source
->Orientation
[i
], 3, props
->Orientation
[i
]);
97 props
->HeadRelative
= source
->HeadRelative
;
98 props
->mDistanceModel
= source
->mDistanceModel
;
99 props
->Resampler
= source
->Resampler
;
100 props
->DirectChannels
= source
->DirectChannels
;
101 props
->SpatializeMode
= source
->Spatialize
;
103 props
->DryGainHFAuto
= source
->DryGainHFAuto
;
104 props
->WetGainAuto
= source
->WetGainAuto
;
105 props
->WetGainHFAuto
= source
->WetGainHFAuto
;
106 props
->OuterGainHF
= source
->OuterGainHF
;
108 props
->AirAbsorptionFactor
= source
->AirAbsorptionFactor
;
109 props
->RoomRolloffFactor
= source
->RoomRolloffFactor
;
110 props
->DopplerFactor
= source
->DopplerFactor
;
112 std::copy_n(source
->StereoPan
, 2, props
->StereoPan
);
114 props
->Radius
= source
->Radius
;
116 props
->Direct
.Gain
= source
->Direct
.Gain
;
117 props
->Direct
.GainHF
= source
->Direct
.GainHF
;
118 props
->Direct
.HFReference
= source
->Direct
.HFReference
;
119 props
->Direct
.GainLF
= source
->Direct
.GainLF
;
120 props
->Direct
.LFReference
= source
->Direct
.LFReference
;
122 for(size_t i
{0u};i
< source
->Send
.size();i
++)
124 props
->Send
[i
].Slot
= source
->Send
[i
].Slot
;
125 props
->Send
[i
].Gain
= source
->Send
[i
].Gain
;
126 props
->Send
[i
].GainHF
= source
->Send
[i
].GainHF
;
127 props
->Send
[i
].HFReference
= source
->Send
[i
].HFReference
;
128 props
->Send
[i
].GainLF
= source
->Send
[i
].GainLF
;
129 props
->Send
[i
].LFReference
= source
->Send
[i
].LFReference
;
132 /* Set the new container for updating internal parameters. */
133 props
= voice
->Update
.exchange(props
, std::memory_order_acq_rel
);
136 /* If there was an unused update container, put it back in the
139 AtomicReplaceHead(context
->FreeVoiceProps
, props
);
144 /* GetSourceSampleOffset
146 * Gets the current read offset for the given Source, in 32.32 fixed-point
147 * samples. The offset is relative to the start of the queue (not the start of
148 * the current buffer).
150 ALint64
GetSourceSampleOffset(ALsource
*Source
, ALCcontext
*context
, std::chrono::nanoseconds
*clocktime
)
152 ALCdevice
*device
{context
->Device
};
153 const ALbufferlistitem
*Current
;
161 while(((refcount
=device
->MixCount
.load(std::memory_order_acquire
))&1))
163 *clocktime
= GetDeviceClockTime(device
);
165 voice
= GetSourceVoice(Source
, context
);
168 Current
= voice
->current_buffer
.load(std::memory_order_relaxed
);
170 readPos
= (ALuint64
)voice
->position
.load(std::memory_order_relaxed
) << 32;
171 readPos
|= (ALuint64
)voice
->position_fraction
.load(std::memory_order_relaxed
) <<
174 std::atomic_thread_fence(std::memory_order_acquire
);
175 } while(refcount
!= device
->MixCount
.load(std::memory_order_relaxed
));
179 const ALbufferlistitem
*BufferList
{Source
->queue
};
180 while(BufferList
&& BufferList
!= Current
)
182 readPos
+= (ALuint64
)BufferList
->max_samples
<< 32;
183 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
185 readPos
= minu64(readPos
, U64(0x7fffffffffffffff));
188 return (ALint64
)readPos
;
191 /* GetSourceSecOffset
193 * Gets the current read offset for the given Source, in seconds. The offset is
194 * relative to the start of the queue (not the start of the current buffer).
196 ALdouble
GetSourceSecOffset(ALsource
*Source
, ALCcontext
*context
, std::chrono::nanoseconds
*clocktime
)
198 ALCdevice
*device
{context
->Device
};
199 const ALbufferlistitem
*Current
;
207 while(((refcount
=device
->MixCount
.load(std::memory_order_acquire
))&1))
209 *clocktime
= GetDeviceClockTime(device
);
211 voice
= GetSourceVoice(Source
, context
);
214 Current
= voice
->current_buffer
.load(std::memory_order_relaxed
);
216 readPos
= (ALuint64
)voice
->position
.load(std::memory_order_relaxed
) << FRACTIONBITS
;
217 readPos
|= voice
->position_fraction
.load(std::memory_order_relaxed
);
219 std::atomic_thread_fence(std::memory_order_acquire
);
220 } while(refcount
!= device
->MixCount
.load(std::memory_order_relaxed
));
222 ALdouble offset
{0.0};
225 const ALbufferlistitem
*BufferList
{Source
->queue
};
226 const ALbuffer
*BufferFmt
{nullptr};
227 while(BufferList
&& BufferList
!= Current
)
229 for(ALsizei i
{0};!BufferFmt
&& i
< BufferList
->num_buffers
;++i
)
230 BufferFmt
= BufferList
->buffers
[i
];
231 readPos
+= (ALuint64
)BufferList
->max_samples
<< FRACTIONBITS
;
232 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
235 while(BufferList
&& !BufferFmt
)
237 for(ALsizei i
{0};!BufferFmt
&& i
< BufferList
->num_buffers
;++i
)
238 BufferFmt
= BufferList
->buffers
[i
];
239 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
241 assert(BufferFmt
!= nullptr);
243 offset
= (ALdouble
)readPos
/ (ALdouble
)FRACTIONONE
/
244 (ALdouble
)BufferFmt
->Frequency
;
252 * Gets the current read offset for the given Source, in the appropriate format
253 * (Bytes, Samples or Seconds). The offset is relative to the start of the
254 * queue (not the start of the current buffer).
256 ALdouble
GetSourceOffset(ALsource
*Source
, ALenum name
, ALCcontext
*context
)
258 ALCdevice
*device
{context
->Device
};
259 const ALbufferlistitem
*Current
;
267 readPos
= readPosFrac
= 0;
268 while(((refcount
=device
->MixCount
.load(std::memory_order_acquire
))&1))
270 voice
= GetSourceVoice(Source
, context
);
273 Current
= voice
->current_buffer
.load(std::memory_order_relaxed
);
275 readPos
= voice
->position
.load(std::memory_order_relaxed
);
276 readPosFrac
= voice
->position_fraction
.load(std::memory_order_relaxed
);
278 std::atomic_thread_fence(std::memory_order_acquire
);
279 } while(refcount
!= device
->MixCount
.load(std::memory_order_relaxed
));
281 ALdouble offset
{0.0};
284 const ALbufferlistitem
*BufferList
{Source
->queue
};
285 const ALbuffer
*BufferFmt
{nullptr};
286 ALboolean readFin
{AL_FALSE
};
287 ALuint totalBufferLen
{0u};
291 for(ALsizei i
{0};!BufferFmt
&& i
< BufferList
->num_buffers
;++i
)
292 BufferFmt
= BufferList
->buffers
[i
];
294 readFin
|= (BufferList
== Current
);
295 totalBufferLen
+= BufferList
->max_samples
;
296 if(!readFin
) readPos
+= BufferList
->max_samples
;
298 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
300 assert(BufferFmt
!= nullptr);
303 readPos
%= totalBufferLen
;
307 if(readPos
>= totalBufferLen
)
308 readPos
= readPosFrac
= 0;
315 offset
= (readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
) / BufferFmt
->Frequency
;
318 case AL_SAMPLE_OFFSET
:
319 offset
= readPos
+ (ALdouble
)readPosFrac
/FRACTIONONE
;
323 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
325 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
326 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
327 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
329 /* Round down to nearest ADPCM block */
330 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
332 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
334 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
335 ALuint BlockSize
= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
336 ALuint FrameBlockSize
= BufferFmt
->OriginalAlign
;
338 /* Round down to nearest ADPCM block */
339 offset
= (ALdouble
)(readPos
/ FrameBlockSize
* BlockSize
);
343 ALuint FrameSize
= FrameSizeFromFmt(BufferFmt
->FmtChannels
,
345 offset
= (ALdouble
)(readPos
* FrameSize
);
357 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
358 * or Second offset supplied by the application). This takes into account the
359 * fact that the buffer format may have been modifed since.
361 ALboolean
GetSampleOffset(ALsource
*Source
, ALuint
*offset
, ALsizei
*frac
)
363 const ALbuffer
*BufferFmt
{nullptr};
364 const ALbufferlistitem
*BufferList
;
366 /* Find the first valid Buffer in the Queue */
367 BufferList
= Source
->queue
;
370 for(ALsizei i
{0};i
< BufferList
->num_buffers
&& !BufferFmt
;i
++)
371 BufferFmt
= BufferList
->buffers
[i
];
373 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
377 Source
->OffsetType
= AL_NONE
;
378 Source
->Offset
= 0.0;
382 ALdouble dbloff
, dblfrac
;
383 switch(Source
->OffsetType
)
386 /* Determine the ByteOffset (and ensure it is block aligned) */
387 *offset
= (ALuint
)Source
->Offset
;
388 if(BufferFmt
->OriginalType
== UserFmtIMA4
)
390 ALsizei align
= (BufferFmt
->OriginalAlign
-1)/2 + 4;
391 *offset
/= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
392 *offset
*= BufferFmt
->OriginalAlign
;
394 else if(BufferFmt
->OriginalType
== UserFmtMSADPCM
)
396 ALsizei align
= (BufferFmt
->OriginalAlign
-2)/2 + 7;
397 *offset
/= align
* ChannelsFromFmt(BufferFmt
->FmtChannels
);
398 *offset
*= BufferFmt
->OriginalAlign
;
401 *offset
/= FrameSizeFromFmt(BufferFmt
->FmtChannels
, BufferFmt
->FmtType
);
405 case AL_SAMPLE_OFFSET
:
406 dblfrac
= modf(Source
->Offset
, &dbloff
);
407 *offset
= (ALuint
)mind(dbloff
, std::numeric_limits
<unsigned int>::max());
408 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
412 dblfrac
= modf(Source
->Offset
*BufferFmt
->Frequency
, &dbloff
);
413 *offset
= (ALuint
)mind(dbloff
, std::numeric_limits
<unsigned int>::max());
414 *frac
= (ALsizei
)mind(dblfrac
*FRACTIONONE
, FRACTIONONE
-1.0);
417 Source
->OffsetType
= AL_NONE
;
418 Source
->Offset
= 0.0;
425 * Apply the stored playback offset to the Source. This function will update
426 * the number of buffers "played" given the stored offset.
428 ALboolean
ApplyOffset(ALsource
*Source
, ALvoice
*voice
)
430 /* Get sample frame offset */
433 if(!GetSampleOffset(Source
, &offset
, &frac
))
436 ALuint totalBufferLen
{0u};
437 ALbufferlistitem
*BufferList
{Source
->queue
};
438 while(BufferList
&& totalBufferLen
<= offset
)
440 if((ALuint
)BufferList
->max_samples
> offset
-totalBufferLen
)
442 /* Offset is in this buffer */
443 voice
->position
.store(offset
- totalBufferLen
, std::memory_order_relaxed
);
444 voice
->position_fraction
.store(frac
, std::memory_order_relaxed
);
445 voice
->current_buffer
.store(BufferList
, std::memory_order_release
);
448 totalBufferLen
+= BufferList
->max_samples
;
450 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
453 /* Offset is out of range of the queue */
458 ALsource
*AllocSource(ALCcontext
*context
)
460 ALCdevice
*device
{context
->Device
};
461 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
462 if(context
->NumSources
>= device
->SourcesMax
)
464 alSetError(context
, AL_OUT_OF_MEMORY
, "Exceeding %u source limit", device
->SourcesMax
);
467 auto sublist
= std::find_if(context
->SourceList
.begin(), context
->SourceList
.end(),
468 [](const SourceSubList
&entry
) -> bool
469 { return entry
.FreeMask
!= 0; }
471 ALsizei lidx
= std::distance(context
->SourceList
.begin(), sublist
);
474 if(LIKELY(sublist
!= context
->SourceList
.end()))
476 slidx
= CTZ64(sublist
->FreeMask
);
477 source
= sublist
->Sources
+ slidx
;
481 /* Don't allocate so many list entries that the 32-bit ID could
484 if(UNLIKELY(context
->SourceList
.size() >= 1<<25))
486 alSetError(context
, AL_OUT_OF_MEMORY
, "Too many sources allocated");
489 context
->SourceList
.emplace_back();
490 sublist
= context
->SourceList
.end() - 1;
492 sublist
->FreeMask
= ~U64(0);
493 sublist
->Sources
= static_cast<ALsource
*>(al_calloc(16, sizeof(ALsource
)*64));
494 if(UNLIKELY(!sublist
->Sources
))
496 context
->SourceList
.pop_back();
497 alSetError(context
, AL_OUT_OF_MEMORY
, "Failed to allocate source batch");
502 source
= sublist
->Sources
+ slidx
;
505 source
= new (source
) ALsource
{device
->NumAuxSends
};
507 /* Add 1 to avoid source ID 0. */
508 source
->id
= ((lidx
<<6) | slidx
) + 1;
510 context
->NumSources
+= 1;
511 sublist
->FreeMask
&= ~(U64(1)<<slidx
);
516 void FreeSource(ALCcontext
*context
, ALsource
*source
)
518 ALuint id
= source
->id
- 1;
519 ALsizei lidx
= id
>> 6;
520 ALsizei slidx
= id
& 0x3f;
522 ALCdevice
*device
{context
->Device
};
523 ALCdevice_Lock(device
);
524 ALvoice
*voice
{GetSourceVoice(source
, context
)};
527 voice
->Source
.store(nullptr, std::memory_order_relaxed
);
528 voice
->Playing
.store(false, std::memory_order_release
);
530 ALCdevice_Unlock(device
);
534 context
->SourceList
[lidx
].FreeMask
|= U64(1) << slidx
;
535 context
->NumSources
--;
539 inline ALsource
*LookupSource(ALCcontext
*context
, ALuint id
) noexcept
541 ALuint lidx
= (id
-1) >> 6;
542 ALsizei slidx
= (id
-1) & 0x3f;
544 if(UNLIKELY(lidx
>= context
->SourceList
.size()))
546 SourceSubList
&sublist
{context
->SourceList
[lidx
]};
547 if(UNLIKELY(sublist
.FreeMask
& (U64(1)<<slidx
)))
549 return sublist
.Sources
+ slidx
;
552 inline ALbuffer
*LookupBuffer(ALCdevice
*device
, ALuint id
) noexcept
554 ALuint lidx
= (id
-1) >> 6;
555 ALsizei slidx
= (id
-1) & 0x3f;
557 if(UNLIKELY(lidx
>= device
->BufferList
.size()))
559 BufferSubList
&sublist
= device
->BufferList
[lidx
];
560 if(UNLIKELY(sublist
.FreeMask
& (U64(1)<<slidx
)))
562 return sublist
.Buffers
+ slidx
;
565 inline ALfilter
*LookupFilter(ALCdevice
*device
, ALuint id
) noexcept
567 ALuint lidx
= (id
-1) >> 6;
568 ALsizei slidx
= (id
-1) & 0x3f;
570 if(UNLIKELY(lidx
>= device
->FilterList
.size()))
572 FilterSubList
&sublist
= device
->FilterList
[lidx
];
573 if(UNLIKELY(sublist
.FreeMask
& (U64(1)<<slidx
)))
575 return sublist
.Filters
+ slidx
;
578 inline ALeffectslot
*LookupEffectSlot(ALCcontext
*context
, ALuint id
) noexcept
581 if(UNLIKELY(id
>= context
->EffectSlotList
.size()))
583 return context
->EffectSlotList
[id
].get();
590 srcMinGain
= AL_MIN_GAIN
,
591 srcMaxGain
= AL_MAX_GAIN
,
592 srcMaxDistance
= AL_MAX_DISTANCE
,
593 srcRolloffFactor
= AL_ROLLOFF_FACTOR
,
594 srcDopplerFactor
= AL_DOPPLER_FACTOR
,
595 srcConeOuterGain
= AL_CONE_OUTER_GAIN
,
596 srcSecOffset
= AL_SEC_OFFSET
,
597 srcSampleOffset
= AL_SAMPLE_OFFSET
,
598 srcByteOffset
= AL_BYTE_OFFSET
,
599 srcConeInnerAngle
= AL_CONE_INNER_ANGLE
,
600 srcConeOuterAngle
= AL_CONE_OUTER_ANGLE
,
601 srcRefDistance
= AL_REFERENCE_DISTANCE
,
603 srcPosition
= AL_POSITION
,
604 srcVelocity
= AL_VELOCITY
,
605 srcDirection
= AL_DIRECTION
,
607 srcSourceRelative
= AL_SOURCE_RELATIVE
,
608 srcLooping
= AL_LOOPING
,
609 srcBuffer
= AL_BUFFER
,
610 srcSourceState
= AL_SOURCE_STATE
,
611 srcBuffersQueued
= AL_BUFFERS_QUEUED
,
612 srcBuffersProcessed
= AL_BUFFERS_PROCESSED
,
613 srcSourceType
= AL_SOURCE_TYPE
,
616 srcConeOuterGainHF
= AL_CONE_OUTER_GAINHF
,
617 srcAirAbsorptionFactor
= AL_AIR_ABSORPTION_FACTOR
,
618 srcRoomRolloffFactor
= AL_ROOM_ROLLOFF_FACTOR
,
619 srcDirectFilterGainHFAuto
= AL_DIRECT_FILTER_GAINHF_AUTO
,
620 srcAuxSendFilterGainAuto
= AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
,
621 srcAuxSendFilterGainHFAuto
= AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
,
622 srcDirectFilter
= AL_DIRECT_FILTER
,
623 srcAuxSendFilter
= AL_AUXILIARY_SEND_FILTER
,
625 /* AL_SOFT_direct_channels */
626 srcDirectChannelsSOFT
= AL_DIRECT_CHANNELS_SOFT
,
628 /* AL_EXT_source_distance_model */
629 srcDistanceModel
= AL_DISTANCE_MODEL
,
631 /* AL_SOFT_source_latency */
632 srcSampleOffsetLatencySOFT
= AL_SAMPLE_OFFSET_LATENCY_SOFT
,
633 srcSecOffsetLatencySOFT
= AL_SEC_OFFSET_LATENCY_SOFT
,
635 /* AL_EXT_STEREO_ANGLES */
636 srcAngles
= AL_STEREO_ANGLES
,
638 /* AL_EXT_SOURCE_RADIUS */
639 srcRadius
= AL_SOURCE_RADIUS
,
642 srcOrientation
= AL_ORIENTATION
,
644 /* AL_SOFT_source_resampler */
645 srcResampler
= AL_SOURCE_RESAMPLER_SOFT
,
647 /* AL_SOFT_source_spatialize */
648 srcSpatialize
= AL_SOURCE_SPATIALIZE_SOFT
,
650 /* ALC_SOFT_device_clock */
651 srcSampleOffsetClockSOFT
= AL_SAMPLE_OFFSET_CLOCK_SOFT
,
652 srcSecOffsetClockSOFT
= AL_SEC_OFFSET_CLOCK_SOFT
,
656 * Returns if the last known state for the source was playing or paused. Does
657 * not sync with the mixer voice.
659 inline bool IsPlayingOrPaused(ALsource
*source
)
660 { return source
->state
== AL_PLAYING
|| source
->state
== AL_PAUSED
; }
663 * Returns an updated source state using the matching voice's status (or lack
666 inline ALenum
GetSourceState(ALsource
*source
, ALvoice
*voice
)
668 if(!voice
&& source
->state
== AL_PLAYING
)
669 source
->state
= AL_STOPPED
;
670 return source
->state
;
674 * Returns if the source should specify an update, given the context's
675 * deferring state and the source's last known state.
677 inline bool SourceShouldUpdate(ALsource
*source
, ALCcontext
*context
)
679 return !context
->DeferUpdates
.load(std::memory_order_acquire
) &&
680 IsPlayingOrPaused(source
);
684 /** Can only be called while the mixer is locked! */
685 void SendStateChangeEvent(ALCcontext
*context
, ALuint id
, ALenum state
)
687 AsyncEvent evt
= ASYNC_EVENT(EventType_SourceStateChange
);
688 ALbitfieldSOFT enabledevt
;
690 enabledevt
= context
->EnabledEvts
.load(std::memory_order_acquire
);
691 if(!(enabledevt
&EventType_SourceStateChange
)) return;
693 evt
.u
.user
.type
= AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT
;
695 evt
.u
.user
.param
= state
;
696 snprintf(evt
.u
.user
.msg
, sizeof(evt
.u
.user
.msg
), "Source ID %u state changed to %s", id
,
697 (state
==AL_INITIAL
) ? "AL_INITIAL" :
698 (state
==AL_PLAYING
) ? "AL_PLAYING" :
699 (state
==AL_PAUSED
) ? "AL_PAUSED" :
700 (state
==AL_STOPPED
) ? "AL_STOPPED" : "<unknown>"
702 /* The mixer may have queued a state change that's not yet been processed,
703 * and we don't want state change messages to occur out of order, so send
704 * it through the async queue to ensure proper ordering.
706 if(ll_ringbuffer_write(context
->AsyncEvents
, &evt
, 1) == 1)
707 alsem_post(&context
->EventSem
);
711 ALint
FloatValsByProp(ALenum prop
)
713 if(prop
!= (ALenum
)((SourceProp
)prop
))
715 switch((SourceProp
)prop
)
721 case AL_MAX_DISTANCE
:
722 case AL_ROLLOFF_FACTOR
:
723 case AL_DOPPLER_FACTOR
:
724 case AL_CONE_OUTER_GAIN
:
726 case AL_SAMPLE_OFFSET
:
728 case AL_CONE_INNER_ANGLE
:
729 case AL_CONE_OUTER_ANGLE
:
730 case AL_REFERENCE_DISTANCE
:
731 case AL_CONE_OUTER_GAINHF
:
732 case AL_AIR_ABSORPTION_FACTOR
:
733 case AL_ROOM_ROLLOFF_FACTOR
:
734 case AL_DIRECT_FILTER_GAINHF_AUTO
:
735 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
736 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
737 case AL_DIRECT_CHANNELS_SOFT
:
738 case AL_DISTANCE_MODEL
:
739 case AL_SOURCE_RELATIVE
:
741 case AL_SOURCE_STATE
:
742 case AL_BUFFERS_QUEUED
:
743 case AL_BUFFERS_PROCESSED
:
745 case AL_SOURCE_RADIUS
:
746 case AL_SOURCE_RESAMPLER_SOFT
:
747 case AL_SOURCE_SPATIALIZE_SOFT
:
750 case AL_STEREO_ANGLES
:
761 case AL_SEC_OFFSET_LATENCY_SOFT
:
762 case AL_SEC_OFFSET_CLOCK_SOFT
:
763 break; /* Double only */
766 case AL_DIRECT_FILTER
:
767 case AL_AUXILIARY_SEND_FILTER
:
768 break; /* i/i64 only */
769 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
770 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
771 break; /* i64 only */
775 ALint
DoubleValsByProp(ALenum prop
)
777 if(prop
!= (ALenum
)((SourceProp
)prop
))
779 switch((SourceProp
)prop
)
785 case AL_MAX_DISTANCE
:
786 case AL_ROLLOFF_FACTOR
:
787 case AL_DOPPLER_FACTOR
:
788 case AL_CONE_OUTER_GAIN
:
790 case AL_SAMPLE_OFFSET
:
792 case AL_CONE_INNER_ANGLE
:
793 case AL_CONE_OUTER_ANGLE
:
794 case AL_REFERENCE_DISTANCE
:
795 case AL_CONE_OUTER_GAINHF
:
796 case AL_AIR_ABSORPTION_FACTOR
:
797 case AL_ROOM_ROLLOFF_FACTOR
:
798 case AL_DIRECT_FILTER_GAINHF_AUTO
:
799 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
800 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
801 case AL_DIRECT_CHANNELS_SOFT
:
802 case AL_DISTANCE_MODEL
:
803 case AL_SOURCE_RELATIVE
:
805 case AL_SOURCE_STATE
:
806 case AL_BUFFERS_QUEUED
:
807 case AL_BUFFERS_PROCESSED
:
809 case AL_SOURCE_RADIUS
:
810 case AL_SOURCE_RESAMPLER_SOFT
:
811 case AL_SOURCE_SPATIALIZE_SOFT
:
814 case AL_SEC_OFFSET_LATENCY_SOFT
:
815 case AL_SEC_OFFSET_CLOCK_SOFT
:
816 case AL_STEREO_ANGLES
:
828 case AL_DIRECT_FILTER
:
829 case AL_AUXILIARY_SEND_FILTER
:
830 break; /* i/i64 only */
831 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
832 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
833 break; /* i64 only */
838 ALint
IntValsByProp(ALenum prop
)
840 if(prop
!= (ALenum
)((SourceProp
)prop
))
842 switch((SourceProp
)prop
)
848 case AL_MAX_DISTANCE
:
849 case AL_ROLLOFF_FACTOR
:
850 case AL_DOPPLER_FACTOR
:
851 case AL_CONE_OUTER_GAIN
:
853 case AL_SAMPLE_OFFSET
:
855 case AL_CONE_INNER_ANGLE
:
856 case AL_CONE_OUTER_ANGLE
:
857 case AL_REFERENCE_DISTANCE
:
858 case AL_CONE_OUTER_GAINHF
:
859 case AL_AIR_ABSORPTION_FACTOR
:
860 case AL_ROOM_ROLLOFF_FACTOR
:
861 case AL_DIRECT_FILTER_GAINHF_AUTO
:
862 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
863 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
864 case AL_DIRECT_CHANNELS_SOFT
:
865 case AL_DISTANCE_MODEL
:
866 case AL_SOURCE_RELATIVE
:
869 case AL_SOURCE_STATE
:
870 case AL_BUFFERS_QUEUED
:
871 case AL_BUFFERS_PROCESSED
:
873 case AL_DIRECT_FILTER
:
874 case AL_SOURCE_RADIUS
:
875 case AL_SOURCE_RESAMPLER_SOFT
:
876 case AL_SOURCE_SPATIALIZE_SOFT
:
882 case AL_AUXILIARY_SEND_FILTER
:
888 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
889 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
890 break; /* i64 only */
891 case AL_SEC_OFFSET_LATENCY_SOFT
:
892 case AL_SEC_OFFSET_CLOCK_SOFT
:
893 break; /* Double only */
894 case AL_STEREO_ANGLES
:
895 break; /* Float/double only */
899 ALint
Int64ValsByProp(ALenum prop
)
901 if(prop
!= (ALenum
)((SourceProp
)prop
))
903 switch((SourceProp
)prop
)
909 case AL_MAX_DISTANCE
:
910 case AL_ROLLOFF_FACTOR
:
911 case AL_DOPPLER_FACTOR
:
912 case AL_CONE_OUTER_GAIN
:
914 case AL_SAMPLE_OFFSET
:
916 case AL_CONE_INNER_ANGLE
:
917 case AL_CONE_OUTER_ANGLE
:
918 case AL_REFERENCE_DISTANCE
:
919 case AL_CONE_OUTER_GAINHF
:
920 case AL_AIR_ABSORPTION_FACTOR
:
921 case AL_ROOM_ROLLOFF_FACTOR
:
922 case AL_DIRECT_FILTER_GAINHF_AUTO
:
923 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
924 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
925 case AL_DIRECT_CHANNELS_SOFT
:
926 case AL_DISTANCE_MODEL
:
927 case AL_SOURCE_RELATIVE
:
930 case AL_SOURCE_STATE
:
931 case AL_BUFFERS_QUEUED
:
932 case AL_BUFFERS_PROCESSED
:
934 case AL_DIRECT_FILTER
:
935 case AL_SOURCE_RADIUS
:
936 case AL_SOURCE_RESAMPLER_SOFT
:
937 case AL_SOURCE_SPATIALIZE_SOFT
:
940 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
941 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
947 case AL_AUXILIARY_SEND_FILTER
:
953 case AL_SEC_OFFSET_LATENCY_SOFT
:
954 case AL_SEC_OFFSET_CLOCK_SOFT
:
955 break; /* Double only */
956 case AL_STEREO_ANGLES
:
957 break; /* Float/double only */
963 ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
);
964 ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
);
965 ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
);
967 #define CHECKVAL(x) do { \
970 alSetError(Context, AL_INVALID_VALUE, "Value out of range"); \
975 #define DO_UPDATEPROPS() do { \
977 if(SourceShouldUpdate(Source, Context) && \
978 (voice=GetSourceVoice(Source, Context)) != nullptr) \
979 UpdateSourceProps(Source, voice, Context); \
981 Source->PropsClean.clear(std::memory_order_release); \
984 ALboolean
SetSourcefv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALfloat
*values
)
990 case AL_SEC_OFFSET_LATENCY_SOFT
:
991 case AL_SEC_OFFSET_CLOCK_SOFT
:
993 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
994 "Setting read-only source property 0x%04x", prop
);
997 CHECKVAL(*values
>= 0.0f
);
999 Source
->Pitch
= *values
;
1003 case AL_CONE_INNER_ANGLE
:
1004 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
1006 Source
->InnerAngle
= *values
;
1010 case AL_CONE_OUTER_ANGLE
:
1011 CHECKVAL(*values
>= 0.0f
&& *values
<= 360.0f
);
1013 Source
->OuterAngle
= *values
;
1018 CHECKVAL(*values
>= 0.0f
);
1020 Source
->Gain
= *values
;
1024 case AL_MAX_DISTANCE
:
1025 CHECKVAL(*values
>= 0.0f
);
1027 Source
->MaxDistance
= *values
;
1031 case AL_ROLLOFF_FACTOR
:
1032 CHECKVAL(*values
>= 0.0f
);
1034 Source
->RolloffFactor
= *values
;
1038 case AL_REFERENCE_DISTANCE
:
1039 CHECKVAL(*values
>= 0.0f
);
1041 Source
->RefDistance
= *values
;
1046 CHECKVAL(*values
>= 0.0f
);
1048 Source
->MinGain
= *values
;
1053 CHECKVAL(*values
>= 0.0f
);
1055 Source
->MaxGain
= *values
;
1059 case AL_CONE_OUTER_GAIN
:
1060 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
1062 Source
->OuterGain
= *values
;
1066 case AL_CONE_OUTER_GAINHF
:
1067 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
1069 Source
->OuterGainHF
= *values
;
1073 case AL_AIR_ABSORPTION_FACTOR
:
1074 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
1076 Source
->AirAbsorptionFactor
= *values
;
1080 case AL_ROOM_ROLLOFF_FACTOR
:
1081 CHECKVAL(*values
>= 0.0f
&& *values
<= 10.0f
);
1083 Source
->RoomRolloffFactor
= *values
;
1087 case AL_DOPPLER_FACTOR
:
1088 CHECKVAL(*values
>= 0.0f
&& *values
<= 1.0f
);
1090 Source
->DopplerFactor
= *values
;
1095 case AL_SAMPLE_OFFSET
:
1096 case AL_BYTE_OFFSET
:
1097 CHECKVAL(*values
>= 0.0f
);
1099 Source
->OffsetType
= prop
;
1100 Source
->Offset
= *values
;
1102 if(IsPlayingOrPaused(Source
))
1106 ALCdevice_Lock(Context
->Device
);
1107 /* Double-check that the source is still playing while we have
1110 voice
= GetSourceVoice(Source
, Context
);
1113 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
1115 ALCdevice_Unlock(Context
->Device
);
1116 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid offset");
1119 ALCdevice_Unlock(Context
->Device
);
1123 case AL_SOURCE_RADIUS
:
1124 CHECKVAL(*values
>= 0.0f
&& std::isfinite(*values
));
1126 Source
->Radius
= *values
;
1130 case AL_STEREO_ANGLES
:
1131 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]));
1133 Source
->StereoPan
[0] = values
[0];
1134 Source
->StereoPan
[1] = values
[1];
1140 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]));
1142 Source
->Position
[0] = values
[0];
1143 Source
->Position
[1] = values
[1];
1144 Source
->Position
[2] = values
[2];
1149 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]));
1151 Source
->Velocity
[0] = values
[0];
1152 Source
->Velocity
[1] = values
[1];
1153 Source
->Velocity
[2] = values
[2];
1158 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]));
1160 Source
->Direction
[0] = values
[0];
1161 Source
->Direction
[1] = values
[1];
1162 Source
->Direction
[2] = values
[2];
1166 case AL_ORIENTATION
:
1167 CHECKVAL(std::isfinite(values
[0]) && std::isfinite(values
[1]) && std::isfinite(values
[2]) &&
1168 std::isfinite(values
[3]) && std::isfinite(values
[4]) && std::isfinite(values
[5]));
1170 Source
->Orientation
[0][0] = values
[0];
1171 Source
->Orientation
[0][1] = values
[1];
1172 Source
->Orientation
[0][2] = values
[2];
1173 Source
->Orientation
[1][0] = values
[3];
1174 Source
->Orientation
[1][1] = values
[4];
1175 Source
->Orientation
[1][2] = values
[5];
1180 case AL_SOURCE_RELATIVE
:
1182 case AL_SOURCE_STATE
:
1183 case AL_SOURCE_TYPE
:
1184 case AL_DISTANCE_MODEL
:
1185 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1186 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1187 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1188 case AL_DIRECT_CHANNELS_SOFT
:
1189 case AL_SOURCE_RESAMPLER_SOFT
:
1190 case AL_SOURCE_SPATIALIZE_SOFT
:
1191 ival
= (ALint
)values
[0];
1192 return SetSourceiv(Source
, Context
, prop
, &ival
);
1194 case AL_BUFFERS_QUEUED
:
1195 case AL_BUFFERS_PROCESSED
:
1196 ival
= (ALint
)((ALuint
)values
[0]);
1197 return SetSourceiv(Source
, Context
, prop
, &ival
);
1200 case AL_DIRECT_FILTER
:
1201 case AL_AUXILIARY_SEND_FILTER
:
1202 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1203 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1207 ERR("Unexpected property: 0x%04x\n", prop
);
1208 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source float property 0x%04x", prop
);
1211 ALboolean
SetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint
*values
)
1213 ALCdevice
*device
{Context
->Device
};
1214 ALbuffer
*buffer
{nullptr};
1215 ALfilter
*filter
{nullptr};
1216 ALeffectslot
*slot
{nullptr};
1217 ALbufferlistitem
*oldlist
{nullptr};
1218 std::unique_lock
<almtx_t
> slotlock
;
1219 std::unique_lock
<almtx_t
> buflock
;
1224 case AL_SOURCE_STATE
:
1225 case AL_SOURCE_TYPE
:
1226 case AL_BUFFERS_QUEUED
:
1227 case AL_BUFFERS_PROCESSED
:
1229 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
1230 "Setting read-only source property 0x%04x", prop
);
1232 case AL_SOURCE_RELATIVE
:
1233 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
1235 Source
->HeadRelative
= (ALboolean
)*values
;
1240 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
1242 Source
->Looping
= (ALboolean
)*values
;
1243 if(IsPlayingOrPaused(Source
))
1245 ALvoice
*voice
{GetSourceVoice(Source
, Context
)};
1249 voice
->loop_buffer
.store(Source
->queue
, std::memory_order_release
);
1251 voice
->loop_buffer
.store(nullptr, std::memory_order_release
);
1253 /* If the source is playing, wait for the current mix to finish
1254 * to ensure it isn't currently looping back or reaching the
1257 while((device
->MixCount
.load(std::memory_order_acquire
)&1))
1264 buflock
= std::unique_lock
<almtx_t
>{device
->BufferLock
};
1265 if(!(*values
== 0 || (buffer
=LookupBuffer(device
, *values
)) != nullptr))
1266 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid buffer ID %u",
1269 if(buffer
&& buffer
->MappedAccess
!= 0 &&
1270 !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
1271 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
1272 "Setting non-persistently mapped buffer %u", buffer
->id
);
1275 ALenum state
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
1276 if(state
== AL_PLAYING
|| state
== AL_PAUSED
)
1277 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
1278 "Setting buffer on playing or paused source %u", Source
->id
);
1281 oldlist
= Source
->queue
;
1282 if(buffer
!= nullptr)
1284 /* Add the selected buffer to a one-item queue */
1285 auto newlist
= static_cast<ALbufferlistitem
*>(al_calloc(DEF_ALIGN
,
1286 FAM_SIZE(ALbufferlistitem
, buffers
, 1)));
1287 ATOMIC_INIT(&newlist
->next
, static_cast<ALbufferlistitem
*>(nullptr));
1288 newlist
->max_samples
= buffer
->SampleLen
;
1289 newlist
->num_buffers
= 1;
1290 newlist
->buffers
[0] = buffer
;
1291 IncrementRef(&buffer
->ref
);
1293 /* Source is now Static */
1294 Source
->SourceType
= AL_STATIC
;
1295 Source
->queue
= newlist
;
1299 /* Source is now Undetermined */
1300 Source
->SourceType
= AL_UNDETERMINED
;
1301 Source
->queue
= nullptr;
1305 /* Delete all elements in the previous queue */
1306 while(oldlist
!= nullptr)
1308 ALbufferlistitem
*temp
{oldlist
};
1309 oldlist
= temp
->next
.load(std::memory_order_relaxed
);
1311 for(ALsizei i
{0};i
< temp
->num_buffers
;i
++)
1313 if(temp
->buffers
[i
])
1314 DecrementRef(&temp
->buffers
[i
]->ref
);
1321 case AL_SAMPLE_OFFSET
:
1322 case AL_BYTE_OFFSET
:
1323 CHECKVAL(*values
>= 0);
1325 Source
->OffsetType
= prop
;
1326 Source
->Offset
= *values
;
1328 if(IsPlayingOrPaused(Source
))
1330 ALCdevice_Lock(Context
->Device
);
1331 ALvoice
*voice
{GetSourceVoice(Source
, Context
)};
1334 if(ApplyOffset(Source
, voice
) == AL_FALSE
)
1336 ALCdevice_Unlock(Context
->Device
);
1337 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
,
1338 "Invalid source offset");
1341 ALCdevice_Unlock(Context
->Device
);
1345 case AL_DIRECT_FILTER
:
1346 LockFilterList(device
);
1347 if(!(*values
== 0 || (filter
=LookupFilter(device
, *values
)) != nullptr))
1349 UnlockFilterList(device
);
1350 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid filter ID %u",
1356 Source
->Direct
.Gain
= 1.0f
;
1357 Source
->Direct
.GainHF
= 1.0f
;
1358 Source
->Direct
.HFReference
= LOWPASSFREQREF
;
1359 Source
->Direct
.GainLF
= 1.0f
;
1360 Source
->Direct
.LFReference
= HIGHPASSFREQREF
;
1364 Source
->Direct
.Gain
= filter
->Gain
;
1365 Source
->Direct
.GainHF
= filter
->GainHF
;
1366 Source
->Direct
.HFReference
= filter
->HFReference
;
1367 Source
->Direct
.GainLF
= filter
->GainLF
;
1368 Source
->Direct
.LFReference
= filter
->LFReference
;
1370 UnlockFilterList(device
);
1374 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1375 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
1377 Source
->DryGainHFAuto
= *values
;
1381 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1382 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
1384 Source
->WetGainAuto
= *values
;
1388 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1389 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
1391 Source
->WetGainHFAuto
= *values
;
1395 case AL_DIRECT_CHANNELS_SOFT
:
1396 CHECKVAL(*values
== AL_FALSE
|| *values
== AL_TRUE
);
1398 Source
->DirectChannels
= *values
;
1402 case AL_DISTANCE_MODEL
:
1403 CHECKVAL(*values
== AL_NONE
||
1404 *values
== AL_INVERSE_DISTANCE
||
1405 *values
== AL_INVERSE_DISTANCE_CLAMPED
||
1406 *values
== AL_LINEAR_DISTANCE
||
1407 *values
== AL_LINEAR_DISTANCE_CLAMPED
||
1408 *values
== AL_EXPONENT_DISTANCE
||
1409 *values
== AL_EXPONENT_DISTANCE_CLAMPED
);
1411 Source
->mDistanceModel
= static_cast<DistanceModel
>(*values
);
1412 if(Context
->SourceDistanceModel
)
1416 case AL_SOURCE_RESAMPLER_SOFT
:
1417 CHECKVAL(*values
>= 0 && *values
<= ResamplerMax
);
1419 Source
->Resampler
= static_cast<enum Resampler
>(*values
);
1423 case AL_SOURCE_SPATIALIZE_SOFT
:
1424 CHECKVAL(*values
>= AL_FALSE
&& *values
<= AL_AUTO_SOFT
);
1426 Source
->Spatialize
= static_cast<enum SpatializeMode
>(*values
);
1431 case AL_AUXILIARY_SEND_FILTER
:
1432 slotlock
= std::unique_lock
<almtx_t
>{Context
->EffectSlotLock
};
1433 if(!(values
[0] == 0 || (slot
=LookupEffectSlot(Context
, values
[0])) != nullptr))
1434 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid effect ID %u",
1436 if((ALuint
)values
[1] >= (ALuint
)device
->NumAuxSends
)
1437 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid send %u", values
[1]);
1438 LockFilterList(device
);
1439 if(!(values
[2] == 0 || (filter
=LookupFilter(device
, values
[2])) != nullptr))
1441 UnlockFilterList(device
);
1442 SETERR_RETURN(Context
, AL_INVALID_VALUE
, AL_FALSE
, "Invalid filter ID %u",
1448 /* Disable filter */
1449 Source
->Send
[values
[1]].Gain
= 1.0f
;
1450 Source
->Send
[values
[1]].GainHF
= 1.0f
;
1451 Source
->Send
[values
[1]].HFReference
= LOWPASSFREQREF
;
1452 Source
->Send
[values
[1]].GainLF
= 1.0f
;
1453 Source
->Send
[values
[1]].LFReference
= HIGHPASSFREQREF
;
1457 Source
->Send
[values
[1]].Gain
= filter
->Gain
;
1458 Source
->Send
[values
[1]].GainHF
= filter
->GainHF
;
1459 Source
->Send
[values
[1]].HFReference
= filter
->HFReference
;
1460 Source
->Send
[values
[1]].GainLF
= filter
->GainLF
;
1461 Source
->Send
[values
[1]].LFReference
= filter
->LFReference
;
1463 UnlockFilterList(device
);
1465 if(slot
!= Source
->Send
[values
[1]].Slot
&& IsPlayingOrPaused(Source
))
1467 /* Add refcount on the new slot, and release the previous slot */
1468 if(slot
) IncrementRef(&slot
->ref
);
1469 if(Source
->Send
[values
[1]].Slot
)
1470 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
1471 Source
->Send
[values
[1]].Slot
= slot
;
1473 /* We must force an update if the auxiliary slot changed on an
1474 * active source, in case the slot is about to be deleted.
1476 ALvoice
*voice
{GetSourceVoice(Source
, Context
)};
1477 if(voice
) UpdateSourceProps(Source
, voice
, Context
);
1478 else Source
->PropsClean
.clear(std::memory_order_release
);
1482 if(slot
) IncrementRef(&slot
->ref
);
1483 if(Source
->Send
[values
[1]].Slot
)
1484 DecrementRef(&Source
->Send
[values
[1]].Slot
->ref
);
1485 Source
->Send
[values
[1]].Slot
= slot
;
1493 case AL_CONE_INNER_ANGLE
:
1494 case AL_CONE_OUTER_ANGLE
:
1499 case AL_REFERENCE_DISTANCE
:
1500 case AL_ROLLOFF_FACTOR
:
1501 case AL_CONE_OUTER_GAIN
:
1502 case AL_MAX_DISTANCE
:
1503 case AL_DOPPLER_FACTOR
:
1504 case AL_CONE_OUTER_GAINHF
:
1505 case AL_AIR_ABSORPTION_FACTOR
:
1506 case AL_ROOM_ROLLOFF_FACTOR
:
1507 case AL_SOURCE_RADIUS
:
1508 fvals
[0] = (ALfloat
)*values
;
1509 return SetSourcefv(Source
, Context
, prop
, fvals
);
1515 fvals
[0] = (ALfloat
)values
[0];
1516 fvals
[1] = (ALfloat
)values
[1];
1517 fvals
[2] = (ALfloat
)values
[2];
1518 return SetSourcefv(Source
, Context
, prop
, fvals
);
1521 case AL_ORIENTATION
:
1522 fvals
[0] = (ALfloat
)values
[0];
1523 fvals
[1] = (ALfloat
)values
[1];
1524 fvals
[2] = (ALfloat
)values
[2];
1525 fvals
[3] = (ALfloat
)values
[3];
1526 fvals
[4] = (ALfloat
)values
[4];
1527 fvals
[5] = (ALfloat
)values
[5];
1528 return SetSourcefv(Source
, Context
, prop
, fvals
);
1530 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1531 case AL_SEC_OFFSET_LATENCY_SOFT
:
1532 case AL_SEC_OFFSET_CLOCK_SOFT
:
1533 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1534 case AL_STEREO_ANGLES
:
1538 ERR("Unexpected property: 0x%04x\n", prop
);
1539 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer property 0x%04x",
1543 ALboolean
SetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, const ALint64SOFT
*values
)
1550 case AL_SOURCE_TYPE
:
1551 case AL_BUFFERS_QUEUED
:
1552 case AL_BUFFERS_PROCESSED
:
1553 case AL_SOURCE_STATE
:
1554 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1555 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1557 SETERR_RETURN(Context
, AL_INVALID_OPERATION
, AL_FALSE
,
1558 "Setting read-only source property 0x%04x", prop
);
1561 case AL_SOURCE_RELATIVE
:
1564 case AL_SAMPLE_OFFSET
:
1565 case AL_BYTE_OFFSET
:
1566 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1567 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1568 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1569 case AL_DIRECT_CHANNELS_SOFT
:
1570 case AL_DISTANCE_MODEL
:
1571 case AL_SOURCE_RESAMPLER_SOFT
:
1572 case AL_SOURCE_SPATIALIZE_SOFT
:
1573 CHECKVAL(*values
<= INT_MAX
&& *values
>= INT_MIN
);
1575 ivals
[0] = (ALint
)*values
;
1576 return SetSourceiv(Source
, Context
, prop
, ivals
);
1580 case AL_DIRECT_FILTER
:
1581 CHECKVAL(*values
<= UINT_MAX
&& *values
>= 0);
1583 ivals
[0] = (ALuint
)*values
;
1584 return SetSourceiv(Source
, Context
, prop
, ivals
);
1587 case AL_AUXILIARY_SEND_FILTER
:
1588 CHECKVAL(values
[0] <= UINT_MAX
&& values
[0] >= 0 &&
1589 values
[1] <= UINT_MAX
&& values
[1] >= 0 &&
1590 values
[2] <= UINT_MAX
&& values
[2] >= 0);
1592 ivals
[0] = (ALuint
)values
[0];
1593 ivals
[1] = (ALuint
)values
[1];
1594 ivals
[2] = (ALuint
)values
[2];
1595 return SetSourceiv(Source
, Context
, prop
, ivals
);
1598 case AL_CONE_INNER_ANGLE
:
1599 case AL_CONE_OUTER_ANGLE
:
1604 case AL_REFERENCE_DISTANCE
:
1605 case AL_ROLLOFF_FACTOR
:
1606 case AL_CONE_OUTER_GAIN
:
1607 case AL_MAX_DISTANCE
:
1608 case AL_DOPPLER_FACTOR
:
1609 case AL_CONE_OUTER_GAINHF
:
1610 case AL_AIR_ABSORPTION_FACTOR
:
1611 case AL_ROOM_ROLLOFF_FACTOR
:
1612 case AL_SOURCE_RADIUS
:
1613 fvals
[0] = (ALfloat
)*values
;
1614 return SetSourcefv(Source
, Context
, prop
, fvals
);
1620 fvals
[0] = (ALfloat
)values
[0];
1621 fvals
[1] = (ALfloat
)values
[1];
1622 fvals
[2] = (ALfloat
)values
[2];
1623 return SetSourcefv(Source
, Context
, prop
, fvals
);
1626 case AL_ORIENTATION
:
1627 fvals
[0] = (ALfloat
)values
[0];
1628 fvals
[1] = (ALfloat
)values
[1];
1629 fvals
[2] = (ALfloat
)values
[2];
1630 fvals
[3] = (ALfloat
)values
[3];
1631 fvals
[4] = (ALfloat
)values
[4];
1632 fvals
[5] = (ALfloat
)values
[5];
1633 return SetSourcefv(Source
, Context
, prop
, fvals
);
1635 case AL_SEC_OFFSET_LATENCY_SOFT
:
1636 case AL_SEC_OFFSET_CLOCK_SOFT
:
1637 case AL_STEREO_ANGLES
:
1641 ERR("Unexpected property: 0x%04x\n", prop
);
1642 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer64 property 0x%04x",
1649 ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
);
1650 ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
);
1651 ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
);
1653 ALboolean
GetSourcedv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALdouble
*values
)
1655 ALCdevice
*device
{Context
->Device
};
1656 ClockLatency clocktime
;
1657 std::chrono::nanoseconds srcclock
;
1664 *values
= Source
->Gain
;
1668 *values
= Source
->Pitch
;
1671 case AL_MAX_DISTANCE
:
1672 *values
= Source
->MaxDistance
;
1675 case AL_ROLLOFF_FACTOR
:
1676 *values
= Source
->RolloffFactor
;
1679 case AL_REFERENCE_DISTANCE
:
1680 *values
= Source
->RefDistance
;
1683 case AL_CONE_INNER_ANGLE
:
1684 *values
= Source
->InnerAngle
;
1687 case AL_CONE_OUTER_ANGLE
:
1688 *values
= Source
->OuterAngle
;
1692 *values
= Source
->MinGain
;
1696 *values
= Source
->MaxGain
;
1699 case AL_CONE_OUTER_GAIN
:
1700 *values
= Source
->OuterGain
;
1704 case AL_SAMPLE_OFFSET
:
1705 case AL_BYTE_OFFSET
:
1706 *values
= GetSourceOffset(Source
, prop
, Context
);
1709 case AL_CONE_OUTER_GAINHF
:
1710 *values
= Source
->OuterGainHF
;
1713 case AL_AIR_ABSORPTION_FACTOR
:
1714 *values
= Source
->AirAbsorptionFactor
;
1717 case AL_ROOM_ROLLOFF_FACTOR
:
1718 *values
= Source
->RoomRolloffFactor
;
1721 case AL_DOPPLER_FACTOR
:
1722 *values
= Source
->DopplerFactor
;
1725 case AL_SOURCE_RADIUS
:
1726 *values
= Source
->Radius
;
1729 case AL_STEREO_ANGLES
:
1730 values
[0] = Source
->StereoPan
[0];
1731 values
[1] = Source
->StereoPan
[1];
1734 case AL_SEC_OFFSET_LATENCY_SOFT
:
1735 /* Get the source offset with the clock time first. Then get the
1736 * clock time with the device latency. Order is important.
1738 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1739 { std::lock_guard
<almtx_t
> _
{device
->BackendLock
};
1740 clocktime
= GetClockLatency(device
);
1742 if(srcclock
== clocktime
.ClockTime
)
1743 values
[1] = (ALdouble
)clocktime
.Latency
.count() / 1000000000.0;
1746 /* If the clock time incremented, reduce the latency by that
1747 * much since it's that much closer to the source offset it got
1750 std::chrono::nanoseconds diff
= clocktime
.ClockTime
- srcclock
;
1751 values
[1] = (ALdouble
)(clocktime
.Latency
- std::min(clocktime
.Latency
, diff
)).count() /
1756 case AL_SEC_OFFSET_CLOCK_SOFT
:
1757 values
[0] = GetSourceSecOffset(Source
, Context
, &srcclock
);
1758 values
[1] = srcclock
.count() / 1000000000.0;
1762 values
[0] = Source
->Position
[0];
1763 values
[1] = Source
->Position
[1];
1764 values
[2] = Source
->Position
[2];
1768 values
[0] = Source
->Velocity
[0];
1769 values
[1] = Source
->Velocity
[1];
1770 values
[2] = Source
->Velocity
[2];
1774 values
[0] = Source
->Direction
[0];
1775 values
[1] = Source
->Direction
[1];
1776 values
[2] = Source
->Direction
[2];
1779 case AL_ORIENTATION
:
1780 values
[0] = Source
->Orientation
[0][0];
1781 values
[1] = Source
->Orientation
[0][1];
1782 values
[2] = Source
->Orientation
[0][2];
1783 values
[3] = Source
->Orientation
[1][0];
1784 values
[4] = Source
->Orientation
[1][1];
1785 values
[5] = Source
->Orientation
[1][2];
1789 case AL_SOURCE_RELATIVE
:
1791 case AL_SOURCE_STATE
:
1792 case AL_BUFFERS_QUEUED
:
1793 case AL_BUFFERS_PROCESSED
:
1794 case AL_SOURCE_TYPE
:
1795 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1796 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1797 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1798 case AL_DIRECT_CHANNELS_SOFT
:
1799 case AL_DISTANCE_MODEL
:
1800 case AL_SOURCE_RESAMPLER_SOFT
:
1801 case AL_SOURCE_SPATIALIZE_SOFT
:
1802 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
1803 *values
= (ALdouble
)ivals
[0];
1807 case AL_DIRECT_FILTER
:
1808 case AL_AUXILIARY_SEND_FILTER
:
1809 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1810 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1814 ERR("Unexpected property: 0x%04x\n", prop
);
1815 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source double property 0x%04x",
1819 ALboolean
GetSourceiv(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint
*values
)
1821 ALbufferlistitem
*BufferList
;
1827 case AL_SOURCE_RELATIVE
:
1828 *values
= Source
->HeadRelative
;
1832 *values
= Source
->Looping
;
1836 BufferList
= (Source
->SourceType
== AL_STATIC
) ? Source
->queue
: nullptr;
1837 *values
= (BufferList
&& BufferList
->num_buffers
>= 1 && BufferList
->buffers
[0]) ?
1838 BufferList
->buffers
[0]->id
: 0;
1841 case AL_SOURCE_STATE
:
1842 *values
= GetSourceState(Source
, GetSourceVoice(Source
, Context
));
1845 case AL_BUFFERS_QUEUED
:
1846 if(!(BufferList
=Source
->queue
))
1852 count
+= BufferList
->num_buffers
;
1853 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
1854 } while(BufferList
!= nullptr);
1859 case AL_BUFFERS_PROCESSED
:
1860 if(Source
->Looping
|| Source
->SourceType
!= AL_STREAMING
)
1862 /* Buffers on a looping source are in a perpetual state of
1863 * PENDING, so don't report any as PROCESSED */
1868 const ALbufferlistitem
*BufferList
{Source
->queue
};
1869 const ALbufferlistitem
*Current
{nullptr};
1872 ALvoice
*voice
{GetSourceVoice(Source
, Context
)};
1873 if(voice
!= nullptr)
1874 Current
= voice
->current_buffer
.load(std::memory_order_relaxed
);
1875 else if(Source
->state
== AL_INITIAL
)
1876 Current
= BufferList
;
1878 while(BufferList
&& BufferList
!= Current
)
1880 played
+= BufferList
->num_buffers
;
1881 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
1887 case AL_SOURCE_TYPE
:
1888 *values
= Source
->SourceType
;
1891 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1892 *values
= Source
->DryGainHFAuto
;
1895 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1896 *values
= Source
->WetGainAuto
;
1899 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1900 *values
= Source
->WetGainHFAuto
;
1903 case AL_DIRECT_CHANNELS_SOFT
:
1904 *values
= Source
->DirectChannels
;
1907 case AL_DISTANCE_MODEL
:
1908 *values
= static_cast<int>(Source
->mDistanceModel
);
1911 case AL_SOURCE_RESAMPLER_SOFT
:
1912 *values
= Source
->Resampler
;
1915 case AL_SOURCE_SPATIALIZE_SOFT
:
1916 *values
= Source
->Spatialize
;
1919 /* 1x float/double */
1920 case AL_CONE_INNER_ANGLE
:
1921 case AL_CONE_OUTER_ANGLE
:
1926 case AL_REFERENCE_DISTANCE
:
1927 case AL_ROLLOFF_FACTOR
:
1928 case AL_CONE_OUTER_GAIN
:
1929 case AL_MAX_DISTANCE
:
1931 case AL_SAMPLE_OFFSET
:
1932 case AL_BYTE_OFFSET
:
1933 case AL_DOPPLER_FACTOR
:
1934 case AL_AIR_ABSORPTION_FACTOR
:
1935 case AL_ROOM_ROLLOFF_FACTOR
:
1936 case AL_CONE_OUTER_GAINHF
:
1937 case AL_SOURCE_RADIUS
:
1938 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1939 *values
= (ALint
)dvals
[0];
1942 /* 3x float/double */
1946 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1948 values
[0] = (ALint
)dvals
[0];
1949 values
[1] = (ALint
)dvals
[1];
1950 values
[2] = (ALint
)dvals
[2];
1954 /* 6x float/double */
1955 case AL_ORIENTATION
:
1956 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
1958 values
[0] = (ALint
)dvals
[0];
1959 values
[1] = (ALint
)dvals
[1];
1960 values
[2] = (ALint
)dvals
[2];
1961 values
[3] = (ALint
)dvals
[3];
1962 values
[4] = (ALint
)dvals
[4];
1963 values
[5] = (ALint
)dvals
[5];
1967 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1968 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
1969 break; /* i64 only */
1970 case AL_SEC_OFFSET_LATENCY_SOFT
:
1971 case AL_SEC_OFFSET_CLOCK_SOFT
:
1972 break; /* Double only */
1973 case AL_STEREO_ANGLES
:
1974 break; /* Float/double only */
1976 case AL_DIRECT_FILTER
:
1977 case AL_AUXILIARY_SEND_FILTER
:
1981 ERR("Unexpected property: 0x%04x\n", prop
);
1982 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer property 0x%04x",
1986 ALboolean
GetSourcei64v(ALsource
*Source
, ALCcontext
*Context
, SourceProp prop
, ALint64
*values
)
1988 ALCdevice
*device
= Context
->Device
;
1989 ClockLatency clocktime
;
1990 std::chrono::nanoseconds srcclock
;
1997 case AL_SAMPLE_OFFSET_LATENCY_SOFT
:
1998 /* Get the source offset with the clock time first. Then get the
1999 * clock time with the device latency. Order is important.
2001 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
2002 { std::lock_guard
<almtx_t
> _
{device
->BackendLock
};
2003 clocktime
= GetClockLatency(device
);
2005 if(srcclock
== clocktime
.ClockTime
)
2006 values
[1] = clocktime
.Latency
.count();
2009 /* If the clock time incremented, reduce the latency by that
2010 * much since it's that much closer to the source offset it got
2013 auto diff
= clocktime
.ClockTime
- srcclock
;
2014 values
[1] = (clocktime
.Latency
- std::min(clocktime
.Latency
, diff
)).count();
2018 case AL_SAMPLE_OFFSET_CLOCK_SOFT
:
2019 values
[0] = GetSourceSampleOffset(Source
, Context
, &srcclock
);
2020 values
[1] = srcclock
.count();
2023 /* 1x float/double */
2024 case AL_CONE_INNER_ANGLE
:
2025 case AL_CONE_OUTER_ANGLE
:
2030 case AL_REFERENCE_DISTANCE
:
2031 case AL_ROLLOFF_FACTOR
:
2032 case AL_CONE_OUTER_GAIN
:
2033 case AL_MAX_DISTANCE
:
2035 case AL_SAMPLE_OFFSET
:
2036 case AL_BYTE_OFFSET
:
2037 case AL_DOPPLER_FACTOR
:
2038 case AL_AIR_ABSORPTION_FACTOR
:
2039 case AL_ROOM_ROLLOFF_FACTOR
:
2040 case AL_CONE_OUTER_GAINHF
:
2041 case AL_SOURCE_RADIUS
:
2042 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
2043 *values
= (ALint64
)dvals
[0];
2046 /* 3x float/double */
2050 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
2052 values
[0] = (ALint64
)dvals
[0];
2053 values
[1] = (ALint64
)dvals
[1];
2054 values
[2] = (ALint64
)dvals
[2];
2058 /* 6x float/double */
2059 case AL_ORIENTATION
:
2060 if((err
=GetSourcedv(Source
, Context
, prop
, dvals
)) != AL_FALSE
)
2062 values
[0] = (ALint64
)dvals
[0];
2063 values
[1] = (ALint64
)dvals
[1];
2064 values
[2] = (ALint64
)dvals
[2];
2065 values
[3] = (ALint64
)dvals
[3];
2066 values
[4] = (ALint64
)dvals
[4];
2067 values
[5] = (ALint64
)dvals
[5];
2072 case AL_SOURCE_RELATIVE
:
2074 case AL_SOURCE_STATE
:
2075 case AL_BUFFERS_QUEUED
:
2076 case AL_BUFFERS_PROCESSED
:
2077 case AL_SOURCE_TYPE
:
2078 case AL_DIRECT_FILTER_GAINHF_AUTO
:
2079 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
2080 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
2081 case AL_DIRECT_CHANNELS_SOFT
:
2082 case AL_DISTANCE_MODEL
:
2083 case AL_SOURCE_RESAMPLER_SOFT
:
2084 case AL_SOURCE_SPATIALIZE_SOFT
:
2085 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
2091 case AL_DIRECT_FILTER
:
2092 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
2093 *values
= (ALuint
)ivals
[0];
2097 case AL_AUXILIARY_SEND_FILTER
:
2098 if((err
=GetSourceiv(Source
, Context
, prop
, ivals
)) != AL_FALSE
)
2100 values
[0] = (ALuint
)ivals
[0];
2101 values
[1] = (ALuint
)ivals
[1];
2102 values
[2] = (ALuint
)ivals
[2];
2106 case AL_SEC_OFFSET_LATENCY_SOFT
:
2107 case AL_SEC_OFFSET_CLOCK_SOFT
:
2108 break; /* Double only */
2109 case AL_STEREO_ANGLES
:
2110 break; /* Float/double only */
2113 ERR("Unexpected property: 0x%04x\n", prop
);
2114 SETERR_RETURN(Context
, AL_INVALID_ENUM
, AL_FALSE
, "Invalid source integer64 property 0x%04x",
2120 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
, ALuint
*sources
)
2122 ContextRef context
{GetContextRef()};
2123 if(UNLIKELY(!context
)) return;
2126 alSetError(context
.get(), AL_INVALID_VALUE
, "Generating %d sources", n
);
2129 ALsource
*source
= AllocSource(context
.get());
2130 if(source
) sources
[0] = source
->id
;
2134 al::vector
<ALuint
> tempids(n
);
2135 auto alloc_end
= std::find_if_not(tempids
.begin(), tempids
.end(),
2136 [&context
](ALuint
&id
) -> bool
2138 ALsource
*source
{AllocSource(context
.get())};
2139 if(!source
) return false;
2144 if(alloc_end
!= tempids
.end())
2145 alDeleteSources(std::distance(tempids
.begin(), alloc_end
), tempids
.data());
2147 std::copy(tempids
.cbegin(), tempids
.cend(), sources
);
2152 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
2154 ContextRef context
{GetContextRef()};
2155 if(UNLIKELY(!context
)) return;
2158 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Deleting %d sources", n
);
2160 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
2162 /* Check that all Sources are valid */
2163 const ALuint
*sources_end
= sources
+ n
;
2164 auto invsrc
= std::find_if_not(sources
, sources_end
,
2165 [&context
](ALuint sid
) -> bool
2167 if(!LookupSource(context
.get(), sid
))
2169 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", sid
);
2175 if(LIKELY(invsrc
== sources_end
))
2177 /* All good. Delete source IDs. */
2178 std::for_each(sources
, sources_end
,
2179 [&context
](ALuint sid
) -> void
2181 ALsource
*src
{LookupSource(context
.get(), sid
)};
2182 if(src
) FreeSource(context
.get(), src
);
2189 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
2191 ContextRef context
{GetContextRef()};
2194 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
2195 if(LookupSource(context
.get(), source
) != nullptr)
2202 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum param
, ALfloat value
)
2204 ContextRef context
{GetContextRef()};
2205 if(UNLIKELY(!context
)) return;
2207 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
2208 std::lock_guard
<almtx_t
> __
{context
->SourceLock
};
2209 ALsource
*Source
= LookupSource(context
.get(), source
);
2210 if(UNLIKELY(!Source
))
2211 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2212 else if(FloatValsByProp(param
) != 1)
2213 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid float property 0x%04x", param
);
2215 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), &value
);
2218 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum param
, ALfloat value1
, ALfloat value2
, ALfloat value3
)
2220 ContextRef context
{GetContextRef()};
2221 if(UNLIKELY(!context
)) return;
2223 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
2224 std::lock_guard
<almtx_t
> __
{context
->SourceLock
};
2225 ALsource
*Source
= LookupSource(context
.get(), source
);
2226 if(UNLIKELY(!Source
))
2227 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2228 else if(FloatValsByProp(param
) != 3)
2229 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid 3-float property 0x%04x", param
);
2232 ALfloat fvals
[3] = { value1
, value2
, value3
};
2233 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), fvals
);
2237 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum param
, const ALfloat
*values
)
2239 ContextRef context
{GetContextRef()};
2240 if(UNLIKELY(!context
)) return;
2242 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
2243 std::lock_guard
<almtx_t
> __
{context
->SourceLock
};
2244 ALsource
*Source
= LookupSource(context
.get(), source
);
2245 if(UNLIKELY(!Source
))
2246 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2248 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2249 else if(FloatValsByProp(param
) < 1)
2250 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid float-vector property 0x%04x", param
);
2252 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), values
);
2256 AL_API ALvoid AL_APIENTRY
alSourcedSOFT(ALuint source
, ALenum param
, ALdouble value
)
2258 ContextRef context
{GetContextRef()};
2259 if(UNLIKELY(!context
)) return;
2261 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
2262 std::lock_guard
<almtx_t
> __
{context
->SourceLock
};
2263 ALsource
*Source
= LookupSource(context
.get(), source
);
2264 if(UNLIKELY(!Source
))
2265 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2266 else if(DoubleValsByProp(param
) != 1)
2267 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid double property 0x%04x", param
);
2270 ALfloat fval
= (ALfloat
)value
;
2271 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), &fval
);
2275 AL_API ALvoid AL_APIENTRY
alSource3dSOFT(ALuint source
, ALenum param
, ALdouble value1
, ALdouble value2
, ALdouble value3
)
2277 ContextRef context
{GetContextRef()};
2278 if(UNLIKELY(!context
)) return;
2280 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
2281 std::lock_guard
<almtx_t
> __
{context
->SourceLock
};
2282 ALsource
*Source
= LookupSource(context
.get(), source
);
2283 if(UNLIKELY(!Source
))
2284 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2285 else if(DoubleValsByProp(param
) != 3)
2286 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid 3-double property 0x%04x", param
);
2289 ALfloat fvals
[3] = { (ALfloat
)value1
, (ALfloat
)value2
, (ALfloat
)value3
};
2290 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), fvals
);
2294 AL_API ALvoid AL_APIENTRY
alSourcedvSOFT(ALuint source
, ALenum param
, const ALdouble
*values
)
2296 ContextRef context
{GetContextRef()};
2297 if(UNLIKELY(!context
)) return;
2299 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
2300 std::lock_guard
<almtx_t
> __
{context
->SourceLock
};
2301 ALsource
*Source
= LookupSource(context
.get(), source
);
2302 if(UNLIKELY(!Source
))
2303 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2305 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2308 ALint count
{DoubleValsByProp(param
)};
2309 if(count
< 1 || count
> 6)
2310 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid double-vector property 0x%04x", param
);
2316 for(i
= 0;i
< count
;i
++)
2317 fvals
[i
] = (ALfloat
)values
[i
];
2318 SetSourcefv(Source
, context
.get(), static_cast<SourceProp
>(param
), fvals
);
2324 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
, ALenum param
, ALint value
)
2326 ContextRef context
{GetContextRef()};
2327 if(UNLIKELY(!context
)) return;
2329 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
2330 std::lock_guard
<almtx_t
> __
{context
->SourceLock
};
2331 ALsource
*Source
= LookupSource(context
.get(), source
);
2332 if(UNLIKELY(!Source
))
2333 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2334 else if(IntValsByProp(param
) != 1)
2335 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid integer property 0x%04x", param
);
2337 SetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), &value
);
2340 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum param
, ALint value1
, ALint value2
, ALint value3
)
2342 ContextRef context
{GetContextRef()};
2343 if(UNLIKELY(!context
)) return;
2345 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
2346 std::lock_guard
<almtx_t
> __
{context
->SourceLock
};
2347 ALsource
*Source
= LookupSource(context
.get(), source
);
2348 if(UNLIKELY(!Source
))
2349 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2350 else if(IntValsByProp(param
) != 3)
2351 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid 3-integer property 0x%04x", param
);
2354 ALint ivals
[3] = { value1
, value2
, value3
};
2355 SetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), ivals
);
2359 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum param
, const ALint
*values
)
2361 ContextRef context
{GetContextRef()};
2362 if(UNLIKELY(!context
)) return;
2364 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
2365 std::lock_guard
<almtx_t
> __
{context
->SourceLock
};
2366 ALsource
*Source
= LookupSource(context
.get(), source
);
2367 if(UNLIKELY(!Source
))
2368 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2370 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2371 else if(IntValsByProp(param
) < 1)
2372 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid integer-vector property 0x%04x", param
);
2374 SetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), values
);
2378 AL_API ALvoid AL_APIENTRY
alSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT value
)
2380 ContextRef context
{GetContextRef()};
2381 if(UNLIKELY(!context
)) return;
2383 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
2384 std::lock_guard
<almtx_t
> __
{context
->SourceLock
};
2385 ALsource
*Source
{LookupSource(context
.get(), source
)};
2386 if(UNLIKELY(!Source
))
2387 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2388 else if(Int64ValsByProp(param
) != 1)
2389 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid integer64 property 0x%04x", param
);
2391 SetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), &value
);
2394 AL_API
void AL_APIENTRY
alSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT value1
, ALint64SOFT value2
, ALint64SOFT value3
)
2396 ContextRef context
{GetContextRef()};
2397 if(UNLIKELY(!context
)) return;
2399 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
2400 std::lock_guard
<almtx_t
> __
{context
->SourceLock
};
2401 ALsource
*Source
{LookupSource(context
.get(), source
)};
2402 if(UNLIKELY(!Source
))
2403 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2404 else if(Int64ValsByProp(param
) != 3)
2405 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid 3-integer64 property 0x%04x", param
);
2408 ALint64SOFT i64vals
[3] = { value1
, value2
, value3
};
2409 SetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), i64vals
);
2413 AL_API
void AL_APIENTRY
alSourcei64vSOFT(ALuint source
, ALenum param
, const ALint64SOFT
*values
)
2415 ContextRef context
{GetContextRef()};
2416 if(UNLIKELY(!context
)) return;
2418 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
2419 std::lock_guard
<almtx_t
> __
{context
->SourceLock
};
2420 ALsource
*Source
{LookupSource(context
.get(), source
)};
2421 if(UNLIKELY(!Source
))
2422 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2424 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2425 else if(Int64ValsByProp(param
) < 1)
2426 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid integer64-vector property 0x%04x", param
);
2428 SetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), values
);
2432 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum param
, ALfloat
*value
)
2434 ContextRef context
{GetContextRef()};
2435 if(UNLIKELY(!context
)) return;
2437 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
2438 ALsource
*Source
{LookupSource(context
.get(), source
)};
2439 if(UNLIKELY(!Source
))
2440 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2442 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2443 else if(FloatValsByProp(param
) != 1)
2444 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid float property 0x%04x", param
);
2448 if(GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), &dval
))
2449 *value
= (ALfloat
)dval
;
2454 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
2456 ContextRef context
{GetContextRef()};
2457 if(UNLIKELY(!context
)) return;
2459 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
2460 ALsource
*Source
{LookupSource(context
.get(), source
)};
2461 if(UNLIKELY(!Source
))
2462 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2463 else if(!(value1
&& value2
&& value3
))
2464 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2465 else if(FloatValsByProp(param
) != 3)
2466 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid 3-float property 0x%04x", param
);
2470 if(GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), dvals
))
2472 *value1
= (ALfloat
)dvals
[0];
2473 *value2
= (ALfloat
)dvals
[1];
2474 *value3
= (ALfloat
)dvals
[2];
2480 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum param
, ALfloat
*values
)
2482 ContextRef context
{GetContextRef()};
2483 if(UNLIKELY(!context
)) return;
2485 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
2486 ALsource
*Source
{LookupSource(context
.get(), source
)};
2487 if(UNLIKELY(!Source
))
2488 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2490 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2493 ALint count
{FloatValsByProp(param
)};
2494 if(count
< 1 && count
> 6)
2495 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid float-vector property 0x%04x", param
);
2499 if(GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), dvals
))
2501 for(ALint i
{0};i
< count
;i
++)
2502 values
[i
] = (ALfloat
)dvals
[i
];
2509 AL_API
void AL_APIENTRY
alGetSourcedSOFT(ALuint source
, ALenum param
, ALdouble
*value
)
2511 ContextRef context
{GetContextRef()};
2512 if(UNLIKELY(!context
)) return;
2514 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
2515 ALsource
*Source
{LookupSource(context
.get(), source
)};
2516 if(UNLIKELY(!Source
))
2517 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2519 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2520 else if(DoubleValsByProp(param
) != 1)
2521 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid double property 0x%04x", param
);
2523 GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), value
);
2526 AL_API
void AL_APIENTRY
alGetSource3dSOFT(ALuint source
, ALenum param
, ALdouble
*value1
, ALdouble
*value2
, ALdouble
*value3
)
2528 ContextRef context
{GetContextRef()};
2529 if(UNLIKELY(!context
)) return;
2531 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
2532 ALsource
*Source
{LookupSource(context
.get(), source
)};
2533 if(UNLIKELY(!Source
))
2534 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2535 else if(!(value1
&& value2
&& value3
))
2536 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2537 else if(DoubleValsByProp(param
) != 3)
2538 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid 3-double property 0x%04x", param
);
2542 if(GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), dvals
))
2551 AL_API
void AL_APIENTRY
alGetSourcedvSOFT(ALuint source
, ALenum param
, ALdouble
*values
)
2553 ContextRef context
{GetContextRef()};
2554 if(UNLIKELY(!context
)) return;
2556 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
2557 ALsource
*Source
{LookupSource(context
.get(), source
)};
2558 if(UNLIKELY(!Source
))
2559 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2561 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2562 else if(DoubleValsByProp(param
) < 1)
2563 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid double-vector property 0x%04x", param
);
2565 GetSourcedv(Source
, context
.get(), static_cast<SourceProp
>(param
), values
);
2569 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum param
, ALint
*value
)
2571 ContextRef context
{GetContextRef()};
2572 if(UNLIKELY(!context
)) return;
2574 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
2575 ALsource
*Source
{LookupSource(context
.get(), source
)};
2576 if(UNLIKELY(!Source
))
2577 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2579 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2580 else if(IntValsByProp(param
) != 1)
2581 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid integer property 0x%04x", param
);
2583 GetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), value
);
2587 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
2589 ContextRef context
{GetContextRef()};
2590 if(UNLIKELY(!context
)) return;
2592 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
2593 ALsource
*Source
{LookupSource(context
.get(), source
)};
2594 if(UNLIKELY(!Source
))
2595 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2596 else if(!(value1
&& value2
&& value3
))
2597 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2598 else if(IntValsByProp(param
) != 3)
2599 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid 3-integer property 0x%04x", param
);
2603 if(GetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), ivals
))
2613 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum param
, ALint
*values
)
2615 ContextRef context
{GetContextRef()};
2616 if(UNLIKELY(!context
)) return;
2618 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
2619 ALsource
*Source
{LookupSource(context
.get(), source
)};
2620 if(UNLIKELY(!Source
))
2621 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2623 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2624 else if(IntValsByProp(param
) < 1)
2625 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid integer-vector property 0x%04x", param
);
2627 GetSourceiv(Source
, context
.get(), static_cast<SourceProp
>(param
), values
);
2631 AL_API
void AL_APIENTRY
alGetSourcei64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value
)
2633 ContextRef context
{GetContextRef()};
2634 if(UNLIKELY(!context
)) return;
2636 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
2637 ALsource
*Source
{LookupSource(context
.get(), source
)};
2638 if(UNLIKELY(!Source
))
2639 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2641 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2642 else if(Int64ValsByProp(param
) != 1)
2643 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid integer64 property 0x%04x", param
);
2645 GetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), value
);
2648 AL_API
void AL_APIENTRY
alGetSource3i64SOFT(ALuint source
, ALenum param
, ALint64SOFT
*value1
, ALint64SOFT
*value2
, ALint64SOFT
*value3
)
2650 ContextRef context
{GetContextRef()};
2651 if(UNLIKELY(!context
)) return;
2653 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
2654 ALsource
*Source
{LookupSource(context
.get(), source
)};
2655 if(UNLIKELY(!Source
))
2656 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2657 else if(!(value1
&& value2
&& value3
))
2658 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2659 else if(Int64ValsByProp(param
) != 3)
2660 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid 3-integer64 property 0x%04x", param
);
2664 if(GetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), i64vals
))
2666 *value1
= i64vals
[0];
2667 *value2
= i64vals
[1];
2668 *value3
= i64vals
[2];
2673 AL_API
void AL_APIENTRY
alGetSourcei64vSOFT(ALuint source
, ALenum param
, ALint64SOFT
*values
)
2675 ContextRef context
{GetContextRef()};
2676 if(UNLIKELY(!context
)) return;
2678 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
2679 ALsource
*Source
{LookupSource(context
.get(), source
)};
2680 if(UNLIKELY(!Source
))
2681 alSetError(context
.get(), AL_INVALID_NAME
, "Invalid source ID %u", source
);
2683 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
2684 else if(Int64ValsByProp(param
) < 1)
2685 alSetError(context
.get(), AL_INVALID_ENUM
, "Invalid integer64-vector property 0x%04x", param
);
2687 GetSourcei64v(Source
, context
.get(), static_cast<SourceProp
>(param
), values
);
2691 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
2693 alSourcePlayv(1, &source
);
2695 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
2697 ContextRef context
{GetContextRef()};
2698 if(UNLIKELY(!context
)) return;
2701 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Playing %d sources", n
);
2704 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
2705 for(ALsizei i
{0};i
< n
;i
++)
2707 if(!LookupSource(context
.get(), sources
[i
]))
2708 SETERR_RETURN(context
.get(), AL_INVALID_NAME
,, "Invalid source ID %u", sources
[i
]);
2711 ALCdevice
*device
{context
->Device
};
2712 ALCdevice_Lock(device
);
2713 /* If the device is disconnected, go right to stopped. */
2714 if(!device
->Connected
.load(std::memory_order_acquire
))
2716 /* TODO: Send state change event? */
2717 for(ALsizei i
{0};i
< n
;i
++)
2719 ALsource
*source
{LookupSource(context
.get(), sources
[i
])};
2720 source
->OffsetType
= AL_NONE
;
2721 source
->Offset
= 0.0;
2722 source
->state
= AL_STOPPED
;
2724 ALCdevice_Unlock(device
);
2728 while(n
> context
->MaxVoices
-context
->VoiceCount
.load(std::memory_order_relaxed
))
2730 ALsizei newcount
= context
->MaxVoices
<< 1;
2731 if(context
->MaxVoices
>= newcount
)
2733 ALCdevice_Unlock(device
);
2734 SETERR_RETURN(context
.get(), AL_OUT_OF_MEMORY
,,
2735 "Overflow increasing voice count %d -> %d", context
->MaxVoices
, newcount
);
2737 AllocateVoices(context
.get(), newcount
, device
->NumAuxSends
);
2740 for(ALsizei i
{0};i
< n
;i
++)
2742 ALsource
*source
{LookupSource(context
.get(), sources
[i
])};
2743 /* Check that there is a queue containing at least one valid, non zero
2746 ALbufferlistitem
*BufferList
{source
->queue
};
2747 while(BufferList
&& BufferList
->max_samples
== 0)
2748 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
2750 /* If there's nothing to play, go right to stopped. */
2751 if(UNLIKELY(!BufferList
))
2753 /* NOTE: A source without any playable buffers should not have an
2754 * ALvoice since it shouldn't be in a playing or paused state. So
2755 * there's no need to look up its voice and clear the source.
2757 ALenum oldstate
{GetSourceState(source
, nullptr)};
2758 source
->OffsetType
= AL_NONE
;
2759 source
->Offset
= 0.0;
2760 if(oldstate
!= AL_STOPPED
)
2762 source
->state
= AL_STOPPED
;
2763 SendStateChangeEvent(context
.get(), source
->id
, AL_STOPPED
);
2768 ALvoice
*voice
{GetSourceVoice(source
, context
.get())};
2769 switch(GetSourceState(source
, voice
))
2772 assert(voice
!= nullptr);
2773 /* A source that's already playing is restarted from the beginning. */
2774 voice
->current_buffer
.store(BufferList
, std::memory_order_relaxed
);
2775 voice
->position
.store(0u, std::memory_order_relaxed
);
2776 voice
->position_fraction
.store(0, std::memory_order_release
);
2780 assert(voice
!= nullptr);
2781 /* A source that's paused simply resumes. */
2782 voice
->Playing
.store(true, std::memory_order_release
);
2783 source
->state
= AL_PLAYING
;
2784 SendStateChangeEvent(context
.get(), source
->id
, AL_PLAYING
);
2791 /* Look for an unused voice to play this source with. */
2792 assert(voice
== nullptr);
2793 auto voices_end
= context
->Voices
+ context
->VoiceCount
.load(std::memory_order_relaxed
);
2794 auto voice_iter
= std::find_if(context
->Voices
, voices_end
,
2795 [](const ALvoice
*voice
) noexcept
-> bool
2796 { return voice
->Source
.load(std::memory_order_relaxed
) == nullptr; }
2798 auto vidx
= static_cast<ALint
>(std::distance(context
->Voices
, voice_iter
));
2799 voice
= *voice_iter
;
2800 voice
->Playing
.store(false, std::memory_order_release
);
2801 if(voice_iter
== voices_end
) context
->VoiceCount
.fetch_add(1, std::memory_order_acq_rel
);
2803 source
->PropsClean
.test_and_set(std::memory_order_acquire
);
2804 UpdateSourceProps(source
, voice
, context
.get());
2806 /* A source that's not playing or paused has any offset applied when it
2810 voice
->loop_buffer
.store(source
->queue
, std::memory_order_relaxed
);
2812 voice
->loop_buffer
.store(nullptr, std::memory_order_relaxed
);
2813 voice
->current_buffer
.store(BufferList
, std::memory_order_relaxed
);
2814 voice
->position
.store(0u, std::memory_order_relaxed
);
2815 voice
->position_fraction
.store(0, std::memory_order_relaxed
);
2816 bool start_fading
{false};
2817 if(ApplyOffset(source
, voice
) != AL_FALSE
)
2818 start_fading
= voice
->position
.load(std::memory_order_relaxed
) != 0 ||
2819 voice
->position_fraction
.load(std::memory_order_relaxed
) != 0 ||
2820 voice
->current_buffer
.load(std::memory_order_relaxed
) != BufferList
;
2822 auto buffers_end
= BufferList
->buffers
+ BufferList
->num_buffers
;
2823 auto buffer
= std::find_if(BufferList
->buffers
, buffers_end
,
2824 [](const ALbuffer
*buffer
) noexcept
-> bool
2825 { return buffer
!= nullptr; }
2827 if(buffer
!= buffers_end
)
2829 voice
->NumChannels
= ChannelsFromFmt((*buffer
)->FmtChannels
);
2830 voice
->SampleSize
= BytesFromFmt((*buffer
)->FmtType
);
2833 /* Clear previous samples. */
2834 for(auto &samples
: voice
->PrevSamples
)
2835 std::fill(std::begin(samples
), std::end(samples
), 0.0f
);
2837 /* Clear the stepping value so the mixer knows not to mix this until
2838 * the update gets applied.
2842 voice
->Flags
= start_fading
? VOICE_IS_FADING
: 0;
2843 if(source
->SourceType
== AL_STATIC
) voice
->Flags
|= VOICE_IS_STATIC
;
2844 memset(voice
->Direct
.Params
, 0, sizeof(voice
->Direct
.Params
[0])*voice
->NumChannels
);
2845 for(ALsizei j
{0};j
< device
->NumAuxSends
;j
++)
2846 memset(voice
->Send
[j
].Params
, 0, sizeof(voice
->Send
[j
].Params
[0])*voice
->NumChannels
);
2847 if(device
->AvgSpeakerDist
> 0.0f
)
2849 ALfloat w1
= SPEEDOFSOUNDMETRESPERSEC
/
2850 (device
->AvgSpeakerDist
* device
->Frequency
);
2851 for(ALsizei j
{0};j
< voice
->NumChannels
;j
++)
2852 NfcFilterCreate(&voice
->Direct
.Params
[j
].NFCtrlFilter
, 0.0f
, w1
);
2855 voice
->Source
.store(source
, std::memory_order_relaxed
);
2856 voice
->Playing
.store(true, std::memory_order_release
);
2857 source
->state
= AL_PLAYING
;
2858 source
->VoiceIdx
= vidx
;
2860 SendStateChangeEvent(context
.get(), source
->id
, AL_PLAYING
);
2862 ALCdevice_Unlock(device
);
2865 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
2867 alSourcePausev(1, &source
);
2869 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
2871 ContextRef context
{GetContextRef()};
2872 if(UNLIKELY(!context
)) return;
2875 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Pausing %d sources", n
);
2878 for(ALsizei i
{0};i
< n
;i
++)
2880 if(!LookupSource(context
.get(), sources
[i
]))
2881 SETERR_RETURN(context
.get(), AL_INVALID_NAME
,, "Invalid source ID %u", sources
[i
]);
2884 ALCdevice
*device
{context
->Device
};
2885 ALCdevice_Lock(device
);
2886 for(ALsizei i
{0};i
< n
;i
++)
2888 ALsource
*source
{LookupSource(context
.get(), sources
[i
])};
2889 ALvoice
*voice
{GetSourceVoice(source
, context
.get())};
2890 if(voice
) voice
->Playing
.store(false, std::memory_order_release
);
2891 if(GetSourceState(source
, voice
) == AL_PLAYING
)
2893 source
->state
= AL_PAUSED
;
2894 SendStateChangeEvent(context
.get(), source
->id
, AL_PAUSED
);
2897 ALCdevice_Unlock(device
);
2900 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
2902 alSourceStopv(1, &source
);
2904 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
2906 ContextRef context
{GetContextRef()};
2907 if(UNLIKELY(!context
)) return;
2910 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Stopping %d sources", n
);
2913 for(ALsizei i
{0};i
< n
;i
++)
2915 if(!LookupSource(context
.get(), sources
[i
]))
2916 SETERR_RETURN(context
.get(), AL_INVALID_NAME
,, "Invalid source ID %u", sources
[i
]);
2919 ALCdevice
*device
{context
->Device
};
2920 ALCdevice_Lock(device
);
2921 for(ALsizei i
{0};i
< n
;i
++)
2923 ALsource
*source
{LookupSource(context
.get(), sources
[i
])};
2924 ALvoice
*voice
{GetSourceVoice(source
, context
.get())};
2925 if(voice
!= nullptr)
2927 voice
->Source
.store(nullptr, std::memory_order_relaxed
);
2928 voice
->Playing
.store(false, std::memory_order_release
);
2931 ALenum oldstate
{GetSourceState(source
, voice
)};
2932 if(oldstate
!= AL_INITIAL
&& oldstate
!= AL_STOPPED
)
2934 source
->state
= AL_STOPPED
;
2935 SendStateChangeEvent(context
.get(), source
->id
, AL_STOPPED
);
2937 source
->OffsetType
= AL_NONE
;
2938 source
->Offset
= 0.0;
2940 ALCdevice_Unlock(device
);
2943 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
2945 alSourceRewindv(1, &source
);
2947 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
2949 ContextRef context
{GetContextRef()};
2950 if(UNLIKELY(!context
)) return;
2953 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Rewinding %d sources", n
);
2956 for(ALsizei i
{0};i
< n
;i
++)
2958 if(!LookupSource(context
.get(), sources
[i
]))
2959 SETERR_RETURN(context
.get(), AL_INVALID_NAME
,, "Invalid source ID %u", sources
[i
]);
2962 ALCdevice
*device
{context
->Device
};
2963 ALCdevice_Lock(device
);
2964 for(ALsizei i
{0};i
< n
;i
++)
2966 ALsource
*source
{LookupSource(context
.get(), sources
[i
])};
2967 ALvoice
*voice
{GetSourceVoice(source
, context
.get())};
2968 if(voice
!= nullptr)
2970 voice
->Source
.store(nullptr, std::memory_order_relaxed
);
2971 voice
->Playing
.store(false, std::memory_order_release
);
2974 if(GetSourceState(source
, voice
) != AL_INITIAL
)
2976 source
->state
= AL_INITIAL
;
2977 SendStateChangeEvent(context
.get(), source
->id
, AL_INITIAL
);
2979 source
->OffsetType
= AL_NONE
;
2980 source
->Offset
= 0.0;
2982 ALCdevice_Unlock(device
);
2986 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
2988 ContextRef context
{GetContextRef()};
2989 if(UNLIKELY(!context
)) return;
2992 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Queueing %d buffers", nb
);
2995 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
2996 ALsource
*source
{LookupSource(context
.get(),src
)};
2998 SETERR_RETURN(context
.get(), AL_INVALID_NAME
,, "Invalid source ID %u", src
);
3000 /* Can't queue on a Static Source */
3001 if(source
->SourceType
== AL_STATIC
)
3002 SETERR_RETURN(context
.get(), AL_INVALID_OPERATION
,, "Queueing onto static source %u", src
);
3004 /* Check for a valid Buffer, for its frequency and format */
3005 ALCdevice
*device
{context
->Device
};
3006 ALbuffer
*BufferFmt
{nullptr};
3007 ALbufferlistitem
*BufferList
{source
->queue
};
3010 for(ALsizei i
{0};i
< BufferList
->num_buffers
;i
++)
3012 if((BufferFmt
=BufferList
->buffers
[i
]) != nullptr)
3015 if(BufferFmt
) break;
3016 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
3019 std::unique_lock
<almtx_t
> buflock
{device
->BufferLock
};
3020 ALbufferlistitem
*BufferListStart
{nullptr};
3021 BufferList
= nullptr;
3022 for(ALsizei i
{0};i
< nb
;i
++)
3024 ALbuffer
*buffer
{nullptr};
3025 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == nullptr)
3027 alSetError(context
.get(), AL_INVALID_NAME
, "Queueing invalid buffer ID %u",
3032 if(!BufferListStart
)
3034 BufferListStart
= static_cast<ALbufferlistitem
*>(al_calloc(DEF_ALIGN
,
3035 FAM_SIZE(ALbufferlistitem
, buffers
, 1)));
3036 BufferList
= BufferListStart
;
3040 auto item
= static_cast<ALbufferlistitem
*>(al_calloc(DEF_ALIGN
,
3041 FAM_SIZE(ALbufferlistitem
, buffers
, 1)));
3042 BufferList
->next
.store(item
, std::memory_order_relaxed
);
3045 ATOMIC_INIT(&BufferList
->next
, static_cast<ALbufferlistitem
*>(nullptr));
3046 BufferList
->max_samples
= buffer
? buffer
->SampleLen
: 0;
3047 BufferList
->num_buffers
= 1;
3048 BufferList
->buffers
[0] = buffer
;
3049 if(!buffer
) continue;
3051 IncrementRef(&buffer
->ref
);
3053 if(buffer
->MappedAccess
!= 0 && !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
3055 alSetError(context
.get(), AL_INVALID_OPERATION
,
3056 "Queueing non-persistently mapped buffer %u", buffer
->id
);
3060 if(BufferFmt
== nullptr)
3062 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
3063 BufferFmt
->FmtChannels
!= buffer
->FmtChannels
||
3064 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
3066 alSetError(context
.get(), AL_INVALID_OPERATION
,
3067 "Queueing buffer with mismatched format");
3070 /* A buffer failed (invalid ID or format), so unlock and release
3071 * each buffer we had. */
3072 while(BufferListStart
)
3074 ALbufferlistitem
*next
= BufferListStart
->next
.load(std::memory_order_relaxed
);
3075 for(i
= 0;i
< BufferListStart
->num_buffers
;i
++)
3077 if((buffer
=BufferListStart
->buffers
[i
]) != nullptr)
3078 DecrementRef(&buffer
->ref
);
3080 al_free(BufferListStart
);
3081 BufferListStart
= next
;
3086 /* All buffers good. */
3089 /* Source is now streaming */
3090 source
->SourceType
= AL_STREAMING
;
3092 if(!(BufferList
=source
->queue
))
3093 source
->queue
= BufferListStart
;
3096 ALbufferlistitem
*next
;
3097 while((next
=BufferList
->next
.load(std::memory_order_relaxed
)) != nullptr)
3099 BufferList
->next
.store(BufferListStart
, std::memory_order_release
);
3103 AL_API
void AL_APIENTRY
alSourceQueueBufferLayersSOFT(ALuint src
, ALsizei nb
, const ALuint
*buffers
)
3105 ContextRef context
{GetContextRef()};
3106 if(UNLIKELY(!context
)) return;
3109 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Queueing %d buffer layers", nb
);
3112 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
3113 ALsource
*source
{LookupSource(context
.get(),src
)};
3115 SETERR_RETURN(context
.get(), AL_INVALID_NAME
,, "Invalid source ID %u", src
);
3117 /* Can't queue on a Static Source */
3118 if(source
->SourceType
== AL_STATIC
)
3119 SETERR_RETURN(context
.get(), AL_INVALID_OPERATION
,, "Queueing onto static source %u", src
);
3121 /* Check for a valid Buffer, for its frequency and format */
3122 ALCdevice
*device
{context
->Device
};
3123 ALbuffer
*BufferFmt
{nullptr};
3124 ALbufferlistitem
*BufferList
{source
->queue
};
3127 for(ALsizei i
{0};i
< BufferList
->num_buffers
;i
++)
3129 if((BufferFmt
=BufferList
->buffers
[i
]) != nullptr)
3132 if(BufferFmt
) break;
3133 BufferList
= BufferList
->next
.load(std::memory_order_relaxed
);
3136 std::unique_lock
<almtx_t
> buflock
{device
->BufferLock
};
3137 auto BufferListStart
= static_cast<ALbufferlistitem
*>(al_calloc(DEF_ALIGN
,
3138 FAM_SIZE(ALbufferlistitem
, buffers
, nb
)));
3139 BufferList
= BufferListStart
;
3140 ATOMIC_INIT(&BufferList
->next
, static_cast<ALbufferlistitem
*>(nullptr));
3141 BufferList
->max_samples
= 0;
3142 BufferList
->num_buffers
= 0;
3144 for(ALsizei i
{0};i
< nb
;i
++)
3146 ALbuffer
*buffer
{nullptr};
3147 if(buffers
[i
] && (buffer
=LookupBuffer(device
, buffers
[i
])) == nullptr)
3149 alSetError(context
.get(), AL_INVALID_NAME
, "Queueing invalid buffer ID %u",
3154 BufferList
->buffers
[BufferList
->num_buffers
++] = buffer
;
3155 if(!buffer
) continue;
3157 IncrementRef(&buffer
->ref
);
3159 BufferList
->max_samples
= maxi(BufferList
->max_samples
, buffer
->SampleLen
);
3161 if(buffer
->MappedAccess
!= 0 && !(buffer
->MappedAccess
&AL_MAP_PERSISTENT_BIT_SOFT
))
3163 alSetError(context
.get(), AL_INVALID_OPERATION
,
3164 "Queueing non-persistently mapped buffer %u", buffer
->id
);
3168 if(BufferFmt
== nullptr)
3170 else if(BufferFmt
->Frequency
!= buffer
->Frequency
||
3171 BufferFmt
->FmtChannels
!= buffer
->FmtChannels
||
3172 BufferFmt
->OriginalType
!= buffer
->OriginalType
)
3174 alSetError(context
.get(), AL_INVALID_OPERATION
,
3175 "Queueing buffer with mismatched format");
3178 /* A buffer failed (invalid ID or format), so unlock and release
3179 * each buffer we had. */
3180 while(BufferListStart
)
3182 ALbufferlistitem
*next
{BufferListStart
->next
.load(std::memory_order_relaxed
)};
3183 for(i
= 0;i
< BufferListStart
->num_buffers
;i
++)
3185 if((buffer
=BufferListStart
->buffers
[i
]) != nullptr)
3186 DecrementRef(&buffer
->ref
);
3188 al_free(BufferListStart
);
3189 BufferListStart
= next
;
3194 /* All buffers good. */
3197 /* Source is now streaming */
3198 source
->SourceType
= AL_STREAMING
;
3200 if(!(BufferList
=source
->queue
))
3201 source
->queue
= BufferListStart
;
3204 ALbufferlistitem
*next
;
3205 while((next
=BufferList
->next
.load(std::memory_order_relaxed
)) != nullptr)
3207 BufferList
->next
.store(BufferListStart
, std::memory_order_release
);
3211 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers(ALuint src
, ALsizei nb
, ALuint
*buffers
)
3213 ContextRef context
{GetContextRef()};
3214 if(UNLIKELY(!context
)) return;
3217 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Unqueueing %d buffers", nb
);
3220 std::lock_guard
<almtx_t
> _
{context
->SourceLock
};
3221 ALsource
*source
{LookupSource(context
.get(),src
)};
3223 SETERR_RETURN(context
.get(), AL_INVALID_NAME
,, "Invalid source ID %u", src
);
3226 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Unqueueing from looping source %u", src
);
3227 if(source
->SourceType
!= AL_STREAMING
)
3228 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,,
3229 "Unqueueing from a non-streaming source %u", src
);
3231 /* Make sure enough buffers have been processed to unqueue. */
3232 ALbufferlistitem
*BufferList
{source
->queue
};
3233 ALvoice
*voice
{GetSourceVoice(source
, context
.get())};
3234 ALbufferlistitem
*Current
{nullptr};
3236 Current
= voice
->current_buffer
.load(std::memory_order_relaxed
);
3237 else if(source
->state
== AL_INITIAL
)
3238 Current
= BufferList
;
3239 if(BufferList
== Current
)
3240 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Unqueueing pending buffers");
3242 ALsizei i
{BufferList
->num_buffers
};
3245 /* If the next bufferlist to check is NULL or is the current one, it's
3246 * trying to unqueue pending buffers.
3248 ALbufferlistitem
*next
{BufferList
->next
.load(std::memory_order_relaxed
)};
3249 if(!next
|| next
== Current
)
3250 SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Unqueueing pending buffers");
3253 i
+= BufferList
->num_buffers
;
3258 ALbufferlistitem
*head
{source
->queue
};
3259 ALbufferlistitem
*next
{head
->next
.load(std::memory_order_relaxed
)};
3260 for(i
= 0;i
< head
->num_buffers
&& nb
> 0;i
++,nb
--)
3262 ALbuffer
*buffer
{head
->buffers
[i
]};
3267 *(buffers
++) = buffer
->id
;
3268 DecrementRef(&buffer
->ref
);
3271 if(i
< head
->num_buffers
)
3273 /* This head has some buffers left over, so move them to the front
3274 * and update the sample and buffer count.
3276 ALsizei max_length
{0};
3278 while(i
< head
->num_buffers
)
3280 ALbuffer
*buffer
{head
->buffers
[i
++]};
3281 if(buffer
) max_length
= maxi(max_length
, buffer
->SampleLen
);
3282 head
->buffers
[j
++] = buffer
;
3284 head
->max_samples
= max_length
;
3285 head
->num_buffers
= j
;
3289 /* Otherwise, free this item and set the source queue head to the next
3293 source
->queue
= next
;
3298 ALsource::ALsource(ALsizei num_sends
)
3300 InnerAngle
= 360.0f
;
3301 OuterAngle
= 360.0f
;
3309 Direction
[0] = 0.0f
;
3310 Direction
[1] = 0.0f
;
3311 Direction
[2] = 0.0f
;
3312 Orientation
[0][0] = 0.0f
;
3313 Orientation
[0][1] = 0.0f
;
3314 Orientation
[0][2] = -1.0f
;
3315 Orientation
[1][0] = 0.0f
;
3316 Orientation
[1][1] = 1.0f
;
3317 Orientation
[1][2] = 0.0f
;
3319 MaxDistance
= FLT_MAX
;
3320 RolloffFactor
= 1.0f
;
3327 DryGainHFAuto
= AL_TRUE
;
3328 WetGainAuto
= AL_TRUE
;
3329 WetGainHFAuto
= AL_TRUE
;
3330 AirAbsorptionFactor
= 0.0f
;
3331 RoomRolloffFactor
= 0.0f
;
3332 DopplerFactor
= 1.0f
;
3333 HeadRelative
= AL_FALSE
;
3335 mDistanceModel
= DistanceModel::Default
;
3336 Resampler
= ResamplerDefault
;
3337 DirectChannels
= AL_FALSE
;
3338 Spatialize
= SpatializeAuto
;
3340 StereoPan
[0] = DEG2RAD( 30.0f
);
3341 StereoPan
[1] = DEG2RAD(-30.0f
);
3346 Direct
.GainHF
= 1.0f
;
3347 Direct
.HFReference
= LOWPASSFREQREF
;
3348 Direct
.GainLF
= 1.0f
;
3349 Direct
.LFReference
= HIGHPASSFREQREF
;
3350 Send
.resize(num_sends
);
3351 for(auto &send
: Send
)
3353 send
.Slot
= nullptr;
3356 send
.HFReference
= LOWPASSFREQREF
;
3358 send
.LFReference
= HIGHPASSFREQREF
;
3362 OffsetType
= AL_NONE
;
3363 SourceType
= AL_UNDETERMINED
;
3371 ALsource::~ALsource()
3373 ALbufferlistitem
*BufferList
{queue
};
3374 while(BufferList
!= nullptr)
3376 ALbufferlistitem
*next
{BufferList
->next
.load(std::memory_order_relaxed
)};
3377 for(ALsizei i
{0};i
< BufferList
->num_buffers
;i
++)
3379 if(BufferList
->buffers
[i
])
3380 DecrementRef(&BufferList
->buffers
[i
]->ref
);
3382 al_free(BufferList
);
3387 std::for_each(Send
.begin(), Send
.end(),
3388 [](ALsource::SendData
&send
) -> void
3391 DecrementRef(&send
.Slot
->ref
);
3392 send
.Slot
= nullptr;
3397 void UpdateAllSourceProps(ALCcontext
*context
)
3399 auto voices_end
= context
->Voices
+ context
->VoiceCount
.load(std::memory_order_relaxed
);
3400 std::for_each(context
->Voices
, voices_end
,
3401 [context
](ALvoice
*voice
) -> void
3403 ALsource
*source
{voice
->Source
.load(std::memory_order_acquire
)};
3404 if(source
&& !source
->PropsClean
.test_and_set(std::memory_order_acq_rel
))
3405 UpdateSourceProps(source
, voice
, context
);
3412 * Destroys all sources in the source map.
3414 ALvoid
ReleaseALSources(ALCcontext
*context
)
3416 size_t leftover
= 0;
3417 for(auto &sublist
: context
->SourceList
)
3419 ALuint64 usemask
= ~sublist
.FreeMask
;
3422 ALsizei idx
{CTZ64(usemask
)};
3423 ALsource
*source
{sublist
.Sources
+ idx
};
3425 source
->~ALsource();
3428 usemask
&= ~(U64(1) << idx
);
3430 sublist
.FreeMask
= ~usemask
;
3433 WARN("(%p) Deleted " SZFMT
" Source%s\n", context
, leftover
, (leftover
==1)?"":"s");