Remove the CONST_CAST hack
[openal-soft.git] / OpenAL32 / alSource.cpp
blob539a5f4fd6733151dbcc7fd0cdcca09d5b063913
1 /**
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
21 #include "config.h"
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <float.h>
27 #include <cmath>
28 #include <algorithm>
30 #include "AL/al.h"
31 #include "AL/alc.h"
33 #include "alMain.h"
34 #include "alcontext.h"
35 #include "alError.h"
36 #include "alSource.h"
37 #include "alBuffer.h"
38 #include "alFilter.h"
39 #include "alAuxEffectSlot.h"
40 #include "ringbuffer.h"
42 #include "backends/base.h"
44 #include "threads.h"
45 #include "almalloc.h"
48 static ALsource *AllocSource(ALCcontext *context);
49 static void FreeSource(ALCcontext *context, ALsource *source);
50 static void InitSourceParams(ALsource *Source, ALsizei num_sends);
51 static void DeinitSource(ALsource *source, ALsizei num_sends);
52 static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends, ALCcontext *context);
53 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime);
54 static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime);
55 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context);
56 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac);
57 static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice);
59 static inline void LockSourceList(ALCcontext *context)
60 { almtx_lock(&context->SourceLock); }
61 static inline void UnlockSourceList(ALCcontext *context)
62 { almtx_unlock(&context->SourceLock); }
64 static inline ALsource *LookupSource(ALCcontext *context, ALuint id)
66 ALuint lidx = (id-1) >> 6;
67 ALsizei slidx = (id-1) & 0x3f;
69 if(UNLIKELY(lidx >= context->SourceList.size()))
70 return nullptr;
71 SourceSubList &sublist{context->SourceList[lidx]};
72 if(UNLIKELY(sublist.FreeMask & (U64(1)<<slidx)))
73 return nullptr;
74 return sublist.Sources + slidx;
77 static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id)
79 ALuint lidx = (id-1) >> 6;
80 ALsizei slidx = (id-1) & 0x3f;
82 if(UNLIKELY(lidx >= device->BufferList.size()))
83 return nullptr;
84 BufferSubList &sublist = device->BufferList[lidx];
85 if(UNLIKELY(sublist.FreeMask & (U64(1)<<slidx)))
86 return nullptr;
87 return sublist.Buffers + slidx;
90 static inline ALfilter *LookupFilter(ALCdevice *device, ALuint id)
92 ALuint lidx = (id-1) >> 6;
93 ALsizei slidx = (id-1) & 0x3f;
95 if(UNLIKELY(lidx >= device->FilterList.size()))
96 return nullptr;
97 FilterSubList &sublist = device->FilterList[lidx];
98 if(UNLIKELY(sublist.FreeMask & (U64(1)<<slidx)))
99 return nullptr;
100 return sublist.Filters + slidx;
103 static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id)
105 --id;
106 if(UNLIKELY(id >= context->EffectSlotList.size()))
107 return nullptr;
108 return context->EffectSlotList[id];
112 typedef enum SourceProp {
113 srcPitch = AL_PITCH,
114 srcGain = AL_GAIN,
115 srcMinGain = AL_MIN_GAIN,
116 srcMaxGain = AL_MAX_GAIN,
117 srcMaxDistance = AL_MAX_DISTANCE,
118 srcRolloffFactor = AL_ROLLOFF_FACTOR,
119 srcDopplerFactor = AL_DOPPLER_FACTOR,
120 srcConeOuterGain = AL_CONE_OUTER_GAIN,
121 srcSecOffset = AL_SEC_OFFSET,
122 srcSampleOffset = AL_SAMPLE_OFFSET,
123 srcByteOffset = AL_BYTE_OFFSET,
124 srcConeInnerAngle = AL_CONE_INNER_ANGLE,
125 srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
126 srcRefDistance = AL_REFERENCE_DISTANCE,
128 srcPosition = AL_POSITION,
129 srcVelocity = AL_VELOCITY,
130 srcDirection = AL_DIRECTION,
132 srcSourceRelative = AL_SOURCE_RELATIVE,
133 srcLooping = AL_LOOPING,
134 srcBuffer = AL_BUFFER,
135 srcSourceState = AL_SOURCE_STATE,
136 srcBuffersQueued = AL_BUFFERS_QUEUED,
137 srcBuffersProcessed = AL_BUFFERS_PROCESSED,
138 srcSourceType = AL_SOURCE_TYPE,
140 /* ALC_EXT_EFX */
141 srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
142 srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
143 srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
144 srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
145 srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
146 srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
147 srcDirectFilter = AL_DIRECT_FILTER,
148 srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
150 /* AL_SOFT_direct_channels */
151 srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
153 /* AL_EXT_source_distance_model */
154 srcDistanceModel = AL_DISTANCE_MODEL,
156 /* AL_SOFT_source_latency */
157 srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
158 srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
160 /* AL_EXT_STEREO_ANGLES */
161 srcAngles = AL_STEREO_ANGLES,
163 /* AL_EXT_SOURCE_RADIUS */
164 srcRadius = AL_SOURCE_RADIUS,
166 /* AL_EXT_BFORMAT */
167 srcOrientation = AL_ORIENTATION,
169 /* AL_SOFT_source_resampler */
170 srcResampler = AL_SOURCE_RESAMPLER_SOFT,
172 /* AL_SOFT_source_spatialize */
173 srcSpatialize = AL_SOURCE_SPATIALIZE_SOFT,
175 /* ALC_SOFT_device_clock */
176 srcSampleOffsetClockSOFT = AL_SAMPLE_OFFSET_CLOCK_SOFT,
177 srcSecOffsetClockSOFT = AL_SEC_OFFSET_CLOCK_SOFT,
178 } SourceProp;
180 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
181 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
182 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
184 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
185 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
186 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
188 static inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context)
190 ALint idx = source->VoiceIdx;
191 if(idx >= 0 && idx < context->VoiceCount)
193 ALvoice *voice = context->Voices[idx];
194 if(ATOMIC_LOAD(&voice->Source, almemory_order_acquire) == source)
195 return voice;
197 source->VoiceIdx = -1;
198 return NULL;
202 * Returns if the last known state for the source was playing or paused. Does
203 * not sync with the mixer voice.
205 static inline bool IsPlayingOrPaused(ALsource *source)
206 { return source->state == AL_PLAYING || source->state == AL_PAUSED; }
209 * Returns an updated source state using the matching voice's status (or lack
210 * thereof).
212 static inline ALenum GetSourceState(ALsource *source, ALvoice *voice)
214 if(!voice && source->state == AL_PLAYING)
215 source->state = AL_STOPPED;
216 return source->state;
220 * Returns if the source should specify an update, given the context's
221 * deferring state and the source's last known state.
223 static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context)
225 return !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) &&
226 IsPlayingOrPaused(source);
230 /** Can only be called while the mixer is locked! */
231 static void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state)
233 AsyncEvent evt = ASYNC_EVENT(EventType_SourceStateChange);
234 ALbitfieldSOFT enabledevt;
236 enabledevt = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire);
237 if(!(enabledevt&EventType_SourceStateChange)) return;
239 evt.u.user.type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT;
240 evt.u.user.id = id;
241 evt.u.user.param = state;
242 snprintf(evt.u.user.msg, sizeof(evt.u.user.msg), "Source ID %u state changed to %s", id,
243 (state==AL_INITIAL) ? "AL_INITIAL" :
244 (state==AL_PLAYING) ? "AL_PLAYING" :
245 (state==AL_PAUSED) ? "AL_PAUSED" :
246 (state==AL_STOPPED) ? "AL_STOPPED" : "<unknown>"
248 /* The mixer may have queued a state change that's not yet been processed,
249 * and we don't want state change messages to occur out of order, so send
250 * it through the async queue to ensure proper ordering.
252 if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1)
253 alsem_post(&context->EventSem);
257 static ALint FloatValsByProp(ALenum prop)
259 if(prop != (ALenum)((SourceProp)prop))
260 return 0;
261 switch((SourceProp)prop)
263 case AL_PITCH:
264 case AL_GAIN:
265 case AL_MIN_GAIN:
266 case AL_MAX_GAIN:
267 case AL_MAX_DISTANCE:
268 case AL_ROLLOFF_FACTOR:
269 case AL_DOPPLER_FACTOR:
270 case AL_CONE_OUTER_GAIN:
271 case AL_SEC_OFFSET:
272 case AL_SAMPLE_OFFSET:
273 case AL_BYTE_OFFSET:
274 case AL_CONE_INNER_ANGLE:
275 case AL_CONE_OUTER_ANGLE:
276 case AL_REFERENCE_DISTANCE:
277 case AL_CONE_OUTER_GAINHF:
278 case AL_AIR_ABSORPTION_FACTOR:
279 case AL_ROOM_ROLLOFF_FACTOR:
280 case AL_DIRECT_FILTER_GAINHF_AUTO:
281 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
282 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
283 case AL_DIRECT_CHANNELS_SOFT:
284 case AL_DISTANCE_MODEL:
285 case AL_SOURCE_RELATIVE:
286 case AL_LOOPING:
287 case AL_SOURCE_STATE:
288 case AL_BUFFERS_QUEUED:
289 case AL_BUFFERS_PROCESSED:
290 case AL_SOURCE_TYPE:
291 case AL_SOURCE_RADIUS:
292 case AL_SOURCE_RESAMPLER_SOFT:
293 case AL_SOURCE_SPATIALIZE_SOFT:
294 return 1;
296 case AL_STEREO_ANGLES:
297 return 2;
299 case AL_POSITION:
300 case AL_VELOCITY:
301 case AL_DIRECTION:
302 return 3;
304 case AL_ORIENTATION:
305 return 6;
307 case AL_SEC_OFFSET_LATENCY_SOFT:
308 case AL_SEC_OFFSET_CLOCK_SOFT:
309 break; /* Double only */
311 case AL_BUFFER:
312 case AL_DIRECT_FILTER:
313 case AL_AUXILIARY_SEND_FILTER:
314 break; /* i/i64 only */
315 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
316 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
317 break; /* i64 only */
319 return 0;
321 static ALint DoubleValsByProp(ALenum prop)
323 if(prop != (ALenum)((SourceProp)prop))
324 return 0;
325 switch((SourceProp)prop)
327 case AL_PITCH:
328 case AL_GAIN:
329 case AL_MIN_GAIN:
330 case AL_MAX_GAIN:
331 case AL_MAX_DISTANCE:
332 case AL_ROLLOFF_FACTOR:
333 case AL_DOPPLER_FACTOR:
334 case AL_CONE_OUTER_GAIN:
335 case AL_SEC_OFFSET:
336 case AL_SAMPLE_OFFSET:
337 case AL_BYTE_OFFSET:
338 case AL_CONE_INNER_ANGLE:
339 case AL_CONE_OUTER_ANGLE:
340 case AL_REFERENCE_DISTANCE:
341 case AL_CONE_OUTER_GAINHF:
342 case AL_AIR_ABSORPTION_FACTOR:
343 case AL_ROOM_ROLLOFF_FACTOR:
344 case AL_DIRECT_FILTER_GAINHF_AUTO:
345 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
346 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
347 case AL_DIRECT_CHANNELS_SOFT:
348 case AL_DISTANCE_MODEL:
349 case AL_SOURCE_RELATIVE:
350 case AL_LOOPING:
351 case AL_SOURCE_STATE:
352 case AL_BUFFERS_QUEUED:
353 case AL_BUFFERS_PROCESSED:
354 case AL_SOURCE_TYPE:
355 case AL_SOURCE_RADIUS:
356 case AL_SOURCE_RESAMPLER_SOFT:
357 case AL_SOURCE_SPATIALIZE_SOFT:
358 return 1;
360 case AL_SEC_OFFSET_LATENCY_SOFT:
361 case AL_SEC_OFFSET_CLOCK_SOFT:
362 case AL_STEREO_ANGLES:
363 return 2;
365 case AL_POSITION:
366 case AL_VELOCITY:
367 case AL_DIRECTION:
368 return 3;
370 case AL_ORIENTATION:
371 return 6;
373 case AL_BUFFER:
374 case AL_DIRECT_FILTER:
375 case AL_AUXILIARY_SEND_FILTER:
376 break; /* i/i64 only */
377 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
378 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
379 break; /* i64 only */
381 return 0;
384 static ALint IntValsByProp(ALenum prop)
386 if(prop != (ALenum)((SourceProp)prop))
387 return 0;
388 switch((SourceProp)prop)
390 case AL_PITCH:
391 case AL_GAIN:
392 case AL_MIN_GAIN:
393 case AL_MAX_GAIN:
394 case AL_MAX_DISTANCE:
395 case AL_ROLLOFF_FACTOR:
396 case AL_DOPPLER_FACTOR:
397 case AL_CONE_OUTER_GAIN:
398 case AL_SEC_OFFSET:
399 case AL_SAMPLE_OFFSET:
400 case AL_BYTE_OFFSET:
401 case AL_CONE_INNER_ANGLE:
402 case AL_CONE_OUTER_ANGLE:
403 case AL_REFERENCE_DISTANCE:
404 case AL_CONE_OUTER_GAINHF:
405 case AL_AIR_ABSORPTION_FACTOR:
406 case AL_ROOM_ROLLOFF_FACTOR:
407 case AL_DIRECT_FILTER_GAINHF_AUTO:
408 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
409 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
410 case AL_DIRECT_CHANNELS_SOFT:
411 case AL_DISTANCE_MODEL:
412 case AL_SOURCE_RELATIVE:
413 case AL_LOOPING:
414 case AL_BUFFER:
415 case AL_SOURCE_STATE:
416 case AL_BUFFERS_QUEUED:
417 case AL_BUFFERS_PROCESSED:
418 case AL_SOURCE_TYPE:
419 case AL_DIRECT_FILTER:
420 case AL_SOURCE_RADIUS:
421 case AL_SOURCE_RESAMPLER_SOFT:
422 case AL_SOURCE_SPATIALIZE_SOFT:
423 return 1;
425 case AL_POSITION:
426 case AL_VELOCITY:
427 case AL_DIRECTION:
428 case AL_AUXILIARY_SEND_FILTER:
429 return 3;
431 case AL_ORIENTATION:
432 return 6;
434 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
435 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
436 break; /* i64 only */
437 case AL_SEC_OFFSET_LATENCY_SOFT:
438 case AL_SEC_OFFSET_CLOCK_SOFT:
439 break; /* Double only */
440 case AL_STEREO_ANGLES:
441 break; /* Float/double only */
443 return 0;
445 static ALint Int64ValsByProp(ALenum prop)
447 if(prop != (ALenum)((SourceProp)prop))
448 return 0;
449 switch((SourceProp)prop)
451 case AL_PITCH:
452 case AL_GAIN:
453 case AL_MIN_GAIN:
454 case AL_MAX_GAIN:
455 case AL_MAX_DISTANCE:
456 case AL_ROLLOFF_FACTOR:
457 case AL_DOPPLER_FACTOR:
458 case AL_CONE_OUTER_GAIN:
459 case AL_SEC_OFFSET:
460 case AL_SAMPLE_OFFSET:
461 case AL_BYTE_OFFSET:
462 case AL_CONE_INNER_ANGLE:
463 case AL_CONE_OUTER_ANGLE:
464 case AL_REFERENCE_DISTANCE:
465 case AL_CONE_OUTER_GAINHF:
466 case AL_AIR_ABSORPTION_FACTOR:
467 case AL_ROOM_ROLLOFF_FACTOR:
468 case AL_DIRECT_FILTER_GAINHF_AUTO:
469 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
470 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
471 case AL_DIRECT_CHANNELS_SOFT:
472 case AL_DISTANCE_MODEL:
473 case AL_SOURCE_RELATIVE:
474 case AL_LOOPING:
475 case AL_BUFFER:
476 case AL_SOURCE_STATE:
477 case AL_BUFFERS_QUEUED:
478 case AL_BUFFERS_PROCESSED:
479 case AL_SOURCE_TYPE:
480 case AL_DIRECT_FILTER:
481 case AL_SOURCE_RADIUS:
482 case AL_SOURCE_RESAMPLER_SOFT:
483 case AL_SOURCE_SPATIALIZE_SOFT:
484 return 1;
486 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
487 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
488 return 2;
490 case AL_POSITION:
491 case AL_VELOCITY:
492 case AL_DIRECTION:
493 case AL_AUXILIARY_SEND_FILTER:
494 return 3;
496 case AL_ORIENTATION:
497 return 6;
499 case AL_SEC_OFFSET_LATENCY_SOFT:
500 case AL_SEC_OFFSET_CLOCK_SOFT:
501 break; /* Double only */
502 case AL_STEREO_ANGLES:
503 break; /* Float/double only */
505 return 0;
509 #define CHECKVAL(x) do { \
510 if(!(x)) \
512 alSetError(Context, AL_INVALID_VALUE, "Value out of range"); \
513 return AL_FALSE; \
515 } while(0)
517 #define DO_UPDATEPROPS() do { \
518 ALvoice *voice; \
519 if(SourceShouldUpdate(Source, Context) && \
520 (voice=GetSourceVoice(Source, Context)) != NULL) \
521 UpdateSourceProps(Source, voice, device->NumAuxSends, Context); \
522 else \
523 ATOMIC_STORE(&Source->PropsClean, AL_FALSE, almemory_order_release); \
524 } while(0)
526 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
528 ALCdevice *device = Context->Device;
529 ALint ival;
531 switch(prop)
533 case AL_SEC_OFFSET_LATENCY_SOFT:
534 case AL_SEC_OFFSET_CLOCK_SOFT:
535 /* Query only */
536 SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
537 "Setting read-only source property 0x%04x", prop);
539 case AL_PITCH:
540 CHECKVAL(*values >= 0.0f);
542 Source->Pitch = *values;
543 DO_UPDATEPROPS();
544 return AL_TRUE;
546 case AL_CONE_INNER_ANGLE:
547 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
549 Source->InnerAngle = *values;
550 DO_UPDATEPROPS();
551 return AL_TRUE;
553 case AL_CONE_OUTER_ANGLE:
554 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
556 Source->OuterAngle = *values;
557 DO_UPDATEPROPS();
558 return AL_TRUE;
560 case AL_GAIN:
561 CHECKVAL(*values >= 0.0f);
563 Source->Gain = *values;
564 DO_UPDATEPROPS();
565 return AL_TRUE;
567 case AL_MAX_DISTANCE:
568 CHECKVAL(*values >= 0.0f);
570 Source->MaxDistance = *values;
571 DO_UPDATEPROPS();
572 return AL_TRUE;
574 case AL_ROLLOFF_FACTOR:
575 CHECKVAL(*values >= 0.0f);
577 Source->RolloffFactor = *values;
578 DO_UPDATEPROPS();
579 return AL_TRUE;
581 case AL_REFERENCE_DISTANCE:
582 CHECKVAL(*values >= 0.0f);
584 Source->RefDistance = *values;
585 DO_UPDATEPROPS();
586 return AL_TRUE;
588 case AL_MIN_GAIN:
589 CHECKVAL(*values >= 0.0f);
591 Source->MinGain = *values;
592 DO_UPDATEPROPS();
593 return AL_TRUE;
595 case AL_MAX_GAIN:
596 CHECKVAL(*values >= 0.0f);
598 Source->MaxGain = *values;
599 DO_UPDATEPROPS();
600 return AL_TRUE;
602 case AL_CONE_OUTER_GAIN:
603 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
605 Source->OuterGain = *values;
606 DO_UPDATEPROPS();
607 return AL_TRUE;
609 case AL_CONE_OUTER_GAINHF:
610 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
612 Source->OuterGainHF = *values;
613 DO_UPDATEPROPS();
614 return AL_TRUE;
616 case AL_AIR_ABSORPTION_FACTOR:
617 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
619 Source->AirAbsorptionFactor = *values;
620 DO_UPDATEPROPS();
621 return AL_TRUE;
623 case AL_ROOM_ROLLOFF_FACTOR:
624 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
626 Source->RoomRolloffFactor = *values;
627 DO_UPDATEPROPS();
628 return AL_TRUE;
630 case AL_DOPPLER_FACTOR:
631 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
633 Source->DopplerFactor = *values;
634 DO_UPDATEPROPS();
635 return AL_TRUE;
637 case AL_SEC_OFFSET:
638 case AL_SAMPLE_OFFSET:
639 case AL_BYTE_OFFSET:
640 CHECKVAL(*values >= 0.0f);
642 Source->OffsetType = prop;
643 Source->Offset = *values;
645 if(IsPlayingOrPaused(Source))
647 ALvoice *voice;
649 ALCdevice_Lock(Context->Device);
650 /* Double-check that the source is still playing while we have
651 * the lock.
653 voice = GetSourceVoice(Source, Context);
654 if(voice)
656 if(ApplyOffset(Source, voice) == AL_FALSE)
658 ALCdevice_Unlock(Context->Device);
659 SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid offset");
662 ALCdevice_Unlock(Context->Device);
664 return AL_TRUE;
666 case AL_SOURCE_RADIUS:
667 CHECKVAL(*values >= 0.0f && std::isfinite(*values));
669 Source->Radius = *values;
670 DO_UPDATEPROPS();
671 return AL_TRUE;
673 case AL_STEREO_ANGLES:
674 CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]));
676 Source->StereoPan[0] = values[0];
677 Source->StereoPan[1] = values[1];
678 DO_UPDATEPROPS();
679 return AL_TRUE;
682 case AL_POSITION:
683 CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]));
685 Source->Position[0] = values[0];
686 Source->Position[1] = values[1];
687 Source->Position[2] = values[2];
688 DO_UPDATEPROPS();
689 return AL_TRUE;
691 case AL_VELOCITY:
692 CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]));
694 Source->Velocity[0] = values[0];
695 Source->Velocity[1] = values[1];
696 Source->Velocity[2] = values[2];
697 DO_UPDATEPROPS();
698 return AL_TRUE;
700 case AL_DIRECTION:
701 CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]));
703 Source->Direction[0] = values[0];
704 Source->Direction[1] = values[1];
705 Source->Direction[2] = values[2];
706 DO_UPDATEPROPS();
707 return AL_TRUE;
709 case AL_ORIENTATION:
710 CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) &&
711 std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5]));
713 Source->Orientation[0][0] = values[0];
714 Source->Orientation[0][1] = values[1];
715 Source->Orientation[0][2] = values[2];
716 Source->Orientation[1][0] = values[3];
717 Source->Orientation[1][1] = values[4];
718 Source->Orientation[1][2] = values[5];
719 DO_UPDATEPROPS();
720 return AL_TRUE;
723 case AL_SOURCE_RELATIVE:
724 case AL_LOOPING:
725 case AL_SOURCE_STATE:
726 case AL_SOURCE_TYPE:
727 case AL_DISTANCE_MODEL:
728 case AL_DIRECT_FILTER_GAINHF_AUTO:
729 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
730 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
731 case AL_DIRECT_CHANNELS_SOFT:
732 case AL_SOURCE_RESAMPLER_SOFT:
733 case AL_SOURCE_SPATIALIZE_SOFT:
734 ival = (ALint)values[0];
735 return SetSourceiv(Source, Context, prop, &ival);
737 case AL_BUFFERS_QUEUED:
738 case AL_BUFFERS_PROCESSED:
739 ival = (ALint)((ALuint)values[0]);
740 return SetSourceiv(Source, Context, prop, &ival);
742 case AL_BUFFER:
743 case AL_DIRECT_FILTER:
744 case AL_AUXILIARY_SEND_FILTER:
745 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
746 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
747 break;
750 ERR("Unexpected property: 0x%04x\n", prop);
751 SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source float property 0x%04x", prop);
754 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
756 ALCdevice *device = Context->Device;
757 ALbuffer *buffer = NULL;
758 ALfilter *filter = NULL;
759 ALeffectslot *slot = NULL;
760 ALbufferlistitem *oldlist;
761 ALfloat fvals[6];
763 switch(prop)
765 case AL_SOURCE_STATE:
766 case AL_SOURCE_TYPE:
767 case AL_BUFFERS_QUEUED:
768 case AL_BUFFERS_PROCESSED:
769 /* Query only */
770 SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
771 "Setting read-only source property 0x%04x", prop);
773 case AL_SOURCE_RELATIVE:
774 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
776 Source->HeadRelative = (ALboolean)*values;
777 DO_UPDATEPROPS();
778 return AL_TRUE;
780 case AL_LOOPING:
781 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
783 Source->Looping = (ALboolean)*values;
784 if(IsPlayingOrPaused(Source))
786 ALvoice *voice = GetSourceVoice(Source, Context);
787 if(voice)
789 if(Source->Looping)
790 ATOMIC_STORE(&voice->loop_buffer, Source->queue, almemory_order_release);
791 else
792 ATOMIC_STORE(&voice->loop_buffer, static_cast<ALbufferlistitem*>(nullptr),
793 almemory_order_release);
795 /* If the source is playing, wait for the current mix to finish
796 * to ensure it isn't currently looping back or reaching the
797 * end.
799 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
800 althrd_yield();
803 return AL_TRUE;
805 case AL_BUFFER:
806 LockBufferList(device);
807 if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
809 UnlockBufferList(device);
810 SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid buffer ID %u",
811 *values);
814 if(buffer && buffer->MappedAccess != 0 &&
815 !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
817 UnlockBufferList(device);
818 SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
819 "Setting non-persistently mapped buffer %u", buffer->id);
821 else
823 ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context));
824 if(state == AL_PLAYING || state == AL_PAUSED)
826 UnlockBufferList(device);
827 SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
828 "Setting buffer on playing or paused source %u", Source->id);
832 oldlist = Source->queue;
833 if(buffer != NULL)
835 /* Add the selected buffer to a one-item queue */
836 ALbufferlistitem *newlist = static_cast<ALbufferlistitem*>(al_calloc(DEF_ALIGN,
837 FAM_SIZE(ALbufferlistitem, buffers, 1)));
838 ATOMIC_INIT(&newlist->next, static_cast<ALbufferlistitem*>(nullptr));
839 newlist->max_samples = buffer->SampleLen;
840 newlist->num_buffers = 1;
841 newlist->buffers[0] = buffer;
842 IncrementRef(&buffer->ref);
844 /* Source is now Static */
845 Source->SourceType = AL_STATIC;
846 Source->queue = newlist;
848 else
850 /* Source is now Undetermined */
851 Source->SourceType = AL_UNDETERMINED;
852 Source->queue = NULL;
854 UnlockBufferList(device);
856 /* Delete all elements in the previous queue */
857 while(oldlist != NULL)
859 ALsizei i;
860 ALbufferlistitem *temp = oldlist;
861 oldlist = ATOMIC_LOAD(&temp->next, almemory_order_relaxed);
863 for(i = 0;i < temp->num_buffers;i++)
865 if(temp->buffers[i])
866 DecrementRef(&temp->buffers[i]->ref);
868 al_free(temp);
870 return AL_TRUE;
872 case AL_SEC_OFFSET:
873 case AL_SAMPLE_OFFSET:
874 case AL_BYTE_OFFSET:
875 CHECKVAL(*values >= 0);
877 Source->OffsetType = prop;
878 Source->Offset = *values;
880 if(IsPlayingOrPaused(Source))
882 ALvoice *voice;
884 ALCdevice_Lock(Context->Device);
885 voice = GetSourceVoice(Source, Context);
886 if(voice)
888 if(ApplyOffset(Source, voice) == AL_FALSE)
890 ALCdevice_Unlock(Context->Device);
891 SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE,
892 "Invalid source offset");
895 ALCdevice_Unlock(Context->Device);
897 return AL_TRUE;
899 case AL_DIRECT_FILTER:
900 LockFilterList(device);
901 if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
903 UnlockFilterList(device);
904 SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u",
905 *values);
908 if(!filter)
910 Source->Direct.Gain = 1.0f;
911 Source->Direct.GainHF = 1.0f;
912 Source->Direct.HFReference = LOWPASSFREQREF;
913 Source->Direct.GainLF = 1.0f;
914 Source->Direct.LFReference = HIGHPASSFREQREF;
916 else
918 Source->Direct.Gain = filter->Gain;
919 Source->Direct.GainHF = filter->GainHF;
920 Source->Direct.HFReference = filter->HFReference;
921 Source->Direct.GainLF = filter->GainLF;
922 Source->Direct.LFReference = filter->LFReference;
924 UnlockFilterList(device);
925 DO_UPDATEPROPS();
926 return AL_TRUE;
928 case AL_DIRECT_FILTER_GAINHF_AUTO:
929 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
931 Source->DryGainHFAuto = *values;
932 DO_UPDATEPROPS();
933 return AL_TRUE;
935 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
936 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
938 Source->WetGainAuto = *values;
939 DO_UPDATEPROPS();
940 return AL_TRUE;
942 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
943 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
945 Source->WetGainHFAuto = *values;
946 DO_UPDATEPROPS();
947 return AL_TRUE;
949 case AL_DIRECT_CHANNELS_SOFT:
950 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
952 Source->DirectChannels = *values;
953 DO_UPDATEPROPS();
954 return AL_TRUE;
956 case AL_DISTANCE_MODEL:
957 CHECKVAL(*values == AL_NONE ||
958 *values == AL_INVERSE_DISTANCE ||
959 *values == AL_INVERSE_DISTANCE_CLAMPED ||
960 *values == AL_LINEAR_DISTANCE ||
961 *values == AL_LINEAR_DISTANCE_CLAMPED ||
962 *values == AL_EXPONENT_DISTANCE ||
963 *values == AL_EXPONENT_DISTANCE_CLAMPED);
965 Source->mDistanceModel = static_cast<DistanceModel>(*values);
966 if(Context->SourceDistanceModel)
967 DO_UPDATEPROPS();
968 return AL_TRUE;
970 case AL_SOURCE_RESAMPLER_SOFT:
971 CHECKVAL(*values >= 0 && *values <= ResamplerMax);
973 Source->Resampler = static_cast<enum Resampler>(*values);
974 DO_UPDATEPROPS();
975 return AL_TRUE;
977 case AL_SOURCE_SPATIALIZE_SOFT:
978 CHECKVAL(*values >= AL_FALSE && *values <= AL_AUTO_SOFT);
980 Source->Spatialize = static_cast<enum SpatializeMode>(*values);
981 DO_UPDATEPROPS();
982 return AL_TRUE;
985 case AL_AUXILIARY_SEND_FILTER:
986 LockEffectSlotList(Context);
987 if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL))
989 UnlockEffectSlotList(Context);
990 SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u",
991 values[0]);
993 if((ALuint)values[1] >= (ALuint)device->NumAuxSends)
995 UnlockEffectSlotList(Context);
996 SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]);
998 LockFilterList(device);
999 if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL))
1001 UnlockFilterList(device);
1002 UnlockEffectSlotList(Context);
1003 SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u",
1004 values[2]);
1007 if(!filter)
1009 /* Disable filter */
1010 Source->Send[values[1]].Gain = 1.0f;
1011 Source->Send[values[1]].GainHF = 1.0f;
1012 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
1013 Source->Send[values[1]].GainLF = 1.0f;
1014 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
1016 else
1018 Source->Send[values[1]].Gain = filter->Gain;
1019 Source->Send[values[1]].GainHF = filter->GainHF;
1020 Source->Send[values[1]].HFReference = filter->HFReference;
1021 Source->Send[values[1]].GainLF = filter->GainLF;
1022 Source->Send[values[1]].LFReference = filter->LFReference;
1024 UnlockFilterList(device);
1026 if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source))
1028 ALvoice *voice;
1029 /* Add refcount on the new slot, and release the previous slot */
1030 if(slot) IncrementRef(&slot->ref);
1031 if(Source->Send[values[1]].Slot)
1032 DecrementRef(&Source->Send[values[1]].Slot->ref);
1033 Source->Send[values[1]].Slot = slot;
1035 /* We must force an update if the auxiliary slot changed on an
1036 * active source, in case the slot is about to be deleted.
1038 if((voice=GetSourceVoice(Source, Context)) != NULL)
1039 UpdateSourceProps(Source, voice, device->NumAuxSends, Context);
1040 else
1041 ATOMIC_STORE(&Source->PropsClean, AL_FALSE, almemory_order_release);
1043 else
1045 if(slot) IncrementRef(&slot->ref);
1046 if(Source->Send[values[1]].Slot)
1047 DecrementRef(&Source->Send[values[1]].Slot->ref);
1048 Source->Send[values[1]].Slot = slot;
1049 DO_UPDATEPROPS();
1051 UnlockEffectSlotList(Context);
1053 return AL_TRUE;
1056 /* 1x float */
1057 case AL_CONE_INNER_ANGLE:
1058 case AL_CONE_OUTER_ANGLE:
1059 case AL_PITCH:
1060 case AL_GAIN:
1061 case AL_MIN_GAIN:
1062 case AL_MAX_GAIN:
1063 case AL_REFERENCE_DISTANCE:
1064 case AL_ROLLOFF_FACTOR:
1065 case AL_CONE_OUTER_GAIN:
1066 case AL_MAX_DISTANCE:
1067 case AL_DOPPLER_FACTOR:
1068 case AL_CONE_OUTER_GAINHF:
1069 case AL_AIR_ABSORPTION_FACTOR:
1070 case AL_ROOM_ROLLOFF_FACTOR:
1071 case AL_SOURCE_RADIUS:
1072 fvals[0] = (ALfloat)*values;
1073 return SetSourcefv(Source, Context, prop, fvals);
1075 /* 3x float */
1076 case AL_POSITION:
1077 case AL_VELOCITY:
1078 case AL_DIRECTION:
1079 fvals[0] = (ALfloat)values[0];
1080 fvals[1] = (ALfloat)values[1];
1081 fvals[2] = (ALfloat)values[2];
1082 return SetSourcefv(Source, Context, prop, fvals);
1084 /* 6x float */
1085 case AL_ORIENTATION:
1086 fvals[0] = (ALfloat)values[0];
1087 fvals[1] = (ALfloat)values[1];
1088 fvals[2] = (ALfloat)values[2];
1089 fvals[3] = (ALfloat)values[3];
1090 fvals[4] = (ALfloat)values[4];
1091 fvals[5] = (ALfloat)values[5];
1092 return SetSourcefv(Source, Context, prop, fvals);
1094 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1095 case AL_SEC_OFFSET_LATENCY_SOFT:
1096 case AL_SEC_OFFSET_CLOCK_SOFT:
1097 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
1098 case AL_STEREO_ANGLES:
1099 break;
1102 ERR("Unexpected property: 0x%04x\n", prop);
1103 SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x",
1104 prop);
1107 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
1109 ALfloat fvals[6];
1110 ALint ivals[3];
1112 switch(prop)
1114 case AL_SOURCE_TYPE:
1115 case AL_BUFFERS_QUEUED:
1116 case AL_BUFFERS_PROCESSED:
1117 case AL_SOURCE_STATE:
1118 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1119 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
1120 /* Query only */
1121 SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
1122 "Setting read-only source property 0x%04x", prop);
1124 /* 1x int */
1125 case AL_SOURCE_RELATIVE:
1126 case AL_LOOPING:
1127 case AL_SEC_OFFSET:
1128 case AL_SAMPLE_OFFSET:
1129 case AL_BYTE_OFFSET:
1130 case AL_DIRECT_FILTER_GAINHF_AUTO:
1131 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1132 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1133 case AL_DIRECT_CHANNELS_SOFT:
1134 case AL_DISTANCE_MODEL:
1135 case AL_SOURCE_RESAMPLER_SOFT:
1136 case AL_SOURCE_SPATIALIZE_SOFT:
1137 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
1139 ivals[0] = (ALint)*values;
1140 return SetSourceiv(Source, Context, prop, ivals);
1142 /* 1x uint */
1143 case AL_BUFFER:
1144 case AL_DIRECT_FILTER:
1145 CHECKVAL(*values <= UINT_MAX && *values >= 0);
1147 ivals[0] = (ALuint)*values;
1148 return SetSourceiv(Source, Context, prop, ivals);
1150 /* 3x uint */
1151 case AL_AUXILIARY_SEND_FILTER:
1152 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
1153 values[1] <= UINT_MAX && values[1] >= 0 &&
1154 values[2] <= UINT_MAX && values[2] >= 0);
1156 ivals[0] = (ALuint)values[0];
1157 ivals[1] = (ALuint)values[1];
1158 ivals[2] = (ALuint)values[2];
1159 return SetSourceiv(Source, Context, prop, ivals);
1161 /* 1x float */
1162 case AL_CONE_INNER_ANGLE:
1163 case AL_CONE_OUTER_ANGLE:
1164 case AL_PITCH:
1165 case AL_GAIN:
1166 case AL_MIN_GAIN:
1167 case AL_MAX_GAIN:
1168 case AL_REFERENCE_DISTANCE:
1169 case AL_ROLLOFF_FACTOR:
1170 case AL_CONE_OUTER_GAIN:
1171 case AL_MAX_DISTANCE:
1172 case AL_DOPPLER_FACTOR:
1173 case AL_CONE_OUTER_GAINHF:
1174 case AL_AIR_ABSORPTION_FACTOR:
1175 case AL_ROOM_ROLLOFF_FACTOR:
1176 case AL_SOURCE_RADIUS:
1177 fvals[0] = (ALfloat)*values;
1178 return SetSourcefv(Source, Context, prop, fvals);
1180 /* 3x float */
1181 case AL_POSITION:
1182 case AL_VELOCITY:
1183 case AL_DIRECTION:
1184 fvals[0] = (ALfloat)values[0];
1185 fvals[1] = (ALfloat)values[1];
1186 fvals[2] = (ALfloat)values[2];
1187 return SetSourcefv(Source, Context, prop, fvals);
1189 /* 6x float */
1190 case AL_ORIENTATION:
1191 fvals[0] = (ALfloat)values[0];
1192 fvals[1] = (ALfloat)values[1];
1193 fvals[2] = (ALfloat)values[2];
1194 fvals[3] = (ALfloat)values[3];
1195 fvals[4] = (ALfloat)values[4];
1196 fvals[5] = (ALfloat)values[5];
1197 return SetSourcefv(Source, Context, prop, fvals);
1199 case AL_SEC_OFFSET_LATENCY_SOFT:
1200 case AL_SEC_OFFSET_CLOCK_SOFT:
1201 case AL_STEREO_ANGLES:
1202 break;
1205 ERR("Unexpected property: 0x%04x\n", prop);
1206 SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x",
1207 prop);
1210 #undef CHECKVAL
1213 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
1215 ALCdevice *device = Context->Device;
1216 ClockLatency clocktime;
1217 ALuint64 srcclock;
1218 ALint ivals[3];
1219 ALboolean err;
1221 switch(prop)
1223 case AL_GAIN:
1224 *values = Source->Gain;
1225 return AL_TRUE;
1227 case AL_PITCH:
1228 *values = Source->Pitch;
1229 return AL_TRUE;
1231 case AL_MAX_DISTANCE:
1232 *values = Source->MaxDistance;
1233 return AL_TRUE;
1235 case AL_ROLLOFF_FACTOR:
1236 *values = Source->RolloffFactor;
1237 return AL_TRUE;
1239 case AL_REFERENCE_DISTANCE:
1240 *values = Source->RefDistance;
1241 return AL_TRUE;
1243 case AL_CONE_INNER_ANGLE:
1244 *values = Source->InnerAngle;
1245 return AL_TRUE;
1247 case AL_CONE_OUTER_ANGLE:
1248 *values = Source->OuterAngle;
1249 return AL_TRUE;
1251 case AL_MIN_GAIN:
1252 *values = Source->MinGain;
1253 return AL_TRUE;
1255 case AL_MAX_GAIN:
1256 *values = Source->MaxGain;
1257 return AL_TRUE;
1259 case AL_CONE_OUTER_GAIN:
1260 *values = Source->OuterGain;
1261 return AL_TRUE;
1263 case AL_SEC_OFFSET:
1264 case AL_SAMPLE_OFFSET:
1265 case AL_BYTE_OFFSET:
1266 *values = GetSourceOffset(Source, prop, Context);
1267 return AL_TRUE;
1269 case AL_CONE_OUTER_GAINHF:
1270 *values = Source->OuterGainHF;
1271 return AL_TRUE;
1273 case AL_AIR_ABSORPTION_FACTOR:
1274 *values = Source->AirAbsorptionFactor;
1275 return AL_TRUE;
1277 case AL_ROOM_ROLLOFF_FACTOR:
1278 *values = Source->RoomRolloffFactor;
1279 return AL_TRUE;
1281 case AL_DOPPLER_FACTOR:
1282 *values = Source->DopplerFactor;
1283 return AL_TRUE;
1285 case AL_SOURCE_RADIUS:
1286 *values = Source->Radius;
1287 return AL_TRUE;
1289 case AL_STEREO_ANGLES:
1290 values[0] = Source->StereoPan[0];
1291 values[1] = Source->StereoPan[1];
1292 return AL_TRUE;
1294 case AL_SEC_OFFSET_LATENCY_SOFT:
1295 /* Get the source offset with the clock time first. Then get the
1296 * clock time with the device latency. Order is important.
1298 values[0] = GetSourceSecOffset(Source, Context, &srcclock);
1299 almtx_lock(&device->BackendLock);
1300 clocktime = GetClockLatency(device);
1301 almtx_unlock(&device->BackendLock);
1302 if(srcclock == (ALuint64)clocktime.ClockTime)
1303 values[1] = (ALdouble)clocktime.Latency / 1000000000.0;
1304 else
1306 /* If the clock time incremented, reduce the latency by that
1307 * much since it's that much closer to the source offset it got
1308 * earlier.
1310 ALuint64 diff = clocktime.ClockTime - srcclock;
1311 values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) /
1312 1000000000.0;
1314 return AL_TRUE;
1316 case AL_SEC_OFFSET_CLOCK_SOFT:
1317 values[0] = GetSourceSecOffset(Source, Context, &srcclock);
1318 values[1] = srcclock / 1000000000.0;
1319 return AL_TRUE;
1321 case AL_POSITION:
1322 values[0] = Source->Position[0];
1323 values[1] = Source->Position[1];
1324 values[2] = Source->Position[2];
1325 return AL_TRUE;
1327 case AL_VELOCITY:
1328 values[0] = Source->Velocity[0];
1329 values[1] = Source->Velocity[1];
1330 values[2] = Source->Velocity[2];
1331 return AL_TRUE;
1333 case AL_DIRECTION:
1334 values[0] = Source->Direction[0];
1335 values[1] = Source->Direction[1];
1336 values[2] = Source->Direction[2];
1337 return AL_TRUE;
1339 case AL_ORIENTATION:
1340 values[0] = Source->Orientation[0][0];
1341 values[1] = Source->Orientation[0][1];
1342 values[2] = Source->Orientation[0][2];
1343 values[3] = Source->Orientation[1][0];
1344 values[4] = Source->Orientation[1][1];
1345 values[5] = Source->Orientation[1][2];
1346 return AL_TRUE;
1348 /* 1x int */
1349 case AL_SOURCE_RELATIVE:
1350 case AL_LOOPING:
1351 case AL_SOURCE_STATE:
1352 case AL_BUFFERS_QUEUED:
1353 case AL_BUFFERS_PROCESSED:
1354 case AL_SOURCE_TYPE:
1355 case AL_DIRECT_FILTER_GAINHF_AUTO:
1356 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1357 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1358 case AL_DIRECT_CHANNELS_SOFT:
1359 case AL_DISTANCE_MODEL:
1360 case AL_SOURCE_RESAMPLER_SOFT:
1361 case AL_SOURCE_SPATIALIZE_SOFT:
1362 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1363 *values = (ALdouble)ivals[0];
1364 return err;
1366 case AL_BUFFER:
1367 case AL_DIRECT_FILTER:
1368 case AL_AUXILIARY_SEND_FILTER:
1369 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1370 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
1371 break;
1374 ERR("Unexpected property: 0x%04x\n", prop);
1375 SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source double property 0x%04x",
1376 prop);
1379 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1381 ALbufferlistitem *BufferList;
1382 ALdouble dvals[6];
1383 ALboolean err;
1385 switch(prop)
1387 case AL_SOURCE_RELATIVE:
1388 *values = Source->HeadRelative;
1389 return AL_TRUE;
1391 case AL_LOOPING:
1392 *values = Source->Looping;
1393 return AL_TRUE;
1395 case AL_BUFFER:
1396 BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : NULL;
1397 *values = (BufferList && BufferList->num_buffers >= 1 && BufferList->buffers[0]) ?
1398 BufferList->buffers[0]->id : 0;
1399 return AL_TRUE;
1401 case AL_SOURCE_STATE:
1402 *values = GetSourceState(Source, GetSourceVoice(Source, Context));
1403 return AL_TRUE;
1405 case AL_BUFFERS_QUEUED:
1406 if(!(BufferList=Source->queue))
1407 *values = 0;
1408 else
1410 ALsizei count = 0;
1411 do {
1412 count += BufferList->num_buffers;
1413 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
1414 } while(BufferList != NULL);
1415 *values = count;
1417 return AL_TRUE;
1419 case AL_BUFFERS_PROCESSED:
1420 if(Source->Looping || Source->SourceType != AL_STREAMING)
1422 /* Buffers on a looping source are in a perpetual state of
1423 * PENDING, so don't report any as PROCESSED */
1424 *values = 0;
1426 else
1428 const ALbufferlistitem *BufferList = Source->queue;
1429 const ALbufferlistitem *Current = NULL;
1430 ALsizei played = 0;
1431 ALvoice *voice;
1433 if((voice=GetSourceVoice(Source, Context)) != NULL)
1434 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
1435 else if(Source->state == AL_INITIAL)
1436 Current = BufferList;
1438 while(BufferList && BufferList != Current)
1440 played += BufferList->num_buffers;
1441 BufferList = BufferList->next.load(std::memory_order_relaxed);
1443 *values = played;
1445 return AL_TRUE;
1447 case AL_SOURCE_TYPE:
1448 *values = Source->SourceType;
1449 return AL_TRUE;
1451 case AL_DIRECT_FILTER_GAINHF_AUTO:
1452 *values = Source->DryGainHFAuto;
1453 return AL_TRUE;
1455 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1456 *values = Source->WetGainAuto;
1457 return AL_TRUE;
1459 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1460 *values = Source->WetGainHFAuto;
1461 return AL_TRUE;
1463 case AL_DIRECT_CHANNELS_SOFT:
1464 *values = Source->DirectChannels;
1465 return AL_TRUE;
1467 case AL_DISTANCE_MODEL:
1468 *values = static_cast<int>(Source->mDistanceModel);
1469 return AL_TRUE;
1471 case AL_SOURCE_RESAMPLER_SOFT:
1472 *values = Source->Resampler;
1473 return AL_TRUE;
1475 case AL_SOURCE_SPATIALIZE_SOFT:
1476 *values = Source->Spatialize;
1477 return AL_TRUE;
1479 /* 1x float/double */
1480 case AL_CONE_INNER_ANGLE:
1481 case AL_CONE_OUTER_ANGLE:
1482 case AL_PITCH:
1483 case AL_GAIN:
1484 case AL_MIN_GAIN:
1485 case AL_MAX_GAIN:
1486 case AL_REFERENCE_DISTANCE:
1487 case AL_ROLLOFF_FACTOR:
1488 case AL_CONE_OUTER_GAIN:
1489 case AL_MAX_DISTANCE:
1490 case AL_SEC_OFFSET:
1491 case AL_SAMPLE_OFFSET:
1492 case AL_BYTE_OFFSET:
1493 case AL_DOPPLER_FACTOR:
1494 case AL_AIR_ABSORPTION_FACTOR:
1495 case AL_ROOM_ROLLOFF_FACTOR:
1496 case AL_CONE_OUTER_GAINHF:
1497 case AL_SOURCE_RADIUS:
1498 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1499 *values = (ALint)dvals[0];
1500 return err;
1502 /* 3x float/double */
1503 case AL_POSITION:
1504 case AL_VELOCITY:
1505 case AL_DIRECTION:
1506 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1508 values[0] = (ALint)dvals[0];
1509 values[1] = (ALint)dvals[1];
1510 values[2] = (ALint)dvals[2];
1512 return err;
1514 /* 6x float/double */
1515 case AL_ORIENTATION:
1516 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1518 values[0] = (ALint)dvals[0];
1519 values[1] = (ALint)dvals[1];
1520 values[2] = (ALint)dvals[2];
1521 values[3] = (ALint)dvals[3];
1522 values[4] = (ALint)dvals[4];
1523 values[5] = (ALint)dvals[5];
1525 return err;
1527 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1528 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
1529 break; /* i64 only */
1530 case AL_SEC_OFFSET_LATENCY_SOFT:
1531 case AL_SEC_OFFSET_CLOCK_SOFT:
1532 break; /* Double only */
1533 case AL_STEREO_ANGLES:
1534 break; /* Float/double only */
1536 case AL_DIRECT_FILTER:
1537 case AL_AUXILIARY_SEND_FILTER:
1538 break; /* ??? */
1541 ERR("Unexpected property: 0x%04x\n", prop);
1542 SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x",
1543 prop);
1546 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1548 ALCdevice *device = Context->Device;
1549 ClockLatency clocktime;
1550 ALuint64 srcclock;
1551 ALdouble dvals[6];
1552 ALint ivals[3];
1553 ALboolean err;
1555 switch(prop)
1557 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1558 /* Get the source offset with the clock time first. Then get the
1559 * clock time with the device latency. Order is important.
1561 values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
1562 almtx_lock(&device->BackendLock);
1563 clocktime = GetClockLatency(device);
1564 almtx_unlock(&device->BackendLock);
1565 if(srcclock == (ALuint64)clocktime.ClockTime)
1566 values[1] = clocktime.Latency;
1567 else
1569 /* If the clock time incremented, reduce the latency by that
1570 * much since it's that much closer to the source offset it got
1571 * earlier.
1573 ALuint64 diff = clocktime.ClockTime - srcclock;
1574 values[1] = clocktime.Latency - minu64(clocktime.Latency, diff);
1576 return AL_TRUE;
1578 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
1579 values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
1580 values[1] = srcclock;
1581 return AL_TRUE;
1583 /* 1x float/double */
1584 case AL_CONE_INNER_ANGLE:
1585 case AL_CONE_OUTER_ANGLE:
1586 case AL_PITCH:
1587 case AL_GAIN:
1588 case AL_MIN_GAIN:
1589 case AL_MAX_GAIN:
1590 case AL_REFERENCE_DISTANCE:
1591 case AL_ROLLOFF_FACTOR:
1592 case AL_CONE_OUTER_GAIN:
1593 case AL_MAX_DISTANCE:
1594 case AL_SEC_OFFSET:
1595 case AL_SAMPLE_OFFSET:
1596 case AL_BYTE_OFFSET:
1597 case AL_DOPPLER_FACTOR:
1598 case AL_AIR_ABSORPTION_FACTOR:
1599 case AL_ROOM_ROLLOFF_FACTOR:
1600 case AL_CONE_OUTER_GAINHF:
1601 case AL_SOURCE_RADIUS:
1602 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1603 *values = (ALint64)dvals[0];
1604 return err;
1606 /* 3x float/double */
1607 case AL_POSITION:
1608 case AL_VELOCITY:
1609 case AL_DIRECTION:
1610 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1612 values[0] = (ALint64)dvals[0];
1613 values[1] = (ALint64)dvals[1];
1614 values[2] = (ALint64)dvals[2];
1616 return err;
1618 /* 6x float/double */
1619 case AL_ORIENTATION:
1620 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1622 values[0] = (ALint64)dvals[0];
1623 values[1] = (ALint64)dvals[1];
1624 values[2] = (ALint64)dvals[2];
1625 values[3] = (ALint64)dvals[3];
1626 values[4] = (ALint64)dvals[4];
1627 values[5] = (ALint64)dvals[5];
1629 return err;
1631 /* 1x int */
1632 case AL_SOURCE_RELATIVE:
1633 case AL_LOOPING:
1634 case AL_SOURCE_STATE:
1635 case AL_BUFFERS_QUEUED:
1636 case AL_BUFFERS_PROCESSED:
1637 case AL_SOURCE_TYPE:
1638 case AL_DIRECT_FILTER_GAINHF_AUTO:
1639 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1640 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1641 case AL_DIRECT_CHANNELS_SOFT:
1642 case AL_DISTANCE_MODEL:
1643 case AL_SOURCE_RESAMPLER_SOFT:
1644 case AL_SOURCE_SPATIALIZE_SOFT:
1645 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1646 *values = ivals[0];
1647 return err;
1649 /* 1x uint */
1650 case AL_BUFFER:
1651 case AL_DIRECT_FILTER:
1652 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1653 *values = (ALuint)ivals[0];
1654 return err;
1656 /* 3x uint */
1657 case AL_AUXILIARY_SEND_FILTER:
1658 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1660 values[0] = (ALuint)ivals[0];
1661 values[1] = (ALuint)ivals[1];
1662 values[2] = (ALuint)ivals[2];
1664 return err;
1666 case AL_SEC_OFFSET_LATENCY_SOFT:
1667 case AL_SEC_OFFSET_CLOCK_SOFT:
1668 break; /* Double only */
1669 case AL_STEREO_ANGLES:
1670 break; /* Float/double only */
1673 ERR("Unexpected property: 0x%04x\n", prop);
1674 SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x",
1675 prop);
1679 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1681 ALCcontext *context;
1682 ALsizei cur = 0;
1684 context = GetContextRef();
1685 if(!context) return;
1687 if(n < 0)
1688 alSetError(context, AL_INVALID_VALUE, "Generating %d sources", n);
1689 else for(cur = 0;cur < n;cur++)
1691 ALsource *source = AllocSource(context);
1692 if(!source)
1694 alDeleteSources(cur, sources);
1695 break;
1697 sources[cur] = source->id;
1700 ALCcontext_DecRef(context);
1704 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1706 ALCcontext *context;
1707 ALsource *Source;
1708 ALsizei i;
1710 context = GetContextRef();
1711 if(!context) return;
1713 LockSourceList(context);
1714 if(n < 0)
1715 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d sources", n);
1717 /* Check that all Sources are valid */
1718 for(i = 0;i < n;i++)
1720 if(LookupSource(context, sources[i]) == NULL)
1721 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]);
1723 for(i = 0;i < n;i++)
1725 if((Source=LookupSource(context, sources[i])) != NULL)
1726 FreeSource(context, Source);
1729 done:
1730 UnlockSourceList(context);
1731 ALCcontext_DecRef(context);
1735 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1737 ALCcontext *context;
1738 ALboolean ret;
1740 context = GetContextRef();
1741 if(!context) return AL_FALSE;
1743 LockSourceList(context);
1744 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1745 UnlockSourceList(context);
1747 ALCcontext_DecRef(context);
1749 return ret;
1753 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1755 ALCcontext *Context;
1756 ALsource *Source;
1758 Context = GetContextRef();
1759 if(!Context) return;
1761 almtx_lock(&Context->PropLock);
1762 LockSourceList(Context);
1763 if((Source=LookupSource(Context, source)) == NULL)
1764 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
1765 else if(FloatValsByProp(param) != 1)
1766 alSetError(Context, AL_INVALID_ENUM, "Invalid float property 0x%04x", param);
1767 else
1768 SetSourcefv(Source, Context, static_cast<SourceProp>(param), &value);
1769 UnlockSourceList(Context);
1770 almtx_unlock(&Context->PropLock);
1772 ALCcontext_DecRef(Context);
1775 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1777 ALCcontext *Context;
1778 ALsource *Source;
1780 Context = GetContextRef();
1781 if(!Context) return;
1783 almtx_lock(&Context->PropLock);
1784 LockSourceList(Context);
1785 if((Source=LookupSource(Context, source)) == NULL)
1786 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
1787 else if(FloatValsByProp(param) != 3)
1788 alSetError(Context, AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param);
1789 else
1791 ALfloat fvals[3] = { value1, value2, value3 };
1792 SetSourcefv(Source, Context, static_cast<SourceProp>(param), fvals);
1794 UnlockSourceList(Context);
1795 almtx_unlock(&Context->PropLock);
1797 ALCcontext_DecRef(Context);
1800 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1802 ALCcontext *Context;
1803 ALsource *Source;
1805 Context = GetContextRef();
1806 if(!Context) return;
1808 almtx_lock(&Context->PropLock);
1809 LockSourceList(Context);
1810 if((Source=LookupSource(Context, source)) == NULL)
1811 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
1812 else if(!values)
1813 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
1814 else if(FloatValsByProp(param) < 1)
1815 alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param);
1816 else
1817 SetSourcefv(Source, Context, static_cast<SourceProp>(param), values);
1818 UnlockSourceList(Context);
1819 almtx_unlock(&Context->PropLock);
1821 ALCcontext_DecRef(Context);
1825 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1827 ALCcontext *Context;
1828 ALsource *Source;
1830 Context = GetContextRef();
1831 if(!Context) return;
1833 almtx_lock(&Context->PropLock);
1834 LockSourceList(Context);
1835 if((Source=LookupSource(Context, source)) == NULL)
1836 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
1837 else if(DoubleValsByProp(param) != 1)
1838 alSetError(Context, AL_INVALID_ENUM, "Invalid double property 0x%04x", param);
1839 else
1841 ALfloat fval = (ALfloat)value;
1842 SetSourcefv(Source, Context, static_cast<SourceProp>(param), &fval);
1844 UnlockSourceList(Context);
1845 almtx_unlock(&Context->PropLock);
1847 ALCcontext_DecRef(Context);
1850 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1852 ALCcontext *Context;
1853 ALsource *Source;
1855 Context = GetContextRef();
1856 if(!Context) return;
1858 almtx_lock(&Context->PropLock);
1859 LockSourceList(Context);
1860 if((Source=LookupSource(Context, source)) == NULL)
1861 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
1862 else if(DoubleValsByProp(param) != 3)
1863 alSetError(Context, AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param);
1864 else
1866 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1867 SetSourcefv(Source, Context, static_cast<SourceProp>(param), fvals);
1869 UnlockSourceList(Context);
1870 almtx_unlock(&Context->PropLock);
1872 ALCcontext_DecRef(Context);
1875 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1877 ALCcontext *Context;
1878 ALsource *Source;
1879 ALint count;
1881 Context = GetContextRef();
1882 if(!Context) return;
1884 almtx_lock(&Context->PropLock);
1885 LockSourceList(Context);
1886 if((Source=LookupSource(Context, source)) == NULL)
1887 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
1888 else if(!values)
1889 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
1890 else if((count=DoubleValsByProp(param)) < 1 || count > 6)
1891 alSetError(Context, AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param);
1892 else
1894 ALfloat fvals[6];
1895 ALint i;
1897 for(i = 0;i < count;i++)
1898 fvals[i] = (ALfloat)values[i];
1899 SetSourcefv(Source, Context, static_cast<SourceProp>(param), fvals);
1901 UnlockSourceList(Context);
1902 almtx_unlock(&Context->PropLock);
1904 ALCcontext_DecRef(Context);
1908 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1910 ALCcontext *Context;
1911 ALsource *Source;
1913 Context = GetContextRef();
1914 if(!Context) return;
1916 almtx_lock(&Context->PropLock);
1917 LockSourceList(Context);
1918 if((Source=LookupSource(Context, source)) == NULL)
1919 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
1920 else if(IntValsByProp(param) != 1)
1921 alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param);
1922 else
1923 SetSourceiv(Source, Context, static_cast<SourceProp>(param), &value);
1924 UnlockSourceList(Context);
1925 almtx_unlock(&Context->PropLock);
1927 ALCcontext_DecRef(Context);
1930 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1932 ALCcontext *Context;
1933 ALsource *Source;
1935 Context = GetContextRef();
1936 if(!Context) return;
1938 almtx_lock(&Context->PropLock);
1939 LockSourceList(Context);
1940 if((Source=LookupSource(Context, source)) == NULL)
1941 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
1942 else if(IntValsByProp(param) != 3)
1943 alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param);
1944 else
1946 ALint ivals[3] = { value1, value2, value3 };
1947 SetSourceiv(Source, Context, static_cast<SourceProp>(param), ivals);
1949 UnlockSourceList(Context);
1950 almtx_unlock(&Context->PropLock);
1952 ALCcontext_DecRef(Context);
1955 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1957 ALCcontext *Context;
1958 ALsource *Source;
1960 Context = GetContextRef();
1961 if(!Context) return;
1963 almtx_lock(&Context->PropLock);
1964 LockSourceList(Context);
1965 if((Source=LookupSource(Context, source)) == NULL)
1966 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
1967 else if(!values)
1968 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
1969 else if(IntValsByProp(param) < 1)
1970 alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param);
1971 else
1972 SetSourceiv(Source, Context, static_cast<SourceProp>(param), values);
1973 UnlockSourceList(Context);
1974 almtx_unlock(&Context->PropLock);
1976 ALCcontext_DecRef(Context);
1980 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1982 ALCcontext *Context;
1983 ALsource *Source;
1985 Context = GetContextRef();
1986 if(!Context) return;
1988 almtx_lock(&Context->PropLock);
1989 LockSourceList(Context);
1990 if((Source=LookupSource(Context, source)) == NULL)
1991 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
1992 else if(Int64ValsByProp(param) != 1)
1993 alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param);
1994 else
1995 SetSourcei64v(Source, Context, static_cast<SourceProp>(param), &value);
1996 UnlockSourceList(Context);
1997 almtx_unlock(&Context->PropLock);
1999 ALCcontext_DecRef(Context);
2002 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
2004 ALCcontext *Context;
2005 ALsource *Source;
2007 Context = GetContextRef();
2008 if(!Context) return;
2010 almtx_lock(&Context->PropLock);
2011 LockSourceList(Context);
2012 if((Source=LookupSource(Context, source)) == NULL)
2013 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2014 else if(Int64ValsByProp(param) != 3)
2015 alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param);
2016 else
2018 ALint64SOFT i64vals[3] = { value1, value2, value3 };
2019 SetSourcei64v(Source, Context, static_cast<SourceProp>(param), i64vals);
2021 UnlockSourceList(Context);
2022 almtx_unlock(&Context->PropLock);
2024 ALCcontext_DecRef(Context);
2027 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
2029 ALCcontext *Context;
2030 ALsource *Source;
2032 Context = GetContextRef();
2033 if(!Context) return;
2035 almtx_lock(&Context->PropLock);
2036 LockSourceList(Context);
2037 if((Source=LookupSource(Context, source)) == NULL)
2038 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2039 else if(!values)
2040 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2041 else if(Int64ValsByProp(param) < 1)
2042 alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param);
2043 else
2044 SetSourcei64v(Source, Context, static_cast<SourceProp>(param), values);
2045 UnlockSourceList(Context);
2046 almtx_unlock(&Context->PropLock);
2048 ALCcontext_DecRef(Context);
2052 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
2054 ALCcontext *Context;
2055 ALsource *Source;
2057 Context = GetContextRef();
2058 if(!Context) return;
2060 LockSourceList(Context);
2061 if((Source=LookupSource(Context, source)) == NULL)
2062 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2063 else if(!value)
2064 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2065 else if(FloatValsByProp(param) != 1)
2066 alSetError(Context, AL_INVALID_ENUM, "Invalid float property 0x%04x", param);
2067 else
2069 ALdouble dval;
2070 if(GetSourcedv(Source, Context, static_cast<SourceProp>(param), &dval))
2071 *value = (ALfloat)dval;
2073 UnlockSourceList(Context);
2075 ALCcontext_DecRef(Context);
2079 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
2081 ALCcontext *Context;
2082 ALsource *Source;
2084 Context = GetContextRef();
2085 if(!Context) return;
2087 LockSourceList(Context);
2088 if((Source=LookupSource(Context, source)) == NULL)
2089 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2090 else if(!(value1 && value2 && value3))
2091 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2092 else if(FloatValsByProp(param) != 3)
2093 alSetError(Context, AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param);
2094 else
2096 ALdouble dvals[3];
2097 if(GetSourcedv(Source, Context, static_cast<SourceProp>(param), dvals))
2099 *value1 = (ALfloat)dvals[0];
2100 *value2 = (ALfloat)dvals[1];
2101 *value3 = (ALfloat)dvals[2];
2104 UnlockSourceList(Context);
2106 ALCcontext_DecRef(Context);
2110 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
2112 ALCcontext *Context;
2113 ALsource *Source;
2114 ALint count;
2116 Context = GetContextRef();
2117 if(!Context) return;
2119 LockSourceList(Context);
2120 if((Source=LookupSource(Context, source)) == NULL)
2121 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2122 else if(!values)
2123 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2124 else if((count=FloatValsByProp(param)) < 1 && count > 6)
2125 alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param);
2126 else
2128 ALdouble dvals[6];
2129 if(GetSourcedv(Source, Context, static_cast<SourceProp>(param), dvals))
2131 ALint i;
2132 for(i = 0;i < count;i++)
2133 values[i] = (ALfloat)dvals[i];
2136 UnlockSourceList(Context);
2138 ALCcontext_DecRef(Context);
2142 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
2144 ALCcontext *Context;
2145 ALsource *Source;
2147 Context = GetContextRef();
2148 if(!Context) return;
2150 LockSourceList(Context);
2151 if((Source=LookupSource(Context, source)) == NULL)
2152 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2153 else if(!value)
2154 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2155 else if(DoubleValsByProp(param) != 1)
2156 alSetError(Context, AL_INVALID_ENUM, "Invalid double property 0x%04x", param);
2157 else
2158 GetSourcedv(Source, Context, static_cast<SourceProp>(param), value);
2159 UnlockSourceList(Context);
2161 ALCcontext_DecRef(Context);
2164 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
2166 ALCcontext *Context;
2167 ALsource *Source;
2169 Context = GetContextRef();
2170 if(!Context) return;
2172 LockSourceList(Context);
2173 if((Source=LookupSource(Context, source)) == NULL)
2174 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2175 else if(!(value1 && value2 && value3))
2176 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2177 else if(DoubleValsByProp(param) != 3)
2178 alSetError(Context, AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param);
2179 else
2181 ALdouble dvals[3];
2182 if(GetSourcedv(Source, Context, static_cast<SourceProp>(param), dvals))
2184 *value1 = dvals[0];
2185 *value2 = dvals[1];
2186 *value3 = dvals[2];
2189 UnlockSourceList(Context);
2191 ALCcontext_DecRef(Context);
2194 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
2196 ALCcontext *Context;
2197 ALsource *Source;
2199 Context = GetContextRef();
2200 if(!Context) return;
2202 LockSourceList(Context);
2203 if((Source=LookupSource(Context, source)) == NULL)
2204 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2205 else if(!values)
2206 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2207 else if(DoubleValsByProp(param) < 1)
2208 alSetError(Context, AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param);
2209 else
2210 GetSourcedv(Source, Context, static_cast<SourceProp>(param), values);
2211 UnlockSourceList(Context);
2213 ALCcontext_DecRef(Context);
2217 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2219 ALCcontext *Context;
2220 ALsource *Source;
2222 Context = GetContextRef();
2223 if(!Context) return;
2225 LockSourceList(Context);
2226 if((Source=LookupSource(Context, source)) == NULL)
2227 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2228 else if(!value)
2229 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2230 else if(IntValsByProp(param) != 1)
2231 alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param);
2232 else
2233 GetSourceiv(Source, Context, static_cast<SourceProp>(param), value);
2234 UnlockSourceList(Context);
2236 ALCcontext_DecRef(Context);
2240 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2242 ALCcontext *Context;
2243 ALsource *Source;
2245 Context = GetContextRef();
2246 if(!Context) return;
2248 LockSourceList(Context);
2249 if((Source=LookupSource(Context, source)) == NULL)
2250 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2251 else if(!(value1 && value2 && value3))
2252 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2253 else if(IntValsByProp(param) != 3)
2254 alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param);
2255 else
2257 ALint ivals[3];
2258 if(GetSourceiv(Source, Context, static_cast<SourceProp>(param), ivals))
2260 *value1 = ivals[0];
2261 *value2 = ivals[1];
2262 *value3 = ivals[2];
2265 UnlockSourceList(Context);
2267 ALCcontext_DecRef(Context);
2271 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2273 ALCcontext *Context;
2274 ALsource *Source;
2276 Context = GetContextRef();
2277 if(!Context) return;
2279 LockSourceList(Context);
2280 if((Source=LookupSource(Context, source)) == NULL)
2281 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2282 else if(!values)
2283 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2284 else if(IntValsByProp(param) < 1)
2285 alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param);
2286 else
2287 GetSourceiv(Source, Context, static_cast<SourceProp>(param), values);
2288 UnlockSourceList(Context);
2290 ALCcontext_DecRef(Context);
2294 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2296 ALCcontext *Context;
2297 ALsource *Source;
2299 Context = GetContextRef();
2300 if(!Context) return;
2302 LockSourceList(Context);
2303 if((Source=LookupSource(Context, source)) == NULL)
2304 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2305 else if(!value)
2306 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2307 else if(Int64ValsByProp(param) != 1)
2308 alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param);
2309 else
2310 GetSourcei64v(Source, Context, static_cast<SourceProp>(param), value);
2311 UnlockSourceList(Context);
2313 ALCcontext_DecRef(Context);
2316 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2318 ALCcontext *Context;
2319 ALsource *Source;
2321 Context = GetContextRef();
2322 if(!Context) return;
2324 LockSourceList(Context);
2325 if((Source=LookupSource(Context, source)) == NULL)
2326 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2327 else if(!(value1 && value2 && value3))
2328 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2329 else if(Int64ValsByProp(param) != 3)
2330 alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param);
2331 else
2333 ALint64 i64vals[3];
2334 if(GetSourcei64v(Source, Context, static_cast<SourceProp>(param), i64vals))
2336 *value1 = i64vals[0];
2337 *value2 = i64vals[1];
2338 *value3 = i64vals[2];
2341 UnlockSourceList(Context);
2343 ALCcontext_DecRef(Context);
2346 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2348 ALCcontext *Context;
2349 ALsource *Source;
2351 Context = GetContextRef();
2352 if(!Context) return;
2354 LockSourceList(Context);
2355 if((Source=LookupSource(Context, source)) == NULL)
2356 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2357 else if(!values)
2358 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2359 else if(Int64ValsByProp(param) < 1)
2360 alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param);
2361 else
2362 GetSourcei64v(Source, Context, static_cast<SourceProp>(param), values);
2363 UnlockSourceList(Context);
2365 ALCcontext_DecRef(Context);
2369 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2371 alSourcePlayv(1, &source);
2373 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2375 ALCcontext *context;
2376 ALCdevice *device;
2377 ALsource *source;
2378 ALvoice *voice;
2379 ALsizei i, j;
2381 context = GetContextRef();
2382 if(!context) return;
2384 LockSourceList(context);
2385 if(!(n >= 0))
2386 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Playing %d sources", n);
2387 for(i = 0;i < n;i++)
2389 if(!LookupSource(context, sources[i]))
2390 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]);
2393 device = context->Device;
2394 ALCdevice_Lock(device);
2395 /* If the device is disconnected, go right to stopped. */
2396 if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
2398 /* TODO: Send state change event? */
2399 for(i = 0;i < n;i++)
2401 source = LookupSource(context, sources[i]);
2402 source->OffsetType = AL_NONE;
2403 source->Offset = 0.0;
2404 source->state = AL_STOPPED;
2406 ALCdevice_Unlock(device);
2407 goto done;
2410 while(n > context->MaxVoices-context->VoiceCount)
2412 ALsizei newcount = context->MaxVoices << 1;
2413 if(context->MaxVoices >= newcount)
2415 ALCdevice_Unlock(device);
2416 SETERR_GOTO(context, AL_OUT_OF_MEMORY, done,
2417 "Overflow increasing voice count %d -> %d", context->MaxVoices, newcount);
2419 AllocateVoices(context, newcount, device->NumAuxSends);
2422 for(i = 0;i < n;i++)
2424 ALbufferlistitem *BufferList;
2425 bool start_fading = false;
2426 ALint vidx = -1;
2428 source = LookupSource(context, sources[i]);
2429 /* Check that there is a queue containing at least one valid, non zero
2430 * length buffer.
2432 BufferList = source->queue;
2433 while(BufferList && BufferList->max_samples == 0)
2434 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
2436 /* If there's nothing to play, go right to stopped. */
2437 if(UNLIKELY(!BufferList))
2439 /* NOTE: A source without any playable buffers should not have an
2440 * ALvoice since it shouldn't be in a playing or paused state. So
2441 * there's no need to look up its voice and clear the source.
2443 ALenum oldstate = GetSourceState(source, NULL);
2444 source->OffsetType = AL_NONE;
2445 source->Offset = 0.0;
2446 if(oldstate != AL_STOPPED)
2448 source->state = AL_STOPPED;
2449 SendStateChangeEvent(context, source->id, AL_STOPPED);
2451 continue;
2454 voice = GetSourceVoice(source, context);
2455 switch(GetSourceState(source, voice))
2457 case AL_PLAYING:
2458 assert(voice != NULL);
2459 /* A source that's already playing is restarted from the beginning. */
2460 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
2461 ATOMIC_STORE(&voice->position, 0u, almemory_order_relaxed);
2462 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release);
2463 continue;
2465 case AL_PAUSED:
2466 assert(voice != NULL);
2467 /* A source that's paused simply resumes. */
2468 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
2469 source->state = AL_PLAYING;
2470 SendStateChangeEvent(context, source->id, AL_PLAYING);
2471 continue;
2473 default:
2474 break;
2477 /* Look for an unused voice to play this source with. */
2478 assert(voice == NULL);
2479 for(j = 0;j < context->VoiceCount;j++)
2481 if(ATOMIC_LOAD(&context->Voices[j]->Source, almemory_order_acquire) == NULL)
2483 vidx = j;
2484 break;
2487 if(vidx == -1)
2488 vidx = context->VoiceCount++;
2489 voice = context->Voices[vidx];
2490 voice->Playing.store(false, std::memory_order_release);
2492 source->PropsClean.exchange(AL_TRUE, std::memory_order_acquire);
2493 UpdateSourceProps(source, voice, device->NumAuxSends, context);
2495 /* A source that's not playing or paused has any offset applied when it
2496 * starts playing.
2498 if(source->Looping)
2499 ATOMIC_STORE(&voice->loop_buffer, source->queue, almemory_order_relaxed);
2500 else
2501 ATOMIC_STORE(&voice->loop_buffer, static_cast<ALbufferlistitem*>(nullptr),
2502 almemory_order_relaxed);
2503 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
2504 ATOMIC_STORE(&voice->position, 0u, almemory_order_relaxed);
2505 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed);
2506 if(ApplyOffset(source, voice) != AL_FALSE)
2507 start_fading = ATOMIC_LOAD(&voice->position, almemory_order_relaxed) != 0 ||
2508 ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) != 0 ||
2509 ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed) != BufferList;
2511 for(j = 0;j < BufferList->num_buffers;j++)
2513 ALbuffer *buffer = BufferList->buffers[j];
2514 if(buffer)
2516 voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2517 voice->SampleSize = BytesFromFmt(buffer->FmtType);
2518 break;
2522 /* Clear previous samples. */
2523 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
2525 /* Clear the stepping value so the mixer knows not to mix this until
2526 * the update gets applied.
2528 voice->Step = 0;
2530 voice->Flags = start_fading ? VOICE_IS_FADING : 0;
2531 if(source->SourceType == AL_STATIC) voice->Flags |= VOICE_IS_STATIC;
2532 memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*voice->NumChannels);
2533 for(j = 0;j < device->NumAuxSends;j++)
2534 memset(voice->Send[j].Params, 0, sizeof(voice->Send[j].Params[0])*voice->NumChannels);
2535 if(device->AvgSpeakerDist > 0.0f)
2537 ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC /
2538 (device->AvgSpeakerDist * device->Frequency);
2539 for(j = 0;j < voice->NumChannels;j++)
2540 NfcFilterCreate(&voice->Direct.Params[j].NFCtrlFilter, 0.0f, w1);
2543 ATOMIC_STORE(&voice->Source, source, almemory_order_relaxed);
2544 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
2545 source->state = AL_PLAYING;
2546 source->VoiceIdx = vidx;
2548 SendStateChangeEvent(context, source->id, AL_PLAYING);
2550 ALCdevice_Unlock(device);
2552 done:
2553 UnlockSourceList(context);
2554 ALCcontext_DecRef(context);
2557 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2559 alSourcePausev(1, &source);
2561 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2563 ALCcontext *context;
2564 ALCdevice *device;
2565 ALsource *source;
2566 ALvoice *voice;
2567 ALsizei i;
2569 context = GetContextRef();
2570 if(!context) return;
2572 LockSourceList(context);
2573 if(n < 0)
2574 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Pausing %d sources", n);
2575 for(i = 0;i < n;i++)
2577 if(!LookupSource(context, sources[i]))
2578 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]);
2581 device = context->Device;
2582 ALCdevice_Lock(device);
2583 for(i = 0;i < n;i++)
2585 source = LookupSource(context, sources[i]);
2586 if((voice=GetSourceVoice(source, context)) != NULL)
2587 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2588 if(GetSourceState(source, voice) == AL_PLAYING)
2590 source->state = AL_PAUSED;
2591 SendStateChangeEvent(context, source->id, AL_PAUSED);
2594 ALCdevice_Unlock(device);
2596 done:
2597 UnlockSourceList(context);
2598 ALCcontext_DecRef(context);
2601 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2603 alSourceStopv(1, &source);
2605 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2607 ALCcontext *context;
2608 ALCdevice *device;
2609 ALsource *source;
2610 ALvoice *voice;
2611 ALsizei i;
2613 context = GetContextRef();
2614 if(!context) return;
2616 LockSourceList(context);
2617 if(n < 0)
2618 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Stopping %d sources", n);
2619 for(i = 0;i < n;i++)
2621 if(!LookupSource(context, sources[i]))
2622 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]);
2625 device = context->Device;
2626 ALCdevice_Lock(device);
2627 for(i = 0;i < n;i++)
2629 ALenum oldstate;
2630 source = LookupSource(context, sources[i]);
2631 if((voice=GetSourceVoice(source, context)) != NULL)
2633 ATOMIC_STORE(&voice->Source, static_cast<ALsource*>(nullptr), almemory_order_relaxed);
2634 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2635 voice = NULL;
2637 oldstate = GetSourceState(source, voice);
2638 if(oldstate != AL_INITIAL && oldstate != AL_STOPPED)
2640 source->state = AL_STOPPED;
2641 SendStateChangeEvent(context, source->id, AL_STOPPED);
2643 source->OffsetType = AL_NONE;
2644 source->Offset = 0.0;
2646 ALCdevice_Unlock(device);
2648 done:
2649 UnlockSourceList(context);
2650 ALCcontext_DecRef(context);
2653 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2655 alSourceRewindv(1, &source);
2657 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2659 ALCcontext *context;
2660 ALCdevice *device;
2661 ALsource *source;
2662 ALvoice *voice;
2663 ALsizei i;
2665 context = GetContextRef();
2666 if(!context) return;
2668 LockSourceList(context);
2669 if(n < 0)
2670 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Rewinding %d sources", n);
2671 for(i = 0;i < n;i++)
2673 if(!LookupSource(context, sources[i]))
2674 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]);
2677 device = context->Device;
2678 ALCdevice_Lock(device);
2679 for(i = 0;i < n;i++)
2681 source = LookupSource(context, sources[i]);
2682 if((voice=GetSourceVoice(source, context)) != NULL)
2684 ATOMIC_STORE(&voice->Source, static_cast<ALsource*>(nullptr), almemory_order_relaxed);
2685 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2686 voice = NULL;
2688 if(GetSourceState(source, voice) != AL_INITIAL)
2690 source->state = AL_INITIAL;
2691 SendStateChangeEvent(context, source->id, AL_INITIAL);
2693 source->OffsetType = AL_NONE;
2694 source->Offset = 0.0;
2696 ALCdevice_Unlock(device);
2698 done:
2699 UnlockSourceList(context);
2700 ALCcontext_DecRef(context);
2704 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2706 ALCdevice *device;
2707 ALCcontext *context;
2708 ALsource *source;
2709 ALsizei i;
2710 ALbufferlistitem *BufferListStart;
2711 ALbufferlistitem *BufferList;
2712 ALbuffer *BufferFmt = NULL;
2714 if(nb == 0)
2715 return;
2717 context = GetContextRef();
2718 if(!context) return;
2720 device = context->Device;
2722 LockSourceList(context);
2723 if(!(nb >= 0))
2724 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Queueing %d buffers", nb);
2725 if((source=LookupSource(context, src)) == NULL)
2726 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src);
2728 if(source->SourceType == AL_STATIC)
2730 /* Can't queue on a Static Source */
2731 SETERR_GOTO(context, AL_INVALID_OPERATION, done, "Queueing onto static source %u", src);
2734 /* Check for a valid Buffer, for its frequency and format */
2735 BufferList = source->queue;
2736 while(BufferList)
2738 for(i = 0;i < BufferList->num_buffers;i++)
2740 if((BufferFmt=BufferList->buffers[i]) != NULL)
2741 break;
2743 if(BufferFmt) break;
2744 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
2747 LockBufferList(device);
2748 BufferListStart = NULL;
2749 BufferList = NULL;
2750 for(i = 0;i < nb;i++)
2752 ALbuffer *buffer = NULL;
2753 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2754 SETERR_GOTO(context, AL_INVALID_NAME, buffer_error, "Queueing invalid buffer ID %u",
2755 buffers[i]);
2757 if(!BufferListStart)
2759 BufferListStart = static_cast<ALbufferlistitem*>(al_calloc(DEF_ALIGN,
2760 FAM_SIZE(ALbufferlistitem, buffers, 1)));
2761 BufferList = BufferListStart;
2763 else
2765 ALbufferlistitem *item = static_cast<ALbufferlistitem*>(al_calloc(DEF_ALIGN,
2766 FAM_SIZE(ALbufferlistitem, buffers, 1)));
2767 ATOMIC_STORE(&BufferList->next, item, almemory_order_relaxed);
2768 BufferList = item;
2770 ATOMIC_INIT(&BufferList->next, static_cast<ALbufferlistitem*>(nullptr));
2771 BufferList->max_samples = buffer ? buffer->SampleLen : 0;
2772 BufferList->num_buffers = 1;
2773 BufferList->buffers[0] = buffer;
2774 if(!buffer) continue;
2776 IncrementRef(&buffer->ref);
2778 if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
2779 SETERR_GOTO(context, AL_INVALID_OPERATION, buffer_error,
2780 "Queueing non-persistently mapped buffer %u", buffer->id);
2782 if(BufferFmt == NULL)
2783 BufferFmt = buffer;
2784 else if(BufferFmt->Frequency != buffer->Frequency ||
2785 BufferFmt->FmtChannels != buffer->FmtChannels ||
2786 BufferFmt->OriginalType != buffer->OriginalType)
2788 alSetError(context, AL_INVALID_OPERATION, "Queueing buffer with mismatched format");
2790 buffer_error:
2791 /* A buffer failed (invalid ID or format), so unlock and release
2792 * each buffer we had. */
2793 while(BufferListStart)
2795 ALbufferlistitem *next = ATOMIC_LOAD(&BufferListStart->next,
2796 almemory_order_relaxed);
2797 for(i = 0;i < BufferListStart->num_buffers;i++)
2799 if((buffer=BufferListStart->buffers[i]) != NULL)
2800 DecrementRef(&buffer->ref);
2802 al_free(BufferListStart);
2803 BufferListStart = next;
2805 UnlockBufferList(device);
2806 goto done;
2809 /* All buffers good. */
2810 UnlockBufferList(device);
2812 /* Source is now streaming */
2813 source->SourceType = AL_STREAMING;
2815 if(!(BufferList=source->queue))
2816 source->queue = BufferListStart;
2817 else
2819 ALbufferlistitem *next;
2820 while((next=ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed)) != NULL)
2821 BufferList = next;
2822 ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release);
2825 done:
2826 UnlockSourceList(context);
2827 ALCcontext_DecRef(context);
2830 AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers)
2832 ALCdevice *device;
2833 ALCcontext *context;
2834 ALbufferlistitem *BufferListStart;
2835 ALbufferlistitem *BufferList;
2836 ALbuffer *BufferFmt = NULL;
2837 ALsource *source;
2838 ALsizei i;
2840 if(nb == 0)
2841 return;
2843 context = GetContextRef();
2844 if(!context) return;
2846 device = context->Device;
2848 LockSourceList(context);
2849 if(!(nb >= 0 && nb < 16))
2850 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Queueing %d buffer layers", nb);
2851 if((source=LookupSource(context, src)) == NULL)
2852 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src);
2854 if(source->SourceType == AL_STATIC)
2856 /* Can't queue on a Static Source */
2857 SETERR_GOTO(context, AL_INVALID_OPERATION, done, "Queueing onto static source %u", src);
2860 /* Check for a valid Buffer, for its frequency and format */
2861 BufferList = source->queue;
2862 while(BufferList)
2864 for(i = 0;i < BufferList->num_buffers;i++)
2866 if((BufferFmt=BufferList->buffers[i]) != NULL)
2867 break;
2869 if(BufferFmt) break;
2870 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
2873 LockBufferList(device);
2874 BufferListStart = static_cast<ALbufferlistitem*>(al_calloc(DEF_ALIGN,
2875 FAM_SIZE(ALbufferlistitem, buffers, nb)));
2876 BufferList = BufferListStart;
2877 ATOMIC_INIT(&BufferList->next, static_cast<ALbufferlistitem*>(nullptr));
2878 BufferList->max_samples = 0;
2879 BufferList->num_buffers = 0;
2880 for(i = 0;i < nb;i++)
2882 ALbuffer *buffer = NULL;
2883 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2884 SETERR_GOTO(context, AL_INVALID_NAME, buffer_error, "Queueing invalid buffer ID %u",
2885 buffers[i]);
2887 BufferList->buffers[BufferList->num_buffers++] = buffer;
2888 if(!buffer) continue;
2890 IncrementRef(&buffer->ref);
2892 BufferList->max_samples = maxi(BufferList->max_samples, buffer->SampleLen);
2894 if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
2895 SETERR_GOTO(context, AL_INVALID_OPERATION, buffer_error,
2896 "Queueing non-persistently mapped buffer %u", buffer->id);
2898 if(BufferFmt == NULL)
2899 BufferFmt = buffer;
2900 else if(BufferFmt->Frequency != buffer->Frequency ||
2901 BufferFmt->FmtChannels != buffer->FmtChannels ||
2902 BufferFmt->OriginalType != buffer->OriginalType)
2904 alSetError(context, AL_INVALID_OPERATION, "Queueing buffer with mismatched format");
2906 buffer_error:
2907 /* A buffer failed (invalid ID or format), so unlock and release
2908 * each buffer we had. */
2909 while(BufferListStart)
2911 ALbufferlistitem *next = ATOMIC_LOAD(&BufferListStart->next,
2912 almemory_order_relaxed);
2913 for(i = 0;i < BufferListStart->num_buffers;i++)
2915 if((buffer=BufferListStart->buffers[i]) != NULL)
2916 DecrementRef(&buffer->ref);
2918 al_free(BufferListStart);
2919 BufferListStart = next;
2921 UnlockBufferList(device);
2922 goto done;
2925 /* All buffers good. */
2926 UnlockBufferList(device);
2928 /* Source is now streaming */
2929 source->SourceType = AL_STREAMING;
2931 if(!(BufferList=source->queue))
2932 source->queue = BufferListStart;
2933 else
2935 ALbufferlistitem *next;
2936 while((next=ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed)) != NULL)
2937 BufferList = next;
2938 ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release);
2941 done:
2942 UnlockSourceList(context);
2943 ALCcontext_DecRef(context);
2946 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2948 ALCcontext *context;
2949 ALsource *source;
2950 ALbufferlistitem *BufferList;
2951 ALbufferlistitem *Current;
2952 ALvoice *voice;
2953 ALsizei i;
2955 context = GetContextRef();
2956 if(!context) return;
2958 LockSourceList(context);
2959 if(!(nb >= 0))
2960 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing %d buffers", nb);
2961 if((source=LookupSource(context, src)) == NULL)
2962 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src);
2964 /* Nothing to unqueue. */
2965 if(nb == 0) goto done;
2967 if(source->Looping)
2968 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing from looping source %u", src);
2969 if(source->SourceType != AL_STREAMING)
2970 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing from a non-streaming source %u",
2971 src);
2973 /* Make sure enough buffers have been processed to unqueue. */
2974 BufferList = source->queue;
2975 Current = NULL;
2976 if((voice=GetSourceVoice(source, context)) != NULL)
2977 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
2978 else if(source->state == AL_INITIAL)
2979 Current = BufferList;
2980 if(BufferList == Current)
2981 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing pending buffers");
2983 i = BufferList->num_buffers;
2984 while(i < nb)
2986 /* If the next bufferlist to check is NULL or is the current one, it's
2987 * trying to unqueue pending buffers.
2989 ALbufferlistitem *next = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
2990 if(!next || next == Current)
2991 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing pending buffers");
2992 BufferList = next;
2994 i += BufferList->num_buffers;
2997 while(nb > 0)
2999 ALbufferlistitem *head = source->queue;
3000 ALbufferlistitem *next = ATOMIC_LOAD(&head->next, almemory_order_relaxed);
3001 for(i = 0;i < head->num_buffers && nb > 0;i++,nb--)
3003 ALbuffer *buffer = head->buffers[i];
3004 if(!buffer)
3005 *(buffers++) = 0;
3006 else
3008 *(buffers++) = buffer->id;
3009 DecrementRef(&buffer->ref);
3012 if(i < head->num_buffers)
3014 /* This head has some buffers left over, so move them to the front
3015 * and update the sample and buffer count.
3017 ALsizei max_length = 0;
3018 ALsizei j = 0;
3019 while(i < head->num_buffers)
3021 ALbuffer *buffer = head->buffers[i++];
3022 if(buffer) max_length = maxi(max_length, buffer->SampleLen);
3023 head->buffers[j++] = buffer;
3025 head->max_samples = max_length;
3026 head->num_buffers = j;
3027 break;
3030 /* Otherwise, free this item and set the source queue head to the next
3031 * one.
3033 al_free(head);
3034 source->queue = next;
3037 done:
3038 UnlockSourceList(context);
3039 ALCcontext_DecRef(context);
3043 static void InitSourceParams(ALsource *Source, ALsizei num_sends)
3045 ALsizei i;
3047 Source->InnerAngle = 360.0f;
3048 Source->OuterAngle = 360.0f;
3049 Source->Pitch = 1.0f;
3050 Source->Position[0] = 0.0f;
3051 Source->Position[1] = 0.0f;
3052 Source->Position[2] = 0.0f;
3053 Source->Velocity[0] = 0.0f;
3054 Source->Velocity[1] = 0.0f;
3055 Source->Velocity[2] = 0.0f;
3056 Source->Direction[0] = 0.0f;
3057 Source->Direction[1] = 0.0f;
3058 Source->Direction[2] = 0.0f;
3059 Source->Orientation[0][0] = 0.0f;
3060 Source->Orientation[0][1] = 0.0f;
3061 Source->Orientation[0][2] = -1.0f;
3062 Source->Orientation[1][0] = 0.0f;
3063 Source->Orientation[1][1] = 1.0f;
3064 Source->Orientation[1][2] = 0.0f;
3065 Source->RefDistance = 1.0f;
3066 Source->MaxDistance = FLT_MAX;
3067 Source->RolloffFactor = 1.0f;
3068 Source->Gain = 1.0f;
3069 Source->MinGain = 0.0f;
3070 Source->MaxGain = 1.0f;
3071 Source->OuterGain = 0.0f;
3072 Source->OuterGainHF = 1.0f;
3074 Source->DryGainHFAuto = AL_TRUE;
3075 Source->WetGainAuto = AL_TRUE;
3076 Source->WetGainHFAuto = AL_TRUE;
3077 Source->AirAbsorptionFactor = 0.0f;
3078 Source->RoomRolloffFactor = 0.0f;
3079 Source->DopplerFactor = 1.0f;
3080 Source->HeadRelative = AL_FALSE;
3081 Source->Looping = AL_FALSE;
3082 Source->mDistanceModel = DistanceModel::Default;
3083 Source->Resampler = ResamplerDefault;
3084 Source->DirectChannels = AL_FALSE;
3085 Source->Spatialize = SpatializeAuto;
3087 Source->StereoPan[0] = DEG2RAD( 30.0f);
3088 Source->StereoPan[1] = DEG2RAD(-30.0f);
3090 Source->Radius = 0.0f;
3092 Source->Direct.Gain = 1.0f;
3093 Source->Direct.GainHF = 1.0f;
3094 Source->Direct.HFReference = LOWPASSFREQREF;
3095 Source->Direct.GainLF = 1.0f;
3096 Source->Direct.LFReference = HIGHPASSFREQREF;
3097 Source->Send = static_cast<decltype(Source->Send)>(al_calloc(16,
3098 num_sends*sizeof(Source->Send[0])));
3099 for(i = 0;i < num_sends;i++)
3101 Source->Send[i].Slot = NULL;
3102 Source->Send[i].Gain = 1.0f;
3103 Source->Send[i].GainHF = 1.0f;
3104 Source->Send[i].HFReference = LOWPASSFREQREF;
3105 Source->Send[i].GainLF = 1.0f;
3106 Source->Send[i].LFReference = HIGHPASSFREQREF;
3109 Source->Offset = 0.0;
3110 Source->OffsetType = AL_NONE;
3111 Source->SourceType = AL_UNDETERMINED;
3112 Source->state = AL_INITIAL;
3114 Source->queue = NULL;
3116 ATOMIC_INIT(&Source->PropsClean, AL_TRUE);
3118 Source->VoiceIdx = -1;
3121 static void DeinitSource(ALsource *source, ALsizei num_sends)
3123 ALbufferlistitem *BufferList;
3124 ALsizei i;
3126 BufferList = source->queue;
3127 while(BufferList != NULL)
3129 ALbufferlistitem *next = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
3130 for(i = 0;i < BufferList->num_buffers;i++)
3132 if(BufferList->buffers[i] != NULL)
3133 DecrementRef(&BufferList->buffers[i]->ref);
3135 al_free(BufferList);
3136 BufferList = next;
3138 source->queue = NULL;
3140 if(source->Send)
3142 for(i = 0;i < num_sends;i++)
3144 if(source->Send[i].Slot)
3145 DecrementRef(&source->Send[i].Slot->ref);
3146 source->Send[i].Slot = NULL;
3148 al_free(source->Send);
3149 source->Send = NULL;
3153 static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends, ALCcontext *context)
3155 struct ALvoiceProps *props;
3156 ALsizei i;
3158 /* Get an unused property container, or allocate a new one as needed. */
3159 props = context->FreeVoiceProps.load(std::memory_order_acquire);
3160 if(!props)
3161 props = static_cast<ALvoiceProps*>(al_calloc(16,
3162 FAM_SIZE(struct ALvoiceProps, Send, num_sends)));
3163 else
3165 struct ALvoiceProps *next;
3166 do {
3167 next = props->next.load(std::memory_order_relaxed);
3168 } while(context->FreeVoiceProps.compare_exchange_weak(props, next,
3169 std::memory_order_acq_rel, std::memory_order_acquire) == 0);
3172 /* Copy in current property values. */
3173 props->Pitch = source->Pitch;
3174 props->Gain = source->Gain;
3175 props->OuterGain = source->OuterGain;
3176 props->MinGain = source->MinGain;
3177 props->MaxGain = source->MaxGain;
3178 props->InnerAngle = source->InnerAngle;
3179 props->OuterAngle = source->OuterAngle;
3180 props->RefDistance = source->RefDistance;
3181 props->MaxDistance = source->MaxDistance;
3182 props->RolloffFactor = source->RolloffFactor;
3183 for(i = 0;i < 3;i++)
3184 props->Position[i] = source->Position[i];
3185 for(i = 0;i < 3;i++)
3186 props->Velocity[i] = source->Velocity[i];
3187 for(i = 0;i < 3;i++)
3188 props->Direction[i] = source->Direction[i];
3189 for(i = 0;i < 2;i++)
3191 ALsizei j;
3192 for(j = 0;j < 3;j++)
3193 props->Orientation[i][j] = source->Orientation[i][j];
3195 props->HeadRelative = source->HeadRelative;
3196 props->mDistanceModel = source->mDistanceModel;
3197 props->Resampler = source->Resampler;
3198 props->DirectChannels = source->DirectChannels;
3199 props->SpatializeMode = source->Spatialize;
3201 props->DryGainHFAuto = source->DryGainHFAuto;
3202 props->WetGainAuto = source->WetGainAuto;
3203 props->WetGainHFAuto = source->WetGainHFAuto;
3204 props->OuterGainHF = source->OuterGainHF;
3206 props->AirAbsorptionFactor = source->AirAbsorptionFactor;
3207 props->RoomRolloffFactor = source->RoomRolloffFactor;
3208 props->DopplerFactor = source->DopplerFactor;
3210 props->StereoPan[0] = source->StereoPan[0];
3211 props->StereoPan[1] = source->StereoPan[1];
3213 props->Radius = source->Radius;
3215 props->Direct.Gain = source->Direct.Gain;
3216 props->Direct.GainHF = source->Direct.GainHF;
3217 props->Direct.HFReference = source->Direct.HFReference;
3218 props->Direct.GainLF = source->Direct.GainLF;
3219 props->Direct.LFReference = source->Direct.LFReference;
3221 for(i = 0;i < num_sends;i++)
3223 props->Send[i].Slot = source->Send[i].Slot;
3224 props->Send[i].Gain = source->Send[i].Gain;
3225 props->Send[i].GainHF = source->Send[i].GainHF;
3226 props->Send[i].HFReference = source->Send[i].HFReference;
3227 props->Send[i].GainLF = source->Send[i].GainLF;
3228 props->Send[i].LFReference = source->Send[i].LFReference;
3231 /* Set the new container for updating internal parameters. */
3232 props = voice->Update.exchange(props, std::memory_order_acq_rel);
3233 if(props)
3235 /* If there was an unused update container, put it back in the
3236 * freelist.
3238 AtomicReplaceHead(context->FreeVoiceProps, props);
3242 void UpdateAllSourceProps(ALCcontext *context)
3244 ALsizei num_sends = context->Device->NumAuxSends;
3245 ALsizei pos;
3247 for(pos = 0;pos < context->VoiceCount;pos++)
3249 ALvoice *voice = context->Voices[pos];
3250 ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire);
3251 if(source && !source->PropsClean.exchange(AL_TRUE, std::memory_order_acq_rel))
3252 UpdateSourceProps(source, voice, num_sends, context);
3257 /* GetSourceSampleOffset
3259 * Gets the current read offset for the given Source, in 32.32 fixed-point
3260 * samples. The offset is relative to the start of the queue (not the start of
3261 * the current buffer).
3263 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3265 ALCdevice *device = context->Device;
3266 const ALbufferlistitem *Current;
3267 ALuint64 readPos;
3268 ALuint refcount;
3269 ALvoice *voice;
3271 do {
3272 Current = NULL;
3273 readPos = 0;
3274 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3275 althrd_yield();
3276 *clocktime = GetDeviceClockTime(device);
3278 voice = GetSourceVoice(Source, context);
3279 if(voice)
3281 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3283 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << 32;
3284 readPos |= (ALuint64)ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) <<
3285 (32-FRACTIONBITS);
3287 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3288 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3290 if(voice)
3292 const ALbufferlistitem *BufferList = Source->queue;
3293 while(BufferList && BufferList != Current)
3295 readPos += (ALuint64)BufferList->max_samples << 32;
3296 BufferList = BufferList->next.load(std::memory_order_relaxed);
3298 readPos = minu64(readPos, U64(0x7fffffffffffffff));
3301 return (ALint64)readPos;
3304 /* GetSourceSecOffset
3306 * Gets the current read offset for the given Source, in seconds. The offset is
3307 * relative to the start of the queue (not the start of the current buffer).
3309 static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3311 ALCdevice *device = context->Device;
3312 const ALbufferlistitem *Current;
3313 ALuint64 readPos;
3314 ALuint refcount;
3315 ALdouble offset;
3316 ALvoice *voice;
3318 do {
3319 Current = NULL;
3320 readPos = 0;
3321 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3322 althrd_yield();
3323 *clocktime = GetDeviceClockTime(device);
3325 voice = GetSourceVoice(Source, context);
3326 if(voice)
3328 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3330 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) <<
3331 FRACTIONBITS;
3332 readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3334 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3335 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3337 offset = 0.0;
3338 if(voice)
3340 const ALbufferlistitem *BufferList = Source->queue;
3341 const ALbuffer *BufferFmt = NULL;
3342 while(BufferList && BufferList != Current)
3344 ALsizei i = 0;
3345 while(!BufferFmt && i < BufferList->num_buffers)
3346 BufferFmt = BufferList->buffers[i++];
3347 readPos += (ALuint64)BufferList->max_samples << FRACTIONBITS;
3348 BufferList = BufferList->next.load(std::memory_order_relaxed);
3351 while(BufferList && !BufferFmt)
3353 ALsizei i = 0;
3354 while(!BufferFmt && i < BufferList->num_buffers)
3355 BufferFmt = BufferList->buffers[i++];
3356 BufferList = BufferList->next.load(std::memory_order_relaxed);
3358 assert(BufferFmt != NULL);
3360 offset = (ALdouble)readPos / (ALdouble)FRACTIONONE /
3361 (ALdouble)BufferFmt->Frequency;
3364 return offset;
3367 /* GetSourceOffset
3369 * Gets the current read offset for the given Source, in the appropriate format
3370 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3371 * queue (not the start of the current buffer).
3373 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context)
3375 ALCdevice *device = context->Device;
3376 const ALbufferlistitem *Current;
3377 ALuint readPos;
3378 ALsizei readPosFrac;
3379 ALuint refcount;
3380 ALdouble offset;
3381 ALvoice *voice;
3383 do {
3384 Current = NULL;
3385 readPos = readPosFrac = 0;
3386 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3387 althrd_yield();
3388 voice = GetSourceVoice(Source, context);
3389 if(voice)
3391 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3393 readPos = ATOMIC_LOAD(&voice->position, almemory_order_relaxed);
3394 readPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3396 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3397 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3399 offset = 0.0;
3400 if(voice)
3402 const ALbufferlistitem *BufferList = Source->queue;
3403 const ALbuffer *BufferFmt = NULL;
3404 ALboolean readFin = AL_FALSE;
3405 ALuint totalBufferLen = 0;
3407 while(BufferList != NULL)
3409 ALsizei i = 0;
3410 while(!BufferFmt && i < BufferList->num_buffers)
3411 BufferFmt = BufferList->buffers[i++];
3413 readFin |= (BufferList == Current);
3414 totalBufferLen += BufferList->max_samples;
3415 if(!readFin) readPos += BufferList->max_samples;
3417 BufferList = BufferList->next.load(std::memory_order_relaxed);
3419 assert(BufferFmt != NULL);
3421 if(Source->Looping)
3422 readPos %= totalBufferLen;
3423 else
3425 /* Wrap back to 0 */
3426 if(readPos >= totalBufferLen)
3427 readPos = readPosFrac = 0;
3430 offset = 0.0;
3431 switch(name)
3433 case AL_SEC_OFFSET:
3434 offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE) / BufferFmt->Frequency;
3435 break;
3437 case AL_SAMPLE_OFFSET:
3438 offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
3439 break;
3441 case AL_BYTE_OFFSET:
3442 if(BufferFmt->OriginalType == UserFmtIMA4)
3444 ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
3445 ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels);
3446 ALuint FrameBlockSize = BufferFmt->OriginalAlign;
3448 /* Round down to nearest ADPCM block */
3449 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3451 else if(BufferFmt->OriginalType == UserFmtMSADPCM)
3453 ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
3454 ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels);
3455 ALuint FrameBlockSize = BufferFmt->OriginalAlign;
3457 /* Round down to nearest ADPCM block */
3458 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3460 else
3462 ALuint FrameSize = FrameSizeFromFmt(BufferFmt->FmtChannels,
3463 BufferFmt->FmtType);
3464 offset = (ALdouble)(readPos * FrameSize);
3466 break;
3470 return offset;
3474 /* ApplyOffset
3476 * Apply the stored playback offset to the Source. This function will update
3477 * the number of buffers "played" given the stored offset.
3479 static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice)
3481 ALbufferlistitem *BufferList;
3482 ALuint totalBufferLen;
3483 ALuint offset = 0;
3484 ALsizei frac = 0;
3486 /* Get sample frame offset */
3487 if(!GetSampleOffset(Source, &offset, &frac))
3488 return AL_FALSE;
3490 totalBufferLen = 0;
3491 BufferList = Source->queue;
3492 while(BufferList && totalBufferLen <= offset)
3494 if((ALuint)BufferList->max_samples > offset-totalBufferLen)
3496 /* Offset is in this buffer */
3497 ATOMIC_STORE(&voice->position, offset - totalBufferLen, almemory_order_relaxed);
3498 ATOMIC_STORE(&voice->position_fraction, frac, almemory_order_relaxed);
3499 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_release);
3500 return AL_TRUE;
3502 totalBufferLen += BufferList->max_samples;
3504 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
3507 /* Offset is out of range of the queue */
3508 return AL_FALSE;
3512 /* GetSampleOffset
3514 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3515 * or Second offset supplied by the application). This takes into account the
3516 * fact that the buffer format may have been modifed since.
3518 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac)
3520 const ALbuffer *BufferFmt = NULL;
3521 const ALbufferlistitem *BufferList;
3522 ALdouble dbloff, dblfrac;
3524 /* Find the first valid Buffer in the Queue */
3525 BufferList = Source->queue;
3526 while(BufferList)
3528 ALsizei i;
3529 for(i = 0;i < BufferList->num_buffers && !BufferFmt;i++)
3530 BufferFmt = BufferList->buffers[i];
3531 if(BufferFmt) break;
3532 BufferList = BufferList->next.load(std::memory_order_relaxed);
3534 if(!BufferFmt)
3536 Source->OffsetType = AL_NONE;
3537 Source->Offset = 0.0;
3538 return AL_FALSE;
3541 switch(Source->OffsetType)
3543 case AL_BYTE_OFFSET:
3544 /* Determine the ByteOffset (and ensure it is block aligned) */
3545 *offset = (ALuint)Source->Offset;
3546 if(BufferFmt->OriginalType == UserFmtIMA4)
3548 ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
3549 *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels);
3550 *offset *= BufferFmt->OriginalAlign;
3552 else if(BufferFmt->OriginalType == UserFmtMSADPCM)
3554 ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
3555 *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels);
3556 *offset *= BufferFmt->OriginalAlign;
3558 else
3559 *offset /= FrameSizeFromFmt(BufferFmt->FmtChannels, BufferFmt->FmtType);
3560 *frac = 0;
3561 break;
3563 case AL_SAMPLE_OFFSET:
3564 dblfrac = modf(Source->Offset, &dbloff);
3565 *offset = (ALuint)mind(dbloff, UINT_MAX);
3566 *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3567 break;
3569 case AL_SEC_OFFSET:
3570 dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff);
3571 *offset = (ALuint)mind(dbloff, UINT_MAX);
3572 *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3573 break;
3575 Source->OffsetType = AL_NONE;
3576 Source->Offset = 0.0;
3578 return AL_TRUE;
3582 static ALsource *AllocSource(ALCcontext *context)
3584 ALCdevice *device{context->Device};
3585 almtx_lock(&context->SourceLock);
3586 if(context->NumSources >= device->SourcesMax)
3588 almtx_unlock(&context->SourceLock);
3589 alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax);
3590 return nullptr;
3592 auto sublist = std::find_if(context->SourceList.begin(), context->SourceList.end(),
3593 [](const SourceSubList &entry) -> bool
3594 { return entry.FreeMask != 0; }
3596 ALsizei lidx = std::distance(context->SourceList.begin(), sublist);
3597 ALsource *source;
3598 ALsizei slidx;
3599 if(LIKELY(sublist != context->SourceList.end()))
3601 slidx = CTZ64(sublist->FreeMask);
3602 source = sublist->Sources + slidx;
3604 else
3606 /* Don't allocate so many list entries that the 32-bit ID could
3607 * overflow...
3609 if(UNLIKELY(context->SourceList.size() >= 1<<25))
3611 almtx_unlock(&device->BufferLock);
3612 alSetError(context, AL_OUT_OF_MEMORY, "Too many sources allocated");
3613 return nullptr;
3615 context->SourceList.emplace_back();
3616 sublist = context->SourceList.end() - 1;
3618 sublist->FreeMask = ~U64(0);
3619 sublist->Sources = static_cast<ALsource*>(al_calloc(16, sizeof(ALsource)*64));
3620 if(UNLIKELY(!sublist->Sources))
3622 context->SourceList.pop_back();
3623 almtx_unlock(&context->SourceLock);
3624 alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate source batch");
3625 return nullptr;
3628 slidx = 0;
3629 source = sublist->Sources + slidx;
3632 source = new (source) ALsource{};
3633 InitSourceParams(source, device->NumAuxSends);
3635 /* Add 1 to avoid source ID 0. */
3636 source->id = ((lidx<<6) | slidx) + 1;
3638 context->NumSources++;
3639 sublist->FreeMask &= ~(U64(1)<<slidx);
3640 almtx_unlock(&context->SourceLock);
3642 return source;
3645 static void FreeSource(ALCcontext *context, ALsource *source)
3647 ALCdevice *device = context->Device;
3648 ALuint id = source->id - 1;
3649 ALsizei lidx = id >> 6;
3650 ALsizei slidx = id & 0x3f;
3651 ALvoice *voice;
3653 ALCdevice_Lock(device);
3654 if((voice=GetSourceVoice(source, context)) != NULL)
3656 ATOMIC_STORE(&voice->Source, static_cast<ALsource*>(nullptr), almemory_order_relaxed);
3657 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
3659 ALCdevice_Unlock(device);
3661 DeinitSource(source, device->NumAuxSends);
3662 source->~ALsource();
3664 context->SourceList[lidx].FreeMask |= U64(1) << slidx;
3665 context->NumSources--;
3668 /* ReleaseALSources
3670 * Destroys all sources in the source map.
3672 ALvoid ReleaseALSources(ALCcontext *context)
3674 ALCdevice *device = context->Device;
3675 size_t leftover = 0;
3676 for(auto &sublist : context->SourceList)
3678 ALuint64 usemask = ~sublist.FreeMask;
3679 while(usemask)
3681 ALsizei idx = CTZ64(usemask);
3682 ALsource *source = sublist.Sources + idx;
3684 DeinitSource(source, device->NumAuxSends);
3685 source->~ALsource();
3686 ++leftover;
3688 usemask &= ~(U64(1) << idx);
3690 sublist.FreeMask = ~usemask;
3692 if(leftover > 0)
3693 WARN("(%p) Deleted " SZFMT " Source%s\n", device, leftover, (leftover==1)?"":"s");