Use separate atomic macros for pointers
[openal-soft.git] / OpenAL32 / alSource.c
blob040078df082363f613378a869e44aab96236d808
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 <math.h>
26 #include <float.h>
28 #include "AL/al.h"
29 #include "AL/alc.h"
30 #include "alMain.h"
31 #include "alError.h"
32 #include "alSource.h"
33 #include "alBuffer.h"
34 #include "alThunk.h"
35 #include "alAuxEffectSlot.h"
37 #include "backends/base.h"
39 #include "threads.h"
40 #include "almalloc.h"
43 extern inline void LockSourcesRead(ALCcontext *context);
44 extern inline void UnlockSourcesRead(ALCcontext *context);
45 extern inline void LockSourcesWrite(ALCcontext *context);
46 extern inline void UnlockSourcesWrite(ALCcontext *context);
47 extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
48 extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
50 static void InitSourceParams(ALsource *Source, ALsizei num_sends);
51 static void DeinitSource(ALsource *source, ALsizei num_sends);
52 static void UpdateSourceProps(ALsource *source, ALsizei num_sends);
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 typedef enum SourceProp {
60 srcPitch = AL_PITCH,
61 srcGain = AL_GAIN,
62 srcMinGain = AL_MIN_GAIN,
63 srcMaxGain = AL_MAX_GAIN,
64 srcMaxDistance = AL_MAX_DISTANCE,
65 srcRolloffFactor = AL_ROLLOFF_FACTOR,
66 srcDopplerFactor = AL_DOPPLER_FACTOR,
67 srcConeOuterGain = AL_CONE_OUTER_GAIN,
68 srcSecOffset = AL_SEC_OFFSET,
69 srcSampleOffset = AL_SAMPLE_OFFSET,
70 srcByteOffset = AL_BYTE_OFFSET,
71 srcConeInnerAngle = AL_CONE_INNER_ANGLE,
72 srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
73 srcRefDistance = AL_REFERENCE_DISTANCE,
75 srcPosition = AL_POSITION,
76 srcVelocity = AL_VELOCITY,
77 srcDirection = AL_DIRECTION,
79 srcSourceRelative = AL_SOURCE_RELATIVE,
80 srcLooping = AL_LOOPING,
81 srcBuffer = AL_BUFFER,
82 srcSourceState = AL_SOURCE_STATE,
83 srcBuffersQueued = AL_BUFFERS_QUEUED,
84 srcBuffersProcessed = AL_BUFFERS_PROCESSED,
85 srcSourceType = AL_SOURCE_TYPE,
87 /* ALC_EXT_EFX */
88 srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
89 srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
90 srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
91 srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
92 srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
93 srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
94 srcDirectFilter = AL_DIRECT_FILTER,
95 srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
97 /* AL_SOFT_direct_channels */
98 srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
100 /* AL_EXT_source_distance_model */
101 srcDistanceModel = AL_DISTANCE_MODEL,
103 srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
104 srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
105 srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
107 /* AL_SOFT_source_latency */
108 srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
109 srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
111 /* AL_EXT_STEREO_ANGLES */
112 srcAngles = AL_STEREO_ANGLES,
114 /* AL_EXT_SOURCE_RADIUS */
115 srcRadius = AL_SOURCE_RADIUS,
117 /* AL_EXT_BFORMAT */
118 srcOrientation = AL_ORIENTATION,
119 } SourceProp;
121 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
122 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
123 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
125 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
126 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
127 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
129 static inline ALvoice *GetSourceVoice(const ALsource *source, const ALCcontext *context)
131 ALvoice **voice = context->Voices;
132 ALvoice **voice_end = voice + context->VoiceCount;
133 while(voice != voice_end)
135 if(ATOMIC_LOAD(&(*voice)->Source, almemory_order_acquire) == source)
136 return *voice;
137 ++voice;
139 return NULL;
143 * Returns if the last known state for the source was playing or paused. Does
144 * not sync with the mixer voice.
146 static inline bool IsPlayingOrPaused(ALsource *source)
148 ALenum state = ATOMIC_LOAD(&source->state, almemory_order_acquire);
149 return state == AL_PLAYING || state == AL_PAUSED;
153 * Returns an updated source state using the matching voice's status (or lack
154 * thereof).
156 static inline ALenum GetSourceState(ALsource *source, ALvoice *voice)
158 if(!voice)
160 ALenum state = AL_PLAYING;
161 if(ATOMIC_COMPARE_EXCHANGE_STRONG(&source->state, &state, AL_STOPPED,
162 almemory_order_acq_rel, almemory_order_acquire))
163 return AL_STOPPED;
164 return state;
166 return ATOMIC_LOAD(&source->state, almemory_order_acquire);
170 * Returns if the source should specify an update, given the context's
171 * deferring state and the source's last known state.
173 static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context)
175 return !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) &&
176 IsPlayingOrPaused(source);
179 static ALint FloatValsByProp(ALenum prop)
181 if(prop != (ALenum)((SourceProp)prop))
182 return 0;
183 switch((SourceProp)prop)
185 case AL_PITCH:
186 case AL_GAIN:
187 case AL_MIN_GAIN:
188 case AL_MAX_GAIN:
189 case AL_MAX_DISTANCE:
190 case AL_ROLLOFF_FACTOR:
191 case AL_DOPPLER_FACTOR:
192 case AL_CONE_OUTER_GAIN:
193 case AL_SEC_OFFSET:
194 case AL_SAMPLE_OFFSET:
195 case AL_BYTE_OFFSET:
196 case AL_CONE_INNER_ANGLE:
197 case AL_CONE_OUTER_ANGLE:
198 case AL_REFERENCE_DISTANCE:
199 case AL_CONE_OUTER_GAINHF:
200 case AL_AIR_ABSORPTION_FACTOR:
201 case AL_ROOM_ROLLOFF_FACTOR:
202 case AL_DIRECT_FILTER_GAINHF_AUTO:
203 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
204 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
205 case AL_DIRECT_CHANNELS_SOFT:
206 case AL_DISTANCE_MODEL:
207 case AL_SOURCE_RELATIVE:
208 case AL_LOOPING:
209 case AL_SOURCE_STATE:
210 case AL_BUFFERS_QUEUED:
211 case AL_BUFFERS_PROCESSED:
212 case AL_SOURCE_TYPE:
213 case AL_BYTE_LENGTH_SOFT:
214 case AL_SAMPLE_LENGTH_SOFT:
215 case AL_SEC_LENGTH_SOFT:
216 case AL_SOURCE_RADIUS:
217 return 1;
219 case AL_STEREO_ANGLES:
220 return 2;
222 case AL_POSITION:
223 case AL_VELOCITY:
224 case AL_DIRECTION:
225 return 3;
227 case AL_ORIENTATION:
228 return 6;
230 case AL_SEC_OFFSET_LATENCY_SOFT:
231 break; /* Double only */
233 case AL_BUFFER:
234 case AL_DIRECT_FILTER:
235 case AL_AUXILIARY_SEND_FILTER:
236 break; /* i/i64 only */
237 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
238 break; /* i64 only */
240 return 0;
242 static ALint DoubleValsByProp(ALenum prop)
244 if(prop != (ALenum)((SourceProp)prop))
245 return 0;
246 switch((SourceProp)prop)
248 case AL_PITCH:
249 case AL_GAIN:
250 case AL_MIN_GAIN:
251 case AL_MAX_GAIN:
252 case AL_MAX_DISTANCE:
253 case AL_ROLLOFF_FACTOR:
254 case AL_DOPPLER_FACTOR:
255 case AL_CONE_OUTER_GAIN:
256 case AL_SEC_OFFSET:
257 case AL_SAMPLE_OFFSET:
258 case AL_BYTE_OFFSET:
259 case AL_CONE_INNER_ANGLE:
260 case AL_CONE_OUTER_ANGLE:
261 case AL_REFERENCE_DISTANCE:
262 case AL_CONE_OUTER_GAINHF:
263 case AL_AIR_ABSORPTION_FACTOR:
264 case AL_ROOM_ROLLOFF_FACTOR:
265 case AL_DIRECT_FILTER_GAINHF_AUTO:
266 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
267 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
268 case AL_DIRECT_CHANNELS_SOFT:
269 case AL_DISTANCE_MODEL:
270 case AL_SOURCE_RELATIVE:
271 case AL_LOOPING:
272 case AL_SOURCE_STATE:
273 case AL_BUFFERS_QUEUED:
274 case AL_BUFFERS_PROCESSED:
275 case AL_SOURCE_TYPE:
276 case AL_BYTE_LENGTH_SOFT:
277 case AL_SAMPLE_LENGTH_SOFT:
278 case AL_SEC_LENGTH_SOFT:
279 case AL_SOURCE_RADIUS:
280 return 1;
282 case AL_SEC_OFFSET_LATENCY_SOFT:
283 case AL_STEREO_ANGLES:
284 return 2;
286 case AL_POSITION:
287 case AL_VELOCITY:
288 case AL_DIRECTION:
289 return 3;
291 case AL_ORIENTATION:
292 return 6;
294 case AL_BUFFER:
295 case AL_DIRECT_FILTER:
296 case AL_AUXILIARY_SEND_FILTER:
297 break; /* i/i64 only */
298 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
299 break; /* i64 only */
301 return 0;
304 static ALint IntValsByProp(ALenum prop)
306 if(prop != (ALenum)((SourceProp)prop))
307 return 0;
308 switch((SourceProp)prop)
310 case AL_PITCH:
311 case AL_GAIN:
312 case AL_MIN_GAIN:
313 case AL_MAX_GAIN:
314 case AL_MAX_DISTANCE:
315 case AL_ROLLOFF_FACTOR:
316 case AL_DOPPLER_FACTOR:
317 case AL_CONE_OUTER_GAIN:
318 case AL_SEC_OFFSET:
319 case AL_SAMPLE_OFFSET:
320 case AL_BYTE_OFFSET:
321 case AL_CONE_INNER_ANGLE:
322 case AL_CONE_OUTER_ANGLE:
323 case AL_REFERENCE_DISTANCE:
324 case AL_CONE_OUTER_GAINHF:
325 case AL_AIR_ABSORPTION_FACTOR:
326 case AL_ROOM_ROLLOFF_FACTOR:
327 case AL_DIRECT_FILTER_GAINHF_AUTO:
328 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
329 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
330 case AL_DIRECT_CHANNELS_SOFT:
331 case AL_DISTANCE_MODEL:
332 case AL_SOURCE_RELATIVE:
333 case AL_LOOPING:
334 case AL_BUFFER:
335 case AL_SOURCE_STATE:
336 case AL_BUFFERS_QUEUED:
337 case AL_BUFFERS_PROCESSED:
338 case AL_SOURCE_TYPE:
339 case AL_DIRECT_FILTER:
340 case AL_BYTE_LENGTH_SOFT:
341 case AL_SAMPLE_LENGTH_SOFT:
342 case AL_SEC_LENGTH_SOFT:
343 case AL_SOURCE_RADIUS:
344 return 1;
346 case AL_POSITION:
347 case AL_VELOCITY:
348 case AL_DIRECTION:
349 case AL_AUXILIARY_SEND_FILTER:
350 return 3;
352 case AL_ORIENTATION:
353 return 6;
355 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
356 break; /* i64 only */
357 case AL_SEC_OFFSET_LATENCY_SOFT:
358 break; /* Double only */
359 case AL_STEREO_ANGLES:
360 break; /* Float/double only */
362 return 0;
364 static ALint Int64ValsByProp(ALenum prop)
366 if(prop != (ALenum)((SourceProp)prop))
367 return 0;
368 switch((SourceProp)prop)
370 case AL_PITCH:
371 case AL_GAIN:
372 case AL_MIN_GAIN:
373 case AL_MAX_GAIN:
374 case AL_MAX_DISTANCE:
375 case AL_ROLLOFF_FACTOR:
376 case AL_DOPPLER_FACTOR:
377 case AL_CONE_OUTER_GAIN:
378 case AL_SEC_OFFSET:
379 case AL_SAMPLE_OFFSET:
380 case AL_BYTE_OFFSET:
381 case AL_CONE_INNER_ANGLE:
382 case AL_CONE_OUTER_ANGLE:
383 case AL_REFERENCE_DISTANCE:
384 case AL_CONE_OUTER_GAINHF:
385 case AL_AIR_ABSORPTION_FACTOR:
386 case AL_ROOM_ROLLOFF_FACTOR:
387 case AL_DIRECT_FILTER_GAINHF_AUTO:
388 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
389 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
390 case AL_DIRECT_CHANNELS_SOFT:
391 case AL_DISTANCE_MODEL:
392 case AL_SOURCE_RELATIVE:
393 case AL_LOOPING:
394 case AL_BUFFER:
395 case AL_SOURCE_STATE:
396 case AL_BUFFERS_QUEUED:
397 case AL_BUFFERS_PROCESSED:
398 case AL_SOURCE_TYPE:
399 case AL_DIRECT_FILTER:
400 case AL_BYTE_LENGTH_SOFT:
401 case AL_SAMPLE_LENGTH_SOFT:
402 case AL_SEC_LENGTH_SOFT:
403 case AL_SOURCE_RADIUS:
404 return 1;
406 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
407 return 2;
409 case AL_POSITION:
410 case AL_VELOCITY:
411 case AL_DIRECTION:
412 case AL_AUXILIARY_SEND_FILTER:
413 return 3;
415 case AL_ORIENTATION:
416 return 6;
418 case AL_SEC_OFFSET_LATENCY_SOFT:
419 break; /* Double only */
420 case AL_STEREO_ANGLES:
421 break; /* Float/double only */
423 return 0;
427 #define CHECKVAL(x) do { \
428 if(!(x)) \
429 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
430 } while(0)
432 #define DO_UPDATEPROPS() do { \
433 if(SourceShouldUpdate(Source, Context)) \
434 UpdateSourceProps(Source, device->NumAuxSends); \
435 else \
436 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \
437 } while(0)
439 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
441 ALCdevice *device = Context->Device;
442 ALint ival;
444 switch(prop)
446 case AL_BYTE_LENGTH_SOFT:
447 case AL_SAMPLE_LENGTH_SOFT:
448 case AL_SEC_LENGTH_SOFT:
449 case AL_SEC_OFFSET_LATENCY_SOFT:
450 /* Query only */
451 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
453 case AL_PITCH:
454 CHECKVAL(*values >= 0.0f);
456 Source->Pitch = *values;
457 DO_UPDATEPROPS();
458 return AL_TRUE;
460 case AL_CONE_INNER_ANGLE:
461 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
463 Source->InnerAngle = *values;
464 DO_UPDATEPROPS();
465 return AL_TRUE;
467 case AL_CONE_OUTER_ANGLE:
468 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
470 Source->OuterAngle = *values;
471 DO_UPDATEPROPS();
472 return AL_TRUE;
474 case AL_GAIN:
475 CHECKVAL(*values >= 0.0f);
477 Source->Gain = *values;
478 DO_UPDATEPROPS();
479 return AL_TRUE;
481 case AL_MAX_DISTANCE:
482 CHECKVAL(*values >= 0.0f);
484 Source->MaxDistance = *values;
485 DO_UPDATEPROPS();
486 return AL_TRUE;
488 case AL_ROLLOFF_FACTOR:
489 CHECKVAL(*values >= 0.0f);
491 Source->RollOffFactor = *values;
492 DO_UPDATEPROPS();
493 return AL_TRUE;
495 case AL_REFERENCE_DISTANCE:
496 CHECKVAL(*values >= 0.0f);
498 Source->RefDistance = *values;
499 DO_UPDATEPROPS();
500 return AL_TRUE;
502 case AL_MIN_GAIN:
503 CHECKVAL(*values >= 0.0f);
505 Source->MinGain = *values;
506 DO_UPDATEPROPS();
507 return AL_TRUE;
509 case AL_MAX_GAIN:
510 CHECKVAL(*values >= 0.0f);
512 Source->MaxGain = *values;
513 DO_UPDATEPROPS();
514 return AL_TRUE;
516 case AL_CONE_OUTER_GAIN:
517 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
519 Source->OuterGain = *values;
520 DO_UPDATEPROPS();
521 return AL_TRUE;
523 case AL_CONE_OUTER_GAINHF:
524 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
526 Source->OuterGainHF = *values;
527 DO_UPDATEPROPS();
528 return AL_TRUE;
530 case AL_AIR_ABSORPTION_FACTOR:
531 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
533 Source->AirAbsorptionFactor = *values;
534 DO_UPDATEPROPS();
535 return AL_TRUE;
537 case AL_ROOM_ROLLOFF_FACTOR:
538 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
540 Source->RoomRolloffFactor = *values;
541 DO_UPDATEPROPS();
542 return AL_TRUE;
544 case AL_DOPPLER_FACTOR:
545 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
547 Source->DopplerFactor = *values;
548 DO_UPDATEPROPS();
549 return AL_TRUE;
551 case AL_SEC_OFFSET:
552 case AL_SAMPLE_OFFSET:
553 case AL_BYTE_OFFSET:
554 CHECKVAL(*values >= 0.0f);
556 Source->OffsetType = prop;
557 Source->Offset = *values;
559 if(IsPlayingOrPaused(Source))
561 ALvoice *voice;
563 ALCdevice_Lock(Context->Device);
564 /* Double-check that the source is still playing while we have
565 * the lock.
567 voice = GetSourceVoice(Source, Context);
568 if(voice)
570 WriteLock(&Source->queue_lock);
571 if(ApplyOffset(Source, voice) == AL_FALSE)
573 WriteUnlock(&Source->queue_lock);
574 ALCdevice_Unlock(Context->Device);
575 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
577 WriteUnlock(&Source->queue_lock);
579 ALCdevice_Unlock(Context->Device);
581 return AL_TRUE;
583 case AL_SOURCE_RADIUS:
584 CHECKVAL(*values >= 0.0f && isfinite(*values));
586 Source->Radius = *values;
587 DO_UPDATEPROPS();
588 return AL_TRUE;
590 case AL_STEREO_ANGLES:
591 CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
593 Source->StereoPan[0] = values[0];
594 Source->StereoPan[1] = values[1];
595 DO_UPDATEPROPS();
596 return AL_TRUE;
599 case AL_POSITION:
600 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
602 Source->Position[0] = values[0];
603 Source->Position[1] = values[1];
604 Source->Position[2] = values[2];
605 DO_UPDATEPROPS();
606 return AL_TRUE;
608 case AL_VELOCITY:
609 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
611 Source->Velocity[0] = values[0];
612 Source->Velocity[1] = values[1];
613 Source->Velocity[2] = values[2];
614 DO_UPDATEPROPS();
615 return AL_TRUE;
617 case AL_DIRECTION:
618 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
620 Source->Direction[0] = values[0];
621 Source->Direction[1] = values[1];
622 Source->Direction[2] = values[2];
623 DO_UPDATEPROPS();
624 return AL_TRUE;
626 case AL_ORIENTATION:
627 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
628 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
630 Source->Orientation[0][0] = values[0];
631 Source->Orientation[0][1] = values[1];
632 Source->Orientation[0][2] = values[2];
633 Source->Orientation[1][0] = values[3];
634 Source->Orientation[1][1] = values[4];
635 Source->Orientation[1][2] = values[5];
636 DO_UPDATEPROPS();
637 return AL_TRUE;
640 case AL_SOURCE_RELATIVE:
641 case AL_LOOPING:
642 case AL_SOURCE_STATE:
643 case AL_SOURCE_TYPE:
644 case AL_DISTANCE_MODEL:
645 case AL_DIRECT_FILTER_GAINHF_AUTO:
646 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
647 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
648 case AL_DIRECT_CHANNELS_SOFT:
649 ival = (ALint)values[0];
650 return SetSourceiv(Source, Context, prop, &ival);
652 case AL_BUFFERS_QUEUED:
653 case AL_BUFFERS_PROCESSED:
654 ival = (ALint)((ALuint)values[0]);
655 return SetSourceiv(Source, Context, prop, &ival);
657 case AL_BUFFER:
658 case AL_DIRECT_FILTER:
659 case AL_AUXILIARY_SEND_FILTER:
660 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
661 break;
664 ERR("Unexpected property: 0x%04x\n", prop);
665 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
668 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
670 ALCdevice *device = Context->Device;
671 ALbuffer *buffer = NULL;
672 ALfilter *filter = NULL;
673 ALeffectslot *slot = NULL;
674 ALbufferlistitem *oldlist;
675 ALbufferlistitem *newlist;
676 ALfloat fvals[6];
678 switch(prop)
680 case AL_SOURCE_STATE:
681 case AL_SOURCE_TYPE:
682 case AL_BUFFERS_QUEUED:
683 case AL_BUFFERS_PROCESSED:
684 case AL_BYTE_LENGTH_SOFT:
685 case AL_SAMPLE_LENGTH_SOFT:
686 case AL_SEC_LENGTH_SOFT:
687 /* Query only */
688 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
690 case AL_SOURCE_RELATIVE:
691 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
693 Source->HeadRelative = (ALboolean)*values;
694 DO_UPDATEPROPS();
695 return AL_TRUE;
697 case AL_LOOPING:
698 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
700 WriteLock(&Source->queue_lock);
701 ATOMIC_STORE_SEQ(&Source->looping, *values);
702 if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) == AL_PLAYING)
704 /* If the source is playing, wait for the current mix to finish
705 * to ensure it isn't currently looping back or reaching the
706 * end.
708 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
709 althrd_yield();
711 WriteUnlock(&Source->queue_lock);
712 return AL_TRUE;
714 case AL_BUFFER:
715 LockBuffersRead(device);
716 if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
718 UnlockBuffersRead(device);
719 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
722 WriteLock(&Source->queue_lock);
724 ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context));
725 if(state == AL_PLAYING || state == AL_PAUSED)
727 WriteUnlock(&Source->queue_lock);
728 UnlockBuffersRead(device);
729 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
733 if(buffer != NULL)
735 /* Add the selected buffer to a one-item queue */
736 newlist = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
737 newlist->buffer = buffer;
738 newlist->next = NULL;
739 IncrementRef(&buffer->ref);
741 /* Source is now Static */
742 Source->SourceType = AL_STATIC;
744 else
746 /* Source is now Undetermined */
747 Source->SourceType = AL_UNDETERMINED;
748 newlist = NULL;
750 oldlist = ATOMIC_EXCHANGE_PTR_SEQ(&Source->queue, newlist);
751 WriteUnlock(&Source->queue_lock);
752 UnlockBuffersRead(device);
754 /* Delete all elements in the previous queue */
755 while(oldlist != NULL)
757 ALbufferlistitem *temp = oldlist;
758 oldlist = temp->next;
760 if(temp->buffer)
761 DecrementRef(&temp->buffer->ref);
762 al_free(temp);
764 return AL_TRUE;
766 case AL_SEC_OFFSET:
767 case AL_SAMPLE_OFFSET:
768 case AL_BYTE_OFFSET:
769 CHECKVAL(*values >= 0);
771 Source->OffsetType = prop;
772 Source->Offset = *values;
774 if(IsPlayingOrPaused(Source))
776 ALvoice *voice;
778 ALCdevice_Lock(Context->Device);
779 voice = GetSourceVoice(Source, Context);
780 if(voice)
782 WriteLock(&Source->queue_lock);
783 if(ApplyOffset(Source, voice) == AL_FALSE)
785 WriteUnlock(&Source->queue_lock);
786 ALCdevice_Unlock(Context->Device);
787 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
789 WriteUnlock(&Source->queue_lock);
791 ALCdevice_Unlock(Context->Device);
793 return AL_TRUE;
795 case AL_DIRECT_FILTER:
796 LockFiltersRead(device);
797 if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
799 UnlockFiltersRead(device);
800 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
803 if(!filter)
805 Source->Direct.Gain = 1.0f;
806 Source->Direct.GainHF = 1.0f;
807 Source->Direct.HFReference = LOWPASSFREQREF;
808 Source->Direct.GainLF = 1.0f;
809 Source->Direct.LFReference = HIGHPASSFREQREF;
811 else
813 Source->Direct.Gain = filter->Gain;
814 Source->Direct.GainHF = filter->GainHF;
815 Source->Direct.HFReference = filter->HFReference;
816 Source->Direct.GainLF = filter->GainLF;
817 Source->Direct.LFReference = filter->LFReference;
819 UnlockFiltersRead(device);
820 DO_UPDATEPROPS();
821 return AL_TRUE;
823 case AL_DIRECT_FILTER_GAINHF_AUTO:
824 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
826 Source->DryGainHFAuto = *values;
827 DO_UPDATEPROPS();
828 return AL_TRUE;
830 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
831 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
833 Source->WetGainAuto = *values;
834 DO_UPDATEPROPS();
835 return AL_TRUE;
837 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
838 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
840 Source->WetGainHFAuto = *values;
841 DO_UPDATEPROPS();
842 return AL_TRUE;
844 case AL_DIRECT_CHANNELS_SOFT:
845 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
847 Source->DirectChannels = *values;
848 DO_UPDATEPROPS();
849 return AL_TRUE;
851 case AL_DISTANCE_MODEL:
852 CHECKVAL(*values == AL_NONE ||
853 *values == AL_INVERSE_DISTANCE ||
854 *values == AL_INVERSE_DISTANCE_CLAMPED ||
855 *values == AL_LINEAR_DISTANCE ||
856 *values == AL_LINEAR_DISTANCE_CLAMPED ||
857 *values == AL_EXPONENT_DISTANCE ||
858 *values == AL_EXPONENT_DISTANCE_CLAMPED);
860 Source->DistanceModel = *values;
861 if(Context->SourceDistanceModel)
862 DO_UPDATEPROPS();
863 return AL_TRUE;
866 case AL_AUXILIARY_SEND_FILTER:
867 LockEffectSlotsRead(Context);
868 LockFiltersRead(device);
869 if(!((ALuint)values[1] < (ALuint)device->NumAuxSends &&
870 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
871 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
873 UnlockFiltersRead(device);
874 UnlockEffectSlotsRead(Context);
875 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
878 if(!filter)
880 /* Disable filter */
881 Source->Send[values[1]].Gain = 1.0f;
882 Source->Send[values[1]].GainHF = 1.0f;
883 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
884 Source->Send[values[1]].GainLF = 1.0f;
885 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
887 else
889 Source->Send[values[1]].Gain = filter->Gain;
890 Source->Send[values[1]].GainHF = filter->GainHF;
891 Source->Send[values[1]].HFReference = filter->HFReference;
892 Source->Send[values[1]].GainLF = filter->GainLF;
893 Source->Send[values[1]].LFReference = filter->LFReference;
895 UnlockFiltersRead(device);
897 if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source))
899 /* Add refcount on the new slot, and release the previous slot */
900 if(slot) IncrementRef(&slot->ref);
901 if(Source->Send[values[1]].Slot)
902 DecrementRef(&Source->Send[values[1]].Slot->ref);
903 Source->Send[values[1]].Slot = slot;
905 /* We must force an update if the auxiliary slot changed on a
906 * playing source, in case the slot is about to be deleted.
908 UpdateSourceProps(Source, device->NumAuxSends);
910 else
912 if(slot) IncrementRef(&slot->ref);
913 if(Source->Send[values[1]].Slot)
914 DecrementRef(&Source->Send[values[1]].Slot->ref);
915 Source->Send[values[1]].Slot = slot;
916 DO_UPDATEPROPS();
918 UnlockEffectSlotsRead(Context);
920 return AL_TRUE;
923 /* 1x float */
924 case AL_CONE_INNER_ANGLE:
925 case AL_CONE_OUTER_ANGLE:
926 case AL_PITCH:
927 case AL_GAIN:
928 case AL_MIN_GAIN:
929 case AL_MAX_GAIN:
930 case AL_REFERENCE_DISTANCE:
931 case AL_ROLLOFF_FACTOR:
932 case AL_CONE_OUTER_GAIN:
933 case AL_MAX_DISTANCE:
934 case AL_DOPPLER_FACTOR:
935 case AL_CONE_OUTER_GAINHF:
936 case AL_AIR_ABSORPTION_FACTOR:
937 case AL_ROOM_ROLLOFF_FACTOR:
938 case AL_SOURCE_RADIUS:
939 fvals[0] = (ALfloat)*values;
940 return SetSourcefv(Source, Context, (int)prop, fvals);
942 /* 3x float */
943 case AL_POSITION:
944 case AL_VELOCITY:
945 case AL_DIRECTION:
946 fvals[0] = (ALfloat)values[0];
947 fvals[1] = (ALfloat)values[1];
948 fvals[2] = (ALfloat)values[2];
949 return SetSourcefv(Source, Context, (int)prop, fvals);
951 /* 6x float */
952 case AL_ORIENTATION:
953 fvals[0] = (ALfloat)values[0];
954 fvals[1] = (ALfloat)values[1];
955 fvals[2] = (ALfloat)values[2];
956 fvals[3] = (ALfloat)values[3];
957 fvals[4] = (ALfloat)values[4];
958 fvals[5] = (ALfloat)values[5];
959 return SetSourcefv(Source, Context, (int)prop, fvals);
961 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
962 case AL_SEC_OFFSET_LATENCY_SOFT:
963 case AL_STEREO_ANGLES:
964 break;
967 ERR("Unexpected property: 0x%04x\n", prop);
968 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
971 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
973 ALfloat fvals[6];
974 ALint ivals[3];
976 switch(prop)
978 case AL_SOURCE_TYPE:
979 case AL_BUFFERS_QUEUED:
980 case AL_BUFFERS_PROCESSED:
981 case AL_SOURCE_STATE:
982 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
983 case AL_BYTE_LENGTH_SOFT:
984 case AL_SAMPLE_LENGTH_SOFT:
985 case AL_SEC_LENGTH_SOFT:
986 /* Query only */
987 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
990 /* 1x int */
991 case AL_SOURCE_RELATIVE:
992 case AL_LOOPING:
993 case AL_SEC_OFFSET:
994 case AL_SAMPLE_OFFSET:
995 case AL_BYTE_OFFSET:
996 case AL_DIRECT_FILTER_GAINHF_AUTO:
997 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
998 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
999 case AL_DIRECT_CHANNELS_SOFT:
1000 case AL_DISTANCE_MODEL:
1001 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
1003 ivals[0] = (ALint)*values;
1004 return SetSourceiv(Source, Context, (int)prop, ivals);
1006 /* 1x uint */
1007 case AL_BUFFER:
1008 case AL_DIRECT_FILTER:
1009 CHECKVAL(*values <= UINT_MAX && *values >= 0);
1011 ivals[0] = (ALuint)*values;
1012 return SetSourceiv(Source, Context, (int)prop, ivals);
1014 /* 3x uint */
1015 case AL_AUXILIARY_SEND_FILTER:
1016 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
1017 values[1] <= UINT_MAX && values[1] >= 0 &&
1018 values[2] <= UINT_MAX && values[2] >= 0);
1020 ivals[0] = (ALuint)values[0];
1021 ivals[1] = (ALuint)values[1];
1022 ivals[2] = (ALuint)values[2];
1023 return SetSourceiv(Source, Context, (int)prop, ivals);
1025 /* 1x float */
1026 case AL_CONE_INNER_ANGLE:
1027 case AL_CONE_OUTER_ANGLE:
1028 case AL_PITCH:
1029 case AL_GAIN:
1030 case AL_MIN_GAIN:
1031 case AL_MAX_GAIN:
1032 case AL_REFERENCE_DISTANCE:
1033 case AL_ROLLOFF_FACTOR:
1034 case AL_CONE_OUTER_GAIN:
1035 case AL_MAX_DISTANCE:
1036 case AL_DOPPLER_FACTOR:
1037 case AL_CONE_OUTER_GAINHF:
1038 case AL_AIR_ABSORPTION_FACTOR:
1039 case AL_ROOM_ROLLOFF_FACTOR:
1040 case AL_SOURCE_RADIUS:
1041 fvals[0] = (ALfloat)*values;
1042 return SetSourcefv(Source, Context, (int)prop, fvals);
1044 /* 3x float */
1045 case AL_POSITION:
1046 case AL_VELOCITY:
1047 case AL_DIRECTION:
1048 fvals[0] = (ALfloat)values[0];
1049 fvals[1] = (ALfloat)values[1];
1050 fvals[2] = (ALfloat)values[2];
1051 return SetSourcefv(Source, Context, (int)prop, fvals);
1053 /* 6x float */
1054 case AL_ORIENTATION:
1055 fvals[0] = (ALfloat)values[0];
1056 fvals[1] = (ALfloat)values[1];
1057 fvals[2] = (ALfloat)values[2];
1058 fvals[3] = (ALfloat)values[3];
1059 fvals[4] = (ALfloat)values[4];
1060 fvals[5] = (ALfloat)values[5];
1061 return SetSourcefv(Source, Context, (int)prop, fvals);
1063 case AL_SEC_OFFSET_LATENCY_SOFT:
1064 case AL_STEREO_ANGLES:
1065 break;
1068 ERR("Unexpected property: 0x%04x\n", prop);
1069 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1072 #undef CHECKVAL
1075 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
1077 ALCdevice *device = Context->Device;
1078 ALbufferlistitem *BufferList;
1079 ClockLatency clocktime;
1080 ALuint64 srcclock;
1081 ALint ivals[3];
1082 ALboolean err;
1084 switch(prop)
1086 case AL_GAIN:
1087 *values = Source->Gain;
1088 return AL_TRUE;
1090 case AL_PITCH:
1091 *values = Source->Pitch;
1092 return AL_TRUE;
1094 case AL_MAX_DISTANCE:
1095 *values = Source->MaxDistance;
1096 return AL_TRUE;
1098 case AL_ROLLOFF_FACTOR:
1099 *values = Source->RollOffFactor;
1100 return AL_TRUE;
1102 case AL_REFERENCE_DISTANCE:
1103 *values = Source->RefDistance;
1104 return AL_TRUE;
1106 case AL_CONE_INNER_ANGLE:
1107 *values = Source->InnerAngle;
1108 return AL_TRUE;
1110 case AL_CONE_OUTER_ANGLE:
1111 *values = Source->OuterAngle;
1112 return AL_TRUE;
1114 case AL_MIN_GAIN:
1115 *values = Source->MinGain;
1116 return AL_TRUE;
1118 case AL_MAX_GAIN:
1119 *values = Source->MaxGain;
1120 return AL_TRUE;
1122 case AL_CONE_OUTER_GAIN:
1123 *values = Source->OuterGain;
1124 return AL_TRUE;
1126 case AL_SEC_OFFSET:
1127 case AL_SAMPLE_OFFSET:
1128 case AL_BYTE_OFFSET:
1129 *values = GetSourceOffset(Source, prop, Context);
1130 return AL_TRUE;
1132 case AL_CONE_OUTER_GAINHF:
1133 *values = Source->OuterGainHF;
1134 return AL_TRUE;
1136 case AL_AIR_ABSORPTION_FACTOR:
1137 *values = Source->AirAbsorptionFactor;
1138 return AL_TRUE;
1140 case AL_ROOM_ROLLOFF_FACTOR:
1141 *values = Source->RoomRolloffFactor;
1142 return AL_TRUE;
1144 case AL_DOPPLER_FACTOR:
1145 *values = Source->DopplerFactor;
1146 return AL_TRUE;
1148 case AL_SEC_LENGTH_SOFT:
1149 ReadLock(&Source->queue_lock);
1150 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1151 *values = 0;
1152 else
1154 ALint length = 0;
1155 ALsizei freq = 1;
1156 do {
1157 ALbuffer *buffer = BufferList->buffer;
1158 if(buffer && buffer->SampleLen > 0)
1160 freq = buffer->Frequency;
1161 length += buffer->SampleLen;
1163 } while((BufferList=BufferList->next) != NULL);
1164 *values = (ALdouble)length / (ALdouble)freq;
1166 ReadUnlock(&Source->queue_lock);
1167 return AL_TRUE;
1169 case AL_SOURCE_RADIUS:
1170 *values = Source->Radius;
1171 return AL_TRUE;
1173 case AL_STEREO_ANGLES:
1174 values[0] = Source->StereoPan[0];
1175 values[1] = Source->StereoPan[1];
1176 return AL_TRUE;
1178 case AL_SEC_OFFSET_LATENCY_SOFT:
1179 /* Get the source offset with the clock time first. Then get the
1180 * clock time with the device latency. Order is important.
1182 values[0] = GetSourceSecOffset(Source, Context, &srcclock);
1183 clocktime = V0(device->Backend,getClockLatency)();
1184 if(srcclock == (ALuint64)clocktime.ClockTime)
1185 values[1] = (ALdouble)clocktime.Latency / 1000000000.0;
1186 else
1188 /* If the clock time incremented, reduce the latency by that
1189 * much since it's that much closer to the source offset it got
1190 * earlier.
1192 ALuint64 diff = clocktime.ClockTime - srcclock;
1193 values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) /
1194 1000000000.0;
1196 return AL_TRUE;
1198 case AL_POSITION:
1199 values[0] = Source->Position[0];
1200 values[1] = Source->Position[1];
1201 values[2] = Source->Position[2];
1202 return AL_TRUE;
1204 case AL_VELOCITY:
1205 values[0] = Source->Velocity[0];
1206 values[1] = Source->Velocity[1];
1207 values[2] = Source->Velocity[2];
1208 return AL_TRUE;
1210 case AL_DIRECTION:
1211 values[0] = Source->Direction[0];
1212 values[1] = Source->Direction[1];
1213 values[2] = Source->Direction[2];
1214 return AL_TRUE;
1216 case AL_ORIENTATION:
1217 values[0] = Source->Orientation[0][0];
1218 values[1] = Source->Orientation[0][1];
1219 values[2] = Source->Orientation[0][2];
1220 values[3] = Source->Orientation[1][0];
1221 values[4] = Source->Orientation[1][1];
1222 values[5] = Source->Orientation[1][2];
1223 return AL_TRUE;
1225 /* 1x int */
1226 case AL_SOURCE_RELATIVE:
1227 case AL_LOOPING:
1228 case AL_SOURCE_STATE:
1229 case AL_BUFFERS_QUEUED:
1230 case AL_BUFFERS_PROCESSED:
1231 case AL_SOURCE_TYPE:
1232 case AL_DIRECT_FILTER_GAINHF_AUTO:
1233 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1234 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1235 case AL_DIRECT_CHANNELS_SOFT:
1236 case AL_BYTE_LENGTH_SOFT:
1237 case AL_SAMPLE_LENGTH_SOFT:
1238 case AL_DISTANCE_MODEL:
1239 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1240 *values = (ALdouble)ivals[0];
1241 return err;
1243 case AL_BUFFER:
1244 case AL_DIRECT_FILTER:
1245 case AL_AUXILIARY_SEND_FILTER:
1246 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1247 break;
1250 ERR("Unexpected property: 0x%04x\n", prop);
1251 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1254 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1256 ALbufferlistitem *BufferList;
1257 ALdouble dvals[6];
1258 ALboolean err;
1260 switch(prop)
1262 case AL_SOURCE_RELATIVE:
1263 *values = Source->HeadRelative;
1264 return AL_TRUE;
1266 case AL_LOOPING:
1267 *values = ATOMIC_LOAD_SEQ(&Source->looping);
1268 return AL_TRUE;
1270 case AL_BUFFER:
1271 ReadLock(&Source->queue_lock);
1272 BufferList = (Source->SourceType == AL_STATIC) ?
1273 ATOMIC_LOAD_SEQ(&Source->queue) : NULL;
1274 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1275 ReadUnlock(&Source->queue_lock);
1276 return AL_TRUE;
1278 case AL_SOURCE_STATE:
1279 *values = GetSourceState(Source, GetSourceVoice(Source, Context));
1280 return AL_TRUE;
1282 case AL_BYTE_LENGTH_SOFT:
1283 ReadLock(&Source->queue_lock);
1284 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1285 *values = 0;
1286 else
1288 ALint length = 0;
1289 do {
1290 ALbuffer *buffer = BufferList->buffer;
1291 if(buffer && buffer->SampleLen > 0)
1293 ALuint byte_align, sample_align;
1294 if(buffer->OriginalType == UserFmtIMA4)
1296 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1297 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1298 sample_align = buffer->OriginalAlign;
1300 else if(buffer->OriginalType == UserFmtMSADPCM)
1302 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1303 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1304 sample_align = buffer->OriginalAlign;
1306 else
1308 ALsizei align = buffer->OriginalAlign;
1309 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1310 sample_align = buffer->OriginalAlign;
1313 length += buffer->SampleLen / sample_align * byte_align;
1315 } while((BufferList=BufferList->next) != NULL);
1316 *values = length;
1318 ReadUnlock(&Source->queue_lock);
1319 return AL_TRUE;
1321 case AL_SAMPLE_LENGTH_SOFT:
1322 ReadLock(&Source->queue_lock);
1323 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1324 *values = 0;
1325 else
1327 ALint length = 0;
1328 do {
1329 ALbuffer *buffer = BufferList->buffer;
1330 if(buffer) length += buffer->SampleLen;
1331 } while((BufferList=BufferList->next) != NULL);
1332 *values = length;
1334 ReadUnlock(&Source->queue_lock);
1335 return AL_TRUE;
1337 case AL_BUFFERS_QUEUED:
1338 ReadLock(&Source->queue_lock);
1339 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1340 *values = 0;
1341 else
1343 ALsizei count = 0;
1344 do {
1345 ++count;
1346 } while((BufferList=BufferList->next) != NULL);
1347 *values = count;
1349 ReadUnlock(&Source->queue_lock);
1350 return AL_TRUE;
1352 case AL_BUFFERS_PROCESSED:
1353 ReadLock(&Source->queue_lock);
1354 if(ATOMIC_LOAD_SEQ(&Source->looping) || Source->SourceType != AL_STREAMING)
1356 /* Buffers on a looping source are in a perpetual state of
1357 * PENDING, so don't report any as PROCESSED */
1358 *values = 0;
1360 else
1362 const ALbufferlistitem *BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
1363 const ALbufferlistitem *Current = NULL;
1364 ALsizei played = 0;
1365 ALvoice *voice;
1367 if((voice=GetSourceVoice(Source, Context)) != NULL)
1368 Current = ATOMIC_LOAD_SEQ(&voice->current_buffer);
1369 else if(ATOMIC_LOAD_SEQ(&Source->state) == AL_INITIAL)
1370 Current = BufferList;
1372 while(BufferList && BufferList != Current)
1374 played++;
1375 BufferList = BufferList->next;
1377 *values = played;
1379 ReadUnlock(&Source->queue_lock);
1380 return AL_TRUE;
1382 case AL_SOURCE_TYPE:
1383 *values = Source->SourceType;
1384 return AL_TRUE;
1386 case AL_DIRECT_FILTER_GAINHF_AUTO:
1387 *values = Source->DryGainHFAuto;
1388 return AL_TRUE;
1390 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1391 *values = Source->WetGainAuto;
1392 return AL_TRUE;
1394 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1395 *values = Source->WetGainHFAuto;
1396 return AL_TRUE;
1398 case AL_DIRECT_CHANNELS_SOFT:
1399 *values = Source->DirectChannels;
1400 return AL_TRUE;
1402 case AL_DISTANCE_MODEL:
1403 *values = Source->DistanceModel;
1404 return AL_TRUE;
1406 /* 1x float/double */
1407 case AL_CONE_INNER_ANGLE:
1408 case AL_CONE_OUTER_ANGLE:
1409 case AL_PITCH:
1410 case AL_GAIN:
1411 case AL_MIN_GAIN:
1412 case AL_MAX_GAIN:
1413 case AL_REFERENCE_DISTANCE:
1414 case AL_ROLLOFF_FACTOR:
1415 case AL_CONE_OUTER_GAIN:
1416 case AL_MAX_DISTANCE:
1417 case AL_SEC_OFFSET:
1418 case AL_SAMPLE_OFFSET:
1419 case AL_BYTE_OFFSET:
1420 case AL_DOPPLER_FACTOR:
1421 case AL_AIR_ABSORPTION_FACTOR:
1422 case AL_ROOM_ROLLOFF_FACTOR:
1423 case AL_CONE_OUTER_GAINHF:
1424 case AL_SEC_LENGTH_SOFT:
1425 case AL_SOURCE_RADIUS:
1426 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1427 *values = (ALint)dvals[0];
1428 return err;
1430 /* 3x float/double */
1431 case AL_POSITION:
1432 case AL_VELOCITY:
1433 case AL_DIRECTION:
1434 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1436 values[0] = (ALint)dvals[0];
1437 values[1] = (ALint)dvals[1];
1438 values[2] = (ALint)dvals[2];
1440 return err;
1442 /* 6x float/double */
1443 case AL_ORIENTATION:
1444 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1446 values[0] = (ALint)dvals[0];
1447 values[1] = (ALint)dvals[1];
1448 values[2] = (ALint)dvals[2];
1449 values[3] = (ALint)dvals[3];
1450 values[4] = (ALint)dvals[4];
1451 values[5] = (ALint)dvals[5];
1453 return err;
1455 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1456 break; /* i64 only */
1457 case AL_SEC_OFFSET_LATENCY_SOFT:
1458 break; /* Double only */
1459 case AL_STEREO_ANGLES:
1460 break; /* Float/double only */
1462 case AL_DIRECT_FILTER:
1463 case AL_AUXILIARY_SEND_FILTER:
1464 break; /* ??? */
1467 ERR("Unexpected property: 0x%04x\n", prop);
1468 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1471 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1473 ALCdevice *device = Context->Device;
1474 ClockLatency clocktime;
1475 ALuint64 srcclock;
1476 ALdouble dvals[6];
1477 ALint ivals[3];
1478 ALboolean err;
1480 switch(prop)
1482 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1483 /* Get the source offset with the clock time first. Then get the
1484 * clock time with the device latency. Order is important.
1486 values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
1487 clocktime = V0(device->Backend,getClockLatency)();
1488 if(srcclock == (ALuint64)clocktime.ClockTime)
1489 values[1] = clocktime.Latency;
1490 else
1492 /* If the clock time incremented, reduce the latency by that
1493 * much since it's that much closer to the source offset it got
1494 * earlier.
1496 ALuint64 diff = clocktime.ClockTime - srcclock;
1497 values[1] = clocktime.Latency - minu64(clocktime.Latency, diff);
1499 return AL_TRUE;
1501 /* 1x float/double */
1502 case AL_CONE_INNER_ANGLE:
1503 case AL_CONE_OUTER_ANGLE:
1504 case AL_PITCH:
1505 case AL_GAIN:
1506 case AL_MIN_GAIN:
1507 case AL_MAX_GAIN:
1508 case AL_REFERENCE_DISTANCE:
1509 case AL_ROLLOFF_FACTOR:
1510 case AL_CONE_OUTER_GAIN:
1511 case AL_MAX_DISTANCE:
1512 case AL_SEC_OFFSET:
1513 case AL_SAMPLE_OFFSET:
1514 case AL_BYTE_OFFSET:
1515 case AL_DOPPLER_FACTOR:
1516 case AL_AIR_ABSORPTION_FACTOR:
1517 case AL_ROOM_ROLLOFF_FACTOR:
1518 case AL_CONE_OUTER_GAINHF:
1519 case AL_SEC_LENGTH_SOFT:
1520 case AL_SOURCE_RADIUS:
1521 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1522 *values = (ALint64)dvals[0];
1523 return err;
1525 /* 3x float/double */
1526 case AL_POSITION:
1527 case AL_VELOCITY:
1528 case AL_DIRECTION:
1529 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1531 values[0] = (ALint64)dvals[0];
1532 values[1] = (ALint64)dvals[1];
1533 values[2] = (ALint64)dvals[2];
1535 return err;
1537 /* 6x float/double */
1538 case AL_ORIENTATION:
1539 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1541 values[0] = (ALint64)dvals[0];
1542 values[1] = (ALint64)dvals[1];
1543 values[2] = (ALint64)dvals[2];
1544 values[3] = (ALint64)dvals[3];
1545 values[4] = (ALint64)dvals[4];
1546 values[5] = (ALint64)dvals[5];
1548 return err;
1550 /* 1x int */
1551 case AL_SOURCE_RELATIVE:
1552 case AL_LOOPING:
1553 case AL_SOURCE_STATE:
1554 case AL_BUFFERS_QUEUED:
1555 case AL_BUFFERS_PROCESSED:
1556 case AL_BYTE_LENGTH_SOFT:
1557 case AL_SAMPLE_LENGTH_SOFT:
1558 case AL_SOURCE_TYPE:
1559 case AL_DIRECT_FILTER_GAINHF_AUTO:
1560 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1561 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1562 case AL_DIRECT_CHANNELS_SOFT:
1563 case AL_DISTANCE_MODEL:
1564 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1565 *values = ivals[0];
1566 return err;
1568 /* 1x uint */
1569 case AL_BUFFER:
1570 case AL_DIRECT_FILTER:
1571 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1572 *values = (ALuint)ivals[0];
1573 return err;
1575 /* 3x uint */
1576 case AL_AUXILIARY_SEND_FILTER:
1577 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1579 values[0] = (ALuint)ivals[0];
1580 values[1] = (ALuint)ivals[1];
1581 values[2] = (ALuint)ivals[2];
1583 return err;
1585 case AL_SEC_OFFSET_LATENCY_SOFT:
1586 break; /* Double only */
1587 case AL_STEREO_ANGLES:
1588 break; /* Float/double only */
1591 ERR("Unexpected property: 0x%04x\n", prop);
1592 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1596 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1598 ALCdevice *device;
1599 ALCcontext *context;
1600 ALsizei cur = 0;
1601 ALenum err;
1603 context = GetContextRef();
1604 if(!context) return;
1606 if(!(n >= 0))
1607 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1608 device = context->Device;
1609 for(cur = 0;cur < n;cur++)
1611 ALsource *source = al_calloc(16, sizeof(ALsource));
1612 if(!source)
1614 alDeleteSources(cur, sources);
1615 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1617 InitSourceParams(source, device->NumAuxSends);
1619 err = NewThunkEntry(&source->id);
1620 if(err == AL_NO_ERROR)
1621 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1622 if(err != AL_NO_ERROR)
1624 FreeThunkEntry(source->id);
1625 memset(source, 0, sizeof(ALsource));
1626 al_free(source);
1628 alDeleteSources(cur, sources);
1629 SET_ERROR_AND_GOTO(context, err, done);
1632 sources[cur] = source->id;
1635 done:
1636 ALCcontext_DecRef(context);
1640 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1642 ALCdevice *device;
1643 ALCcontext *context;
1644 ALsource *Source;
1645 ALsizei i;
1647 context = GetContextRef();
1648 if(!context) return;
1650 LockSourcesWrite(context);
1651 if(!(n >= 0))
1652 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1654 /* Check that all Sources are valid */
1655 for(i = 0;i < n;i++)
1657 if(LookupSource(context, sources[i]) == NULL)
1658 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1660 device = context->Device;
1661 for(i = 0;i < n;i++)
1663 ALvoice *voice;
1665 if((Source=RemoveSource(context, sources[i])) == NULL)
1666 continue;
1667 FreeThunkEntry(Source->id);
1669 ALCdevice_Lock(device);
1670 if((voice=GetSourceVoice(Source, context)) != NULL)
1672 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
1673 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
1675 ALCdevice_Unlock(device);
1677 DeinitSource(Source, device->NumAuxSends);
1679 memset(Source, 0, sizeof(*Source));
1680 al_free(Source);
1683 done:
1684 UnlockSourcesWrite(context);
1685 ALCcontext_DecRef(context);
1689 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1691 ALCcontext *context;
1692 ALboolean ret;
1694 context = GetContextRef();
1695 if(!context) return AL_FALSE;
1697 LockSourcesRead(context);
1698 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1699 UnlockSourcesRead(context);
1701 ALCcontext_DecRef(context);
1703 return ret;
1707 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1709 ALCcontext *Context;
1710 ALsource *Source;
1712 Context = GetContextRef();
1713 if(!Context) return;
1715 WriteLock(&Context->PropLock);
1716 LockSourcesRead(Context);
1717 if((Source=LookupSource(Context, source)) == NULL)
1718 alSetError(Context, AL_INVALID_NAME);
1719 else if(!(FloatValsByProp(param) == 1))
1720 alSetError(Context, AL_INVALID_ENUM);
1721 else
1722 SetSourcefv(Source, Context, param, &value);
1723 UnlockSourcesRead(Context);
1724 WriteUnlock(&Context->PropLock);
1726 ALCcontext_DecRef(Context);
1729 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1731 ALCcontext *Context;
1732 ALsource *Source;
1734 Context = GetContextRef();
1735 if(!Context) return;
1737 WriteLock(&Context->PropLock);
1738 LockSourcesRead(Context);
1739 if((Source=LookupSource(Context, source)) == NULL)
1740 alSetError(Context, AL_INVALID_NAME);
1741 else if(!(FloatValsByProp(param) == 3))
1742 alSetError(Context, AL_INVALID_ENUM);
1743 else
1745 ALfloat fvals[3] = { value1, value2, value3 };
1746 SetSourcefv(Source, Context, param, fvals);
1748 UnlockSourcesRead(Context);
1749 WriteUnlock(&Context->PropLock);
1751 ALCcontext_DecRef(Context);
1754 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1756 ALCcontext *Context;
1757 ALsource *Source;
1759 Context = GetContextRef();
1760 if(!Context) return;
1762 WriteLock(&Context->PropLock);
1763 LockSourcesRead(Context);
1764 if((Source=LookupSource(Context, source)) == NULL)
1765 alSetError(Context, AL_INVALID_NAME);
1766 else if(!values)
1767 alSetError(Context, AL_INVALID_VALUE);
1768 else if(!(FloatValsByProp(param) > 0))
1769 alSetError(Context, AL_INVALID_ENUM);
1770 else
1771 SetSourcefv(Source, Context, param, values);
1772 UnlockSourcesRead(Context);
1773 WriteUnlock(&Context->PropLock);
1775 ALCcontext_DecRef(Context);
1779 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1781 ALCcontext *Context;
1782 ALsource *Source;
1784 Context = GetContextRef();
1785 if(!Context) return;
1787 WriteLock(&Context->PropLock);
1788 LockSourcesRead(Context);
1789 if((Source=LookupSource(Context, source)) == NULL)
1790 alSetError(Context, AL_INVALID_NAME);
1791 else if(!(DoubleValsByProp(param) == 1))
1792 alSetError(Context, AL_INVALID_ENUM);
1793 else
1795 ALfloat fval = (ALfloat)value;
1796 SetSourcefv(Source, Context, param, &fval);
1798 UnlockSourcesRead(Context);
1799 WriteUnlock(&Context->PropLock);
1801 ALCcontext_DecRef(Context);
1804 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1806 ALCcontext *Context;
1807 ALsource *Source;
1809 Context = GetContextRef();
1810 if(!Context) return;
1812 WriteLock(&Context->PropLock);
1813 LockSourcesRead(Context);
1814 if((Source=LookupSource(Context, source)) == NULL)
1815 alSetError(Context, AL_INVALID_NAME);
1816 else if(!(DoubleValsByProp(param) == 3))
1817 alSetError(Context, AL_INVALID_ENUM);
1818 else
1820 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1821 SetSourcefv(Source, Context, param, fvals);
1823 UnlockSourcesRead(Context);
1824 WriteUnlock(&Context->PropLock);
1826 ALCcontext_DecRef(Context);
1829 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1831 ALCcontext *Context;
1832 ALsource *Source;
1833 ALint count;
1835 Context = GetContextRef();
1836 if(!Context) return;
1838 WriteLock(&Context->PropLock);
1839 LockSourcesRead(Context);
1840 if((Source=LookupSource(Context, source)) == NULL)
1841 alSetError(Context, AL_INVALID_NAME);
1842 else if(!values)
1843 alSetError(Context, AL_INVALID_VALUE);
1844 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1845 alSetError(Context, AL_INVALID_ENUM);
1846 else
1848 ALfloat fvals[6];
1849 ALint i;
1851 for(i = 0;i < count;i++)
1852 fvals[i] = (ALfloat)values[i];
1853 SetSourcefv(Source, Context, param, fvals);
1855 UnlockSourcesRead(Context);
1856 WriteUnlock(&Context->PropLock);
1858 ALCcontext_DecRef(Context);
1862 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1864 ALCcontext *Context;
1865 ALsource *Source;
1867 Context = GetContextRef();
1868 if(!Context) return;
1870 WriteLock(&Context->PropLock);
1871 LockSourcesRead(Context);
1872 if((Source=LookupSource(Context, source)) == NULL)
1873 alSetError(Context, AL_INVALID_NAME);
1874 else if(!(IntValsByProp(param) == 1))
1875 alSetError(Context, AL_INVALID_ENUM);
1876 else
1877 SetSourceiv(Source, Context, param, &value);
1878 UnlockSourcesRead(Context);
1879 WriteUnlock(&Context->PropLock);
1881 ALCcontext_DecRef(Context);
1884 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1886 ALCcontext *Context;
1887 ALsource *Source;
1889 Context = GetContextRef();
1890 if(!Context) return;
1892 WriteLock(&Context->PropLock);
1893 LockSourcesRead(Context);
1894 if((Source=LookupSource(Context, source)) == NULL)
1895 alSetError(Context, AL_INVALID_NAME);
1896 else if(!(IntValsByProp(param) == 3))
1897 alSetError(Context, AL_INVALID_ENUM);
1898 else
1900 ALint ivals[3] = { value1, value2, value3 };
1901 SetSourceiv(Source, Context, param, ivals);
1903 UnlockSourcesRead(Context);
1904 WriteUnlock(&Context->PropLock);
1906 ALCcontext_DecRef(Context);
1909 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1911 ALCcontext *Context;
1912 ALsource *Source;
1914 Context = GetContextRef();
1915 if(!Context) return;
1917 WriteLock(&Context->PropLock);
1918 LockSourcesRead(Context);
1919 if((Source=LookupSource(Context, source)) == NULL)
1920 alSetError(Context, AL_INVALID_NAME);
1921 else if(!values)
1922 alSetError(Context, AL_INVALID_VALUE);
1923 else if(!(IntValsByProp(param) > 0))
1924 alSetError(Context, AL_INVALID_ENUM);
1925 else
1926 SetSourceiv(Source, Context, param, values);
1927 UnlockSourcesRead(Context);
1928 WriteUnlock(&Context->PropLock);
1930 ALCcontext_DecRef(Context);
1934 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1936 ALCcontext *Context;
1937 ALsource *Source;
1939 Context = GetContextRef();
1940 if(!Context) return;
1942 WriteLock(&Context->PropLock);
1943 LockSourcesRead(Context);
1944 if((Source=LookupSource(Context, source)) == NULL)
1945 alSetError(Context, AL_INVALID_NAME);
1946 else if(!(Int64ValsByProp(param) == 1))
1947 alSetError(Context, AL_INVALID_ENUM);
1948 else
1949 SetSourcei64v(Source, Context, param, &value);
1950 UnlockSourcesRead(Context);
1951 WriteUnlock(&Context->PropLock);
1953 ALCcontext_DecRef(Context);
1956 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1958 ALCcontext *Context;
1959 ALsource *Source;
1961 Context = GetContextRef();
1962 if(!Context) return;
1964 WriteLock(&Context->PropLock);
1965 LockSourcesRead(Context);
1966 if((Source=LookupSource(Context, source)) == NULL)
1967 alSetError(Context, AL_INVALID_NAME);
1968 else if(!(Int64ValsByProp(param) == 3))
1969 alSetError(Context, AL_INVALID_ENUM);
1970 else
1972 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1973 SetSourcei64v(Source, Context, param, i64vals);
1975 UnlockSourcesRead(Context);
1976 WriteUnlock(&Context->PropLock);
1978 ALCcontext_DecRef(Context);
1981 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1983 ALCcontext *Context;
1984 ALsource *Source;
1986 Context = GetContextRef();
1987 if(!Context) return;
1989 WriteLock(&Context->PropLock);
1990 LockSourcesRead(Context);
1991 if((Source=LookupSource(Context, source)) == NULL)
1992 alSetError(Context, AL_INVALID_NAME);
1993 else if(!values)
1994 alSetError(Context, AL_INVALID_VALUE);
1995 else if(!(Int64ValsByProp(param) > 0))
1996 alSetError(Context, AL_INVALID_ENUM);
1997 else
1998 SetSourcei64v(Source, Context, param, values);
1999 UnlockSourcesRead(Context);
2000 WriteUnlock(&Context->PropLock);
2002 ALCcontext_DecRef(Context);
2006 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
2008 ALCcontext *Context;
2009 ALsource *Source;
2011 Context = GetContextRef();
2012 if(!Context) return;
2014 ReadLock(&Context->PropLock);
2015 LockSourcesRead(Context);
2016 if((Source=LookupSource(Context, source)) == NULL)
2017 alSetError(Context, AL_INVALID_NAME);
2018 else if(!value)
2019 alSetError(Context, AL_INVALID_VALUE);
2020 else if(!(FloatValsByProp(param) == 1))
2021 alSetError(Context, AL_INVALID_ENUM);
2022 else
2024 ALdouble dval;
2025 if(GetSourcedv(Source, Context, param, &dval))
2026 *value = (ALfloat)dval;
2028 UnlockSourcesRead(Context);
2029 ReadUnlock(&Context->PropLock);
2031 ALCcontext_DecRef(Context);
2035 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
2037 ALCcontext *Context;
2038 ALsource *Source;
2040 Context = GetContextRef();
2041 if(!Context) return;
2043 ReadLock(&Context->PropLock);
2044 LockSourcesRead(Context);
2045 if((Source=LookupSource(Context, source)) == NULL)
2046 alSetError(Context, AL_INVALID_NAME);
2047 else if(!(value1 && value2 && value3))
2048 alSetError(Context, AL_INVALID_VALUE);
2049 else if(!(FloatValsByProp(param) == 3))
2050 alSetError(Context, AL_INVALID_ENUM);
2051 else
2053 ALdouble dvals[3];
2054 if(GetSourcedv(Source, Context, param, dvals))
2056 *value1 = (ALfloat)dvals[0];
2057 *value2 = (ALfloat)dvals[1];
2058 *value3 = (ALfloat)dvals[2];
2061 UnlockSourcesRead(Context);
2062 ReadUnlock(&Context->PropLock);
2064 ALCcontext_DecRef(Context);
2068 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
2070 ALCcontext *Context;
2071 ALsource *Source;
2072 ALint count;
2074 Context = GetContextRef();
2075 if(!Context) return;
2077 ReadLock(&Context->PropLock);
2078 LockSourcesRead(Context);
2079 if((Source=LookupSource(Context, source)) == NULL)
2080 alSetError(Context, AL_INVALID_NAME);
2081 else if(!values)
2082 alSetError(Context, AL_INVALID_VALUE);
2083 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
2084 alSetError(Context, AL_INVALID_ENUM);
2085 else
2087 ALdouble dvals[6];
2088 if(GetSourcedv(Source, Context, param, dvals))
2090 ALint i;
2091 for(i = 0;i < count;i++)
2092 values[i] = (ALfloat)dvals[i];
2095 UnlockSourcesRead(Context);
2096 ReadUnlock(&Context->PropLock);
2098 ALCcontext_DecRef(Context);
2102 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
2104 ALCcontext *Context;
2105 ALsource *Source;
2107 Context = GetContextRef();
2108 if(!Context) return;
2110 ReadLock(&Context->PropLock);
2111 LockSourcesRead(Context);
2112 if((Source=LookupSource(Context, source)) == NULL)
2113 alSetError(Context, AL_INVALID_NAME);
2114 else if(!value)
2115 alSetError(Context, AL_INVALID_VALUE);
2116 else if(!(DoubleValsByProp(param) == 1))
2117 alSetError(Context, AL_INVALID_ENUM);
2118 else
2119 GetSourcedv(Source, Context, param, value);
2120 UnlockSourcesRead(Context);
2121 ReadUnlock(&Context->PropLock);
2123 ALCcontext_DecRef(Context);
2126 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
2128 ALCcontext *Context;
2129 ALsource *Source;
2131 Context = GetContextRef();
2132 if(!Context) return;
2134 ReadLock(&Context->PropLock);
2135 LockSourcesRead(Context);
2136 if((Source=LookupSource(Context, source)) == NULL)
2137 alSetError(Context, AL_INVALID_NAME);
2138 else if(!(value1 && value2 && value3))
2139 alSetError(Context, AL_INVALID_VALUE);
2140 else if(!(DoubleValsByProp(param) == 3))
2141 alSetError(Context, AL_INVALID_ENUM);
2142 else
2144 ALdouble dvals[3];
2145 if(GetSourcedv(Source, Context, param, dvals))
2147 *value1 = dvals[0];
2148 *value2 = dvals[1];
2149 *value3 = dvals[2];
2152 UnlockSourcesRead(Context);
2153 ReadUnlock(&Context->PropLock);
2155 ALCcontext_DecRef(Context);
2158 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
2160 ALCcontext *Context;
2161 ALsource *Source;
2163 Context = GetContextRef();
2164 if(!Context) return;
2166 ReadLock(&Context->PropLock);
2167 LockSourcesRead(Context);
2168 if((Source=LookupSource(Context, source)) == NULL)
2169 alSetError(Context, AL_INVALID_NAME);
2170 else if(!values)
2171 alSetError(Context, AL_INVALID_VALUE);
2172 else if(!(DoubleValsByProp(param) > 0))
2173 alSetError(Context, AL_INVALID_ENUM);
2174 else
2175 GetSourcedv(Source, Context, param, values);
2176 UnlockSourcesRead(Context);
2177 ReadUnlock(&Context->PropLock);
2179 ALCcontext_DecRef(Context);
2183 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2185 ALCcontext *Context;
2186 ALsource *Source;
2188 Context = GetContextRef();
2189 if(!Context) return;
2191 ReadLock(&Context->PropLock);
2192 LockSourcesRead(Context);
2193 if((Source=LookupSource(Context, source)) == NULL)
2194 alSetError(Context, AL_INVALID_NAME);
2195 else if(!value)
2196 alSetError(Context, AL_INVALID_VALUE);
2197 else if(!(IntValsByProp(param) == 1))
2198 alSetError(Context, AL_INVALID_ENUM);
2199 else
2200 GetSourceiv(Source, Context, param, value);
2201 UnlockSourcesRead(Context);
2202 ReadUnlock(&Context->PropLock);
2204 ALCcontext_DecRef(Context);
2208 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2210 ALCcontext *Context;
2211 ALsource *Source;
2213 Context = GetContextRef();
2214 if(!Context) return;
2216 ReadLock(&Context->PropLock);
2217 LockSourcesRead(Context);
2218 if((Source=LookupSource(Context, source)) == NULL)
2219 alSetError(Context, AL_INVALID_NAME);
2220 else if(!(value1 && value2 && value3))
2221 alSetError(Context, AL_INVALID_VALUE);
2222 else if(!(IntValsByProp(param) == 3))
2223 alSetError(Context, AL_INVALID_ENUM);
2224 else
2226 ALint ivals[3];
2227 if(GetSourceiv(Source, Context, param, ivals))
2229 *value1 = ivals[0];
2230 *value2 = ivals[1];
2231 *value3 = ivals[2];
2234 UnlockSourcesRead(Context);
2235 ReadUnlock(&Context->PropLock);
2237 ALCcontext_DecRef(Context);
2241 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2243 ALCcontext *Context;
2244 ALsource *Source;
2246 Context = GetContextRef();
2247 if(!Context) return;
2249 ReadLock(&Context->PropLock);
2250 LockSourcesRead(Context);
2251 if((Source=LookupSource(Context, source)) == NULL)
2252 alSetError(Context, AL_INVALID_NAME);
2253 else if(!values)
2254 alSetError(Context, AL_INVALID_VALUE);
2255 else if(!(IntValsByProp(param) > 0))
2256 alSetError(Context, AL_INVALID_ENUM);
2257 else
2258 GetSourceiv(Source, Context, param, values);
2259 UnlockSourcesRead(Context);
2260 ReadUnlock(&Context->PropLock);
2262 ALCcontext_DecRef(Context);
2266 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2268 ALCcontext *Context;
2269 ALsource *Source;
2271 Context = GetContextRef();
2272 if(!Context) return;
2274 ReadLock(&Context->PropLock);
2275 LockSourcesRead(Context);
2276 if((Source=LookupSource(Context, source)) == NULL)
2277 alSetError(Context, AL_INVALID_NAME);
2278 else if(!value)
2279 alSetError(Context, AL_INVALID_VALUE);
2280 else if(!(Int64ValsByProp(param) == 1))
2281 alSetError(Context, AL_INVALID_ENUM);
2282 else
2283 GetSourcei64v(Source, Context, param, value);
2284 UnlockSourcesRead(Context);
2285 ReadUnlock(&Context->PropLock);
2287 ALCcontext_DecRef(Context);
2290 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2292 ALCcontext *Context;
2293 ALsource *Source;
2295 Context = GetContextRef();
2296 if(!Context) return;
2298 ReadLock(&Context->PropLock);
2299 LockSourcesRead(Context);
2300 if((Source=LookupSource(Context, source)) == NULL)
2301 alSetError(Context, AL_INVALID_NAME);
2302 else if(!(value1 && value2 && value3))
2303 alSetError(Context, AL_INVALID_VALUE);
2304 else if(!(Int64ValsByProp(param) == 3))
2305 alSetError(Context, AL_INVALID_ENUM);
2306 else
2308 ALint64 i64vals[3];
2309 if(GetSourcei64v(Source, Context, param, i64vals))
2311 *value1 = i64vals[0];
2312 *value2 = i64vals[1];
2313 *value3 = i64vals[2];
2316 UnlockSourcesRead(Context);
2317 ReadUnlock(&Context->PropLock);
2319 ALCcontext_DecRef(Context);
2322 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2324 ALCcontext *Context;
2325 ALsource *Source;
2327 Context = GetContextRef();
2328 if(!Context) return;
2330 ReadLock(&Context->PropLock);
2331 LockSourcesRead(Context);
2332 if((Source=LookupSource(Context, source)) == NULL)
2333 alSetError(Context, AL_INVALID_NAME);
2334 else if(!values)
2335 alSetError(Context, AL_INVALID_VALUE);
2336 else if(!(Int64ValsByProp(param) > 0))
2337 alSetError(Context, AL_INVALID_ENUM);
2338 else
2339 GetSourcei64v(Source, Context, param, values);
2340 UnlockSourcesRead(Context);
2341 ReadUnlock(&Context->PropLock);
2343 ALCcontext_DecRef(Context);
2347 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2349 alSourcePlayv(1, &source);
2351 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2353 ALCcontext *context;
2354 ALCdevice *device;
2355 ALsource *source;
2356 ALvoice *voice;
2357 ALsizei i, j;
2359 context = GetContextRef();
2360 if(!context) return;
2362 LockSourcesRead(context);
2363 if(!(n >= 0))
2364 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2365 for(i = 0;i < n;i++)
2367 if(!LookupSource(context, sources[i]))
2368 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2371 device = context->Device;
2372 ALCdevice_Lock(device);
2373 /* If the device is disconnected, go right to stopped. */
2374 if(!device->Connected)
2376 for(i = 0;i < n;i++)
2378 source = LookupSource(context, sources[i]);
2379 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2381 ALCdevice_Unlock(device);
2382 goto done;
2385 while(n > context->MaxVoices-context->VoiceCount)
2387 ALsizei newcount = context->MaxVoices << 1;
2388 if(context->MaxVoices >= newcount)
2390 ALCdevice_Unlock(device);
2391 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2393 AllocateVoices(context, newcount, device->NumAuxSends);
2396 for(i = 0;i < n;i++)
2398 ALbufferlistitem *BufferList;
2399 ALbuffer *buffer = NULL;
2401 source = LookupSource(context, sources[i]);
2402 WriteLock(&source->queue_lock);
2403 /* Check that there is a queue containing at least one valid, non zero
2404 * length Buffer.
2406 BufferList = ATOMIC_LOAD_SEQ(&source->queue);
2407 while(BufferList)
2409 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2410 break;
2411 BufferList = BufferList->next;
2414 /* If there's nothing to play, go right to stopped. */
2415 if(!BufferList)
2417 /* NOTE: A source without any playable buffers should not have an
2418 * ALvoice since it shouldn't be in a playing or paused state. So
2419 * there's no need to look up its voice and clear the source.
2421 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2422 source->OffsetType = AL_NONE;
2423 source->Offset = 0.0;
2424 goto finish_play;
2427 voice = GetSourceVoice(source, context);
2428 switch(GetSourceState(source, voice))
2430 case AL_PLAYING:
2431 assert(voice != NULL);
2432 /* A source that's already playing is restarted from the beginning. */
2433 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
2434 ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
2435 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release);
2436 goto finish_play;
2438 case AL_PAUSED:
2439 assert(voice != NULL);
2440 /* A source that's paused simply resumes. Make sure it uses the
2441 * volume last specified; there's no reason to fade from where
2442 * it stopped at.
2444 voice->Flags &= ~VOICE_IS_MOVING;
2445 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
2446 ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release);
2447 goto finish_play;
2449 default:
2450 break;
2453 ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acquire);
2454 UpdateSourceProps(source, device->NumAuxSends);
2456 /* Make sure this source isn't already active, and if not, look for an
2457 * unused voice to put it in.
2459 assert(voice == NULL);
2460 for(j = 0;j < context->VoiceCount;j++)
2462 if(ATOMIC_LOAD(&context->Voices[j]->Source, almemory_order_acquire) == NULL)
2464 voice = context->Voices[j];
2465 break;
2468 if(voice == NULL)
2469 voice = context->Voices[context->VoiceCount++];
2470 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2471 ATOMIC_THREAD_FENCE(almemory_order_acquire);
2473 /* A source that's not playing or paused has any offset applied when it
2474 * starts playing.
2476 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
2477 ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
2478 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed);
2479 if(source->OffsetType != AL_NONE)
2480 ApplyOffset(source, voice);
2482 voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2483 voice->SampleSize = BytesFromFmt(buffer->FmtType);
2485 /* Clear previous samples. */
2486 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
2488 /* Clear the stepping value so the mixer knows not to mix this until
2489 * the update gets applied.
2491 voice->Step = 0;
2493 voice->Flags = 0;
2494 for(j = 0;j < voice->NumChannels;j++)
2495 memset(&voice->Direct.Params[j].Hrtf.State, 0,
2496 sizeof(voice->Direct.Params[j].Hrtf.State));
2497 if(device->AvgSpeakerDist > 0.0f)
2499 ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC /
2500 (device->AvgSpeakerDist * device->Frequency);
2501 for(j = 0;j < voice->NumChannels;j++)
2503 NfcFilterCreate1(&voice->Direct.Params[j].NFCtrlFilter[0], 0.0f, w1);
2504 NfcFilterCreate2(&voice->Direct.Params[j].NFCtrlFilter[1], 0.0f, w1);
2505 NfcFilterCreate3(&voice->Direct.Params[j].NFCtrlFilter[2], 0.0f, w1);
2509 ATOMIC_STORE(&voice->Source, source, almemory_order_relaxed);
2510 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
2511 ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release);
2512 finish_play:
2513 WriteUnlock(&source->queue_lock);
2515 ALCdevice_Unlock(device);
2517 done:
2518 UnlockSourcesRead(context);
2519 ALCcontext_DecRef(context);
2522 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2524 alSourcePausev(1, &source);
2526 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2528 ALCcontext *context;
2529 ALCdevice *device;
2530 ALsource *source;
2531 ALvoice *voice;
2532 ALsizei i;
2534 context = GetContextRef();
2535 if(!context) return;
2537 LockSourcesRead(context);
2538 if(!(n >= 0))
2539 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2540 for(i = 0;i < n;i++)
2542 if(!LookupSource(context, sources[i]))
2543 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2546 device = context->Device;
2547 ALCdevice_Lock(device);
2548 for(i = 0;i < n;i++)
2550 source = LookupSource(context, sources[i]);
2551 WriteLock(&source->queue_lock);
2552 if((voice=GetSourceVoice(source, context)) != NULL)
2554 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2555 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2556 althrd_yield();
2558 if(GetSourceState(source, voice) == AL_PLAYING)
2559 ATOMIC_STORE(&source->state, AL_PAUSED, almemory_order_release);
2560 WriteUnlock(&source->queue_lock);
2562 ALCdevice_Unlock(device);
2564 done:
2565 UnlockSourcesRead(context);
2566 ALCcontext_DecRef(context);
2569 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2571 alSourceStopv(1, &source);
2573 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2575 ALCcontext *context;
2576 ALCdevice *device;
2577 ALsource *source;
2578 ALvoice *voice;
2579 ALsizei i;
2581 context = GetContextRef();
2582 if(!context) return;
2584 LockSourcesRead(context);
2585 if(!(n >= 0))
2586 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2587 for(i = 0;i < n;i++)
2589 if(!LookupSource(context, sources[i]))
2590 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2593 device = context->Device;
2594 ALCdevice_Lock(device);
2595 for(i = 0;i < n;i++)
2597 source = LookupSource(context, sources[i]);
2598 WriteLock(&source->queue_lock);
2599 if((voice=GetSourceVoice(source, context)) != NULL)
2601 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
2602 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2603 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2604 althrd_yield();
2606 if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL)
2607 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2608 source->OffsetType = AL_NONE;
2609 source->Offset = 0.0;
2610 WriteUnlock(&source->queue_lock);
2612 ALCdevice_Unlock(device);
2614 done:
2615 UnlockSourcesRead(context);
2616 ALCcontext_DecRef(context);
2619 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2621 alSourceRewindv(1, &source);
2623 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2625 ALCcontext *context;
2626 ALCdevice *device;
2627 ALsource *source;
2628 ALvoice *voice;
2629 ALsizei i;
2631 context = GetContextRef();
2632 if(!context) return;
2634 LockSourcesRead(context);
2635 if(!(n >= 0))
2636 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2637 for(i = 0;i < n;i++)
2639 if(!LookupSource(context, sources[i]))
2640 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2643 device = context->Device;
2644 ALCdevice_Lock(device);
2645 for(i = 0;i < n;i++)
2647 source = LookupSource(context, sources[i]);
2648 WriteLock(&source->queue_lock);
2649 if((voice=GetSourceVoice(source, context)) != NULL)
2651 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
2652 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2653 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2654 althrd_yield();
2656 if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL)
2657 ATOMIC_STORE(&source->state, AL_INITIAL, almemory_order_relaxed);
2658 source->OffsetType = AL_NONE;
2659 source->Offset = 0.0;
2660 WriteUnlock(&source->queue_lock);
2662 ALCdevice_Unlock(device);
2664 done:
2665 UnlockSourcesRead(context);
2666 ALCcontext_DecRef(context);
2670 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2672 ALCdevice *device;
2673 ALCcontext *context;
2674 ALsource *source;
2675 ALsizei i;
2676 ALbufferlistitem *BufferListStart;
2677 ALbufferlistitem *BufferList;
2678 ALbuffer *BufferFmt = NULL;
2680 if(nb == 0)
2681 return;
2683 context = GetContextRef();
2684 if(!context) return;
2686 device = context->Device;
2688 LockSourcesRead(context);
2689 if(!(nb >= 0))
2690 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2691 if((source=LookupSource(context, src)) == NULL)
2692 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2694 WriteLock(&source->queue_lock);
2695 if(source->SourceType == AL_STATIC)
2697 WriteUnlock(&source->queue_lock);
2698 /* Can't queue on a Static Source */
2699 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2702 /* Check for a valid Buffer, for its frequency and format */
2703 BufferList = ATOMIC_LOAD_SEQ(&source->queue);
2704 while(BufferList)
2706 if(BufferList->buffer)
2708 BufferFmt = BufferList->buffer;
2709 break;
2711 BufferList = BufferList->next;
2714 LockBuffersRead(device);
2715 BufferListStart = NULL;
2716 BufferList = NULL;
2717 for(i = 0;i < nb;i++)
2719 ALbuffer *buffer = NULL;
2720 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2722 WriteUnlock(&source->queue_lock);
2723 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2726 if(!BufferListStart)
2728 BufferListStart = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
2729 BufferList = BufferListStart;
2731 else
2733 BufferList->next = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
2734 BufferList = BufferList->next;
2736 BufferList->buffer = buffer;
2737 BufferList->next = NULL;
2738 if(!buffer) continue;
2740 /* Hold a read lock on each buffer being queued while checking all
2741 * provided buffers. This is done so other threads don't see an extra
2742 * reference on some buffers if this operation ends up failing. */
2743 ReadLock(&buffer->lock);
2744 IncrementRef(&buffer->ref);
2746 if(BufferFmt == NULL)
2747 BufferFmt = buffer;
2748 else if(BufferFmt->Frequency != buffer->Frequency ||
2749 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2750 BufferFmt->OriginalType != buffer->OriginalType)
2752 WriteUnlock(&source->queue_lock);
2753 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2755 buffer_error:
2756 /* A buffer failed (invalid ID or format), so unlock and release
2757 * each buffer we had. */
2758 while(BufferListStart)
2760 ALbufferlistitem *next = BufferListStart->next;
2761 if((buffer=BufferListStart->buffer) != NULL)
2763 DecrementRef(&buffer->ref);
2764 ReadUnlock(&buffer->lock);
2766 al_free(BufferListStart);
2767 BufferListStart = next;
2769 UnlockBuffersRead(device);
2770 goto done;
2773 /* All buffers good, unlock them now. */
2774 BufferList = BufferListStart;
2775 while(BufferList != NULL)
2777 ALbuffer *buffer = BufferList->buffer;
2778 if(buffer) ReadUnlock(&buffer->lock);
2779 BufferList = BufferList->next;
2781 UnlockBuffersRead(device);
2783 /* Source is now streaming */
2784 source->SourceType = AL_STREAMING;
2786 BufferList = NULL;
2787 if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&source->queue, &BufferList,
2788 BufferListStart))
2790 /* Queue head is not NULL, append to the end of the queue */
2791 while(BufferList->next != NULL)
2792 BufferList = BufferList->next;
2793 BufferList->next = BufferListStart;
2795 WriteUnlock(&source->queue_lock);
2797 done:
2798 UnlockSourcesRead(context);
2799 ALCcontext_DecRef(context);
2802 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2804 ALCcontext *context;
2805 ALsource *source;
2806 ALbufferlistitem *OldHead;
2807 ALbufferlistitem *OldTail;
2808 ALbufferlistitem *Current;
2809 ALvoice *voice;
2810 ALsizei i = 0;
2812 context = GetContextRef();
2813 if(!context) return;
2815 LockSourcesRead(context);
2816 if(!(nb >= 0))
2817 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2819 if((source=LookupSource(context, src)) == NULL)
2820 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2822 /* Nothing to unqueue. */
2823 if(nb == 0) goto done;
2825 WriteLock(&source->queue_lock);
2826 if(ATOMIC_LOAD_SEQ(&source->looping) || source->SourceType != AL_STREAMING)
2828 WriteUnlock(&source->queue_lock);
2829 /* Trying to unqueue buffers on a looping or non-streaming source. */
2830 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2833 /* Find the new buffer queue head */
2834 OldTail = ATOMIC_LOAD_SEQ(&source->queue);
2835 Current = NULL;
2836 if((voice=GetSourceVoice(source, context)) != NULL)
2837 Current = ATOMIC_LOAD_SEQ(&voice->current_buffer);
2838 else if(ATOMIC_LOAD_SEQ(&source->state) == AL_INITIAL)
2839 Current = OldTail;
2840 if(OldTail != Current)
2842 for(i = 1;i < nb;i++)
2844 ALbufferlistitem *next = OldTail->next;
2845 if(!next || next == Current) break;
2846 OldTail = next;
2849 if(i != nb)
2851 WriteUnlock(&source->queue_lock);
2852 /* Trying to unqueue pending buffers. */
2853 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2856 /* Swap it, and cut the new head from the old. */
2857 OldHead = ATOMIC_EXCHANGE_PTR_SEQ(&source->queue, OldTail->next);
2858 if(OldTail->next)
2860 ALCdevice *device = context->Device;
2861 uint count;
2863 /* Once the active mix (if any) is done, it's safe to cut the old tail
2864 * from the new head.
2866 if(((count=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
2868 while(count == ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))
2869 althrd_yield();
2871 ATOMIC_THREAD_FENCE(almemory_order_acq_rel);
2872 OldTail->next = NULL;
2874 WriteUnlock(&source->queue_lock);
2876 while(OldHead != NULL)
2878 ALbufferlistitem *next = OldHead->next;
2879 ALbuffer *buffer = OldHead->buffer;
2881 if(!buffer)
2882 *(buffers++) = 0;
2883 else
2885 *(buffers++) = buffer->id;
2886 DecrementRef(&buffer->ref);
2889 al_free(OldHead);
2890 OldHead = next;
2893 done:
2894 UnlockSourcesRead(context);
2895 ALCcontext_DecRef(context);
2899 static void InitSourceParams(ALsource *Source, ALsizei num_sends)
2901 ALsizei i;
2903 RWLockInit(&Source->queue_lock);
2905 Source->InnerAngle = 360.0f;
2906 Source->OuterAngle = 360.0f;
2907 Source->Pitch = 1.0f;
2908 Source->Position[0] = 0.0f;
2909 Source->Position[1] = 0.0f;
2910 Source->Position[2] = 0.0f;
2911 Source->Velocity[0] = 0.0f;
2912 Source->Velocity[1] = 0.0f;
2913 Source->Velocity[2] = 0.0f;
2914 Source->Direction[0] = 0.0f;
2915 Source->Direction[1] = 0.0f;
2916 Source->Direction[2] = 0.0f;
2917 Source->Orientation[0][0] = 0.0f;
2918 Source->Orientation[0][1] = 0.0f;
2919 Source->Orientation[0][2] = -1.0f;
2920 Source->Orientation[1][0] = 0.0f;
2921 Source->Orientation[1][1] = 1.0f;
2922 Source->Orientation[1][2] = 0.0f;
2923 Source->RefDistance = 1.0f;
2924 Source->MaxDistance = FLT_MAX;
2925 Source->RollOffFactor = 1.0f;
2926 Source->Gain = 1.0f;
2927 Source->MinGain = 0.0f;
2928 Source->MaxGain = 1.0f;
2929 Source->OuterGain = 0.0f;
2930 Source->OuterGainHF = 1.0f;
2932 Source->DryGainHFAuto = AL_TRUE;
2933 Source->WetGainAuto = AL_TRUE;
2934 Source->WetGainHFAuto = AL_TRUE;
2935 Source->AirAbsorptionFactor = 0.0f;
2936 Source->RoomRolloffFactor = 0.0f;
2937 Source->DopplerFactor = 1.0f;
2938 Source->DirectChannels = AL_FALSE;
2940 Source->StereoPan[0] = DEG2RAD( 30.0f);
2941 Source->StereoPan[1] = DEG2RAD(-30.0f);
2943 Source->Radius = 0.0f;
2945 Source->DistanceModel = DefaultDistanceModel;
2947 Source->Direct.Gain = 1.0f;
2948 Source->Direct.GainHF = 1.0f;
2949 Source->Direct.HFReference = LOWPASSFREQREF;
2950 Source->Direct.GainLF = 1.0f;
2951 Source->Direct.LFReference = HIGHPASSFREQREF;
2952 Source->Send = al_calloc(16, num_sends*sizeof(Source->Send[0]));
2953 for(i = 0;i < num_sends;i++)
2955 Source->Send[i].Slot = NULL;
2956 Source->Send[i].Gain = 1.0f;
2957 Source->Send[i].GainHF = 1.0f;
2958 Source->Send[i].HFReference = LOWPASSFREQREF;
2959 Source->Send[i].GainLF = 1.0f;
2960 Source->Send[i].LFReference = HIGHPASSFREQREF;
2963 Source->Offset = 0.0;
2964 Source->OffsetType = AL_NONE;
2965 Source->SourceType = AL_UNDETERMINED;
2966 ATOMIC_INIT(&Source->state, AL_INITIAL);
2968 ATOMIC_INIT(&Source->queue, NULL);
2970 ATOMIC_INIT(&Source->looping, AL_FALSE);
2972 /* No way to do an 'init' here, so just test+set with relaxed ordering and
2973 * ignore the test.
2975 ATOMIC_FLAG_TEST_AND_SET(&Source->PropsClean, almemory_order_relaxed);
2977 ATOMIC_INIT(&Source->Update, NULL);
2978 ATOMIC_INIT(&Source->FreeList, NULL);
2981 static void DeinitSource(ALsource *source, ALsizei num_sends)
2983 ALbufferlistitem *BufferList;
2984 struct ALsourceProps *props;
2985 size_t count = 0;
2986 ALsizei i;
2988 props = ATOMIC_LOAD_SEQ(&source->Update);
2989 if(props) al_free(props);
2991 props = ATOMIC_LOAD(&source->FreeList, almemory_order_relaxed);
2992 while(props)
2994 struct ALsourceProps *next;
2995 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2996 al_free(props);
2997 props = next;
2998 ++count;
3000 /* This is excessively spammy if it traces every source destruction, so
3001 * just warn if it was unexpectedly large.
3003 if(count > 3)
3004 WARN("Freed "SZFMT" Source property objects\n", count);
3006 BufferList = ATOMIC_EXCHANGE_PTR_SEQ(&source->queue, NULL);
3007 while(BufferList != NULL)
3009 ALbufferlistitem *next = BufferList->next;
3010 if(BufferList->buffer != NULL)
3011 DecrementRef(&BufferList->buffer->ref);
3012 al_free(BufferList);
3013 BufferList = next;
3016 if(source->Send)
3018 for(i = 0;i < num_sends;i++)
3020 if(source->Send[i].Slot)
3021 DecrementRef(&source->Send[i].Slot->ref);
3022 source->Send[i].Slot = NULL;
3024 al_free(source->Send);
3025 source->Send = NULL;
3029 static void UpdateSourceProps(ALsource *source, ALsizei num_sends)
3031 struct ALsourceProps *props;
3032 ALsizei i;
3034 /* Get an unused property container, or allocate a new one as needed. */
3035 props = ATOMIC_LOAD(&source->FreeList, almemory_order_acquire);
3036 if(!props)
3037 props = al_calloc(16, offsetof(struct ALsourceProps, Send[num_sends]));
3038 else
3040 struct ALsourceProps *next;
3041 do {
3042 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
3043 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&source->FreeList, &props, next,
3044 almemory_order_acq_rel, almemory_order_acquire) == 0);
3047 /* Copy in current property values. */
3048 props->Pitch = source->Pitch;
3049 props->Gain = source->Gain;
3050 props->OuterGain = source->OuterGain;
3051 props->MinGain = source->MinGain;
3052 props->MaxGain = source->MaxGain;
3053 props->InnerAngle = source->InnerAngle;
3054 props->OuterAngle = source->OuterAngle;
3055 props->RefDistance = source->RefDistance;
3056 props->MaxDistance = source->MaxDistance;
3057 props->RollOffFactor = source->RollOffFactor;
3058 for(i = 0;i < 3;i++)
3059 props->Position[i] = source->Position[i];
3060 for(i = 0;i < 3;i++)
3061 props->Velocity[i] = source->Velocity[i];
3062 for(i = 0;i < 3;i++)
3063 props->Direction[i] = source->Direction[i];
3064 for(i = 0;i < 2;i++)
3066 ALsizei j;
3067 for(j = 0;j < 3;j++)
3068 props->Orientation[i][j] = source->Orientation[i][j];
3070 props->HeadRelative = source->HeadRelative;
3071 props->DistanceModel = source->DistanceModel;
3072 props->DirectChannels = source->DirectChannels;
3074 props->DryGainHFAuto = source->DryGainHFAuto;
3075 props->WetGainAuto = source->WetGainAuto;
3076 props->WetGainHFAuto = source->WetGainHFAuto;
3077 props->OuterGainHF = source->OuterGainHF;
3079 props->AirAbsorptionFactor = source->AirAbsorptionFactor;
3080 props->RoomRolloffFactor = source->RoomRolloffFactor;
3081 props->DopplerFactor = source->DopplerFactor;
3083 props->StereoPan[0] = source->StereoPan[0];
3084 props->StereoPan[1] = source->StereoPan[1];
3086 props->Radius = source->Radius;
3088 props->Direct.Gain = source->Direct.Gain;
3089 props->Direct.GainHF = source->Direct.GainHF;
3090 props->Direct.HFReference = source->Direct.HFReference;
3091 props->Direct.GainLF = source->Direct.GainLF;
3092 props->Direct.LFReference = source->Direct.LFReference;
3094 for(i = 0;i < num_sends;i++)
3096 props->Send[i].Slot = source->Send[i].Slot;
3097 props->Send[i].Gain = source->Send[i].Gain;
3098 props->Send[i].GainHF = source->Send[i].GainHF;
3099 props->Send[i].HFReference = source->Send[i].HFReference;
3100 props->Send[i].GainLF = source->Send[i].GainLF;
3101 props->Send[i].LFReference = source->Send[i].LFReference;
3104 /* Set the new container for updating internal parameters. */
3105 props = ATOMIC_EXCHANGE_PTR(&source->Update, props, almemory_order_acq_rel);
3106 if(props)
3108 /* If there was an unused update container, put it back in the
3109 * freelist.
3111 ATOMIC_REPLACE_HEAD(struct ALsourceProps*, &source->FreeList, props);
3115 void UpdateAllSourceProps(ALCcontext *context)
3117 ALsizei num_sends = context->Device->NumAuxSends;
3118 ALsizei pos;
3120 for(pos = 0;pos < context->VoiceCount;pos++)
3122 ALvoice *voice = context->Voices[pos];
3123 ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire);
3124 if(source != NULL && !ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acq_rel))
3125 UpdateSourceProps(source, num_sends);
3130 /* GetSourceSampleOffset
3132 * Gets the current read offset for the given Source, in 32.32 fixed-point
3133 * samples. The offset is relative to the start of the queue (not the start of
3134 * the current buffer).
3136 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3138 ALCdevice *device = context->Device;
3139 const ALbufferlistitem *BufferList;
3140 const ALbufferlistitem *Current;
3141 ALuint64 readPos;
3142 ALuint refcount;
3143 ALvoice *voice;
3145 ReadLock(&Source->queue_lock);
3146 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3147 do {
3148 Current = NULL;
3149 readPos = 0;
3150 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3151 althrd_yield();
3152 *clocktime = GetDeviceClockTime(device);
3154 voice = GetSourceVoice(Source, context);
3155 if(voice)
3157 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3159 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << 32;
3160 readPos |= (ALuint64)ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) <<
3161 (32-FRACTIONBITS);
3163 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3164 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3166 if(voice)
3168 while(BufferList && BufferList != Current)
3170 if(BufferList->buffer)
3171 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
3172 BufferList = BufferList->next;
3174 readPos = minu64(readPos, U64(0x7fffffffffffffff));
3177 ReadUnlock(&Source->queue_lock);
3178 return (ALint64)readPos;
3181 /* GetSourceSecOffset
3183 * Gets the current read offset for the given Source, in seconds. The offset is
3184 * relative to the start of the queue (not the start of the current buffer).
3186 static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3188 ALCdevice *device = context->Device;
3189 const ALbufferlistitem *BufferList;
3190 const ALbufferlistitem *Current;
3191 ALuint64 readPos;
3192 ALuint refcount;
3193 ALdouble offset;
3194 ALvoice *voice;
3196 ReadLock(&Source->queue_lock);
3197 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3198 do {
3199 Current = NULL;
3200 readPos = 0;
3201 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3202 althrd_yield();
3203 *clocktime = GetDeviceClockTime(device);
3205 voice = GetSourceVoice(Source, context);
3206 if(voice)
3208 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3210 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) <<
3211 FRACTIONBITS;
3212 readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3214 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3215 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3217 offset = 0.0;
3218 if(voice)
3220 const ALbuffer *Buffer = NULL;
3221 while(BufferList && BufferList != Current)
3223 const ALbuffer *buffer = BufferList->buffer;
3224 if(buffer != NULL)
3226 if(!Buffer) Buffer = buffer;
3227 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
3229 BufferList = BufferList->next;
3232 while(BufferList && !Buffer)
3234 Buffer = BufferList->buffer;
3235 BufferList = BufferList->next;
3237 assert(Buffer != NULL);
3239 offset = (ALdouble)readPos / (ALdouble)FRACTIONONE /
3240 (ALdouble)Buffer->Frequency;
3243 ReadUnlock(&Source->queue_lock);
3244 return offset;
3247 /* GetSourceOffset
3249 * Gets the current read offset for the given Source, in the appropriate format
3250 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3251 * queue (not the start of the current buffer).
3253 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context)
3255 ALCdevice *device = context->Device;
3256 const ALbufferlistitem *BufferList;
3257 const ALbufferlistitem *Current;
3258 const ALbuffer *Buffer = NULL;
3259 ALboolean readFin = AL_FALSE;
3260 ALuint readPos;
3261 ALsizei readPosFrac;
3262 ALuint totalBufferLen;
3263 ALboolean looping;
3264 ALuint refcount;
3265 ALdouble offset;
3266 ALvoice *voice;
3268 ReadLock(&Source->queue_lock);
3269 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3270 looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed);
3271 do {
3272 Current = NULL;
3273 readPos = readPosFrac = 0;
3274 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3275 althrd_yield();
3276 voice = GetSourceVoice(Source, context);
3277 if(voice)
3279 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3281 readPos = ATOMIC_LOAD(&voice->position, almemory_order_relaxed);
3282 readPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3284 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3285 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3287 if(!voice)
3289 ReadUnlock(&Source->queue_lock);
3290 return 0.0;
3293 totalBufferLen = 0;
3294 while(BufferList != NULL)
3296 const ALbuffer *buffer;
3297 readFin = readFin || (BufferList == Current);
3298 if((buffer=BufferList->buffer) != NULL)
3300 if(!Buffer) Buffer = buffer;
3301 totalBufferLen += buffer->SampleLen;
3302 if(!readFin) readPos += buffer->SampleLen;
3304 BufferList = BufferList->next;
3306 assert(Buffer != NULL);
3308 if(looping)
3309 readPos %= totalBufferLen;
3310 else
3312 /* Wrap back to 0 */
3313 if(readPos >= totalBufferLen)
3314 readPos = readPosFrac = 0;
3317 offset = 0.0;
3318 switch(name)
3320 case AL_SEC_OFFSET:
3321 offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
3322 break;
3324 case AL_SAMPLE_OFFSET:
3325 offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
3326 break;
3328 case AL_BYTE_OFFSET:
3329 if(Buffer->OriginalType == UserFmtIMA4)
3331 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3332 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3333 ALuint FrameBlockSize = Buffer->OriginalAlign;
3335 /* Round down to nearest ADPCM block */
3336 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3338 else if(Buffer->OriginalType == UserFmtMSADPCM)
3340 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3341 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3342 ALuint FrameBlockSize = Buffer->OriginalAlign;
3344 /* Round down to nearest ADPCM block */
3345 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3347 else
3349 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3350 offset = (ALdouble)(readPos * FrameSize);
3352 break;
3355 ReadUnlock(&Source->queue_lock);
3356 return offset;
3360 /* ApplyOffset
3362 * Apply the stored playback offset to the Source. This function will update
3363 * the number of buffers "played" given the stored offset.
3365 static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice)
3367 ALbufferlistitem *BufferList;
3368 const ALbuffer *Buffer;
3369 ALuint bufferLen, totalBufferLen;
3370 ALuint offset = 0;
3371 ALsizei frac = 0;
3373 /* Get sample frame offset */
3374 if(!GetSampleOffset(Source, &offset, &frac))
3375 return AL_FALSE;
3377 totalBufferLen = 0;
3378 BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
3379 while(BufferList && totalBufferLen <= offset)
3381 Buffer = BufferList->buffer;
3382 bufferLen = Buffer ? Buffer->SampleLen : 0;
3384 if(bufferLen > offset-totalBufferLen)
3386 /* Offset is in this buffer */
3387 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
3388 ATOMIC_STORE(&voice->position, offset - totalBufferLen, almemory_order_relaxed);
3389 ATOMIC_STORE(&voice->position_fraction, frac, almemory_order_release);
3390 return AL_TRUE;
3393 totalBufferLen += bufferLen;
3395 BufferList = BufferList->next;
3398 /* Offset is out of range of the queue */
3399 return AL_FALSE;
3403 /* GetSampleOffset
3405 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3406 * or Second offset supplied by the application). This takes into account the
3407 * fact that the buffer format may have been modifed since.
3409 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac)
3411 const ALbuffer *Buffer = NULL;
3412 const ALbufferlistitem *BufferList;
3413 ALdouble dbloff, dblfrac;
3415 /* Find the first valid Buffer in the Queue */
3416 BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
3417 while(BufferList)
3419 if(BufferList->buffer)
3421 Buffer = BufferList->buffer;
3422 break;
3424 BufferList = BufferList->next;
3426 if(!Buffer)
3428 Source->OffsetType = AL_NONE;
3429 Source->Offset = 0.0;
3430 return AL_FALSE;
3433 switch(Source->OffsetType)
3435 case AL_BYTE_OFFSET:
3436 /* Determine the ByteOffset (and ensure it is block aligned) */
3437 *offset = (ALuint)Source->Offset;
3438 if(Buffer->OriginalType == UserFmtIMA4)
3440 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3441 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3442 *offset *= Buffer->OriginalAlign;
3444 else if(Buffer->OriginalType == UserFmtMSADPCM)
3446 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3447 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3448 *offset *= Buffer->OriginalAlign;
3450 else
3451 *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3452 *frac = 0;
3453 break;
3455 case AL_SAMPLE_OFFSET:
3456 dblfrac = modf(Source->Offset, &dbloff);
3457 *offset = (ALuint)mind(dbloff, UINT_MAX);
3458 *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3459 break;
3461 case AL_SEC_OFFSET:
3462 dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
3463 *offset = (ALuint)mind(dbloff, UINT_MAX);
3464 *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3465 break;
3467 Source->OffsetType = AL_NONE;
3468 Source->Offset = 0.0;
3470 return AL_TRUE;
3474 /* ReleaseALSources
3476 * Destroys all sources in the source map.
3478 ALvoid ReleaseALSources(ALCcontext *Context)
3480 ALCdevice *device = Context->Device;
3481 ALsizei pos;
3482 for(pos = 0;pos < Context->SourceMap.size;pos++)
3484 ALsource *temp = Context->SourceMap.values[pos];
3485 Context->SourceMap.values[pos] = NULL;
3487 DeinitSource(temp, device->NumAuxSends);
3489 FreeThunkEntry(temp->id);
3490 memset(temp, 0, sizeof(*temp));
3491 al_free(temp);