Make the voice's source pointer atomic
[openal-soft.git] / OpenAL32 / alSource.c
blobdf0e71364af563565b7965959589c97cf0cbf655
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);
49 extern inline ALboolean IsPlayingOrPaused(const ALsource *source);
51 static void InitSourceParams(ALsource *Source, ALsizei num_sends);
52 static void DeinitSource(ALsource *source, ALsizei num_sends);
53 static void UpdateSourceProps(ALsource *source, ALsizei num_sends);
54 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime);
55 static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime);
56 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context);
57 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac);
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;
142 static inline bool IsPlayingOrPausedSeq(const ALsource *source)
144 ALenum state = ATOMIC_LOAD_SEQ(&source->state);
145 return state == AL_PLAYING || state == AL_PAUSED;
148 static inline bool SourceShouldUpdate(const ALsource *source, const ALCcontext *context)
150 return IsPlayingOrPausedSeq(source) &&
151 !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire);
154 static ALint FloatValsByProp(ALenum prop)
156 if(prop != (ALenum)((SourceProp)prop))
157 return 0;
158 switch((SourceProp)prop)
160 case AL_PITCH:
161 case AL_GAIN:
162 case AL_MIN_GAIN:
163 case AL_MAX_GAIN:
164 case AL_MAX_DISTANCE:
165 case AL_ROLLOFF_FACTOR:
166 case AL_DOPPLER_FACTOR:
167 case AL_CONE_OUTER_GAIN:
168 case AL_SEC_OFFSET:
169 case AL_SAMPLE_OFFSET:
170 case AL_BYTE_OFFSET:
171 case AL_CONE_INNER_ANGLE:
172 case AL_CONE_OUTER_ANGLE:
173 case AL_REFERENCE_DISTANCE:
174 case AL_CONE_OUTER_GAINHF:
175 case AL_AIR_ABSORPTION_FACTOR:
176 case AL_ROOM_ROLLOFF_FACTOR:
177 case AL_DIRECT_FILTER_GAINHF_AUTO:
178 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
179 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
180 case AL_DIRECT_CHANNELS_SOFT:
181 case AL_DISTANCE_MODEL:
182 case AL_SOURCE_RELATIVE:
183 case AL_LOOPING:
184 case AL_SOURCE_STATE:
185 case AL_BUFFERS_QUEUED:
186 case AL_BUFFERS_PROCESSED:
187 case AL_SOURCE_TYPE:
188 case AL_BYTE_LENGTH_SOFT:
189 case AL_SAMPLE_LENGTH_SOFT:
190 case AL_SEC_LENGTH_SOFT:
191 case AL_SOURCE_RADIUS:
192 return 1;
194 case AL_STEREO_ANGLES:
195 return 2;
197 case AL_POSITION:
198 case AL_VELOCITY:
199 case AL_DIRECTION:
200 return 3;
202 case AL_ORIENTATION:
203 return 6;
205 case AL_SEC_OFFSET_LATENCY_SOFT:
206 break; /* Double only */
208 case AL_BUFFER:
209 case AL_DIRECT_FILTER:
210 case AL_AUXILIARY_SEND_FILTER:
211 break; /* i/i64 only */
212 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
213 break; /* i64 only */
215 return 0;
217 static ALint DoubleValsByProp(ALenum prop)
219 if(prop != (ALenum)((SourceProp)prop))
220 return 0;
221 switch((SourceProp)prop)
223 case AL_PITCH:
224 case AL_GAIN:
225 case AL_MIN_GAIN:
226 case AL_MAX_GAIN:
227 case AL_MAX_DISTANCE:
228 case AL_ROLLOFF_FACTOR:
229 case AL_DOPPLER_FACTOR:
230 case AL_CONE_OUTER_GAIN:
231 case AL_SEC_OFFSET:
232 case AL_SAMPLE_OFFSET:
233 case AL_BYTE_OFFSET:
234 case AL_CONE_INNER_ANGLE:
235 case AL_CONE_OUTER_ANGLE:
236 case AL_REFERENCE_DISTANCE:
237 case AL_CONE_OUTER_GAINHF:
238 case AL_AIR_ABSORPTION_FACTOR:
239 case AL_ROOM_ROLLOFF_FACTOR:
240 case AL_DIRECT_FILTER_GAINHF_AUTO:
241 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
242 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
243 case AL_DIRECT_CHANNELS_SOFT:
244 case AL_DISTANCE_MODEL:
245 case AL_SOURCE_RELATIVE:
246 case AL_LOOPING:
247 case AL_SOURCE_STATE:
248 case AL_BUFFERS_QUEUED:
249 case AL_BUFFERS_PROCESSED:
250 case AL_SOURCE_TYPE:
251 case AL_BYTE_LENGTH_SOFT:
252 case AL_SAMPLE_LENGTH_SOFT:
253 case AL_SEC_LENGTH_SOFT:
254 case AL_SOURCE_RADIUS:
255 return 1;
257 case AL_SEC_OFFSET_LATENCY_SOFT:
258 case AL_STEREO_ANGLES:
259 return 2;
261 case AL_POSITION:
262 case AL_VELOCITY:
263 case AL_DIRECTION:
264 return 3;
266 case AL_ORIENTATION:
267 return 6;
269 case AL_BUFFER:
270 case AL_DIRECT_FILTER:
271 case AL_AUXILIARY_SEND_FILTER:
272 break; /* i/i64 only */
273 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
274 break; /* i64 only */
276 return 0;
279 static ALint IntValsByProp(ALenum prop)
281 if(prop != (ALenum)((SourceProp)prop))
282 return 0;
283 switch((SourceProp)prop)
285 case AL_PITCH:
286 case AL_GAIN:
287 case AL_MIN_GAIN:
288 case AL_MAX_GAIN:
289 case AL_MAX_DISTANCE:
290 case AL_ROLLOFF_FACTOR:
291 case AL_DOPPLER_FACTOR:
292 case AL_CONE_OUTER_GAIN:
293 case AL_SEC_OFFSET:
294 case AL_SAMPLE_OFFSET:
295 case AL_BYTE_OFFSET:
296 case AL_CONE_INNER_ANGLE:
297 case AL_CONE_OUTER_ANGLE:
298 case AL_REFERENCE_DISTANCE:
299 case AL_CONE_OUTER_GAINHF:
300 case AL_AIR_ABSORPTION_FACTOR:
301 case AL_ROOM_ROLLOFF_FACTOR:
302 case AL_DIRECT_FILTER_GAINHF_AUTO:
303 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
304 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
305 case AL_DIRECT_CHANNELS_SOFT:
306 case AL_DISTANCE_MODEL:
307 case AL_SOURCE_RELATIVE:
308 case AL_LOOPING:
309 case AL_BUFFER:
310 case AL_SOURCE_STATE:
311 case AL_BUFFERS_QUEUED:
312 case AL_BUFFERS_PROCESSED:
313 case AL_SOURCE_TYPE:
314 case AL_DIRECT_FILTER:
315 case AL_BYTE_LENGTH_SOFT:
316 case AL_SAMPLE_LENGTH_SOFT:
317 case AL_SEC_LENGTH_SOFT:
318 case AL_SOURCE_RADIUS:
319 return 1;
321 case AL_POSITION:
322 case AL_VELOCITY:
323 case AL_DIRECTION:
324 case AL_AUXILIARY_SEND_FILTER:
325 return 3;
327 case AL_ORIENTATION:
328 return 6;
330 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
331 break; /* i64 only */
332 case AL_SEC_OFFSET_LATENCY_SOFT:
333 break; /* Double only */
334 case AL_STEREO_ANGLES:
335 break; /* Float/double only */
337 return 0;
339 static ALint Int64ValsByProp(ALenum prop)
341 if(prop != (ALenum)((SourceProp)prop))
342 return 0;
343 switch((SourceProp)prop)
345 case AL_PITCH:
346 case AL_GAIN:
347 case AL_MIN_GAIN:
348 case AL_MAX_GAIN:
349 case AL_MAX_DISTANCE:
350 case AL_ROLLOFF_FACTOR:
351 case AL_DOPPLER_FACTOR:
352 case AL_CONE_OUTER_GAIN:
353 case AL_SEC_OFFSET:
354 case AL_SAMPLE_OFFSET:
355 case AL_BYTE_OFFSET:
356 case AL_CONE_INNER_ANGLE:
357 case AL_CONE_OUTER_ANGLE:
358 case AL_REFERENCE_DISTANCE:
359 case AL_CONE_OUTER_GAINHF:
360 case AL_AIR_ABSORPTION_FACTOR:
361 case AL_ROOM_ROLLOFF_FACTOR:
362 case AL_DIRECT_FILTER_GAINHF_AUTO:
363 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
364 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
365 case AL_DIRECT_CHANNELS_SOFT:
366 case AL_DISTANCE_MODEL:
367 case AL_SOURCE_RELATIVE:
368 case AL_LOOPING:
369 case AL_BUFFER:
370 case AL_SOURCE_STATE:
371 case AL_BUFFERS_QUEUED:
372 case AL_BUFFERS_PROCESSED:
373 case AL_SOURCE_TYPE:
374 case AL_DIRECT_FILTER:
375 case AL_BYTE_LENGTH_SOFT:
376 case AL_SAMPLE_LENGTH_SOFT:
377 case AL_SEC_LENGTH_SOFT:
378 case AL_SOURCE_RADIUS:
379 return 1;
381 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
382 return 2;
384 case AL_POSITION:
385 case AL_VELOCITY:
386 case AL_DIRECTION:
387 case AL_AUXILIARY_SEND_FILTER:
388 return 3;
390 case AL_ORIENTATION:
391 return 6;
393 case AL_SEC_OFFSET_LATENCY_SOFT:
394 break; /* Double only */
395 case AL_STEREO_ANGLES:
396 break; /* Float/double only */
398 return 0;
402 #define CHECKVAL(x) do { \
403 if(!(x)) \
404 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
405 } while(0)
407 #define DO_UPDATEPROPS() do { \
408 if(SourceShouldUpdate(Source, Context)) \
409 UpdateSourceProps(Source, device->NumAuxSends); \
410 else \
411 Source->NeedsUpdate = AL_TRUE; \
412 } while(0)
414 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
416 ALCdevice *device = Context->Device;
417 ALint ival;
419 switch(prop)
421 case AL_BYTE_LENGTH_SOFT:
422 case AL_SAMPLE_LENGTH_SOFT:
423 case AL_SEC_LENGTH_SOFT:
424 case AL_SEC_OFFSET_LATENCY_SOFT:
425 /* Query only */
426 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
428 case AL_PITCH:
429 CHECKVAL(*values >= 0.0f);
431 Source->Pitch = *values;
432 DO_UPDATEPROPS();
433 return AL_TRUE;
435 case AL_CONE_INNER_ANGLE:
436 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
438 Source->InnerAngle = *values;
439 DO_UPDATEPROPS();
440 return AL_TRUE;
442 case AL_CONE_OUTER_ANGLE:
443 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
445 Source->OuterAngle = *values;
446 DO_UPDATEPROPS();
447 return AL_TRUE;
449 case AL_GAIN:
450 CHECKVAL(*values >= 0.0f);
452 Source->Gain = *values;
453 DO_UPDATEPROPS();
454 return AL_TRUE;
456 case AL_MAX_DISTANCE:
457 CHECKVAL(*values >= 0.0f);
459 Source->MaxDistance = *values;
460 DO_UPDATEPROPS();
461 return AL_TRUE;
463 case AL_ROLLOFF_FACTOR:
464 CHECKVAL(*values >= 0.0f);
466 Source->RollOffFactor = *values;
467 DO_UPDATEPROPS();
468 return AL_TRUE;
470 case AL_REFERENCE_DISTANCE:
471 CHECKVAL(*values >= 0.0f);
473 Source->RefDistance = *values;
474 DO_UPDATEPROPS();
475 return AL_TRUE;
477 case AL_MIN_GAIN:
478 CHECKVAL(*values >= 0.0f);
480 Source->MinGain = *values;
481 DO_UPDATEPROPS();
482 return AL_TRUE;
484 case AL_MAX_GAIN:
485 CHECKVAL(*values >= 0.0f);
487 Source->MaxGain = *values;
488 DO_UPDATEPROPS();
489 return AL_TRUE;
491 case AL_CONE_OUTER_GAIN:
492 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
494 Source->OuterGain = *values;
495 DO_UPDATEPROPS();
496 return AL_TRUE;
498 case AL_CONE_OUTER_GAINHF:
499 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
501 Source->OuterGainHF = *values;
502 DO_UPDATEPROPS();
503 return AL_TRUE;
505 case AL_AIR_ABSORPTION_FACTOR:
506 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
508 Source->AirAbsorptionFactor = *values;
509 DO_UPDATEPROPS();
510 return AL_TRUE;
512 case AL_ROOM_ROLLOFF_FACTOR:
513 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
515 Source->RoomRolloffFactor = *values;
516 DO_UPDATEPROPS();
517 return AL_TRUE;
519 case AL_DOPPLER_FACTOR:
520 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
522 Source->DopplerFactor = *values;
523 DO_UPDATEPROPS();
524 return AL_TRUE;
526 case AL_SEC_OFFSET:
527 case AL_SAMPLE_OFFSET:
528 case AL_BYTE_OFFSET:
529 CHECKVAL(*values >= 0.0f);
531 Source->OffsetType = prop;
532 Source->Offset = *values;
534 if(!ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire) &&
535 IsPlayingOrPausedSeq(Source))
537 ALvoice *voice;
539 ALCdevice_Lock(Context->Device);
540 /* Double-check that the source is still playing while we have
541 * the lock.
543 voice = GetSourceVoice(Source, Context);
544 if(voice)
546 WriteLock(&Source->queue_lock);
547 if(ApplyOffset(Source, voice) == AL_FALSE)
549 WriteUnlock(&Source->queue_lock);
550 ALCdevice_Unlock(Context->Device);
551 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
553 WriteUnlock(&Source->queue_lock);
555 ALCdevice_Unlock(Context->Device);
557 return AL_TRUE;
559 case AL_SOURCE_RADIUS:
560 CHECKVAL(*values >= 0.0f && isfinite(*values));
562 Source->Radius = *values;
563 DO_UPDATEPROPS();
564 return AL_TRUE;
566 case AL_STEREO_ANGLES:
567 CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
569 Source->StereoPan[0] = values[0];
570 Source->StereoPan[1] = values[1];
571 DO_UPDATEPROPS();
572 return AL_TRUE;
575 case AL_POSITION:
576 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
578 Source->Position[0] = values[0];
579 Source->Position[1] = values[1];
580 Source->Position[2] = values[2];
581 DO_UPDATEPROPS();
582 return AL_TRUE;
584 case AL_VELOCITY:
585 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
587 Source->Velocity[0] = values[0];
588 Source->Velocity[1] = values[1];
589 Source->Velocity[2] = values[2];
590 DO_UPDATEPROPS();
591 return AL_TRUE;
593 case AL_DIRECTION:
594 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
596 Source->Direction[0] = values[0];
597 Source->Direction[1] = values[1];
598 Source->Direction[2] = values[2];
599 DO_UPDATEPROPS();
600 return AL_TRUE;
602 case AL_ORIENTATION:
603 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
604 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
606 Source->Orientation[0][0] = values[0];
607 Source->Orientation[0][1] = values[1];
608 Source->Orientation[0][2] = values[2];
609 Source->Orientation[1][0] = values[3];
610 Source->Orientation[1][1] = values[4];
611 Source->Orientation[1][2] = values[5];
612 DO_UPDATEPROPS();
613 return AL_TRUE;
616 case AL_SOURCE_RELATIVE:
617 case AL_LOOPING:
618 case AL_SOURCE_STATE:
619 case AL_SOURCE_TYPE:
620 case AL_DISTANCE_MODEL:
621 case AL_DIRECT_FILTER_GAINHF_AUTO:
622 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
623 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
624 case AL_DIRECT_CHANNELS_SOFT:
625 ival = (ALint)values[0];
626 return SetSourceiv(Source, Context, prop, &ival);
628 case AL_BUFFERS_QUEUED:
629 case AL_BUFFERS_PROCESSED:
630 ival = (ALint)((ALuint)values[0]);
631 return SetSourceiv(Source, Context, prop, &ival);
633 case AL_BUFFER:
634 case AL_DIRECT_FILTER:
635 case AL_AUXILIARY_SEND_FILTER:
636 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
637 break;
640 ERR("Unexpected property: 0x%04x\n", prop);
641 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
644 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
646 ALCdevice *device = Context->Device;
647 ALbuffer *buffer = NULL;
648 ALfilter *filter = NULL;
649 ALeffectslot *slot = NULL;
650 ALbufferlistitem *oldlist;
651 ALbufferlistitem *newlist;
652 ALfloat fvals[6];
654 switch(prop)
656 case AL_SOURCE_STATE:
657 case AL_SOURCE_TYPE:
658 case AL_BUFFERS_QUEUED:
659 case AL_BUFFERS_PROCESSED:
660 case AL_BYTE_LENGTH_SOFT:
661 case AL_SAMPLE_LENGTH_SOFT:
662 case AL_SEC_LENGTH_SOFT:
663 /* Query only */
664 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
666 case AL_SOURCE_RELATIVE:
667 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
669 Source->HeadRelative = (ALboolean)*values;
670 DO_UPDATEPROPS();
671 return AL_TRUE;
673 case AL_LOOPING:
674 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
676 WriteLock(&Source->queue_lock);
677 ATOMIC_STORE_SEQ(&Source->looping, *values);
678 WriteUnlock(&Source->queue_lock);
679 return AL_TRUE;
681 case AL_BUFFER:
682 LockBuffersRead(device);
683 if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
685 UnlockBuffersRead(device);
686 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
689 WriteLock(&Source->queue_lock);
690 if(IsPlayingOrPausedSeq(Source))
692 WriteUnlock(&Source->queue_lock);
693 UnlockBuffersRead(device);
694 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
697 if(buffer != NULL)
699 /* Add the selected buffer to a one-item queue */
700 newlist = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
701 newlist->buffer = buffer;
702 newlist->next = NULL;
703 IncrementRef(&buffer->ref);
705 /* Source is now Static */
706 Source->SourceType = AL_STATIC;
708 ReadLock(&buffer->lock);
709 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
710 Source->SampleSize = BytesFromFmt(buffer->FmtType);
711 ReadUnlock(&buffer->lock);
713 else
715 /* Source is now Undetermined */
716 Source->SourceType = AL_UNDETERMINED;
717 newlist = NULL;
719 oldlist = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &Source->queue, newlist);
720 WriteUnlock(&Source->queue_lock);
721 UnlockBuffersRead(device);
723 /* Delete all elements in the previous queue */
724 while(oldlist != NULL)
726 ALbufferlistitem *temp = oldlist;
727 oldlist = temp->next;
729 if(temp->buffer)
730 DecrementRef(&temp->buffer->ref);
731 al_free(temp);
733 return AL_TRUE;
735 case AL_SEC_OFFSET:
736 case AL_SAMPLE_OFFSET:
737 case AL_BYTE_OFFSET:
738 CHECKVAL(*values >= 0);
740 Source->OffsetType = prop;
741 Source->Offset = *values;
743 if(!ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire) &&
744 IsPlayingOrPausedSeq(Source))
746 ALvoice *voice;
748 ALCdevice_Lock(Context->Device);
749 voice = GetSourceVoice(Source, Context);
750 if(voice)
752 WriteLock(&Source->queue_lock);
753 if(ApplyOffset(Source, voice) == AL_FALSE)
755 WriteUnlock(&Source->queue_lock);
756 ALCdevice_Unlock(Context->Device);
757 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
759 WriteUnlock(&Source->queue_lock);
761 ALCdevice_Unlock(Context->Device);
763 return AL_TRUE;
765 case AL_DIRECT_FILTER:
766 LockFiltersRead(device);
767 if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
769 UnlockFiltersRead(device);
770 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
773 if(!filter)
775 Source->Direct.Gain = 1.0f;
776 Source->Direct.GainHF = 1.0f;
777 Source->Direct.HFReference = LOWPASSFREQREF;
778 Source->Direct.GainLF = 1.0f;
779 Source->Direct.LFReference = HIGHPASSFREQREF;
781 else
783 Source->Direct.Gain = filter->Gain;
784 Source->Direct.GainHF = filter->GainHF;
785 Source->Direct.HFReference = filter->HFReference;
786 Source->Direct.GainLF = filter->GainLF;
787 Source->Direct.LFReference = filter->LFReference;
789 UnlockFiltersRead(device);
790 DO_UPDATEPROPS();
791 return AL_TRUE;
793 case AL_DIRECT_FILTER_GAINHF_AUTO:
794 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
796 Source->DryGainHFAuto = *values;
797 DO_UPDATEPROPS();
798 return AL_TRUE;
800 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
801 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
803 Source->WetGainAuto = *values;
804 DO_UPDATEPROPS();
805 return AL_TRUE;
807 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
808 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
810 Source->WetGainHFAuto = *values;
811 DO_UPDATEPROPS();
812 return AL_TRUE;
814 case AL_DIRECT_CHANNELS_SOFT:
815 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
817 Source->DirectChannels = *values;
818 DO_UPDATEPROPS();
819 return AL_TRUE;
821 case AL_DISTANCE_MODEL:
822 CHECKVAL(*values == AL_NONE ||
823 *values == AL_INVERSE_DISTANCE ||
824 *values == AL_INVERSE_DISTANCE_CLAMPED ||
825 *values == AL_LINEAR_DISTANCE ||
826 *values == AL_LINEAR_DISTANCE_CLAMPED ||
827 *values == AL_EXPONENT_DISTANCE ||
828 *values == AL_EXPONENT_DISTANCE_CLAMPED);
830 Source->DistanceModel = *values;
831 if(Context->SourceDistanceModel)
832 DO_UPDATEPROPS();
833 return AL_TRUE;
836 case AL_AUXILIARY_SEND_FILTER:
837 LockEffectSlotsRead(Context);
838 LockFiltersRead(device);
839 if(!((ALuint)values[1] < (ALuint)device->NumAuxSends &&
840 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
841 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
843 UnlockFiltersRead(device);
844 UnlockEffectSlotsRead(Context);
845 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
848 if(!filter)
850 /* Disable filter */
851 Source->Send[values[1]].Gain = 1.0f;
852 Source->Send[values[1]].GainHF = 1.0f;
853 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
854 Source->Send[values[1]].GainLF = 1.0f;
855 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
857 else
859 Source->Send[values[1]].Gain = filter->Gain;
860 Source->Send[values[1]].GainHF = filter->GainHF;
861 Source->Send[values[1]].HFReference = filter->HFReference;
862 Source->Send[values[1]].GainLF = filter->GainLF;
863 Source->Send[values[1]].LFReference = filter->LFReference;
865 UnlockFiltersRead(device);
867 if(slot != Source->Send[values[1]].Slot && IsPlayingOrPausedSeq(Source))
869 /* Add refcount on the new slot, and release the previous slot */
870 if(slot) IncrementRef(&slot->ref);
871 if(Source->Send[values[1]].Slot)
872 DecrementRef(&Source->Send[values[1]].Slot->ref);
873 Source->Send[values[1]].Slot = slot;
875 /* We must force an update if the auxiliary slot changed on a
876 * playing source, in case the slot is about to be deleted.
878 UpdateSourceProps(Source, device->NumAuxSends);
880 else
882 if(slot) IncrementRef(&slot->ref);
883 if(Source->Send[values[1]].Slot)
884 DecrementRef(&Source->Send[values[1]].Slot->ref);
885 Source->Send[values[1]].Slot = slot;
886 DO_UPDATEPROPS();
888 UnlockEffectSlotsRead(Context);
890 return AL_TRUE;
893 /* 1x float */
894 case AL_CONE_INNER_ANGLE:
895 case AL_CONE_OUTER_ANGLE:
896 case AL_PITCH:
897 case AL_GAIN:
898 case AL_MIN_GAIN:
899 case AL_MAX_GAIN:
900 case AL_REFERENCE_DISTANCE:
901 case AL_ROLLOFF_FACTOR:
902 case AL_CONE_OUTER_GAIN:
903 case AL_MAX_DISTANCE:
904 case AL_DOPPLER_FACTOR:
905 case AL_CONE_OUTER_GAINHF:
906 case AL_AIR_ABSORPTION_FACTOR:
907 case AL_ROOM_ROLLOFF_FACTOR:
908 case AL_SOURCE_RADIUS:
909 fvals[0] = (ALfloat)*values;
910 return SetSourcefv(Source, Context, (int)prop, fvals);
912 /* 3x float */
913 case AL_POSITION:
914 case AL_VELOCITY:
915 case AL_DIRECTION:
916 fvals[0] = (ALfloat)values[0];
917 fvals[1] = (ALfloat)values[1];
918 fvals[2] = (ALfloat)values[2];
919 return SetSourcefv(Source, Context, (int)prop, fvals);
921 /* 6x float */
922 case AL_ORIENTATION:
923 fvals[0] = (ALfloat)values[0];
924 fvals[1] = (ALfloat)values[1];
925 fvals[2] = (ALfloat)values[2];
926 fvals[3] = (ALfloat)values[3];
927 fvals[4] = (ALfloat)values[4];
928 fvals[5] = (ALfloat)values[5];
929 return SetSourcefv(Source, Context, (int)prop, fvals);
931 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
932 case AL_SEC_OFFSET_LATENCY_SOFT:
933 case AL_STEREO_ANGLES:
934 break;
937 ERR("Unexpected property: 0x%04x\n", prop);
938 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
941 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
943 ALfloat fvals[6];
944 ALint ivals[3];
946 switch(prop)
948 case AL_SOURCE_TYPE:
949 case AL_BUFFERS_QUEUED:
950 case AL_BUFFERS_PROCESSED:
951 case AL_SOURCE_STATE:
952 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
953 case AL_BYTE_LENGTH_SOFT:
954 case AL_SAMPLE_LENGTH_SOFT:
955 case AL_SEC_LENGTH_SOFT:
956 /* Query only */
957 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
960 /* 1x int */
961 case AL_SOURCE_RELATIVE:
962 case AL_LOOPING:
963 case AL_SEC_OFFSET:
964 case AL_SAMPLE_OFFSET:
965 case AL_BYTE_OFFSET:
966 case AL_DIRECT_FILTER_GAINHF_AUTO:
967 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
968 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
969 case AL_DIRECT_CHANNELS_SOFT:
970 case AL_DISTANCE_MODEL:
971 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
973 ivals[0] = (ALint)*values;
974 return SetSourceiv(Source, Context, (int)prop, ivals);
976 /* 1x uint */
977 case AL_BUFFER:
978 case AL_DIRECT_FILTER:
979 CHECKVAL(*values <= UINT_MAX && *values >= 0);
981 ivals[0] = (ALuint)*values;
982 return SetSourceiv(Source, Context, (int)prop, ivals);
984 /* 3x uint */
985 case AL_AUXILIARY_SEND_FILTER:
986 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
987 values[1] <= UINT_MAX && values[1] >= 0 &&
988 values[2] <= UINT_MAX && values[2] >= 0);
990 ivals[0] = (ALuint)values[0];
991 ivals[1] = (ALuint)values[1];
992 ivals[2] = (ALuint)values[2];
993 return SetSourceiv(Source, Context, (int)prop, ivals);
995 /* 1x float */
996 case AL_CONE_INNER_ANGLE:
997 case AL_CONE_OUTER_ANGLE:
998 case AL_PITCH:
999 case AL_GAIN:
1000 case AL_MIN_GAIN:
1001 case AL_MAX_GAIN:
1002 case AL_REFERENCE_DISTANCE:
1003 case AL_ROLLOFF_FACTOR:
1004 case AL_CONE_OUTER_GAIN:
1005 case AL_MAX_DISTANCE:
1006 case AL_DOPPLER_FACTOR:
1007 case AL_CONE_OUTER_GAINHF:
1008 case AL_AIR_ABSORPTION_FACTOR:
1009 case AL_ROOM_ROLLOFF_FACTOR:
1010 case AL_SOURCE_RADIUS:
1011 fvals[0] = (ALfloat)*values;
1012 return SetSourcefv(Source, Context, (int)prop, fvals);
1014 /* 3x float */
1015 case AL_POSITION:
1016 case AL_VELOCITY:
1017 case AL_DIRECTION:
1018 fvals[0] = (ALfloat)values[0];
1019 fvals[1] = (ALfloat)values[1];
1020 fvals[2] = (ALfloat)values[2];
1021 return SetSourcefv(Source, Context, (int)prop, fvals);
1023 /* 6x float */
1024 case AL_ORIENTATION:
1025 fvals[0] = (ALfloat)values[0];
1026 fvals[1] = (ALfloat)values[1];
1027 fvals[2] = (ALfloat)values[2];
1028 fvals[3] = (ALfloat)values[3];
1029 fvals[4] = (ALfloat)values[4];
1030 fvals[5] = (ALfloat)values[5];
1031 return SetSourcefv(Source, Context, (int)prop, fvals);
1033 case AL_SEC_OFFSET_LATENCY_SOFT:
1034 case AL_STEREO_ANGLES:
1035 break;
1038 ERR("Unexpected property: 0x%04x\n", prop);
1039 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1042 #undef CHECKVAL
1045 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
1047 ALCdevice *device = Context->Device;
1048 ALbufferlistitem *BufferList;
1049 ClockLatency clocktime;
1050 ALuint64 srcclock;
1051 ALint ivals[3];
1052 ALboolean err;
1054 switch(prop)
1056 case AL_GAIN:
1057 *values = Source->Gain;
1058 return AL_TRUE;
1060 case AL_PITCH:
1061 *values = Source->Pitch;
1062 return AL_TRUE;
1064 case AL_MAX_DISTANCE:
1065 *values = Source->MaxDistance;
1066 return AL_TRUE;
1068 case AL_ROLLOFF_FACTOR:
1069 *values = Source->RollOffFactor;
1070 return AL_TRUE;
1072 case AL_REFERENCE_DISTANCE:
1073 *values = Source->RefDistance;
1074 return AL_TRUE;
1076 case AL_CONE_INNER_ANGLE:
1077 *values = Source->InnerAngle;
1078 return AL_TRUE;
1080 case AL_CONE_OUTER_ANGLE:
1081 *values = Source->OuterAngle;
1082 return AL_TRUE;
1084 case AL_MIN_GAIN:
1085 *values = Source->MinGain;
1086 return AL_TRUE;
1088 case AL_MAX_GAIN:
1089 *values = Source->MaxGain;
1090 return AL_TRUE;
1092 case AL_CONE_OUTER_GAIN:
1093 *values = Source->OuterGain;
1094 return AL_TRUE;
1096 case AL_SEC_OFFSET:
1097 case AL_SAMPLE_OFFSET:
1098 case AL_BYTE_OFFSET:
1099 *values = GetSourceOffset(Source, prop, Context);
1100 return AL_TRUE;
1102 case AL_CONE_OUTER_GAINHF:
1103 *values = Source->OuterGainHF;
1104 return AL_TRUE;
1106 case AL_AIR_ABSORPTION_FACTOR:
1107 *values = Source->AirAbsorptionFactor;
1108 return AL_TRUE;
1110 case AL_ROOM_ROLLOFF_FACTOR:
1111 *values = Source->RoomRolloffFactor;
1112 return AL_TRUE;
1114 case AL_DOPPLER_FACTOR:
1115 *values = Source->DopplerFactor;
1116 return AL_TRUE;
1118 case AL_SEC_LENGTH_SOFT:
1119 ReadLock(&Source->queue_lock);
1120 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1121 *values = 0;
1122 else
1124 ALint length = 0;
1125 ALsizei freq = 1;
1126 do {
1127 ALbuffer *buffer = BufferList->buffer;
1128 if(buffer && buffer->SampleLen > 0)
1130 freq = buffer->Frequency;
1131 length += buffer->SampleLen;
1133 } while((BufferList=BufferList->next) != NULL);
1134 *values = (ALdouble)length / (ALdouble)freq;
1136 ReadUnlock(&Source->queue_lock);
1137 return AL_TRUE;
1139 case AL_SOURCE_RADIUS:
1140 *values = Source->Radius;
1141 return AL_TRUE;
1143 case AL_STEREO_ANGLES:
1144 values[0] = Source->StereoPan[0];
1145 values[1] = Source->StereoPan[1];
1146 return AL_TRUE;
1148 case AL_SEC_OFFSET_LATENCY_SOFT:
1149 /* Get the source offset with the clock time first. Then get the
1150 * clock time with the device latency. Order is important.
1152 values[0] = GetSourceSecOffset(Source, Context, &srcclock);
1153 clocktime = V0(device->Backend,getClockLatency)();
1154 if(srcclock == (ALuint64)clocktime.ClockTime)
1155 values[1] = (ALdouble)clocktime.Latency / 1000000000.0;
1156 else
1158 /* If the clock time incremented, reduce the latency by that
1159 * much since it's that much closer to the source offset it got
1160 * earlier.
1162 ALuint64 diff = clocktime.ClockTime - srcclock;
1163 values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) /
1164 1000000000.0;
1166 return AL_TRUE;
1168 case AL_POSITION:
1169 values[0] = Source->Position[0];
1170 values[1] = Source->Position[1];
1171 values[2] = Source->Position[2];
1172 return AL_TRUE;
1174 case AL_VELOCITY:
1175 values[0] = Source->Velocity[0];
1176 values[1] = Source->Velocity[1];
1177 values[2] = Source->Velocity[2];
1178 return AL_TRUE;
1180 case AL_DIRECTION:
1181 values[0] = Source->Direction[0];
1182 values[1] = Source->Direction[1];
1183 values[2] = Source->Direction[2];
1184 return AL_TRUE;
1186 case AL_ORIENTATION:
1187 values[0] = Source->Orientation[0][0];
1188 values[1] = Source->Orientation[0][1];
1189 values[2] = Source->Orientation[0][2];
1190 values[3] = Source->Orientation[1][0];
1191 values[4] = Source->Orientation[1][1];
1192 values[5] = Source->Orientation[1][2];
1193 return AL_TRUE;
1195 /* 1x int */
1196 case AL_SOURCE_RELATIVE:
1197 case AL_LOOPING:
1198 case AL_SOURCE_STATE:
1199 case AL_BUFFERS_QUEUED:
1200 case AL_BUFFERS_PROCESSED:
1201 case AL_SOURCE_TYPE:
1202 case AL_DIRECT_FILTER_GAINHF_AUTO:
1203 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1204 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1205 case AL_DIRECT_CHANNELS_SOFT:
1206 case AL_BYTE_LENGTH_SOFT:
1207 case AL_SAMPLE_LENGTH_SOFT:
1208 case AL_DISTANCE_MODEL:
1209 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1210 *values = (ALdouble)ivals[0];
1211 return err;
1213 case AL_BUFFER:
1214 case AL_DIRECT_FILTER:
1215 case AL_AUXILIARY_SEND_FILTER:
1216 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1217 break;
1220 ERR("Unexpected property: 0x%04x\n", prop);
1221 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1224 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1226 ALbufferlistitem *BufferList;
1227 ALdouble dvals[6];
1228 ALboolean err;
1230 switch(prop)
1232 case AL_SOURCE_RELATIVE:
1233 *values = Source->HeadRelative;
1234 return AL_TRUE;
1236 case AL_LOOPING:
1237 *values = ATOMIC_LOAD_SEQ(&Source->looping);
1238 return AL_TRUE;
1240 case AL_BUFFER:
1241 ReadLock(&Source->queue_lock);
1242 BufferList = (Source->SourceType == AL_STATIC) ?
1243 ATOMIC_LOAD_SEQ(&Source->queue) : NULL;
1244 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1245 ReadUnlock(&Source->queue_lock);
1246 return AL_TRUE;
1248 case AL_SOURCE_STATE:
1249 *values = ATOMIC_LOAD_SEQ(&Source->state);
1250 return AL_TRUE;
1252 case AL_BYTE_LENGTH_SOFT:
1253 ReadLock(&Source->queue_lock);
1254 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1255 *values = 0;
1256 else
1258 ALint length = 0;
1259 do {
1260 ALbuffer *buffer = BufferList->buffer;
1261 if(buffer && buffer->SampleLen > 0)
1263 ALuint byte_align, sample_align;
1264 if(buffer->OriginalType == UserFmtIMA4)
1266 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1267 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1268 sample_align = buffer->OriginalAlign;
1270 else if(buffer->OriginalType == UserFmtMSADPCM)
1272 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1273 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1274 sample_align = buffer->OriginalAlign;
1276 else
1278 ALsizei align = buffer->OriginalAlign;
1279 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1280 sample_align = buffer->OriginalAlign;
1283 length += buffer->SampleLen / sample_align * byte_align;
1285 } while((BufferList=BufferList->next) != NULL);
1286 *values = length;
1288 ReadUnlock(&Source->queue_lock);
1289 return AL_TRUE;
1291 case AL_SAMPLE_LENGTH_SOFT:
1292 ReadLock(&Source->queue_lock);
1293 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1294 *values = 0;
1295 else
1297 ALint length = 0;
1298 do {
1299 ALbuffer *buffer = BufferList->buffer;
1300 if(buffer) length += buffer->SampleLen;
1301 } while((BufferList=BufferList->next) != NULL);
1302 *values = length;
1304 ReadUnlock(&Source->queue_lock);
1305 return AL_TRUE;
1307 case AL_BUFFERS_QUEUED:
1308 ReadLock(&Source->queue_lock);
1309 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1310 *values = 0;
1311 else
1313 ALsizei count = 0;
1314 do {
1315 ++count;
1316 } while((BufferList=BufferList->next) != NULL);
1317 *values = count;
1319 ReadUnlock(&Source->queue_lock);
1320 return AL_TRUE;
1322 case AL_BUFFERS_PROCESSED:
1323 ReadLock(&Source->queue_lock);
1324 if(ATOMIC_LOAD_SEQ(&Source->looping) || Source->SourceType != AL_STREAMING)
1326 /* Buffers on a looping source are in a perpetual state of
1327 * PENDING, so don't report any as PROCESSED */
1328 *values = 0;
1330 else
1332 const ALbufferlistitem *BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
1333 const ALbufferlistitem *Current = NULL;
1334 ALsizei played = 0;
1335 ALvoice *voice;
1337 if((voice=GetSourceVoice(Source, Context)) != NULL)
1338 Current = ATOMIC_LOAD_SEQ(&voice->current_buffer);
1339 else if(ATOMIC_LOAD_SEQ(&Source->state) == AL_INITIAL)
1340 Current = BufferList;
1342 while(BufferList && BufferList != Current)
1344 played++;
1345 BufferList = BufferList->next;
1347 *values = played;
1349 ReadUnlock(&Source->queue_lock);
1350 return AL_TRUE;
1352 case AL_SOURCE_TYPE:
1353 *values = Source->SourceType;
1354 return AL_TRUE;
1356 case AL_DIRECT_FILTER_GAINHF_AUTO:
1357 *values = Source->DryGainHFAuto;
1358 return AL_TRUE;
1360 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1361 *values = Source->WetGainAuto;
1362 return AL_TRUE;
1364 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1365 *values = Source->WetGainHFAuto;
1366 return AL_TRUE;
1368 case AL_DIRECT_CHANNELS_SOFT:
1369 *values = Source->DirectChannels;
1370 return AL_TRUE;
1372 case AL_DISTANCE_MODEL:
1373 *values = Source->DistanceModel;
1374 return AL_TRUE;
1376 /* 1x float/double */
1377 case AL_CONE_INNER_ANGLE:
1378 case AL_CONE_OUTER_ANGLE:
1379 case AL_PITCH:
1380 case AL_GAIN:
1381 case AL_MIN_GAIN:
1382 case AL_MAX_GAIN:
1383 case AL_REFERENCE_DISTANCE:
1384 case AL_ROLLOFF_FACTOR:
1385 case AL_CONE_OUTER_GAIN:
1386 case AL_MAX_DISTANCE:
1387 case AL_SEC_OFFSET:
1388 case AL_SAMPLE_OFFSET:
1389 case AL_BYTE_OFFSET:
1390 case AL_DOPPLER_FACTOR:
1391 case AL_AIR_ABSORPTION_FACTOR:
1392 case AL_ROOM_ROLLOFF_FACTOR:
1393 case AL_CONE_OUTER_GAINHF:
1394 case AL_SEC_LENGTH_SOFT:
1395 case AL_SOURCE_RADIUS:
1396 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1397 *values = (ALint)dvals[0];
1398 return err;
1400 /* 3x float/double */
1401 case AL_POSITION:
1402 case AL_VELOCITY:
1403 case AL_DIRECTION:
1404 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1406 values[0] = (ALint)dvals[0];
1407 values[1] = (ALint)dvals[1];
1408 values[2] = (ALint)dvals[2];
1410 return err;
1412 /* 6x float/double */
1413 case AL_ORIENTATION:
1414 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1416 values[0] = (ALint)dvals[0];
1417 values[1] = (ALint)dvals[1];
1418 values[2] = (ALint)dvals[2];
1419 values[3] = (ALint)dvals[3];
1420 values[4] = (ALint)dvals[4];
1421 values[5] = (ALint)dvals[5];
1423 return err;
1425 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1426 break; /* i64 only */
1427 case AL_SEC_OFFSET_LATENCY_SOFT:
1428 break; /* Double only */
1429 case AL_STEREO_ANGLES:
1430 break; /* Float/double only */
1432 case AL_DIRECT_FILTER:
1433 case AL_AUXILIARY_SEND_FILTER:
1434 break; /* ??? */
1437 ERR("Unexpected property: 0x%04x\n", prop);
1438 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1441 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1443 ALCdevice *device = Context->Device;
1444 ClockLatency clocktime;
1445 ALuint64 srcclock;
1446 ALdouble dvals[6];
1447 ALint ivals[3];
1448 ALboolean err;
1450 switch(prop)
1452 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1453 /* Get the source offset with the clock time first. Then get the
1454 * clock time with the device latency. Order is important.
1456 values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
1457 clocktime = V0(device->Backend,getClockLatency)();
1458 if(srcclock == (ALuint64)clocktime.ClockTime)
1459 values[1] = clocktime.Latency;
1460 else
1462 /* If the clock time incremented, reduce the latency by that
1463 * much since it's that much closer to the source offset it got
1464 * earlier.
1466 ALuint64 diff = clocktime.ClockTime - srcclock;
1467 values[1] = clocktime.Latency - minu64(clocktime.Latency, diff);
1469 return AL_TRUE;
1471 /* 1x float/double */
1472 case AL_CONE_INNER_ANGLE:
1473 case AL_CONE_OUTER_ANGLE:
1474 case AL_PITCH:
1475 case AL_GAIN:
1476 case AL_MIN_GAIN:
1477 case AL_MAX_GAIN:
1478 case AL_REFERENCE_DISTANCE:
1479 case AL_ROLLOFF_FACTOR:
1480 case AL_CONE_OUTER_GAIN:
1481 case AL_MAX_DISTANCE:
1482 case AL_SEC_OFFSET:
1483 case AL_SAMPLE_OFFSET:
1484 case AL_BYTE_OFFSET:
1485 case AL_DOPPLER_FACTOR:
1486 case AL_AIR_ABSORPTION_FACTOR:
1487 case AL_ROOM_ROLLOFF_FACTOR:
1488 case AL_CONE_OUTER_GAINHF:
1489 case AL_SEC_LENGTH_SOFT:
1490 case AL_SOURCE_RADIUS:
1491 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1492 *values = (ALint64)dvals[0];
1493 return err;
1495 /* 3x float/double */
1496 case AL_POSITION:
1497 case AL_VELOCITY:
1498 case AL_DIRECTION:
1499 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1501 values[0] = (ALint64)dvals[0];
1502 values[1] = (ALint64)dvals[1];
1503 values[2] = (ALint64)dvals[2];
1505 return err;
1507 /* 6x float/double */
1508 case AL_ORIENTATION:
1509 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1511 values[0] = (ALint64)dvals[0];
1512 values[1] = (ALint64)dvals[1];
1513 values[2] = (ALint64)dvals[2];
1514 values[3] = (ALint64)dvals[3];
1515 values[4] = (ALint64)dvals[4];
1516 values[5] = (ALint64)dvals[5];
1518 return err;
1520 /* 1x int */
1521 case AL_SOURCE_RELATIVE:
1522 case AL_LOOPING:
1523 case AL_SOURCE_STATE:
1524 case AL_BUFFERS_QUEUED:
1525 case AL_BUFFERS_PROCESSED:
1526 case AL_BYTE_LENGTH_SOFT:
1527 case AL_SAMPLE_LENGTH_SOFT:
1528 case AL_SOURCE_TYPE:
1529 case AL_DIRECT_FILTER_GAINHF_AUTO:
1530 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1531 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1532 case AL_DIRECT_CHANNELS_SOFT:
1533 case AL_DISTANCE_MODEL:
1534 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1535 *values = ivals[0];
1536 return err;
1538 /* 1x uint */
1539 case AL_BUFFER:
1540 case AL_DIRECT_FILTER:
1541 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1542 *values = (ALuint)ivals[0];
1543 return err;
1545 /* 3x uint */
1546 case AL_AUXILIARY_SEND_FILTER:
1547 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1549 values[0] = (ALuint)ivals[0];
1550 values[1] = (ALuint)ivals[1];
1551 values[2] = (ALuint)ivals[2];
1553 return err;
1555 case AL_SEC_OFFSET_LATENCY_SOFT:
1556 break; /* Double only */
1557 case AL_STEREO_ANGLES:
1558 break; /* Float/double only */
1561 ERR("Unexpected property: 0x%04x\n", prop);
1562 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1566 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1568 ALCdevice *device;
1569 ALCcontext *context;
1570 ALsizei cur = 0;
1571 ALenum err;
1573 context = GetContextRef();
1574 if(!context) return;
1576 if(!(n >= 0))
1577 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1578 device = context->Device;
1579 for(cur = 0;cur < n;cur++)
1581 ALsource *source = al_calloc(16, sizeof(ALsource));
1582 if(!source)
1584 alDeleteSources(cur, sources);
1585 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1587 InitSourceParams(source, device->NumAuxSends);
1589 err = NewThunkEntry(&source->id);
1590 if(err == AL_NO_ERROR)
1591 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1592 if(err != AL_NO_ERROR)
1594 FreeThunkEntry(source->id);
1595 memset(source, 0, sizeof(ALsource));
1596 al_free(source);
1598 alDeleteSources(cur, sources);
1599 SET_ERROR_AND_GOTO(context, err, done);
1602 sources[cur] = source->id;
1605 done:
1606 ALCcontext_DecRef(context);
1610 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1612 ALCdevice *device;
1613 ALCcontext *context;
1614 ALsource *Source;
1615 ALsizei i;
1617 context = GetContextRef();
1618 if(!context) return;
1620 LockSourcesWrite(context);
1621 if(!(n >= 0))
1622 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1624 /* Check that all Sources are valid */
1625 for(i = 0;i < n;i++)
1627 if(LookupSource(context, sources[i]) == NULL)
1628 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1630 device = context->Device;
1631 for(i = 0;i < n;i++)
1633 ALvoice *voice;
1635 if((Source=RemoveSource(context, sources[i])) == NULL)
1636 continue;
1637 FreeThunkEntry(Source->id);
1639 ALCdevice_Lock(device);
1640 if((voice=GetSourceVoice(Source, context)) != NULL)
1642 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
1643 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
1645 ALCdevice_Unlock(device);
1647 DeinitSource(Source, device->NumAuxSends);
1649 memset(Source, 0, sizeof(*Source));
1650 al_free(Source);
1653 done:
1654 UnlockSourcesWrite(context);
1655 ALCcontext_DecRef(context);
1659 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1661 ALCcontext *context;
1662 ALboolean ret;
1664 context = GetContextRef();
1665 if(!context) return AL_FALSE;
1667 LockSourcesRead(context);
1668 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1669 UnlockSourcesRead(context);
1671 ALCcontext_DecRef(context);
1673 return ret;
1677 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1679 ALCcontext *Context;
1680 ALsource *Source;
1682 Context = GetContextRef();
1683 if(!Context) return;
1685 WriteLock(&Context->PropLock);
1686 LockSourcesRead(Context);
1687 if((Source=LookupSource(Context, source)) == NULL)
1688 alSetError(Context, AL_INVALID_NAME);
1689 else if(!(FloatValsByProp(param) == 1))
1690 alSetError(Context, AL_INVALID_ENUM);
1691 else
1692 SetSourcefv(Source, Context, param, &value);
1693 UnlockSourcesRead(Context);
1694 WriteUnlock(&Context->PropLock);
1696 ALCcontext_DecRef(Context);
1699 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1701 ALCcontext *Context;
1702 ALsource *Source;
1704 Context = GetContextRef();
1705 if(!Context) return;
1707 WriteLock(&Context->PropLock);
1708 LockSourcesRead(Context);
1709 if((Source=LookupSource(Context, source)) == NULL)
1710 alSetError(Context, AL_INVALID_NAME);
1711 else if(!(FloatValsByProp(param) == 3))
1712 alSetError(Context, AL_INVALID_ENUM);
1713 else
1715 ALfloat fvals[3] = { value1, value2, value3 };
1716 SetSourcefv(Source, Context, param, fvals);
1718 UnlockSourcesRead(Context);
1719 WriteUnlock(&Context->PropLock);
1721 ALCcontext_DecRef(Context);
1724 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1726 ALCcontext *Context;
1727 ALsource *Source;
1729 Context = GetContextRef();
1730 if(!Context) return;
1732 WriteLock(&Context->PropLock);
1733 LockSourcesRead(Context);
1734 if((Source=LookupSource(Context, source)) == NULL)
1735 alSetError(Context, AL_INVALID_NAME);
1736 else if(!values)
1737 alSetError(Context, AL_INVALID_VALUE);
1738 else if(!(FloatValsByProp(param) > 0))
1739 alSetError(Context, AL_INVALID_ENUM);
1740 else
1741 SetSourcefv(Source, Context, param, values);
1742 UnlockSourcesRead(Context);
1743 WriteUnlock(&Context->PropLock);
1745 ALCcontext_DecRef(Context);
1749 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1751 ALCcontext *Context;
1752 ALsource *Source;
1754 Context = GetContextRef();
1755 if(!Context) return;
1757 WriteLock(&Context->PropLock);
1758 LockSourcesRead(Context);
1759 if((Source=LookupSource(Context, source)) == NULL)
1760 alSetError(Context, AL_INVALID_NAME);
1761 else if(!(DoubleValsByProp(param) == 1))
1762 alSetError(Context, AL_INVALID_ENUM);
1763 else
1765 ALfloat fval = (ALfloat)value;
1766 SetSourcefv(Source, Context, param, &fval);
1768 UnlockSourcesRead(Context);
1769 WriteUnlock(&Context->PropLock);
1771 ALCcontext_DecRef(Context);
1774 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1776 ALCcontext *Context;
1777 ALsource *Source;
1779 Context = GetContextRef();
1780 if(!Context) return;
1782 WriteLock(&Context->PropLock);
1783 LockSourcesRead(Context);
1784 if((Source=LookupSource(Context, source)) == NULL)
1785 alSetError(Context, AL_INVALID_NAME);
1786 else if(!(DoubleValsByProp(param) == 3))
1787 alSetError(Context, AL_INVALID_ENUM);
1788 else
1790 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1791 SetSourcefv(Source, Context, param, fvals);
1793 UnlockSourcesRead(Context);
1794 WriteUnlock(&Context->PropLock);
1796 ALCcontext_DecRef(Context);
1799 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1801 ALCcontext *Context;
1802 ALsource *Source;
1803 ALint count;
1805 Context = GetContextRef();
1806 if(!Context) return;
1808 WriteLock(&Context->PropLock);
1809 LockSourcesRead(Context);
1810 if((Source=LookupSource(Context, source)) == NULL)
1811 alSetError(Context, AL_INVALID_NAME);
1812 else if(!values)
1813 alSetError(Context, AL_INVALID_VALUE);
1814 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1815 alSetError(Context, AL_INVALID_ENUM);
1816 else
1818 ALfloat fvals[6];
1819 ALint i;
1821 for(i = 0;i < count;i++)
1822 fvals[i] = (ALfloat)values[i];
1823 SetSourcefv(Source, Context, param, fvals);
1825 UnlockSourcesRead(Context);
1826 WriteUnlock(&Context->PropLock);
1828 ALCcontext_DecRef(Context);
1832 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1834 ALCcontext *Context;
1835 ALsource *Source;
1837 Context = GetContextRef();
1838 if(!Context) return;
1840 WriteLock(&Context->PropLock);
1841 LockSourcesRead(Context);
1842 if((Source=LookupSource(Context, source)) == NULL)
1843 alSetError(Context, AL_INVALID_NAME);
1844 else if(!(IntValsByProp(param) == 1))
1845 alSetError(Context, AL_INVALID_ENUM);
1846 else
1847 SetSourceiv(Source, Context, param, &value);
1848 UnlockSourcesRead(Context);
1849 WriteUnlock(&Context->PropLock);
1851 ALCcontext_DecRef(Context);
1854 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1856 ALCcontext *Context;
1857 ALsource *Source;
1859 Context = GetContextRef();
1860 if(!Context) return;
1862 WriteLock(&Context->PropLock);
1863 LockSourcesRead(Context);
1864 if((Source=LookupSource(Context, source)) == NULL)
1865 alSetError(Context, AL_INVALID_NAME);
1866 else if(!(IntValsByProp(param) == 3))
1867 alSetError(Context, AL_INVALID_ENUM);
1868 else
1870 ALint ivals[3] = { value1, value2, value3 };
1871 SetSourceiv(Source, Context, param, ivals);
1873 UnlockSourcesRead(Context);
1874 WriteUnlock(&Context->PropLock);
1876 ALCcontext_DecRef(Context);
1879 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1881 ALCcontext *Context;
1882 ALsource *Source;
1884 Context = GetContextRef();
1885 if(!Context) return;
1887 WriteLock(&Context->PropLock);
1888 LockSourcesRead(Context);
1889 if((Source=LookupSource(Context, source)) == NULL)
1890 alSetError(Context, AL_INVALID_NAME);
1891 else if(!values)
1892 alSetError(Context, AL_INVALID_VALUE);
1893 else if(!(IntValsByProp(param) > 0))
1894 alSetError(Context, AL_INVALID_ENUM);
1895 else
1896 SetSourceiv(Source, Context, param, values);
1897 UnlockSourcesRead(Context);
1898 WriteUnlock(&Context->PropLock);
1900 ALCcontext_DecRef(Context);
1904 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1906 ALCcontext *Context;
1907 ALsource *Source;
1909 Context = GetContextRef();
1910 if(!Context) return;
1912 WriteLock(&Context->PropLock);
1913 LockSourcesRead(Context);
1914 if((Source=LookupSource(Context, source)) == NULL)
1915 alSetError(Context, AL_INVALID_NAME);
1916 else if(!(Int64ValsByProp(param) == 1))
1917 alSetError(Context, AL_INVALID_ENUM);
1918 else
1919 SetSourcei64v(Source, Context, param, &value);
1920 UnlockSourcesRead(Context);
1921 WriteUnlock(&Context->PropLock);
1923 ALCcontext_DecRef(Context);
1926 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1928 ALCcontext *Context;
1929 ALsource *Source;
1931 Context = GetContextRef();
1932 if(!Context) return;
1934 WriteLock(&Context->PropLock);
1935 LockSourcesRead(Context);
1936 if((Source=LookupSource(Context, source)) == NULL)
1937 alSetError(Context, AL_INVALID_NAME);
1938 else if(!(Int64ValsByProp(param) == 3))
1939 alSetError(Context, AL_INVALID_ENUM);
1940 else
1942 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1943 SetSourcei64v(Source, Context, param, i64vals);
1945 UnlockSourcesRead(Context);
1946 WriteUnlock(&Context->PropLock);
1948 ALCcontext_DecRef(Context);
1951 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1953 ALCcontext *Context;
1954 ALsource *Source;
1956 Context = GetContextRef();
1957 if(!Context) return;
1959 WriteLock(&Context->PropLock);
1960 LockSourcesRead(Context);
1961 if((Source=LookupSource(Context, source)) == NULL)
1962 alSetError(Context, AL_INVALID_NAME);
1963 else if(!values)
1964 alSetError(Context, AL_INVALID_VALUE);
1965 else if(!(Int64ValsByProp(param) > 0))
1966 alSetError(Context, AL_INVALID_ENUM);
1967 else
1968 SetSourcei64v(Source, Context, param, values);
1969 UnlockSourcesRead(Context);
1970 WriteUnlock(&Context->PropLock);
1972 ALCcontext_DecRef(Context);
1976 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1978 ALCcontext *Context;
1979 ALsource *Source;
1981 Context = GetContextRef();
1982 if(!Context) return;
1984 ReadLock(&Context->PropLock);
1985 LockSourcesRead(Context);
1986 if((Source=LookupSource(Context, source)) == NULL)
1987 alSetError(Context, AL_INVALID_NAME);
1988 else if(!value)
1989 alSetError(Context, AL_INVALID_VALUE);
1990 else if(!(FloatValsByProp(param) == 1))
1991 alSetError(Context, AL_INVALID_ENUM);
1992 else
1994 ALdouble dval;
1995 if(GetSourcedv(Source, Context, param, &dval))
1996 *value = (ALfloat)dval;
1998 UnlockSourcesRead(Context);
1999 ReadUnlock(&Context->PropLock);
2001 ALCcontext_DecRef(Context);
2005 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
2007 ALCcontext *Context;
2008 ALsource *Source;
2010 Context = GetContextRef();
2011 if(!Context) return;
2013 ReadLock(&Context->PropLock);
2014 LockSourcesRead(Context);
2015 if((Source=LookupSource(Context, source)) == NULL)
2016 alSetError(Context, AL_INVALID_NAME);
2017 else if(!(value1 && value2 && value3))
2018 alSetError(Context, AL_INVALID_VALUE);
2019 else if(!(FloatValsByProp(param) == 3))
2020 alSetError(Context, AL_INVALID_ENUM);
2021 else
2023 ALdouble dvals[3];
2024 if(GetSourcedv(Source, Context, param, dvals))
2026 *value1 = (ALfloat)dvals[0];
2027 *value2 = (ALfloat)dvals[1];
2028 *value3 = (ALfloat)dvals[2];
2031 UnlockSourcesRead(Context);
2032 ReadUnlock(&Context->PropLock);
2034 ALCcontext_DecRef(Context);
2038 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
2040 ALCcontext *Context;
2041 ALsource *Source;
2042 ALint count;
2044 Context = GetContextRef();
2045 if(!Context) return;
2047 ReadLock(&Context->PropLock);
2048 LockSourcesRead(Context);
2049 if((Source=LookupSource(Context, source)) == NULL)
2050 alSetError(Context, AL_INVALID_NAME);
2051 else if(!values)
2052 alSetError(Context, AL_INVALID_VALUE);
2053 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
2054 alSetError(Context, AL_INVALID_ENUM);
2055 else
2057 ALdouble dvals[6];
2058 if(GetSourcedv(Source, Context, param, dvals))
2060 ALint i;
2061 for(i = 0;i < count;i++)
2062 values[i] = (ALfloat)dvals[i];
2065 UnlockSourcesRead(Context);
2066 ReadUnlock(&Context->PropLock);
2068 ALCcontext_DecRef(Context);
2072 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
2074 ALCcontext *Context;
2075 ALsource *Source;
2077 Context = GetContextRef();
2078 if(!Context) return;
2080 ReadLock(&Context->PropLock);
2081 LockSourcesRead(Context);
2082 if((Source=LookupSource(Context, source)) == NULL)
2083 alSetError(Context, AL_INVALID_NAME);
2084 else if(!value)
2085 alSetError(Context, AL_INVALID_VALUE);
2086 else if(!(DoubleValsByProp(param) == 1))
2087 alSetError(Context, AL_INVALID_ENUM);
2088 else
2089 GetSourcedv(Source, Context, param, value);
2090 UnlockSourcesRead(Context);
2091 ReadUnlock(&Context->PropLock);
2093 ALCcontext_DecRef(Context);
2096 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
2098 ALCcontext *Context;
2099 ALsource *Source;
2101 Context = GetContextRef();
2102 if(!Context) return;
2104 ReadLock(&Context->PropLock);
2105 LockSourcesRead(Context);
2106 if((Source=LookupSource(Context, source)) == NULL)
2107 alSetError(Context, AL_INVALID_NAME);
2108 else if(!(value1 && value2 && value3))
2109 alSetError(Context, AL_INVALID_VALUE);
2110 else if(!(DoubleValsByProp(param) == 3))
2111 alSetError(Context, AL_INVALID_ENUM);
2112 else
2114 ALdouble dvals[3];
2115 if(GetSourcedv(Source, Context, param, dvals))
2117 *value1 = dvals[0];
2118 *value2 = dvals[1];
2119 *value3 = dvals[2];
2122 UnlockSourcesRead(Context);
2123 ReadUnlock(&Context->PropLock);
2125 ALCcontext_DecRef(Context);
2128 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
2130 ALCcontext *Context;
2131 ALsource *Source;
2133 Context = GetContextRef();
2134 if(!Context) return;
2136 ReadLock(&Context->PropLock);
2137 LockSourcesRead(Context);
2138 if((Source=LookupSource(Context, source)) == NULL)
2139 alSetError(Context, AL_INVALID_NAME);
2140 else if(!values)
2141 alSetError(Context, AL_INVALID_VALUE);
2142 else if(!(DoubleValsByProp(param) > 0))
2143 alSetError(Context, AL_INVALID_ENUM);
2144 else
2145 GetSourcedv(Source, Context, param, values);
2146 UnlockSourcesRead(Context);
2147 ReadUnlock(&Context->PropLock);
2149 ALCcontext_DecRef(Context);
2153 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2155 ALCcontext *Context;
2156 ALsource *Source;
2158 Context = GetContextRef();
2159 if(!Context) return;
2161 ReadLock(&Context->PropLock);
2162 LockSourcesRead(Context);
2163 if((Source=LookupSource(Context, source)) == NULL)
2164 alSetError(Context, AL_INVALID_NAME);
2165 else if(!value)
2166 alSetError(Context, AL_INVALID_VALUE);
2167 else if(!(IntValsByProp(param) == 1))
2168 alSetError(Context, AL_INVALID_ENUM);
2169 else
2170 GetSourceiv(Source, Context, param, value);
2171 UnlockSourcesRead(Context);
2172 ReadUnlock(&Context->PropLock);
2174 ALCcontext_DecRef(Context);
2178 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2180 ALCcontext *Context;
2181 ALsource *Source;
2183 Context = GetContextRef();
2184 if(!Context) return;
2186 ReadLock(&Context->PropLock);
2187 LockSourcesRead(Context);
2188 if((Source=LookupSource(Context, source)) == NULL)
2189 alSetError(Context, AL_INVALID_NAME);
2190 else if(!(value1 && value2 && value3))
2191 alSetError(Context, AL_INVALID_VALUE);
2192 else if(!(IntValsByProp(param) == 3))
2193 alSetError(Context, AL_INVALID_ENUM);
2194 else
2196 ALint ivals[3];
2197 if(GetSourceiv(Source, Context, param, ivals))
2199 *value1 = ivals[0];
2200 *value2 = ivals[1];
2201 *value3 = ivals[2];
2204 UnlockSourcesRead(Context);
2205 ReadUnlock(&Context->PropLock);
2207 ALCcontext_DecRef(Context);
2211 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2213 ALCcontext *Context;
2214 ALsource *Source;
2216 Context = GetContextRef();
2217 if(!Context) return;
2219 ReadLock(&Context->PropLock);
2220 LockSourcesRead(Context);
2221 if((Source=LookupSource(Context, source)) == NULL)
2222 alSetError(Context, AL_INVALID_NAME);
2223 else if(!values)
2224 alSetError(Context, AL_INVALID_VALUE);
2225 else if(!(IntValsByProp(param) > 0))
2226 alSetError(Context, AL_INVALID_ENUM);
2227 else
2228 GetSourceiv(Source, Context, param, values);
2229 UnlockSourcesRead(Context);
2230 ReadUnlock(&Context->PropLock);
2232 ALCcontext_DecRef(Context);
2236 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2238 ALCcontext *Context;
2239 ALsource *Source;
2241 Context = GetContextRef();
2242 if(!Context) return;
2244 ReadLock(&Context->PropLock);
2245 LockSourcesRead(Context);
2246 if((Source=LookupSource(Context, source)) == NULL)
2247 alSetError(Context, AL_INVALID_NAME);
2248 else if(!value)
2249 alSetError(Context, AL_INVALID_VALUE);
2250 else if(!(Int64ValsByProp(param) == 1))
2251 alSetError(Context, AL_INVALID_ENUM);
2252 else
2253 GetSourcei64v(Source, Context, param, value);
2254 UnlockSourcesRead(Context);
2255 ReadUnlock(&Context->PropLock);
2257 ALCcontext_DecRef(Context);
2260 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2262 ALCcontext *Context;
2263 ALsource *Source;
2265 Context = GetContextRef();
2266 if(!Context) return;
2268 ReadLock(&Context->PropLock);
2269 LockSourcesRead(Context);
2270 if((Source=LookupSource(Context, source)) == NULL)
2271 alSetError(Context, AL_INVALID_NAME);
2272 else if(!(value1 && value2 && value3))
2273 alSetError(Context, AL_INVALID_VALUE);
2274 else if(!(Int64ValsByProp(param) == 3))
2275 alSetError(Context, AL_INVALID_ENUM);
2276 else
2278 ALint64 i64vals[3];
2279 if(GetSourcei64v(Source, Context, param, i64vals))
2281 *value1 = i64vals[0];
2282 *value2 = i64vals[1];
2283 *value3 = i64vals[2];
2286 UnlockSourcesRead(Context);
2287 ReadUnlock(&Context->PropLock);
2289 ALCcontext_DecRef(Context);
2292 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2294 ALCcontext *Context;
2295 ALsource *Source;
2297 Context = GetContextRef();
2298 if(!Context) return;
2300 ReadLock(&Context->PropLock);
2301 LockSourcesRead(Context);
2302 if((Source=LookupSource(Context, source)) == NULL)
2303 alSetError(Context, AL_INVALID_NAME);
2304 else if(!values)
2305 alSetError(Context, AL_INVALID_VALUE);
2306 else if(!(Int64ValsByProp(param) > 0))
2307 alSetError(Context, AL_INVALID_ENUM);
2308 else
2309 GetSourcei64v(Source, Context, param, values);
2310 UnlockSourcesRead(Context);
2311 ReadUnlock(&Context->PropLock);
2313 ALCcontext_DecRef(Context);
2317 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2319 alSourcePlayv(1, &source);
2321 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2323 ALCcontext *context;
2324 ALsource *source;
2325 ALsizei i;
2327 context = GetContextRef();
2328 if(!context) return;
2330 LockSourcesRead(context);
2331 if(!(n >= 0))
2332 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2333 for(i = 0;i < n;i++)
2335 if(!LookupSource(context, sources[i]))
2336 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2339 ALCdevice_Lock(context->Device);
2340 while(n > context->MaxVoices-context->VoiceCount)
2342 ALsizei newcount = context->MaxVoices << 1;
2343 if(context->MaxVoices >= newcount)
2345 ALCdevice_Unlock(context->Device);
2346 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2348 AllocateVoices(context, newcount, context->Device->NumAuxSends);
2351 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll)
2353 for(i = 0;i < n;i++)
2355 source = LookupSource(context, sources[i]);
2356 source->new_state = AL_PLAYING;
2359 else
2361 for(i = 0;i < n;i++)
2363 source = LookupSource(context, sources[i]);
2364 SetSourceState(source, context, AL_PLAYING);
2367 ALCdevice_Unlock(context->Device);
2369 done:
2370 UnlockSourcesRead(context);
2371 ALCcontext_DecRef(context);
2374 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2376 alSourcePausev(1, &source);
2378 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2380 ALCcontext *context;
2381 ALsource *source;
2382 ALsizei i;
2384 context = GetContextRef();
2385 if(!context) return;
2387 LockSourcesRead(context);
2388 if(!(n >= 0))
2389 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2390 for(i = 0;i < n;i++)
2392 if(!LookupSource(context, sources[i]))
2393 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2396 ALCdevice_Lock(context->Device);
2397 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
2399 for(i = 0;i < n;i++)
2401 source = LookupSource(context, sources[i]);
2402 source->new_state = AL_PAUSED;
2405 else
2407 for(i = 0;i < n;i++)
2409 source = LookupSource(context, sources[i]);
2410 SetSourceState(source, context, AL_PAUSED);
2413 ALCdevice_Unlock(context->Device);
2415 done:
2416 UnlockSourcesRead(context);
2417 ALCcontext_DecRef(context);
2420 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2422 alSourceStopv(1, &source);
2424 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2426 ALCcontext *context;
2427 ALsource *source;
2428 ALsizei i;
2430 context = GetContextRef();
2431 if(!context) return;
2433 LockSourcesRead(context);
2434 if(!(n >= 0))
2435 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2436 for(i = 0;i < n;i++)
2438 if(!LookupSource(context, sources[i]))
2439 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2442 ALCdevice_Lock(context->Device);
2443 for(i = 0;i < n;i++)
2445 source = LookupSource(context, sources[i]);
2446 source->new_state = AL_NONE;
2447 SetSourceState(source, context, AL_STOPPED);
2449 ALCdevice_Unlock(context->Device);
2451 done:
2452 UnlockSourcesRead(context);
2453 ALCcontext_DecRef(context);
2456 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2458 alSourceRewindv(1, &source);
2460 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2462 ALCcontext *context;
2463 ALsource *source;
2464 ALsizei i;
2466 context = GetContextRef();
2467 if(!context) return;
2469 LockSourcesRead(context);
2470 if(!(n >= 0))
2471 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2472 for(i = 0;i < n;i++)
2474 if(!LookupSource(context, sources[i]))
2475 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2478 ALCdevice_Lock(context->Device);
2479 for(i = 0;i < n;i++)
2481 source = LookupSource(context, sources[i]);
2482 source->new_state = AL_NONE;
2483 SetSourceState(source, context, AL_INITIAL);
2485 ALCdevice_Unlock(context->Device);
2487 done:
2488 UnlockSourcesRead(context);
2489 ALCcontext_DecRef(context);
2493 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2495 ALCdevice *device;
2496 ALCcontext *context;
2497 ALsource *source;
2498 ALsizei i;
2499 ALbufferlistitem *BufferListStart;
2500 ALbufferlistitem *BufferList;
2501 ALbuffer *BufferFmt = NULL;
2503 if(nb == 0)
2504 return;
2506 context = GetContextRef();
2507 if(!context) return;
2509 device = context->Device;
2511 LockSourcesRead(context);
2512 if(!(nb >= 0))
2513 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2514 if((source=LookupSource(context, src)) == NULL)
2515 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2517 WriteLock(&source->queue_lock);
2518 if(source->SourceType == AL_STATIC)
2520 WriteUnlock(&source->queue_lock);
2521 /* Can't queue on a Static Source */
2522 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2525 /* Check for a valid Buffer, for its frequency and format */
2526 BufferList = ATOMIC_LOAD_SEQ(&source->queue);
2527 while(BufferList)
2529 if(BufferList->buffer)
2531 BufferFmt = BufferList->buffer;
2532 break;
2534 BufferList = BufferList->next;
2537 LockBuffersRead(device);
2538 BufferListStart = NULL;
2539 BufferList = NULL;
2540 for(i = 0;i < nb;i++)
2542 ALbuffer *buffer = NULL;
2543 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2545 WriteUnlock(&source->queue_lock);
2546 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2549 if(!BufferListStart)
2551 BufferListStart = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
2552 BufferList = BufferListStart;
2554 else
2556 BufferList->next = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
2557 BufferList = BufferList->next;
2559 BufferList->buffer = buffer;
2560 BufferList->next = NULL;
2561 if(!buffer) continue;
2563 /* Hold a read lock on each buffer being queued while checking all
2564 * provided buffers. This is done so other threads don't see an extra
2565 * reference on some buffers if this operation ends up failing. */
2566 ReadLock(&buffer->lock);
2567 IncrementRef(&buffer->ref);
2569 if(BufferFmt == NULL)
2571 BufferFmt = buffer;
2573 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2574 source->SampleSize = BytesFromFmt(buffer->FmtType);
2576 else if(BufferFmt->Frequency != buffer->Frequency ||
2577 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2578 BufferFmt->OriginalType != buffer->OriginalType)
2580 WriteUnlock(&source->queue_lock);
2581 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2583 buffer_error:
2584 /* A buffer failed (invalid ID or format), so unlock and release
2585 * each buffer we had. */
2586 while(BufferListStart)
2588 ALbufferlistitem *next = BufferListStart->next;
2589 if((buffer=BufferListStart->buffer) != NULL)
2591 DecrementRef(&buffer->ref);
2592 ReadUnlock(&buffer->lock);
2594 al_free(BufferListStart);
2595 BufferListStart = next;
2597 UnlockBuffersRead(device);
2598 goto done;
2601 /* All buffers good, unlock them now. */
2602 BufferList = BufferListStart;
2603 while(BufferList != NULL)
2605 ALbuffer *buffer = BufferList->buffer;
2606 if(buffer) ReadUnlock(&buffer->lock);
2607 BufferList = BufferList->next;
2609 UnlockBuffersRead(device);
2611 /* Source is now streaming */
2612 source->SourceType = AL_STREAMING;
2614 BufferList = NULL;
2615 if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem*, &source->queue,
2616 &BufferList, BufferListStart))
2618 /* Queue head is not NULL, append to the end of the queue */
2619 while(BufferList->next != NULL)
2620 BufferList = BufferList->next;
2621 BufferList->next = BufferListStart;
2623 WriteUnlock(&source->queue_lock);
2625 done:
2626 UnlockSourcesRead(context);
2627 ALCcontext_DecRef(context);
2630 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2632 ALCcontext *context;
2633 ALsource *source;
2634 ALbufferlistitem *OldHead;
2635 ALbufferlistitem *OldTail;
2636 ALbufferlistitem *Current;
2637 ALvoice *voice;
2638 ALsizei i = 0;
2640 context = GetContextRef();
2641 if(!context) return;
2643 LockSourcesRead(context);
2644 if(!(nb >= 0))
2645 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2647 if((source=LookupSource(context, src)) == NULL)
2648 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2650 /* Nothing to unqueue. */
2651 if(nb == 0) goto done;
2653 WriteLock(&source->queue_lock);
2654 if(ATOMIC_LOAD_SEQ(&source->looping) || source->SourceType != AL_STREAMING)
2656 WriteUnlock(&source->queue_lock);
2657 /* Trying to unqueue buffers on a looping or non-streaming source. */
2658 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2661 /* Find the new buffer queue head */
2662 OldTail = ATOMIC_LOAD_SEQ(&source->queue);
2663 Current = NULL;
2664 if((voice=GetSourceVoice(source, context)) != NULL)
2665 Current = ATOMIC_LOAD_SEQ(&voice->current_buffer);
2666 else if(ATOMIC_LOAD_SEQ(&source->state) == AL_INITIAL)
2667 Current = OldTail;
2668 if(OldTail != Current)
2670 for(i = 1;i < nb;i++)
2672 ALbufferlistitem *next = OldTail->next;
2673 if(!next || next == Current) break;
2674 OldTail = next;
2677 if(i != nb)
2679 WriteUnlock(&source->queue_lock);
2680 /* Trying to unqueue pending buffers. */
2681 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2684 /* Swap it, and cut the new head from the old. */
2685 OldHead = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &source->queue, OldTail->next);
2686 if(OldTail->next)
2688 ALCdevice *device = context->Device;
2689 uint count;
2691 /* Once the active mix (if any) is done, it's safe to cut the old tail
2692 * from the new head.
2694 if(((count=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
2696 while(count == ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))
2697 althrd_yield();
2699 ATOMIC_THREAD_FENCE(almemory_order_acq_rel);
2700 OldTail->next = NULL;
2702 WriteUnlock(&source->queue_lock);
2704 while(OldHead != NULL)
2706 ALbufferlistitem *next = OldHead->next;
2707 ALbuffer *buffer = OldHead->buffer;
2709 if(!buffer)
2710 *(buffers++) = 0;
2711 else
2713 *(buffers++) = buffer->id;
2714 DecrementRef(&buffer->ref);
2717 al_free(OldHead);
2718 OldHead = next;
2721 done:
2722 UnlockSourcesRead(context);
2723 ALCcontext_DecRef(context);
2727 static void InitSourceParams(ALsource *Source, ALsizei num_sends)
2729 ALsizei i;
2731 RWLockInit(&Source->queue_lock);
2733 Source->InnerAngle = 360.0f;
2734 Source->OuterAngle = 360.0f;
2735 Source->Pitch = 1.0f;
2736 Source->Position[0] = 0.0f;
2737 Source->Position[1] = 0.0f;
2738 Source->Position[2] = 0.0f;
2739 Source->Velocity[0] = 0.0f;
2740 Source->Velocity[1] = 0.0f;
2741 Source->Velocity[2] = 0.0f;
2742 Source->Direction[0] = 0.0f;
2743 Source->Direction[1] = 0.0f;
2744 Source->Direction[2] = 0.0f;
2745 Source->Orientation[0][0] = 0.0f;
2746 Source->Orientation[0][1] = 0.0f;
2747 Source->Orientation[0][2] = -1.0f;
2748 Source->Orientation[1][0] = 0.0f;
2749 Source->Orientation[1][1] = 1.0f;
2750 Source->Orientation[1][2] = 0.0f;
2751 Source->RefDistance = 1.0f;
2752 Source->MaxDistance = FLT_MAX;
2753 Source->RollOffFactor = 1.0f;
2754 Source->Gain = 1.0f;
2755 Source->MinGain = 0.0f;
2756 Source->MaxGain = 1.0f;
2757 Source->OuterGain = 0.0f;
2758 Source->OuterGainHF = 1.0f;
2760 Source->DryGainHFAuto = AL_TRUE;
2761 Source->WetGainAuto = AL_TRUE;
2762 Source->WetGainHFAuto = AL_TRUE;
2763 Source->AirAbsorptionFactor = 0.0f;
2764 Source->RoomRolloffFactor = 0.0f;
2765 Source->DopplerFactor = 1.0f;
2766 Source->DirectChannels = AL_FALSE;
2768 Source->StereoPan[0] = DEG2RAD( 30.0f);
2769 Source->StereoPan[1] = DEG2RAD(-30.0f);
2771 Source->Radius = 0.0f;
2773 Source->DistanceModel = DefaultDistanceModel;
2775 Source->Direct.Gain = 1.0f;
2776 Source->Direct.GainHF = 1.0f;
2777 Source->Direct.HFReference = LOWPASSFREQREF;
2778 Source->Direct.GainLF = 1.0f;
2779 Source->Direct.LFReference = HIGHPASSFREQREF;
2780 Source->Send = al_calloc(16, num_sends*sizeof(Source->Send[0]));
2781 for(i = 0;i < num_sends;i++)
2783 Source->Send[i].Slot = NULL;
2784 Source->Send[i].Gain = 1.0f;
2785 Source->Send[i].GainHF = 1.0f;
2786 Source->Send[i].HFReference = LOWPASSFREQREF;
2787 Source->Send[i].GainLF = 1.0f;
2788 Source->Send[i].LFReference = HIGHPASSFREQREF;
2791 Source->Offset = 0.0;
2792 Source->OffsetType = AL_NONE;
2793 Source->SourceType = AL_UNDETERMINED;
2794 ATOMIC_INIT(&Source->state, AL_INITIAL);
2795 Source->new_state = AL_NONE;
2797 ATOMIC_INIT(&Source->queue, NULL);
2799 ATOMIC_INIT(&Source->looping, AL_FALSE);
2801 Source->NeedsUpdate = AL_TRUE;
2803 ATOMIC_INIT(&Source->Update, NULL);
2804 ATOMIC_INIT(&Source->FreeList, NULL);
2807 static void DeinitSource(ALsource *source, ALsizei num_sends)
2809 ALbufferlistitem *BufferList;
2810 struct ALsourceProps *props;
2811 size_t count = 0;
2812 ALsizei i;
2814 props = ATOMIC_LOAD_SEQ(&source->Update);
2815 if(props) al_free(props);
2817 props = ATOMIC_LOAD(&source->FreeList, almemory_order_relaxed);
2818 while(props)
2820 struct ALsourceProps *next;
2821 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2822 al_free(props);
2823 props = next;
2824 ++count;
2826 /* This is excessively spammy if it traces every source destruction, so
2827 * just warn if it was unexpectedly large.
2829 if(count > 3)
2830 WARN("Freed "SZFMT" Source property objects\n", count);
2832 BufferList = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &source->queue, NULL);
2833 while(BufferList != NULL)
2835 ALbufferlistitem *next = BufferList->next;
2836 if(BufferList->buffer != NULL)
2837 DecrementRef(&BufferList->buffer->ref);
2838 al_free(BufferList);
2839 BufferList = next;
2842 if(source->Send)
2844 for(i = 0;i < num_sends;i++)
2846 if(source->Send[i].Slot)
2847 DecrementRef(&source->Send[i].Slot->ref);
2848 source->Send[i].Slot = NULL;
2850 al_free(source->Send);
2851 source->Send = NULL;
2855 static void UpdateSourceProps(ALsource *source, ALsizei num_sends)
2857 struct ALsourceProps *props;
2858 ALsizei i;
2860 /* Get an unused property container, or allocate a new one as needed. */
2861 props = ATOMIC_LOAD(&source->FreeList, almemory_order_acquire);
2862 if(!props)
2863 props = al_calloc(16, offsetof(struct ALsourceProps, Send[num_sends]));
2864 else
2866 struct ALsourceProps *next;
2867 do {
2868 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2869 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*,
2870 &source->FreeList, &props, next, almemory_order_acq_rel,
2871 almemory_order_acquire) == 0);
2874 /* Copy in current property values. */
2875 ATOMIC_STORE(&props->Pitch, source->Pitch, almemory_order_relaxed);
2876 ATOMIC_STORE(&props->Gain, source->Gain, almemory_order_relaxed);
2877 ATOMIC_STORE(&props->OuterGain, source->OuterGain, almemory_order_relaxed);
2878 ATOMIC_STORE(&props->MinGain, source->MinGain, almemory_order_relaxed);
2879 ATOMIC_STORE(&props->MaxGain, source->MaxGain, almemory_order_relaxed);
2880 ATOMIC_STORE(&props->InnerAngle, source->InnerAngle, almemory_order_relaxed);
2881 ATOMIC_STORE(&props->OuterAngle, source->OuterAngle, almemory_order_relaxed);
2882 ATOMIC_STORE(&props->RefDistance, source->RefDistance, almemory_order_relaxed);
2883 ATOMIC_STORE(&props->MaxDistance, source->MaxDistance, almemory_order_relaxed);
2884 ATOMIC_STORE(&props->RollOffFactor, source->RollOffFactor, almemory_order_relaxed);
2885 for(i = 0;i < 3;i++)
2886 ATOMIC_STORE(&props->Position[i], source->Position[i], almemory_order_relaxed);
2887 for(i = 0;i < 3;i++)
2888 ATOMIC_STORE(&props->Velocity[i], source->Velocity[i], almemory_order_relaxed);
2889 for(i = 0;i < 3;i++)
2890 ATOMIC_STORE(&props->Direction[i], source->Direction[i], almemory_order_relaxed);
2891 for(i = 0;i < 2;i++)
2893 ALsizei j;
2894 for(j = 0;j < 3;j++)
2895 ATOMIC_STORE(&props->Orientation[i][j], source->Orientation[i][j],
2896 almemory_order_relaxed);
2898 ATOMIC_STORE(&props->HeadRelative, source->HeadRelative, almemory_order_relaxed);
2899 ATOMIC_STORE(&props->DistanceModel, source->DistanceModel, almemory_order_relaxed);
2900 ATOMIC_STORE(&props->DirectChannels, source->DirectChannels, almemory_order_relaxed);
2902 ATOMIC_STORE(&props->DryGainHFAuto, source->DryGainHFAuto, almemory_order_relaxed);
2903 ATOMIC_STORE(&props->WetGainAuto, source->WetGainAuto, almemory_order_relaxed);
2904 ATOMIC_STORE(&props->WetGainHFAuto, source->WetGainHFAuto, almemory_order_relaxed);
2905 ATOMIC_STORE(&props->OuterGainHF, source->OuterGainHF, almemory_order_relaxed);
2907 ATOMIC_STORE(&props->AirAbsorptionFactor, source->AirAbsorptionFactor, almemory_order_relaxed);
2908 ATOMIC_STORE(&props->RoomRolloffFactor, source->RoomRolloffFactor, almemory_order_relaxed);
2909 ATOMIC_STORE(&props->DopplerFactor, source->DopplerFactor, almemory_order_relaxed);
2911 ATOMIC_STORE(&props->StereoPan[0], source->StereoPan[0], almemory_order_relaxed);
2912 ATOMIC_STORE(&props->StereoPan[1], source->StereoPan[1], almemory_order_relaxed);
2914 ATOMIC_STORE(&props->Radius, source->Radius, almemory_order_relaxed);
2916 ATOMIC_STORE(&props->Direct.Gain, source->Direct.Gain, almemory_order_relaxed);
2917 ATOMIC_STORE(&props->Direct.GainHF, source->Direct.GainHF, almemory_order_relaxed);
2918 ATOMIC_STORE(&props->Direct.HFReference, source->Direct.HFReference, almemory_order_relaxed);
2919 ATOMIC_STORE(&props->Direct.GainLF, source->Direct.GainLF, almemory_order_relaxed);
2920 ATOMIC_STORE(&props->Direct.LFReference, source->Direct.LFReference, almemory_order_relaxed);
2922 for(i = 0;i < num_sends;i++)
2924 ATOMIC_STORE(&props->Send[i].Slot, source->Send[i].Slot, almemory_order_relaxed);
2925 ATOMIC_STORE(&props->Send[i].Gain, source->Send[i].Gain, almemory_order_relaxed);
2926 ATOMIC_STORE(&props->Send[i].GainHF, source->Send[i].GainHF, almemory_order_relaxed);
2927 ATOMIC_STORE(&props->Send[i].HFReference, source->Send[i].HFReference,
2928 almemory_order_relaxed);
2929 ATOMIC_STORE(&props->Send[i].GainLF, source->Send[i].GainLF, almemory_order_relaxed);
2930 ATOMIC_STORE(&props->Send[i].LFReference, source->Send[i].LFReference,
2931 almemory_order_relaxed);
2934 /* Set the new container for updating internal parameters. */
2935 props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, props, almemory_order_acq_rel);
2936 if(props)
2938 /* If there was an unused update container, put it back in the
2939 * freelist.
2941 ATOMIC_REPLACE_HEAD(struct ALsourceProps*, &source->FreeList, props);
2945 void UpdateAllSourceProps(ALCcontext *context)
2947 ALsizei num_sends = context->Device->NumAuxSends;
2948 ALsizei pos;
2950 for(pos = 0;pos < context->VoiceCount;pos++)
2952 ALvoice *voice = context->Voices[pos];
2953 ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire);
2954 if(source != NULL && source->NeedsUpdate && IsPlayingOrPausedSeq(source))
2956 source->NeedsUpdate = AL_FALSE;
2957 UpdateSourceProps(source, num_sends);
2963 /* SetSourceState
2965 * Sets the source's new play state given its current state.
2967 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2969 ALCdevice *device = Context->Device;
2970 ALuint refcount;
2971 ALvoice *voice;
2973 WriteLock(&Source->queue_lock);
2974 if(state == AL_PLAYING)
2976 ALCdevice *device = Context->Device;
2977 ALbufferlistitem *BufferList;
2978 ALsizei i;
2980 /* Check that there is a queue containing at least one valid, non zero
2981 * length Buffer. */
2982 BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
2983 while(BufferList)
2985 ALbuffer *buffer;
2986 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2987 break;
2988 BufferList = BufferList->next;
2991 /* If there's nothing to play, or the device is disconnected, go right
2992 * to stopped.
2994 if(!BufferList || !device->Connected)
2995 goto do_stop;
2997 voice = GetSourceVoice(Source, Context);
2998 switch(ATOMIC_EXCHANGE(ALenum, &Source->state, AL_PLAYING, almemory_order_acq_rel))
3000 case AL_PLAYING:
3001 assert(voice != NULL);
3002 /* A source that's already playing is restarted from the beginning. */
3003 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
3004 ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
3005 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release);
3006 goto done;
3008 case AL_PAUSED:
3009 assert(voice != NULL);
3010 /* A source that's paused simply resumes. Make sure it uses the
3011 * volume last specified; there's no reason to fade from where
3012 * it stopped at.
3014 voice->Moving = AL_FALSE;
3015 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
3016 goto done;
3018 default:
3019 break;
3022 Source->NeedsUpdate = AL_FALSE;
3023 UpdateSourceProps(Source, device->NumAuxSends);
3025 /* Make sure this source isn't already active, and if not, look for an
3026 * unused voice to put it in.
3028 assert(voice == NULL);
3029 for(i = 0;i < Context->VoiceCount;i++)
3031 if(ATOMIC_LOAD(&Context->Voices[i]->Source, almemory_order_acquire) == NULL)
3033 voice = Context->Voices[i];
3034 break;
3037 if(voice == NULL)
3038 voice = Context->Voices[Context->VoiceCount++];
3039 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
3040 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3042 /* A source that's not playing or paused has any offset applied when it
3043 * starts playing.
3045 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
3046 ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
3047 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed);
3048 if(Source->OffsetType != AL_NONE)
3049 ApplyOffset(Source, voice);
3051 /* Clear previous samples. */
3052 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
3054 /* Clear the stepping value so the mixer knows not to mix this until
3055 * the update gets applied.
3057 voice->Step = 0;
3059 voice->Moving = AL_FALSE;
3060 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
3062 ALsizei j;
3063 for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
3064 voice->Direct.Params[i].Hrtf.State.History[j] = 0.0f;
3065 for(j = 0;j < HRIR_LENGTH;j++)
3067 voice->Direct.Params[i].Hrtf.State.Values[j][0] = 0.0f;
3068 voice->Direct.Params[i].Hrtf.State.Values[j][1] = 0.0f;
3072 ATOMIC_STORE(&voice->Source, Source, almemory_order_relaxed);
3073 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
3075 else if(state == AL_PAUSED)
3077 ALenum playing = AL_PLAYING;
3078 if((voice=GetSourceVoice(Source, Context)) != NULL)
3080 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
3081 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3082 althrd_yield();
3084 ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum, &Source->state, &playing, AL_PAUSED);
3086 else if(state == AL_STOPPED)
3088 do_stop:
3089 if((voice=GetSourceVoice(Source, Context)) != NULL)
3091 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
3092 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
3093 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3094 althrd_yield();
3096 if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL)
3097 ATOMIC_STORE(&Source->state, AL_STOPPED, almemory_order_relaxed);
3098 Source->OffsetType = AL_NONE;
3099 Source->Offset = 0.0;
3101 else if(state == AL_INITIAL)
3103 if((voice=GetSourceVoice(Source, Context)) != NULL)
3105 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
3106 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
3107 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3108 althrd_yield();
3110 if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL)
3111 ATOMIC_STORE(&Source->state, AL_INITIAL, almemory_order_relaxed);
3112 Source->OffsetType = AL_NONE;
3113 Source->Offset = 0.0;
3115 done:
3116 WriteUnlock(&Source->queue_lock);
3119 /* GetSourceSampleOffset
3121 * Gets the current read offset for the given Source, in 32.32 fixed-point
3122 * samples. The offset is relative to the start of the queue (not the start of
3123 * the current buffer).
3125 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3127 ALCdevice *device = context->Device;
3128 const ALbufferlistitem *BufferList;
3129 const ALbufferlistitem *Current;
3130 ALuint64 readPos;
3131 ALuint refcount;
3132 ALvoice *voice;
3134 ReadLock(&Source->queue_lock);
3135 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3136 do {
3137 Current = NULL;
3138 readPos = 0;
3139 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3140 althrd_yield();
3141 *clocktime = GetDeviceClockTime(device);
3143 voice = GetSourceVoice(Source, context);
3144 if(voice)
3146 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3148 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << 32;
3149 readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) <<
3150 (32-FRACTIONBITS);
3152 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3153 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3155 if(voice)
3157 while(BufferList && BufferList != Current)
3159 if(BufferList->buffer)
3160 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
3161 BufferList = BufferList->next;
3163 readPos = minu64(readPos, U64(0x7fffffffffffffff));
3166 ReadUnlock(&Source->queue_lock);
3167 return (ALint64)readPos;
3170 /* GetSourceSecOffset
3172 * Gets the current read offset for the given Source, in seconds. The offset is
3173 * relative to the start of the queue (not the start of the current buffer).
3175 static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3177 ALCdevice *device = context->Device;
3178 const ALbufferlistitem *BufferList;
3179 const ALbufferlistitem *Current;
3180 ALuint64 readPos;
3181 ALuint refcount;
3182 ALdouble offset;
3183 ALvoice *voice;
3185 ReadLock(&Source->queue_lock);
3186 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3187 do {
3188 Current = NULL;
3189 readPos = 0;
3190 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3191 althrd_yield();
3192 *clocktime = GetDeviceClockTime(device);
3194 voice = GetSourceVoice(Source, context);
3195 if(voice)
3197 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3199 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) <<
3200 FRACTIONBITS;
3201 readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3203 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3204 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3206 offset = 0.0;
3207 if(voice)
3209 const ALbuffer *Buffer = NULL;
3210 while(BufferList && BufferList != Current)
3212 const ALbuffer *buffer = BufferList->buffer;
3213 if(buffer != NULL)
3215 if(!Buffer) Buffer = buffer;
3216 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
3218 BufferList = BufferList->next;
3221 while(BufferList && !Buffer)
3223 Buffer = BufferList->buffer;
3224 BufferList = BufferList->next;
3226 assert(Buffer != NULL);
3228 offset = (ALdouble)readPos / (ALdouble)FRACTIONONE /
3229 (ALdouble)Buffer->Frequency;
3232 ReadUnlock(&Source->queue_lock);
3233 return offset;
3236 /* GetSourceOffset
3238 * Gets the current read offset for the given Source, in the appropriate format
3239 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3240 * queue (not the start of the current buffer).
3242 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context)
3244 ALCdevice *device = context->Device;
3245 const ALbufferlistitem *BufferList;
3246 const ALbufferlistitem *Current;
3247 const ALbuffer *Buffer = NULL;
3248 ALboolean readFin = AL_FALSE;
3249 ALuint readPos, readPosFrac;
3250 ALuint totalBufferLen;
3251 ALboolean looping;
3252 ALuint refcount;
3253 ALdouble offset;
3254 ALvoice *voice;
3256 ReadLock(&Source->queue_lock);
3257 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3258 looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed);
3259 do {
3260 Current = NULL;
3261 readPos = readPosFrac = 0;
3262 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3263 althrd_yield();
3264 voice = GetSourceVoice(Source, context);
3265 if(voice)
3267 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3269 readPos = ATOMIC_LOAD(&voice->position, almemory_order_relaxed);
3270 readPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3272 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3273 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3275 if(!voice)
3277 ReadUnlock(&Source->queue_lock);
3278 return 0.0;
3281 totalBufferLen = 0;
3282 while(BufferList != NULL)
3284 const ALbuffer *buffer;
3285 readFin = readFin || (BufferList == Current);
3286 if((buffer=BufferList->buffer) != NULL)
3288 if(!Buffer) Buffer = buffer;
3289 totalBufferLen += buffer->SampleLen;
3290 if(!readFin) readPos += buffer->SampleLen;
3292 BufferList = BufferList->next;
3294 assert(Buffer != NULL);
3296 if(looping)
3297 readPos %= totalBufferLen;
3298 else
3300 /* Wrap back to 0 */
3301 if(readPos >= totalBufferLen)
3302 readPos = readPosFrac = 0;
3305 offset = 0.0;
3306 switch(name)
3308 case AL_SEC_OFFSET:
3309 offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
3310 break;
3312 case AL_SAMPLE_OFFSET:
3313 offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
3314 break;
3316 case AL_BYTE_OFFSET:
3317 if(Buffer->OriginalType == UserFmtIMA4)
3319 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3320 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3321 ALuint FrameBlockSize = Buffer->OriginalAlign;
3323 /* Round down to nearest ADPCM block */
3324 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3326 else if(Buffer->OriginalType == UserFmtMSADPCM)
3328 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3329 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3330 ALuint FrameBlockSize = Buffer->OriginalAlign;
3332 /* Round down to nearest ADPCM block */
3333 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3335 else
3337 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3338 offset = (ALdouble)(readPos * FrameSize);
3340 break;
3343 ReadUnlock(&Source->queue_lock);
3344 return offset;
3348 /* ApplyOffset
3350 * Apply the stored playback offset to the Source. This function will update
3351 * the number of buffers "played" given the stored offset.
3353 ALboolean ApplyOffset(ALsource *Source, ALvoice *voice)
3355 ALbufferlistitem *BufferList;
3356 const ALbuffer *Buffer;
3357 ALuint bufferLen, totalBufferLen;
3358 ALuint offset=0, frac=0;
3360 /* Get sample frame offset */
3361 if(!GetSampleOffset(Source, &offset, &frac))
3362 return AL_FALSE;
3364 totalBufferLen = 0;
3365 BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
3366 while(BufferList && totalBufferLen <= offset)
3368 Buffer = BufferList->buffer;
3369 bufferLen = Buffer ? Buffer->SampleLen : 0;
3371 if(bufferLen > offset-totalBufferLen)
3373 /* Offset is in this buffer */
3374 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
3375 ATOMIC_STORE(&voice->position, offset - totalBufferLen, almemory_order_relaxed);
3376 ATOMIC_STORE(&voice->position_fraction, frac, almemory_order_release);
3377 return AL_TRUE;
3380 totalBufferLen += bufferLen;
3382 BufferList = BufferList->next;
3385 /* Offset is out of range of the queue */
3386 return AL_FALSE;
3390 /* GetSampleOffset
3392 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3393 * or Second offset supplied by the application). This takes into account the
3394 * fact that the buffer format may have been modifed since.
3396 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
3398 const ALbuffer *Buffer = NULL;
3399 const ALbufferlistitem *BufferList;
3400 ALdouble dbloff, dblfrac;
3402 /* Find the first valid Buffer in the Queue */
3403 BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
3404 while(BufferList)
3406 if(BufferList->buffer)
3408 Buffer = BufferList->buffer;
3409 break;
3411 BufferList = BufferList->next;
3413 if(!Buffer)
3415 Source->OffsetType = AL_NONE;
3416 Source->Offset = 0.0;
3417 return AL_FALSE;
3420 switch(Source->OffsetType)
3422 case AL_BYTE_OFFSET:
3423 /* Determine the ByteOffset (and ensure it is block aligned) */
3424 *offset = (ALuint)Source->Offset;
3425 if(Buffer->OriginalType == UserFmtIMA4)
3427 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3428 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3429 *offset *= Buffer->OriginalAlign;
3431 else if(Buffer->OriginalType == UserFmtMSADPCM)
3433 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3434 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3435 *offset *= Buffer->OriginalAlign;
3437 else
3438 *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3439 *frac = 0;
3440 break;
3442 case AL_SAMPLE_OFFSET:
3443 dblfrac = modf(Source->Offset, &dbloff);
3444 *offset = (ALuint)mind(dbloff, UINT_MAX);
3445 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3446 break;
3448 case AL_SEC_OFFSET:
3449 dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
3450 *offset = (ALuint)mind(dbloff, UINT_MAX);
3451 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3452 break;
3454 Source->OffsetType = AL_NONE;
3455 Source->Offset = 0.0;
3457 return AL_TRUE;
3461 /* ReleaseALSources
3463 * Destroys all sources in the source map.
3465 ALvoid ReleaseALSources(ALCcontext *Context)
3467 ALCdevice *device = Context->Device;
3468 ALsizei pos;
3469 for(pos = 0;pos < Context->SourceMap.size;pos++)
3471 ALsource *temp = Context->SourceMap.values[pos];
3472 Context->SourceMap.values[pos] = NULL;
3474 DeinitSource(temp, device->NumAuxSends);
3476 FreeThunkEntry(temp->id);
3477 memset(temp, 0, sizeof(*temp));
3478 al_free(temp);