Improve handling of source state reads
[openal-soft.git] / OpenAL32 / alSource.c
blobbb70a05615603492b4ff4bbc551c0b2929107e92
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, ALCdevice *device, ALuint64 *clocktime);
55 static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime);
56 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device);
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((*voice)->Source == 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(IsPlayingOrPausedSeq(Source) &&
535 !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire))
537 ALCdevice_Lock(Context->Device);
538 /* Double-check that the source is still playing while we have
539 * the lock.
541 if(IsPlayingOrPaused(Source))
543 WriteLock(&Source->queue_lock);
544 if(ApplyOffset(Source) == AL_FALSE)
546 WriteUnlock(&Source->queue_lock);
547 ALCdevice_Unlock(Context->Device);
548 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
550 WriteUnlock(&Source->queue_lock);
552 ALCdevice_Unlock(Context->Device);
554 return AL_TRUE;
556 case AL_SOURCE_RADIUS:
557 CHECKVAL(*values >= 0.0f && isfinite(*values));
559 Source->Radius = *values;
560 DO_UPDATEPROPS();
561 return AL_TRUE;
563 case AL_STEREO_ANGLES:
564 CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
566 Source->StereoPan[0] = values[0];
567 Source->StereoPan[1] = values[1];
568 DO_UPDATEPROPS();
569 return AL_TRUE;
572 case AL_POSITION:
573 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
575 Source->Position[0] = values[0];
576 Source->Position[1] = values[1];
577 Source->Position[2] = values[2];
578 DO_UPDATEPROPS();
579 return AL_TRUE;
581 case AL_VELOCITY:
582 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
584 Source->Velocity[0] = values[0];
585 Source->Velocity[1] = values[1];
586 Source->Velocity[2] = values[2];
587 DO_UPDATEPROPS();
588 return AL_TRUE;
590 case AL_DIRECTION:
591 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
593 Source->Direction[0] = values[0];
594 Source->Direction[1] = values[1];
595 Source->Direction[2] = values[2];
596 DO_UPDATEPROPS();
597 return AL_TRUE;
599 case AL_ORIENTATION:
600 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
601 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
603 Source->Orientation[0][0] = values[0];
604 Source->Orientation[0][1] = values[1];
605 Source->Orientation[0][2] = values[2];
606 Source->Orientation[1][0] = values[3];
607 Source->Orientation[1][1] = values[4];
608 Source->Orientation[1][2] = values[5];
609 DO_UPDATEPROPS();
610 return AL_TRUE;
613 case AL_SOURCE_RELATIVE:
614 case AL_LOOPING:
615 case AL_SOURCE_STATE:
616 case AL_SOURCE_TYPE:
617 case AL_DISTANCE_MODEL:
618 case AL_DIRECT_FILTER_GAINHF_AUTO:
619 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
620 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
621 case AL_DIRECT_CHANNELS_SOFT:
622 ival = (ALint)values[0];
623 return SetSourceiv(Source, Context, prop, &ival);
625 case AL_BUFFERS_QUEUED:
626 case AL_BUFFERS_PROCESSED:
627 ival = (ALint)((ALuint)values[0]);
628 return SetSourceiv(Source, Context, prop, &ival);
630 case AL_BUFFER:
631 case AL_DIRECT_FILTER:
632 case AL_AUXILIARY_SEND_FILTER:
633 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
634 break;
637 ERR("Unexpected property: 0x%04x\n", prop);
638 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
641 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
643 ALCdevice *device = Context->Device;
644 ALbuffer *buffer = NULL;
645 ALfilter *filter = NULL;
646 ALeffectslot *slot = NULL;
647 ALbufferlistitem *oldlist;
648 ALbufferlistitem *newlist;
649 ALfloat fvals[6];
651 switch(prop)
653 case AL_SOURCE_STATE:
654 case AL_SOURCE_TYPE:
655 case AL_BUFFERS_QUEUED:
656 case AL_BUFFERS_PROCESSED:
657 case AL_BYTE_LENGTH_SOFT:
658 case AL_SAMPLE_LENGTH_SOFT:
659 case AL_SEC_LENGTH_SOFT:
660 /* Query only */
661 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
663 case AL_SOURCE_RELATIVE:
664 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
666 Source->HeadRelative = (ALboolean)*values;
667 DO_UPDATEPROPS();
668 return AL_TRUE;
670 case AL_LOOPING:
671 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
673 WriteLock(&Source->queue_lock);
674 ATOMIC_STORE_SEQ(&Source->looping, *values);
675 WriteUnlock(&Source->queue_lock);
676 return AL_TRUE;
678 case AL_BUFFER:
679 LockBuffersRead(device);
680 if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
682 UnlockBuffersRead(device);
683 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
686 WriteLock(&Source->queue_lock);
687 if(IsPlayingOrPausedSeq(Source))
689 WriteUnlock(&Source->queue_lock);
690 UnlockBuffersRead(device);
691 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
694 if(buffer != NULL)
696 /* Add the selected buffer to a one-item queue */
697 newlist = malloc(sizeof(ALbufferlistitem));
698 newlist->buffer = buffer;
699 newlist->next = NULL;
700 IncrementRef(&buffer->ref);
702 /* Source is now Static */
703 Source->SourceType = AL_STATIC;
705 ReadLock(&buffer->lock);
706 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
707 Source->SampleSize = BytesFromFmt(buffer->FmtType);
708 ReadUnlock(&buffer->lock);
710 else
712 /* Source is now Undetermined */
713 Source->SourceType = AL_UNDETERMINED;
714 newlist = NULL;
716 oldlist = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &Source->queue, newlist);
717 ATOMIC_STORE_SEQ(&Source->current_buffer, newlist);
718 WriteUnlock(&Source->queue_lock);
719 UnlockBuffersRead(device);
721 /* Delete all elements in the previous queue */
722 while(oldlist != NULL)
724 ALbufferlistitem *temp = oldlist;
725 oldlist = temp->next;
727 if(temp->buffer)
728 DecrementRef(&temp->buffer->ref);
729 free(temp);
731 return AL_TRUE;
733 case AL_SEC_OFFSET:
734 case AL_SAMPLE_OFFSET:
735 case AL_BYTE_OFFSET:
736 CHECKVAL(*values >= 0);
738 Source->OffsetType = prop;
739 Source->Offset = *values;
741 if(IsPlayingOrPausedSeq(Source) &&
742 !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire))
744 ALCdevice_Lock(Context->Device);
745 if(IsPlayingOrPaused(Source))
747 WriteLock(&Source->queue_lock);
748 if(ApplyOffset(Source) == AL_FALSE)
750 WriteUnlock(&Source->queue_lock);
751 ALCdevice_Unlock(Context->Device);
752 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
754 WriteUnlock(&Source->queue_lock);
756 ALCdevice_Unlock(Context->Device);
758 return AL_TRUE;
760 case AL_DIRECT_FILTER:
761 LockFiltersRead(device);
762 if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
764 UnlockFiltersRead(device);
765 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
768 if(!filter)
770 Source->Direct.Gain = 1.0f;
771 Source->Direct.GainHF = 1.0f;
772 Source->Direct.HFReference = LOWPASSFREQREF;
773 Source->Direct.GainLF = 1.0f;
774 Source->Direct.LFReference = HIGHPASSFREQREF;
776 else
778 Source->Direct.Gain = filter->Gain;
779 Source->Direct.GainHF = filter->GainHF;
780 Source->Direct.HFReference = filter->HFReference;
781 Source->Direct.GainLF = filter->GainLF;
782 Source->Direct.LFReference = filter->LFReference;
784 UnlockFiltersRead(device);
785 DO_UPDATEPROPS();
786 return AL_TRUE;
788 case AL_DIRECT_FILTER_GAINHF_AUTO:
789 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
791 Source->DryGainHFAuto = *values;
792 DO_UPDATEPROPS();
793 return AL_TRUE;
795 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
796 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
798 Source->WetGainAuto = *values;
799 DO_UPDATEPROPS();
800 return AL_TRUE;
802 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
803 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
805 Source->WetGainHFAuto = *values;
806 DO_UPDATEPROPS();
807 return AL_TRUE;
809 case AL_DIRECT_CHANNELS_SOFT:
810 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
812 Source->DirectChannels = *values;
813 DO_UPDATEPROPS();
814 return AL_TRUE;
816 case AL_DISTANCE_MODEL:
817 CHECKVAL(*values == AL_NONE ||
818 *values == AL_INVERSE_DISTANCE ||
819 *values == AL_INVERSE_DISTANCE_CLAMPED ||
820 *values == AL_LINEAR_DISTANCE ||
821 *values == AL_LINEAR_DISTANCE_CLAMPED ||
822 *values == AL_EXPONENT_DISTANCE ||
823 *values == AL_EXPONENT_DISTANCE_CLAMPED);
825 Source->DistanceModel = *values;
826 if(Context->SourceDistanceModel)
827 DO_UPDATEPROPS();
828 return AL_TRUE;
831 case AL_AUXILIARY_SEND_FILTER:
832 LockEffectSlotsRead(Context);
833 LockFiltersRead(device);
834 if(!((ALuint)values[1] < (ALuint)device->NumAuxSends &&
835 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
836 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
838 UnlockFiltersRead(device);
839 UnlockEffectSlotsRead(Context);
840 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
843 if(!filter)
845 /* Disable filter */
846 Source->Send[values[1]].Gain = 1.0f;
847 Source->Send[values[1]].GainHF = 1.0f;
848 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
849 Source->Send[values[1]].GainLF = 1.0f;
850 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
852 else
854 Source->Send[values[1]].Gain = filter->Gain;
855 Source->Send[values[1]].GainHF = filter->GainHF;
856 Source->Send[values[1]].HFReference = filter->HFReference;
857 Source->Send[values[1]].GainLF = filter->GainLF;
858 Source->Send[values[1]].LFReference = filter->LFReference;
860 UnlockFiltersRead(device);
862 if(slot != Source->Send[values[1]].Slot && IsPlayingOrPausedSeq(Source))
864 /* Add refcount on the new slot, and release the previous slot */
865 if(slot) IncrementRef(&slot->ref);
866 if(Source->Send[values[1]].Slot)
867 DecrementRef(&Source->Send[values[1]].Slot->ref);
868 Source->Send[values[1]].Slot = slot;
870 /* We must force an update if the auxiliary slot changed on a
871 * playing source, in case the slot is about to be deleted.
873 UpdateSourceProps(Source, device->NumAuxSends);
875 else
877 if(slot) IncrementRef(&slot->ref);
878 if(Source->Send[values[1]].Slot)
879 DecrementRef(&Source->Send[values[1]].Slot->ref);
880 Source->Send[values[1]].Slot = slot;
881 DO_UPDATEPROPS();
883 UnlockEffectSlotsRead(Context);
885 return AL_TRUE;
888 /* 1x float */
889 case AL_CONE_INNER_ANGLE:
890 case AL_CONE_OUTER_ANGLE:
891 case AL_PITCH:
892 case AL_GAIN:
893 case AL_MIN_GAIN:
894 case AL_MAX_GAIN:
895 case AL_REFERENCE_DISTANCE:
896 case AL_ROLLOFF_FACTOR:
897 case AL_CONE_OUTER_GAIN:
898 case AL_MAX_DISTANCE:
899 case AL_DOPPLER_FACTOR:
900 case AL_CONE_OUTER_GAINHF:
901 case AL_AIR_ABSORPTION_FACTOR:
902 case AL_ROOM_ROLLOFF_FACTOR:
903 case AL_SOURCE_RADIUS:
904 fvals[0] = (ALfloat)*values;
905 return SetSourcefv(Source, Context, (int)prop, fvals);
907 /* 3x float */
908 case AL_POSITION:
909 case AL_VELOCITY:
910 case AL_DIRECTION:
911 fvals[0] = (ALfloat)values[0];
912 fvals[1] = (ALfloat)values[1];
913 fvals[2] = (ALfloat)values[2];
914 return SetSourcefv(Source, Context, (int)prop, fvals);
916 /* 6x float */
917 case AL_ORIENTATION:
918 fvals[0] = (ALfloat)values[0];
919 fvals[1] = (ALfloat)values[1];
920 fvals[2] = (ALfloat)values[2];
921 fvals[3] = (ALfloat)values[3];
922 fvals[4] = (ALfloat)values[4];
923 fvals[5] = (ALfloat)values[5];
924 return SetSourcefv(Source, Context, (int)prop, fvals);
926 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
927 case AL_SEC_OFFSET_LATENCY_SOFT:
928 case AL_STEREO_ANGLES:
929 break;
932 ERR("Unexpected property: 0x%04x\n", prop);
933 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
936 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
938 ALfloat fvals[6];
939 ALint ivals[3];
941 switch(prop)
943 case AL_SOURCE_TYPE:
944 case AL_BUFFERS_QUEUED:
945 case AL_BUFFERS_PROCESSED:
946 case AL_SOURCE_STATE:
947 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
948 case AL_BYTE_LENGTH_SOFT:
949 case AL_SAMPLE_LENGTH_SOFT:
950 case AL_SEC_LENGTH_SOFT:
951 /* Query only */
952 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
955 /* 1x int */
956 case AL_SOURCE_RELATIVE:
957 case AL_LOOPING:
958 case AL_SEC_OFFSET:
959 case AL_SAMPLE_OFFSET:
960 case AL_BYTE_OFFSET:
961 case AL_DIRECT_FILTER_GAINHF_AUTO:
962 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
963 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
964 case AL_DIRECT_CHANNELS_SOFT:
965 case AL_DISTANCE_MODEL:
966 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
968 ivals[0] = (ALint)*values;
969 return SetSourceiv(Source, Context, (int)prop, ivals);
971 /* 1x uint */
972 case AL_BUFFER:
973 case AL_DIRECT_FILTER:
974 CHECKVAL(*values <= UINT_MAX && *values >= 0);
976 ivals[0] = (ALuint)*values;
977 return SetSourceiv(Source, Context, (int)prop, ivals);
979 /* 3x uint */
980 case AL_AUXILIARY_SEND_FILTER:
981 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
982 values[1] <= UINT_MAX && values[1] >= 0 &&
983 values[2] <= UINT_MAX && values[2] >= 0);
985 ivals[0] = (ALuint)values[0];
986 ivals[1] = (ALuint)values[1];
987 ivals[2] = (ALuint)values[2];
988 return SetSourceiv(Source, Context, (int)prop, ivals);
990 /* 1x float */
991 case AL_CONE_INNER_ANGLE:
992 case AL_CONE_OUTER_ANGLE:
993 case AL_PITCH:
994 case AL_GAIN:
995 case AL_MIN_GAIN:
996 case AL_MAX_GAIN:
997 case AL_REFERENCE_DISTANCE:
998 case AL_ROLLOFF_FACTOR:
999 case AL_CONE_OUTER_GAIN:
1000 case AL_MAX_DISTANCE:
1001 case AL_DOPPLER_FACTOR:
1002 case AL_CONE_OUTER_GAINHF:
1003 case AL_AIR_ABSORPTION_FACTOR:
1004 case AL_ROOM_ROLLOFF_FACTOR:
1005 case AL_SOURCE_RADIUS:
1006 fvals[0] = (ALfloat)*values;
1007 return SetSourcefv(Source, Context, (int)prop, fvals);
1009 /* 3x float */
1010 case AL_POSITION:
1011 case AL_VELOCITY:
1012 case AL_DIRECTION:
1013 fvals[0] = (ALfloat)values[0];
1014 fvals[1] = (ALfloat)values[1];
1015 fvals[2] = (ALfloat)values[2];
1016 return SetSourcefv(Source, Context, (int)prop, fvals);
1018 /* 6x float */
1019 case AL_ORIENTATION:
1020 fvals[0] = (ALfloat)values[0];
1021 fvals[1] = (ALfloat)values[1];
1022 fvals[2] = (ALfloat)values[2];
1023 fvals[3] = (ALfloat)values[3];
1024 fvals[4] = (ALfloat)values[4];
1025 fvals[5] = (ALfloat)values[5];
1026 return SetSourcefv(Source, Context, (int)prop, fvals);
1028 case AL_SEC_OFFSET_LATENCY_SOFT:
1029 case AL_STEREO_ANGLES:
1030 break;
1033 ERR("Unexpected property: 0x%04x\n", prop);
1034 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1037 #undef CHECKVAL
1040 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
1042 ALCdevice *device = Context->Device;
1043 ALbufferlistitem *BufferList;
1044 ClockLatency clocktime;
1045 ALuint64 srcclock;
1046 ALint ivals[3];
1047 ALboolean err;
1049 switch(prop)
1051 case AL_GAIN:
1052 *values = Source->Gain;
1053 return AL_TRUE;
1055 case AL_PITCH:
1056 *values = Source->Pitch;
1057 return AL_TRUE;
1059 case AL_MAX_DISTANCE:
1060 *values = Source->MaxDistance;
1061 return AL_TRUE;
1063 case AL_ROLLOFF_FACTOR:
1064 *values = Source->RollOffFactor;
1065 return AL_TRUE;
1067 case AL_REFERENCE_DISTANCE:
1068 *values = Source->RefDistance;
1069 return AL_TRUE;
1071 case AL_CONE_INNER_ANGLE:
1072 *values = Source->InnerAngle;
1073 return AL_TRUE;
1075 case AL_CONE_OUTER_ANGLE:
1076 *values = Source->OuterAngle;
1077 return AL_TRUE;
1079 case AL_MIN_GAIN:
1080 *values = Source->MinGain;
1081 return AL_TRUE;
1083 case AL_MAX_GAIN:
1084 *values = Source->MaxGain;
1085 return AL_TRUE;
1087 case AL_CONE_OUTER_GAIN:
1088 *values = Source->OuterGain;
1089 return AL_TRUE;
1091 case AL_SEC_OFFSET:
1092 case AL_SAMPLE_OFFSET:
1093 case AL_BYTE_OFFSET:
1094 *values = GetSourceOffset(Source, prop, device);
1095 return AL_TRUE;
1097 case AL_CONE_OUTER_GAINHF:
1098 *values = Source->OuterGainHF;
1099 return AL_TRUE;
1101 case AL_AIR_ABSORPTION_FACTOR:
1102 *values = Source->AirAbsorptionFactor;
1103 return AL_TRUE;
1105 case AL_ROOM_ROLLOFF_FACTOR:
1106 *values = Source->RoomRolloffFactor;
1107 return AL_TRUE;
1109 case AL_DOPPLER_FACTOR:
1110 *values = Source->DopplerFactor;
1111 return AL_TRUE;
1113 case AL_SEC_LENGTH_SOFT:
1114 ReadLock(&Source->queue_lock);
1115 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1116 *values = 0;
1117 else
1119 ALint length = 0;
1120 ALsizei freq = 1;
1121 do {
1122 ALbuffer *buffer = BufferList->buffer;
1123 if(buffer && buffer->SampleLen > 0)
1125 freq = buffer->Frequency;
1126 length += buffer->SampleLen;
1128 } while((BufferList=BufferList->next) != NULL);
1129 *values = (ALdouble)length / (ALdouble)freq;
1131 ReadUnlock(&Source->queue_lock);
1132 return AL_TRUE;
1134 case AL_SOURCE_RADIUS:
1135 *values = Source->Radius;
1136 return AL_TRUE;
1138 case AL_STEREO_ANGLES:
1139 values[0] = Source->StereoPan[0];
1140 values[1] = Source->StereoPan[1];
1141 return AL_TRUE;
1143 case AL_SEC_OFFSET_LATENCY_SOFT:
1144 /* Get the source offset with the clock time first. Then get the
1145 * clock time with the device latency. Order is important.
1147 values[0] = GetSourceSecOffset(Source, device, &srcclock);
1148 clocktime = V0(device->Backend,getClockLatency)();
1149 if(srcclock == (ALuint64)clocktime.ClockTime)
1150 values[1] = (ALdouble)clocktime.Latency / 1000000000.0;
1151 else
1153 /* If the clock time incremented, reduce the latency by that
1154 * much since it's that much closer to the source offset it got
1155 * earlier.
1157 ALuint64 diff = clocktime.ClockTime - srcclock;
1158 values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) /
1159 1000000000.0;
1161 return AL_TRUE;
1163 case AL_POSITION:
1164 values[0] = Source->Position[0];
1165 values[1] = Source->Position[1];
1166 values[2] = Source->Position[2];
1167 return AL_TRUE;
1169 case AL_VELOCITY:
1170 values[0] = Source->Velocity[0];
1171 values[1] = Source->Velocity[1];
1172 values[2] = Source->Velocity[2];
1173 return AL_TRUE;
1175 case AL_DIRECTION:
1176 values[0] = Source->Direction[0];
1177 values[1] = Source->Direction[1];
1178 values[2] = Source->Direction[2];
1179 return AL_TRUE;
1181 case AL_ORIENTATION:
1182 values[0] = Source->Orientation[0][0];
1183 values[1] = Source->Orientation[0][1];
1184 values[2] = Source->Orientation[0][2];
1185 values[3] = Source->Orientation[1][0];
1186 values[4] = Source->Orientation[1][1];
1187 values[5] = Source->Orientation[1][2];
1188 return AL_TRUE;
1190 /* 1x int */
1191 case AL_SOURCE_RELATIVE:
1192 case AL_LOOPING:
1193 case AL_SOURCE_STATE:
1194 case AL_BUFFERS_QUEUED:
1195 case AL_BUFFERS_PROCESSED:
1196 case AL_SOURCE_TYPE:
1197 case AL_DIRECT_FILTER_GAINHF_AUTO:
1198 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1199 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1200 case AL_DIRECT_CHANNELS_SOFT:
1201 case AL_BYTE_LENGTH_SOFT:
1202 case AL_SAMPLE_LENGTH_SOFT:
1203 case AL_DISTANCE_MODEL:
1204 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1205 *values = (ALdouble)ivals[0];
1206 return err;
1208 case AL_BUFFER:
1209 case AL_DIRECT_FILTER:
1210 case AL_AUXILIARY_SEND_FILTER:
1211 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1212 break;
1215 ERR("Unexpected property: 0x%04x\n", prop);
1216 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1219 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1221 ALbufferlistitem *BufferList;
1222 ALdouble dvals[6];
1223 ALboolean err;
1225 switch(prop)
1227 case AL_SOURCE_RELATIVE:
1228 *values = Source->HeadRelative;
1229 return AL_TRUE;
1231 case AL_LOOPING:
1232 *values = ATOMIC_LOAD_SEQ(&Source->looping);
1233 return AL_TRUE;
1235 case AL_BUFFER:
1236 ReadLock(&Source->queue_lock);
1237 BufferList = (Source->SourceType == AL_STATIC) ?
1238 ATOMIC_LOAD_SEQ(&Source->queue) :
1239 ATOMIC_LOAD_SEQ(&Source->current_buffer);
1240 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1241 ReadUnlock(&Source->queue_lock);
1242 return AL_TRUE;
1244 case AL_SOURCE_STATE:
1245 *values = ATOMIC_LOAD_SEQ(&Source->state);
1246 return AL_TRUE;
1248 case AL_BYTE_LENGTH_SOFT:
1249 ReadLock(&Source->queue_lock);
1250 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1251 *values = 0;
1252 else
1254 ALint length = 0;
1255 do {
1256 ALbuffer *buffer = BufferList->buffer;
1257 if(buffer && buffer->SampleLen > 0)
1259 ALuint byte_align, sample_align;
1260 if(buffer->OriginalType == UserFmtIMA4)
1262 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1263 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1264 sample_align = buffer->OriginalAlign;
1266 else if(buffer->OriginalType == UserFmtMSADPCM)
1268 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1269 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1270 sample_align = buffer->OriginalAlign;
1272 else
1274 ALsizei align = buffer->OriginalAlign;
1275 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1276 sample_align = buffer->OriginalAlign;
1279 length += buffer->SampleLen / sample_align * byte_align;
1281 } while((BufferList=BufferList->next) != NULL);
1282 *values = length;
1284 ReadUnlock(&Source->queue_lock);
1285 return AL_TRUE;
1287 case AL_SAMPLE_LENGTH_SOFT:
1288 ReadLock(&Source->queue_lock);
1289 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1290 *values = 0;
1291 else
1293 ALint length = 0;
1294 do {
1295 ALbuffer *buffer = BufferList->buffer;
1296 if(buffer) length += buffer->SampleLen;
1297 } while((BufferList=BufferList->next) != NULL);
1298 *values = length;
1300 ReadUnlock(&Source->queue_lock);
1301 return AL_TRUE;
1303 case AL_BUFFERS_QUEUED:
1304 ReadLock(&Source->queue_lock);
1305 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1306 *values = 0;
1307 else
1309 ALsizei count = 0;
1310 do {
1311 ++count;
1312 } while((BufferList=BufferList->next) != NULL);
1313 *values = count;
1315 ReadUnlock(&Source->queue_lock);
1316 return AL_TRUE;
1318 case AL_BUFFERS_PROCESSED:
1319 ReadLock(&Source->queue_lock);
1320 if(ATOMIC_LOAD_SEQ(&Source->looping) || Source->SourceType != AL_STREAMING)
1322 /* Buffers on a looping source are in a perpetual state of
1323 * PENDING, so don't report any as PROCESSED */
1324 *values = 0;
1326 else
1328 const ALbufferlistitem *BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
1329 const ALbufferlistitem *Current = ATOMIC_LOAD_SEQ(&Source->current_buffer);
1330 ALsizei played = 0;
1331 while(BufferList && BufferList != Current)
1333 played++;
1334 BufferList = BufferList->next;
1336 *values = played;
1338 ReadUnlock(&Source->queue_lock);
1339 return AL_TRUE;
1341 case AL_SOURCE_TYPE:
1342 *values = Source->SourceType;
1343 return AL_TRUE;
1345 case AL_DIRECT_FILTER_GAINHF_AUTO:
1346 *values = Source->DryGainHFAuto;
1347 return AL_TRUE;
1349 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1350 *values = Source->WetGainAuto;
1351 return AL_TRUE;
1353 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1354 *values = Source->WetGainHFAuto;
1355 return AL_TRUE;
1357 case AL_DIRECT_CHANNELS_SOFT:
1358 *values = Source->DirectChannels;
1359 return AL_TRUE;
1361 case AL_DISTANCE_MODEL:
1362 *values = Source->DistanceModel;
1363 return AL_TRUE;
1365 /* 1x float/double */
1366 case AL_CONE_INNER_ANGLE:
1367 case AL_CONE_OUTER_ANGLE:
1368 case AL_PITCH:
1369 case AL_GAIN:
1370 case AL_MIN_GAIN:
1371 case AL_MAX_GAIN:
1372 case AL_REFERENCE_DISTANCE:
1373 case AL_ROLLOFF_FACTOR:
1374 case AL_CONE_OUTER_GAIN:
1375 case AL_MAX_DISTANCE:
1376 case AL_SEC_OFFSET:
1377 case AL_SAMPLE_OFFSET:
1378 case AL_BYTE_OFFSET:
1379 case AL_DOPPLER_FACTOR:
1380 case AL_AIR_ABSORPTION_FACTOR:
1381 case AL_ROOM_ROLLOFF_FACTOR:
1382 case AL_CONE_OUTER_GAINHF:
1383 case AL_SEC_LENGTH_SOFT:
1384 case AL_SOURCE_RADIUS:
1385 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1386 *values = (ALint)dvals[0];
1387 return err;
1389 /* 3x float/double */
1390 case AL_POSITION:
1391 case AL_VELOCITY:
1392 case AL_DIRECTION:
1393 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1395 values[0] = (ALint)dvals[0];
1396 values[1] = (ALint)dvals[1];
1397 values[2] = (ALint)dvals[2];
1399 return err;
1401 /* 6x float/double */
1402 case AL_ORIENTATION:
1403 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1405 values[0] = (ALint)dvals[0];
1406 values[1] = (ALint)dvals[1];
1407 values[2] = (ALint)dvals[2];
1408 values[3] = (ALint)dvals[3];
1409 values[4] = (ALint)dvals[4];
1410 values[5] = (ALint)dvals[5];
1412 return err;
1414 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1415 break; /* i64 only */
1416 case AL_SEC_OFFSET_LATENCY_SOFT:
1417 break; /* Double only */
1418 case AL_STEREO_ANGLES:
1419 break; /* Float/double only */
1421 case AL_DIRECT_FILTER:
1422 case AL_AUXILIARY_SEND_FILTER:
1423 break; /* ??? */
1426 ERR("Unexpected property: 0x%04x\n", prop);
1427 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1430 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1432 ALCdevice *device = Context->Device;
1433 ClockLatency clocktime;
1434 ALuint64 srcclock;
1435 ALdouble dvals[6];
1436 ALint ivals[3];
1437 ALboolean err;
1439 switch(prop)
1441 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1442 /* Get the source offset with the clock time first. Then get the
1443 * clock time with the device latency. Order is important.
1445 values[0] = GetSourceSampleOffset(Source, device, &srcclock);
1446 clocktime = V0(device->Backend,getClockLatency)();
1447 if(srcclock == (ALuint64)clocktime.ClockTime)
1448 values[1] = clocktime.Latency;
1449 else
1451 /* If the clock time incremented, reduce the latency by that
1452 * much since it's that much closer to the source offset it got
1453 * earlier.
1455 ALuint64 diff = clocktime.ClockTime - srcclock;
1456 values[1] = clocktime.Latency - minu64(clocktime.Latency, diff);
1458 return AL_TRUE;
1460 /* 1x float/double */
1461 case AL_CONE_INNER_ANGLE:
1462 case AL_CONE_OUTER_ANGLE:
1463 case AL_PITCH:
1464 case AL_GAIN:
1465 case AL_MIN_GAIN:
1466 case AL_MAX_GAIN:
1467 case AL_REFERENCE_DISTANCE:
1468 case AL_ROLLOFF_FACTOR:
1469 case AL_CONE_OUTER_GAIN:
1470 case AL_MAX_DISTANCE:
1471 case AL_SEC_OFFSET:
1472 case AL_SAMPLE_OFFSET:
1473 case AL_BYTE_OFFSET:
1474 case AL_DOPPLER_FACTOR:
1475 case AL_AIR_ABSORPTION_FACTOR:
1476 case AL_ROOM_ROLLOFF_FACTOR:
1477 case AL_CONE_OUTER_GAINHF:
1478 case AL_SEC_LENGTH_SOFT:
1479 case AL_SOURCE_RADIUS:
1480 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1481 *values = (ALint64)dvals[0];
1482 return err;
1484 /* 3x float/double */
1485 case AL_POSITION:
1486 case AL_VELOCITY:
1487 case AL_DIRECTION:
1488 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1490 values[0] = (ALint64)dvals[0];
1491 values[1] = (ALint64)dvals[1];
1492 values[2] = (ALint64)dvals[2];
1494 return err;
1496 /* 6x float/double */
1497 case AL_ORIENTATION:
1498 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1500 values[0] = (ALint64)dvals[0];
1501 values[1] = (ALint64)dvals[1];
1502 values[2] = (ALint64)dvals[2];
1503 values[3] = (ALint64)dvals[3];
1504 values[4] = (ALint64)dvals[4];
1505 values[5] = (ALint64)dvals[5];
1507 return err;
1509 /* 1x int */
1510 case AL_SOURCE_RELATIVE:
1511 case AL_LOOPING:
1512 case AL_SOURCE_STATE:
1513 case AL_BUFFERS_QUEUED:
1514 case AL_BUFFERS_PROCESSED:
1515 case AL_BYTE_LENGTH_SOFT:
1516 case AL_SAMPLE_LENGTH_SOFT:
1517 case AL_SOURCE_TYPE:
1518 case AL_DIRECT_FILTER_GAINHF_AUTO:
1519 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1520 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1521 case AL_DIRECT_CHANNELS_SOFT:
1522 case AL_DISTANCE_MODEL:
1523 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1524 *values = ivals[0];
1525 return err;
1527 /* 1x uint */
1528 case AL_BUFFER:
1529 case AL_DIRECT_FILTER:
1530 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1531 *values = (ALuint)ivals[0];
1532 return err;
1534 /* 3x uint */
1535 case AL_AUXILIARY_SEND_FILTER:
1536 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1538 values[0] = (ALuint)ivals[0];
1539 values[1] = (ALuint)ivals[1];
1540 values[2] = (ALuint)ivals[2];
1542 return err;
1544 case AL_SEC_OFFSET_LATENCY_SOFT:
1545 break; /* Double only */
1546 case AL_STEREO_ANGLES:
1547 break; /* Float/double only */
1550 ERR("Unexpected property: 0x%04x\n", prop);
1551 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1555 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1557 ALCdevice *device;
1558 ALCcontext *context;
1559 ALsizei cur = 0;
1560 ALenum err;
1562 context = GetContextRef();
1563 if(!context) return;
1565 if(!(n >= 0))
1566 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1567 device = context->Device;
1568 for(cur = 0;cur < n;cur++)
1570 ALsource *source = al_calloc(16, sizeof(ALsource));
1571 if(!source)
1573 alDeleteSources(cur, sources);
1574 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1576 InitSourceParams(source, device->NumAuxSends);
1578 err = NewThunkEntry(&source->id);
1579 if(err == AL_NO_ERROR)
1580 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1581 if(err != AL_NO_ERROR)
1583 FreeThunkEntry(source->id);
1584 memset(source, 0, sizeof(ALsource));
1585 al_free(source);
1587 alDeleteSources(cur, sources);
1588 SET_ERROR_AND_GOTO(context, err, done);
1591 sources[cur] = source->id;
1594 done:
1595 ALCcontext_DecRef(context);
1599 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1601 ALCdevice *device;
1602 ALCcontext *context;
1603 ALsource *Source;
1604 ALsizei i;
1606 context = GetContextRef();
1607 if(!context) return;
1609 LockSourcesWrite(context);
1610 if(!(n >= 0))
1611 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1613 /* Check that all Sources are valid */
1614 for(i = 0;i < n;i++)
1616 if(LookupSource(context, sources[i]) == NULL)
1617 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1619 device = context->Device;
1620 for(i = 0;i < n;i++)
1622 ALvoice *voice;
1624 if((Source=RemoveSource(context, sources[i])) == NULL)
1625 continue;
1626 FreeThunkEntry(Source->id);
1628 ALCdevice_Lock(device);
1629 voice = GetSourceVoice(Source, context);
1630 if(voice) voice->Source = NULL;
1631 ALCdevice_Unlock(device);
1633 DeinitSource(Source, device->NumAuxSends);
1635 memset(Source, 0, sizeof(*Source));
1636 al_free(Source);
1639 done:
1640 UnlockSourcesWrite(context);
1641 ALCcontext_DecRef(context);
1645 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1647 ALCcontext *context;
1648 ALboolean ret;
1650 context = GetContextRef();
1651 if(!context) return AL_FALSE;
1653 LockSourcesRead(context);
1654 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1655 UnlockSourcesRead(context);
1657 ALCcontext_DecRef(context);
1659 return ret;
1663 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1665 ALCcontext *Context;
1666 ALsource *Source;
1668 Context = GetContextRef();
1669 if(!Context) return;
1671 WriteLock(&Context->PropLock);
1672 LockSourcesRead(Context);
1673 if((Source=LookupSource(Context, source)) == NULL)
1674 alSetError(Context, AL_INVALID_NAME);
1675 else if(!(FloatValsByProp(param) == 1))
1676 alSetError(Context, AL_INVALID_ENUM);
1677 else
1678 SetSourcefv(Source, Context, param, &value);
1679 UnlockSourcesRead(Context);
1680 WriteUnlock(&Context->PropLock);
1682 ALCcontext_DecRef(Context);
1685 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1687 ALCcontext *Context;
1688 ALsource *Source;
1690 Context = GetContextRef();
1691 if(!Context) return;
1693 WriteLock(&Context->PropLock);
1694 LockSourcesRead(Context);
1695 if((Source=LookupSource(Context, source)) == NULL)
1696 alSetError(Context, AL_INVALID_NAME);
1697 else if(!(FloatValsByProp(param) == 3))
1698 alSetError(Context, AL_INVALID_ENUM);
1699 else
1701 ALfloat fvals[3] = { value1, value2, value3 };
1702 SetSourcefv(Source, Context, param, fvals);
1704 UnlockSourcesRead(Context);
1705 WriteUnlock(&Context->PropLock);
1707 ALCcontext_DecRef(Context);
1710 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1712 ALCcontext *Context;
1713 ALsource *Source;
1715 Context = GetContextRef();
1716 if(!Context) return;
1718 WriteLock(&Context->PropLock);
1719 LockSourcesRead(Context);
1720 if((Source=LookupSource(Context, source)) == NULL)
1721 alSetError(Context, AL_INVALID_NAME);
1722 else if(!values)
1723 alSetError(Context, AL_INVALID_VALUE);
1724 else if(!(FloatValsByProp(param) > 0))
1725 alSetError(Context, AL_INVALID_ENUM);
1726 else
1727 SetSourcefv(Source, Context, param, values);
1728 UnlockSourcesRead(Context);
1729 WriteUnlock(&Context->PropLock);
1731 ALCcontext_DecRef(Context);
1735 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1737 ALCcontext *Context;
1738 ALsource *Source;
1740 Context = GetContextRef();
1741 if(!Context) return;
1743 WriteLock(&Context->PropLock);
1744 LockSourcesRead(Context);
1745 if((Source=LookupSource(Context, source)) == NULL)
1746 alSetError(Context, AL_INVALID_NAME);
1747 else if(!(DoubleValsByProp(param) == 1))
1748 alSetError(Context, AL_INVALID_ENUM);
1749 else
1751 ALfloat fval = (ALfloat)value;
1752 SetSourcefv(Source, Context, param, &fval);
1754 UnlockSourcesRead(Context);
1755 WriteUnlock(&Context->PropLock);
1757 ALCcontext_DecRef(Context);
1760 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1762 ALCcontext *Context;
1763 ALsource *Source;
1765 Context = GetContextRef();
1766 if(!Context) return;
1768 WriteLock(&Context->PropLock);
1769 LockSourcesRead(Context);
1770 if((Source=LookupSource(Context, source)) == NULL)
1771 alSetError(Context, AL_INVALID_NAME);
1772 else if(!(DoubleValsByProp(param) == 3))
1773 alSetError(Context, AL_INVALID_ENUM);
1774 else
1776 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1777 SetSourcefv(Source, Context, param, fvals);
1779 UnlockSourcesRead(Context);
1780 WriteUnlock(&Context->PropLock);
1782 ALCcontext_DecRef(Context);
1785 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1787 ALCcontext *Context;
1788 ALsource *Source;
1789 ALint count;
1791 Context = GetContextRef();
1792 if(!Context) return;
1794 WriteLock(&Context->PropLock);
1795 LockSourcesRead(Context);
1796 if((Source=LookupSource(Context, source)) == NULL)
1797 alSetError(Context, AL_INVALID_NAME);
1798 else if(!values)
1799 alSetError(Context, AL_INVALID_VALUE);
1800 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1801 alSetError(Context, AL_INVALID_ENUM);
1802 else
1804 ALfloat fvals[6];
1805 ALint i;
1807 for(i = 0;i < count;i++)
1808 fvals[i] = (ALfloat)values[i];
1809 SetSourcefv(Source, Context, param, fvals);
1811 UnlockSourcesRead(Context);
1812 WriteUnlock(&Context->PropLock);
1814 ALCcontext_DecRef(Context);
1818 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1820 ALCcontext *Context;
1821 ALsource *Source;
1823 Context = GetContextRef();
1824 if(!Context) return;
1826 WriteLock(&Context->PropLock);
1827 LockSourcesRead(Context);
1828 if((Source=LookupSource(Context, source)) == NULL)
1829 alSetError(Context, AL_INVALID_NAME);
1830 else if(!(IntValsByProp(param) == 1))
1831 alSetError(Context, AL_INVALID_ENUM);
1832 else
1833 SetSourceiv(Source, Context, param, &value);
1834 UnlockSourcesRead(Context);
1835 WriteUnlock(&Context->PropLock);
1837 ALCcontext_DecRef(Context);
1840 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1842 ALCcontext *Context;
1843 ALsource *Source;
1845 Context = GetContextRef();
1846 if(!Context) return;
1848 WriteLock(&Context->PropLock);
1849 LockSourcesRead(Context);
1850 if((Source=LookupSource(Context, source)) == NULL)
1851 alSetError(Context, AL_INVALID_NAME);
1852 else if(!(IntValsByProp(param) == 3))
1853 alSetError(Context, AL_INVALID_ENUM);
1854 else
1856 ALint ivals[3] = { value1, value2, value3 };
1857 SetSourceiv(Source, Context, param, ivals);
1859 UnlockSourcesRead(Context);
1860 WriteUnlock(&Context->PropLock);
1862 ALCcontext_DecRef(Context);
1865 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1867 ALCcontext *Context;
1868 ALsource *Source;
1870 Context = GetContextRef();
1871 if(!Context) return;
1873 WriteLock(&Context->PropLock);
1874 LockSourcesRead(Context);
1875 if((Source=LookupSource(Context, source)) == NULL)
1876 alSetError(Context, AL_INVALID_NAME);
1877 else if(!values)
1878 alSetError(Context, AL_INVALID_VALUE);
1879 else if(!(IntValsByProp(param) > 0))
1880 alSetError(Context, AL_INVALID_ENUM);
1881 else
1882 SetSourceiv(Source, Context, param, values);
1883 UnlockSourcesRead(Context);
1884 WriteUnlock(&Context->PropLock);
1886 ALCcontext_DecRef(Context);
1890 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1892 ALCcontext *Context;
1893 ALsource *Source;
1895 Context = GetContextRef();
1896 if(!Context) return;
1898 WriteLock(&Context->PropLock);
1899 LockSourcesRead(Context);
1900 if((Source=LookupSource(Context, source)) == NULL)
1901 alSetError(Context, AL_INVALID_NAME);
1902 else if(!(Int64ValsByProp(param) == 1))
1903 alSetError(Context, AL_INVALID_ENUM);
1904 else
1905 SetSourcei64v(Source, Context, param, &value);
1906 UnlockSourcesRead(Context);
1907 WriteUnlock(&Context->PropLock);
1909 ALCcontext_DecRef(Context);
1912 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1914 ALCcontext *Context;
1915 ALsource *Source;
1917 Context = GetContextRef();
1918 if(!Context) return;
1920 WriteLock(&Context->PropLock);
1921 LockSourcesRead(Context);
1922 if((Source=LookupSource(Context, source)) == NULL)
1923 alSetError(Context, AL_INVALID_NAME);
1924 else if(!(Int64ValsByProp(param) == 3))
1925 alSetError(Context, AL_INVALID_ENUM);
1926 else
1928 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1929 SetSourcei64v(Source, Context, param, i64vals);
1931 UnlockSourcesRead(Context);
1932 WriteUnlock(&Context->PropLock);
1934 ALCcontext_DecRef(Context);
1937 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1939 ALCcontext *Context;
1940 ALsource *Source;
1942 Context = GetContextRef();
1943 if(!Context) return;
1945 WriteLock(&Context->PropLock);
1946 LockSourcesRead(Context);
1947 if((Source=LookupSource(Context, source)) == NULL)
1948 alSetError(Context, AL_INVALID_NAME);
1949 else if(!values)
1950 alSetError(Context, AL_INVALID_VALUE);
1951 else if(!(Int64ValsByProp(param) > 0))
1952 alSetError(Context, AL_INVALID_ENUM);
1953 else
1954 SetSourcei64v(Source, Context, param, values);
1955 UnlockSourcesRead(Context);
1956 WriteUnlock(&Context->PropLock);
1958 ALCcontext_DecRef(Context);
1962 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1964 ALCcontext *Context;
1965 ALsource *Source;
1967 Context = GetContextRef();
1968 if(!Context) return;
1970 ReadLock(&Context->PropLock);
1971 LockSourcesRead(Context);
1972 if((Source=LookupSource(Context, source)) == NULL)
1973 alSetError(Context, AL_INVALID_NAME);
1974 else if(!value)
1975 alSetError(Context, AL_INVALID_VALUE);
1976 else if(!(FloatValsByProp(param) == 1))
1977 alSetError(Context, AL_INVALID_ENUM);
1978 else
1980 ALdouble dval;
1981 if(GetSourcedv(Source, Context, param, &dval))
1982 *value = (ALfloat)dval;
1984 UnlockSourcesRead(Context);
1985 ReadUnlock(&Context->PropLock);
1987 ALCcontext_DecRef(Context);
1991 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1993 ALCcontext *Context;
1994 ALsource *Source;
1996 Context = GetContextRef();
1997 if(!Context) return;
1999 ReadLock(&Context->PropLock);
2000 LockSourcesRead(Context);
2001 if((Source=LookupSource(Context, source)) == NULL)
2002 alSetError(Context, AL_INVALID_NAME);
2003 else if(!(value1 && value2 && value3))
2004 alSetError(Context, AL_INVALID_VALUE);
2005 else if(!(FloatValsByProp(param) == 3))
2006 alSetError(Context, AL_INVALID_ENUM);
2007 else
2009 ALdouble dvals[3];
2010 if(GetSourcedv(Source, Context, param, dvals))
2012 *value1 = (ALfloat)dvals[0];
2013 *value2 = (ALfloat)dvals[1];
2014 *value3 = (ALfloat)dvals[2];
2017 UnlockSourcesRead(Context);
2018 ReadUnlock(&Context->PropLock);
2020 ALCcontext_DecRef(Context);
2024 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
2026 ALCcontext *Context;
2027 ALsource *Source;
2028 ALint count;
2030 Context = GetContextRef();
2031 if(!Context) return;
2033 ReadLock(&Context->PropLock);
2034 LockSourcesRead(Context);
2035 if((Source=LookupSource(Context, source)) == NULL)
2036 alSetError(Context, AL_INVALID_NAME);
2037 else if(!values)
2038 alSetError(Context, AL_INVALID_VALUE);
2039 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
2040 alSetError(Context, AL_INVALID_ENUM);
2041 else
2043 ALdouble dvals[6];
2044 if(GetSourcedv(Source, Context, param, dvals))
2046 ALint i;
2047 for(i = 0;i < count;i++)
2048 values[i] = (ALfloat)dvals[i];
2051 UnlockSourcesRead(Context);
2052 ReadUnlock(&Context->PropLock);
2054 ALCcontext_DecRef(Context);
2058 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
2060 ALCcontext *Context;
2061 ALsource *Source;
2063 Context = GetContextRef();
2064 if(!Context) return;
2066 ReadLock(&Context->PropLock);
2067 LockSourcesRead(Context);
2068 if((Source=LookupSource(Context, source)) == NULL)
2069 alSetError(Context, AL_INVALID_NAME);
2070 else if(!value)
2071 alSetError(Context, AL_INVALID_VALUE);
2072 else if(!(DoubleValsByProp(param) == 1))
2073 alSetError(Context, AL_INVALID_ENUM);
2074 else
2075 GetSourcedv(Source, Context, param, value);
2076 UnlockSourcesRead(Context);
2077 ReadUnlock(&Context->PropLock);
2079 ALCcontext_DecRef(Context);
2082 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
2084 ALCcontext *Context;
2085 ALsource *Source;
2087 Context = GetContextRef();
2088 if(!Context) return;
2090 ReadLock(&Context->PropLock);
2091 LockSourcesRead(Context);
2092 if((Source=LookupSource(Context, source)) == NULL)
2093 alSetError(Context, AL_INVALID_NAME);
2094 else if(!(value1 && value2 && value3))
2095 alSetError(Context, AL_INVALID_VALUE);
2096 else if(!(DoubleValsByProp(param) == 3))
2097 alSetError(Context, AL_INVALID_ENUM);
2098 else
2100 ALdouble dvals[3];
2101 if(GetSourcedv(Source, Context, param, dvals))
2103 *value1 = dvals[0];
2104 *value2 = dvals[1];
2105 *value3 = dvals[2];
2108 UnlockSourcesRead(Context);
2109 ReadUnlock(&Context->PropLock);
2111 ALCcontext_DecRef(Context);
2114 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
2116 ALCcontext *Context;
2117 ALsource *Source;
2119 Context = GetContextRef();
2120 if(!Context) return;
2122 ReadLock(&Context->PropLock);
2123 LockSourcesRead(Context);
2124 if((Source=LookupSource(Context, source)) == NULL)
2125 alSetError(Context, AL_INVALID_NAME);
2126 else if(!values)
2127 alSetError(Context, AL_INVALID_VALUE);
2128 else if(!(DoubleValsByProp(param) > 0))
2129 alSetError(Context, AL_INVALID_ENUM);
2130 else
2131 GetSourcedv(Source, Context, param, values);
2132 UnlockSourcesRead(Context);
2133 ReadUnlock(&Context->PropLock);
2135 ALCcontext_DecRef(Context);
2139 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2141 ALCcontext *Context;
2142 ALsource *Source;
2144 Context = GetContextRef();
2145 if(!Context) return;
2147 ReadLock(&Context->PropLock);
2148 LockSourcesRead(Context);
2149 if((Source=LookupSource(Context, source)) == NULL)
2150 alSetError(Context, AL_INVALID_NAME);
2151 else if(!value)
2152 alSetError(Context, AL_INVALID_VALUE);
2153 else if(!(IntValsByProp(param) == 1))
2154 alSetError(Context, AL_INVALID_ENUM);
2155 else
2156 GetSourceiv(Source, Context, param, value);
2157 UnlockSourcesRead(Context);
2158 ReadUnlock(&Context->PropLock);
2160 ALCcontext_DecRef(Context);
2164 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2166 ALCcontext *Context;
2167 ALsource *Source;
2169 Context = GetContextRef();
2170 if(!Context) return;
2172 ReadLock(&Context->PropLock);
2173 LockSourcesRead(Context);
2174 if((Source=LookupSource(Context, source)) == NULL)
2175 alSetError(Context, AL_INVALID_NAME);
2176 else if(!(value1 && value2 && value3))
2177 alSetError(Context, AL_INVALID_VALUE);
2178 else if(!(IntValsByProp(param) == 3))
2179 alSetError(Context, AL_INVALID_ENUM);
2180 else
2182 ALint ivals[3];
2183 if(GetSourceiv(Source, Context, param, ivals))
2185 *value1 = ivals[0];
2186 *value2 = ivals[1];
2187 *value3 = ivals[2];
2190 UnlockSourcesRead(Context);
2191 ReadUnlock(&Context->PropLock);
2193 ALCcontext_DecRef(Context);
2197 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2199 ALCcontext *Context;
2200 ALsource *Source;
2202 Context = GetContextRef();
2203 if(!Context) return;
2205 ReadLock(&Context->PropLock);
2206 LockSourcesRead(Context);
2207 if((Source=LookupSource(Context, source)) == NULL)
2208 alSetError(Context, AL_INVALID_NAME);
2209 else if(!values)
2210 alSetError(Context, AL_INVALID_VALUE);
2211 else if(!(IntValsByProp(param) > 0))
2212 alSetError(Context, AL_INVALID_ENUM);
2213 else
2214 GetSourceiv(Source, Context, param, values);
2215 UnlockSourcesRead(Context);
2216 ReadUnlock(&Context->PropLock);
2218 ALCcontext_DecRef(Context);
2222 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2224 ALCcontext *Context;
2225 ALsource *Source;
2227 Context = GetContextRef();
2228 if(!Context) return;
2230 ReadLock(&Context->PropLock);
2231 LockSourcesRead(Context);
2232 if((Source=LookupSource(Context, source)) == NULL)
2233 alSetError(Context, AL_INVALID_NAME);
2234 else if(!value)
2235 alSetError(Context, AL_INVALID_VALUE);
2236 else if(!(Int64ValsByProp(param) == 1))
2237 alSetError(Context, AL_INVALID_ENUM);
2238 else
2239 GetSourcei64v(Source, Context, param, value);
2240 UnlockSourcesRead(Context);
2241 ReadUnlock(&Context->PropLock);
2243 ALCcontext_DecRef(Context);
2246 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2248 ALCcontext *Context;
2249 ALsource *Source;
2251 Context = GetContextRef();
2252 if(!Context) return;
2254 ReadLock(&Context->PropLock);
2255 LockSourcesRead(Context);
2256 if((Source=LookupSource(Context, source)) == NULL)
2257 alSetError(Context, AL_INVALID_NAME);
2258 else if(!(value1 && value2 && value3))
2259 alSetError(Context, AL_INVALID_VALUE);
2260 else if(!(Int64ValsByProp(param) == 3))
2261 alSetError(Context, AL_INVALID_ENUM);
2262 else
2264 ALint64 i64vals[3];
2265 if(GetSourcei64v(Source, Context, param, i64vals))
2267 *value1 = i64vals[0];
2268 *value2 = i64vals[1];
2269 *value3 = i64vals[2];
2272 UnlockSourcesRead(Context);
2273 ReadUnlock(&Context->PropLock);
2275 ALCcontext_DecRef(Context);
2278 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2280 ALCcontext *Context;
2281 ALsource *Source;
2283 Context = GetContextRef();
2284 if(!Context) return;
2286 ReadLock(&Context->PropLock);
2287 LockSourcesRead(Context);
2288 if((Source=LookupSource(Context, source)) == NULL)
2289 alSetError(Context, AL_INVALID_NAME);
2290 else if(!values)
2291 alSetError(Context, AL_INVALID_VALUE);
2292 else if(!(Int64ValsByProp(param) > 0))
2293 alSetError(Context, AL_INVALID_ENUM);
2294 else
2295 GetSourcei64v(Source, Context, param, values);
2296 UnlockSourcesRead(Context);
2297 ReadUnlock(&Context->PropLock);
2299 ALCcontext_DecRef(Context);
2303 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2305 alSourcePlayv(1, &source);
2307 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2309 ALCcontext *context;
2310 ALsource *source;
2311 ALsizei i;
2313 context = GetContextRef();
2314 if(!context) return;
2316 LockSourcesRead(context);
2317 if(!(n >= 0))
2318 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2319 for(i = 0;i < n;i++)
2321 if(!LookupSource(context, sources[i]))
2322 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2325 ALCdevice_Lock(context->Device);
2326 while(n > context->MaxVoices-context->VoiceCount)
2328 ALsizei newcount = context->MaxVoices << 1;
2329 if(context->MaxVoices >= newcount)
2331 ALCdevice_Unlock(context->Device);
2332 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2334 AllocateVoices(context, newcount, context->Device->NumAuxSends);
2337 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll)
2339 for(i = 0;i < n;i++)
2341 source = LookupSource(context, sources[i]);
2342 source->new_state = AL_PLAYING;
2345 else
2347 for(i = 0;i < n;i++)
2349 source = LookupSource(context, sources[i]);
2350 SetSourceState(source, context, AL_PLAYING);
2353 ALCdevice_Unlock(context->Device);
2355 done:
2356 UnlockSourcesRead(context);
2357 ALCcontext_DecRef(context);
2360 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2362 alSourcePausev(1, &source);
2364 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2366 ALCcontext *context;
2367 ALsource *source;
2368 ALsizei i;
2370 context = GetContextRef();
2371 if(!context) return;
2373 LockSourcesRead(context);
2374 if(!(n >= 0))
2375 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2376 for(i = 0;i < n;i++)
2378 if(!LookupSource(context, sources[i]))
2379 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2382 ALCdevice_Lock(context->Device);
2383 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
2385 for(i = 0;i < n;i++)
2387 source = LookupSource(context, sources[i]);
2388 source->new_state = AL_PAUSED;
2391 else
2393 for(i = 0;i < n;i++)
2395 source = LookupSource(context, sources[i]);
2396 SetSourceState(source, context, AL_PAUSED);
2399 ALCdevice_Unlock(context->Device);
2401 done:
2402 UnlockSourcesRead(context);
2403 ALCcontext_DecRef(context);
2406 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2408 alSourceStopv(1, &source);
2410 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2412 ALCcontext *context;
2413 ALsource *source;
2414 ALsizei i;
2416 context = GetContextRef();
2417 if(!context) return;
2419 LockSourcesRead(context);
2420 if(!(n >= 0))
2421 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2422 for(i = 0;i < n;i++)
2424 if(!LookupSource(context, sources[i]))
2425 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2428 ALCdevice_Lock(context->Device);
2429 for(i = 0;i < n;i++)
2431 source = LookupSource(context, sources[i]);
2432 source->new_state = AL_NONE;
2433 SetSourceState(source, context, AL_STOPPED);
2435 ALCdevice_Unlock(context->Device);
2437 done:
2438 UnlockSourcesRead(context);
2439 ALCcontext_DecRef(context);
2442 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2444 alSourceRewindv(1, &source);
2446 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2448 ALCcontext *context;
2449 ALsource *source;
2450 ALsizei i;
2452 context = GetContextRef();
2453 if(!context) return;
2455 LockSourcesRead(context);
2456 if(!(n >= 0))
2457 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2458 for(i = 0;i < n;i++)
2460 if(!LookupSource(context, sources[i]))
2461 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2464 ALCdevice_Lock(context->Device);
2465 for(i = 0;i < n;i++)
2467 source = LookupSource(context, sources[i]);
2468 source->new_state = AL_NONE;
2469 SetSourceState(source, context, AL_INITIAL);
2471 ALCdevice_Unlock(context->Device);
2473 done:
2474 UnlockSourcesRead(context);
2475 ALCcontext_DecRef(context);
2479 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2481 ALCdevice *device;
2482 ALCcontext *context;
2483 ALsource *source;
2484 ALsizei i;
2485 ALbufferlistitem *BufferListStart;
2486 ALbufferlistitem *BufferList;
2487 ALbuffer *BufferFmt = NULL;
2489 if(nb == 0)
2490 return;
2492 context = GetContextRef();
2493 if(!context) return;
2495 device = context->Device;
2497 LockSourcesRead(context);
2498 if(!(nb >= 0))
2499 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2500 if((source=LookupSource(context, src)) == NULL)
2501 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2503 WriteLock(&source->queue_lock);
2504 if(source->SourceType == AL_STATIC)
2506 WriteUnlock(&source->queue_lock);
2507 /* Can't queue on a Static Source */
2508 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2511 /* Check for a valid Buffer, for its frequency and format */
2512 BufferList = ATOMIC_LOAD_SEQ(&source->queue);
2513 while(BufferList)
2515 if(BufferList->buffer)
2517 BufferFmt = BufferList->buffer;
2518 break;
2520 BufferList = BufferList->next;
2523 LockBuffersRead(device);
2524 BufferListStart = NULL;
2525 BufferList = NULL;
2526 for(i = 0;i < nb;i++)
2528 ALbuffer *buffer = NULL;
2529 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2531 WriteUnlock(&source->queue_lock);
2532 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2535 if(!BufferListStart)
2537 BufferListStart = malloc(sizeof(ALbufferlistitem));
2538 BufferList = BufferListStart;
2540 else
2542 BufferList->next = malloc(sizeof(ALbufferlistitem));
2543 BufferList = BufferList->next;
2545 BufferList->buffer = buffer;
2546 BufferList->next = NULL;
2547 if(!buffer) continue;
2549 /* Hold a read lock on each buffer being queued while checking all
2550 * provided buffers. This is done so other threads don't see an extra
2551 * reference on some buffers if this operation ends up failing. */
2552 ReadLock(&buffer->lock);
2553 IncrementRef(&buffer->ref);
2555 if(BufferFmt == NULL)
2557 BufferFmt = buffer;
2559 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2560 source->SampleSize = BytesFromFmt(buffer->FmtType);
2562 else if(BufferFmt->Frequency != buffer->Frequency ||
2563 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2564 BufferFmt->OriginalType != buffer->OriginalType)
2566 WriteUnlock(&source->queue_lock);
2567 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2569 buffer_error:
2570 /* A buffer failed (invalid ID or format), so unlock and release
2571 * each buffer we had. */
2572 while(BufferListStart)
2574 ALbufferlistitem *next = BufferListStart->next;
2575 if((buffer=BufferListStart->buffer) != NULL)
2577 DecrementRef(&buffer->ref);
2578 ReadUnlock(&buffer->lock);
2580 free(BufferListStart);
2581 BufferListStart = next;
2583 UnlockBuffersRead(device);
2584 goto done;
2587 /* All buffers good, unlock them now. */
2588 BufferList = BufferListStart;
2589 while(BufferList != NULL)
2591 ALbuffer *buffer = BufferList->buffer;
2592 if(buffer) ReadUnlock(&buffer->lock);
2593 BufferList = BufferList->next;
2595 UnlockBuffersRead(device);
2597 /* Source is now streaming */
2598 source->SourceType = AL_STREAMING;
2600 BufferList = NULL;
2601 if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem*, &source->queue,
2602 &BufferList, BufferListStart))
2604 /* Queue head is not NULL, append to the end of the queue */
2605 while(BufferList->next != NULL)
2606 BufferList = BufferList->next;
2607 BufferList->next = BufferListStart;
2609 /* If the current buffer was at the end (NULL), put it at the start of the newly queued
2610 * buffers.
2612 BufferList = NULL;
2613 ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem*, &source->current_buffer,
2614 &BufferList, BufferListStart);
2615 WriteUnlock(&source->queue_lock);
2617 done:
2618 UnlockSourcesRead(context);
2619 ALCcontext_DecRef(context);
2622 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2624 ALCcontext *context;
2625 ALsource *source;
2626 ALbufferlistitem *OldHead;
2627 ALbufferlistitem *OldTail;
2628 ALbufferlistitem *Current;
2629 ALsizei i = 0;
2631 if(nb == 0)
2632 return;
2634 context = GetContextRef();
2635 if(!context) return;
2637 LockSourcesRead(context);
2638 if(!(nb >= 0))
2639 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2641 if((source=LookupSource(context, src)) == NULL)
2642 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2644 WriteLock(&source->queue_lock);
2645 if(ATOMIC_LOAD_SEQ(&source->looping) || source->SourceType != AL_STREAMING)
2647 WriteUnlock(&source->queue_lock);
2648 /* Trying to unqueue buffers on a looping or non-streaming source. */
2649 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2652 /* Find the new buffer queue head */
2653 OldTail = ATOMIC_LOAD_SEQ(&source->queue);
2654 Current = ATOMIC_LOAD_SEQ(&source->current_buffer);
2655 if(OldTail != Current)
2657 for(i = 1;i < nb;i++)
2659 ALbufferlistitem *next = OldTail->next;
2660 if(!next || next == Current) break;
2661 OldTail = next;
2664 if(i != nb)
2666 WriteUnlock(&source->queue_lock);
2667 /* Trying to unqueue pending buffers. */
2668 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2671 /* Swap it, and cut the new head from the old. */
2672 OldHead = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &source->queue, OldTail->next);
2673 if(OldTail->next)
2675 ALCdevice *device = context->Device;
2676 uint count;
2678 /* Once the active mix (if any) is done, it's safe to cut the old tail
2679 * from the new head.
2681 if(((count=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
2683 while(count == ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))
2684 althrd_yield();
2686 ATOMIC_THREAD_FENCE(almemory_order_acq_rel);
2687 OldTail->next = NULL;
2689 WriteUnlock(&source->queue_lock);
2691 while(OldHead != NULL)
2693 ALbufferlistitem *next = OldHead->next;
2694 ALbuffer *buffer = OldHead->buffer;
2696 if(!buffer)
2697 *(buffers++) = 0;
2698 else
2700 *(buffers++) = buffer->id;
2701 DecrementRef(&buffer->ref);
2704 free(OldHead);
2705 OldHead = next;
2708 done:
2709 UnlockSourcesRead(context);
2710 ALCcontext_DecRef(context);
2714 static void InitSourceParams(ALsource *Source, ALsizei num_sends)
2716 ALsizei i;
2718 RWLockInit(&Source->queue_lock);
2720 Source->InnerAngle = 360.0f;
2721 Source->OuterAngle = 360.0f;
2722 Source->Pitch = 1.0f;
2723 Source->Position[0] = 0.0f;
2724 Source->Position[1] = 0.0f;
2725 Source->Position[2] = 0.0f;
2726 Source->Velocity[0] = 0.0f;
2727 Source->Velocity[1] = 0.0f;
2728 Source->Velocity[2] = 0.0f;
2729 Source->Direction[0] = 0.0f;
2730 Source->Direction[1] = 0.0f;
2731 Source->Direction[2] = 0.0f;
2732 Source->Orientation[0][0] = 0.0f;
2733 Source->Orientation[0][1] = 0.0f;
2734 Source->Orientation[0][2] = -1.0f;
2735 Source->Orientation[1][0] = 0.0f;
2736 Source->Orientation[1][1] = 1.0f;
2737 Source->Orientation[1][2] = 0.0f;
2738 Source->RefDistance = 1.0f;
2739 Source->MaxDistance = FLT_MAX;
2740 Source->RollOffFactor = 1.0f;
2741 Source->Gain = 1.0f;
2742 Source->MinGain = 0.0f;
2743 Source->MaxGain = 1.0f;
2744 Source->OuterGain = 0.0f;
2745 Source->OuterGainHF = 1.0f;
2747 Source->DryGainHFAuto = AL_TRUE;
2748 Source->WetGainAuto = AL_TRUE;
2749 Source->WetGainHFAuto = AL_TRUE;
2750 Source->AirAbsorptionFactor = 0.0f;
2751 Source->RoomRolloffFactor = 0.0f;
2752 Source->DopplerFactor = 1.0f;
2753 Source->DirectChannels = AL_FALSE;
2755 Source->StereoPan[0] = DEG2RAD( 30.0f);
2756 Source->StereoPan[1] = DEG2RAD(-30.0f);
2758 Source->Radius = 0.0f;
2760 Source->DistanceModel = DefaultDistanceModel;
2762 Source->Direct.Gain = 1.0f;
2763 Source->Direct.GainHF = 1.0f;
2764 Source->Direct.HFReference = LOWPASSFREQREF;
2765 Source->Direct.GainLF = 1.0f;
2766 Source->Direct.LFReference = HIGHPASSFREQREF;
2767 Source->Send = al_calloc(16, num_sends*sizeof(Source->Send[0]));
2768 for(i = 0;i < num_sends;i++)
2770 Source->Send[i].Slot = NULL;
2771 Source->Send[i].Gain = 1.0f;
2772 Source->Send[i].GainHF = 1.0f;
2773 Source->Send[i].HFReference = LOWPASSFREQREF;
2774 Source->Send[i].GainLF = 1.0f;
2775 Source->Send[i].LFReference = HIGHPASSFREQREF;
2778 Source->Offset = 0.0;
2779 Source->OffsetType = AL_NONE;
2780 Source->SourceType = AL_UNDETERMINED;
2781 ATOMIC_INIT(&Source->state, AL_INITIAL);
2782 Source->new_state = AL_NONE;
2784 ATOMIC_INIT(&Source->queue, NULL);
2785 ATOMIC_INIT(&Source->current_buffer, NULL);
2787 ATOMIC_INIT(&Source->position, 0);
2788 ATOMIC_INIT(&Source->position_fraction, 0);
2790 ATOMIC_INIT(&Source->looping, AL_FALSE);
2792 Source->NeedsUpdate = AL_TRUE;
2794 ATOMIC_INIT(&Source->Update, NULL);
2795 ATOMIC_INIT(&Source->FreeList, NULL);
2798 static void DeinitSource(ALsource *source, ALsizei num_sends)
2800 ALbufferlistitem *BufferList;
2801 struct ALsourceProps *props;
2802 size_t count = 0;
2803 ALsizei i;
2805 props = ATOMIC_LOAD_SEQ(&source->Update);
2806 if(props) al_free(props);
2808 props = ATOMIC_LOAD(&source->FreeList, almemory_order_relaxed);
2809 while(props)
2811 struct ALsourceProps *next;
2812 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2813 al_free(props);
2814 props = next;
2815 ++count;
2817 /* This is excessively spammy if it traces every source destruction, so
2818 * just warn if it was unexpectedly large.
2820 if(count > 3)
2821 WARN("Freed "SZFMT" Source property objects\n", count);
2823 BufferList = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &source->queue, NULL);
2824 while(BufferList != NULL)
2826 ALbufferlistitem *next = BufferList->next;
2827 if(BufferList->buffer != NULL)
2828 DecrementRef(&BufferList->buffer->ref);
2829 free(BufferList);
2830 BufferList = next;
2833 if(source->Send)
2835 for(i = 0;i < num_sends;i++)
2837 if(source->Send[i].Slot)
2838 DecrementRef(&source->Send[i].Slot->ref);
2839 source->Send[i].Slot = NULL;
2841 al_free(source->Send);
2842 source->Send = NULL;
2846 static void UpdateSourceProps(ALsource *source, ALsizei num_sends)
2848 struct ALsourceProps *props;
2849 ALsizei i;
2851 /* Get an unused property container, or allocate a new one as needed. */
2852 props = ATOMIC_LOAD(&source->FreeList, almemory_order_acquire);
2853 if(!props)
2854 props = al_calloc(16, offsetof(struct ALsourceProps, Send[num_sends]));
2855 else
2857 struct ALsourceProps *next;
2858 do {
2859 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2860 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*,
2861 &source->FreeList, &props, next, almemory_order_acq_rel,
2862 almemory_order_acquire) == 0);
2865 /* Copy in current property values. */
2866 ATOMIC_STORE(&props->Pitch, source->Pitch, almemory_order_relaxed);
2867 ATOMIC_STORE(&props->Gain, source->Gain, almemory_order_relaxed);
2868 ATOMIC_STORE(&props->OuterGain, source->OuterGain, almemory_order_relaxed);
2869 ATOMIC_STORE(&props->MinGain, source->MinGain, almemory_order_relaxed);
2870 ATOMIC_STORE(&props->MaxGain, source->MaxGain, almemory_order_relaxed);
2871 ATOMIC_STORE(&props->InnerAngle, source->InnerAngle, almemory_order_relaxed);
2872 ATOMIC_STORE(&props->OuterAngle, source->OuterAngle, almemory_order_relaxed);
2873 ATOMIC_STORE(&props->RefDistance, source->RefDistance, almemory_order_relaxed);
2874 ATOMIC_STORE(&props->MaxDistance, source->MaxDistance, almemory_order_relaxed);
2875 ATOMIC_STORE(&props->RollOffFactor, source->RollOffFactor, almemory_order_relaxed);
2876 for(i = 0;i < 3;i++)
2877 ATOMIC_STORE(&props->Position[i], source->Position[i], almemory_order_relaxed);
2878 for(i = 0;i < 3;i++)
2879 ATOMIC_STORE(&props->Velocity[i], source->Velocity[i], almemory_order_relaxed);
2880 for(i = 0;i < 3;i++)
2881 ATOMIC_STORE(&props->Direction[i], source->Direction[i], almemory_order_relaxed);
2882 for(i = 0;i < 2;i++)
2884 ALsizei j;
2885 for(j = 0;j < 3;j++)
2886 ATOMIC_STORE(&props->Orientation[i][j], source->Orientation[i][j],
2887 almemory_order_relaxed);
2889 ATOMIC_STORE(&props->HeadRelative, source->HeadRelative, almemory_order_relaxed);
2890 ATOMIC_STORE(&props->DistanceModel, source->DistanceModel, almemory_order_relaxed);
2891 ATOMIC_STORE(&props->DirectChannels, source->DirectChannels, almemory_order_relaxed);
2893 ATOMIC_STORE(&props->DryGainHFAuto, source->DryGainHFAuto, almemory_order_relaxed);
2894 ATOMIC_STORE(&props->WetGainAuto, source->WetGainAuto, almemory_order_relaxed);
2895 ATOMIC_STORE(&props->WetGainHFAuto, source->WetGainHFAuto, almemory_order_relaxed);
2896 ATOMIC_STORE(&props->OuterGainHF, source->OuterGainHF, almemory_order_relaxed);
2898 ATOMIC_STORE(&props->AirAbsorptionFactor, source->AirAbsorptionFactor, almemory_order_relaxed);
2899 ATOMIC_STORE(&props->RoomRolloffFactor, source->RoomRolloffFactor, almemory_order_relaxed);
2900 ATOMIC_STORE(&props->DopplerFactor, source->DopplerFactor, almemory_order_relaxed);
2902 ATOMIC_STORE(&props->StereoPan[0], source->StereoPan[0], almemory_order_relaxed);
2903 ATOMIC_STORE(&props->StereoPan[1], source->StereoPan[1], almemory_order_relaxed);
2905 ATOMIC_STORE(&props->Radius, source->Radius, almemory_order_relaxed);
2907 ATOMIC_STORE(&props->Direct.Gain, source->Direct.Gain, almemory_order_relaxed);
2908 ATOMIC_STORE(&props->Direct.GainHF, source->Direct.GainHF, almemory_order_relaxed);
2909 ATOMIC_STORE(&props->Direct.HFReference, source->Direct.HFReference, almemory_order_relaxed);
2910 ATOMIC_STORE(&props->Direct.GainLF, source->Direct.GainLF, almemory_order_relaxed);
2911 ATOMIC_STORE(&props->Direct.LFReference, source->Direct.LFReference, almemory_order_relaxed);
2913 for(i = 0;i < num_sends;i++)
2915 ATOMIC_STORE(&props->Send[i].Slot, source->Send[i].Slot, almemory_order_relaxed);
2916 ATOMIC_STORE(&props->Send[i].Gain, source->Send[i].Gain, almemory_order_relaxed);
2917 ATOMIC_STORE(&props->Send[i].GainHF, source->Send[i].GainHF, almemory_order_relaxed);
2918 ATOMIC_STORE(&props->Send[i].HFReference, source->Send[i].HFReference,
2919 almemory_order_relaxed);
2920 ATOMIC_STORE(&props->Send[i].GainLF, source->Send[i].GainLF, almemory_order_relaxed);
2921 ATOMIC_STORE(&props->Send[i].LFReference, source->Send[i].LFReference,
2922 almemory_order_relaxed);
2925 /* Set the new container for updating internal parameters. */
2926 props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, props, almemory_order_acq_rel);
2927 if(props)
2929 /* If there was an unused update container, put it back in the
2930 * freelist.
2932 ATOMIC_REPLACE_HEAD(struct ALsourceProps*, &source->FreeList, props);
2936 void UpdateAllSourceProps(ALCcontext *context)
2938 ALsizei num_sends = context->Device->NumAuxSends;
2939 ALsizei pos;
2941 for(pos = 0;pos < context->VoiceCount;pos++)
2943 ALvoice *voice = context->Voices[pos];
2944 ALsource *source = voice->Source;
2945 if(source != NULL && source->NeedsUpdate && IsPlayingOrPausedSeq(source))
2947 source->NeedsUpdate = AL_FALSE;
2948 UpdateSourceProps(source, num_sends);
2954 /* SetSourceState
2956 * Sets the source's new play state given its current state.
2958 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2960 WriteLock(&Source->queue_lock);
2961 if(state == AL_PLAYING)
2963 ALCdevice *device = Context->Device;
2964 ALbufferlistitem *BufferList;
2965 ALboolean discontinuity;
2966 ALvoice *voice = NULL;
2967 ALsizei i;
2969 /* Check that there is a queue containing at least one valid, non zero
2970 * length Buffer. */
2971 BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
2972 while(BufferList)
2974 ALbuffer *buffer;
2975 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2976 break;
2977 BufferList = BufferList->next;
2980 if(ATOMIC_EXCHANGE(ALenum, &Source->state, AL_PLAYING, almemory_order_acq_rel) == AL_PAUSED)
2981 discontinuity = AL_FALSE;
2982 else
2984 ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed);
2985 ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed);
2986 ATOMIC_STORE(&Source->position_fraction, 0, almemory_order_release);
2987 discontinuity = AL_TRUE;
2990 // Check if an Offset has been set
2991 if(Source->OffsetType != AL_NONE)
2993 ApplyOffset(Source);
2994 /* discontinuity = AL_TRUE;??? */
2997 /* If there's nothing to play, or device is disconnected, go right to
2998 * stopped */
2999 if(!BufferList || !device->Connected)
3000 goto do_stop;
3002 /* Make sure this source isn't already active, and if not, look for an
3003 * unused voice to put it in.
3005 voice = GetSourceVoice(Source, Context);
3006 if(voice == NULL)
3008 for(i = 0;i < Context->VoiceCount;i++)
3010 if(Context->Voices[i]->Source == NULL)
3012 voice = Context->Voices[i];
3013 voice->Source = Source;
3014 break;
3017 if(voice == NULL)
3019 voice = Context->Voices[Context->VoiceCount++];
3020 voice->Source = Source;
3022 discontinuity = AL_TRUE;
3025 if(discontinuity)
3027 /* Clear previous samples if playback is discontinuous. */
3028 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
3030 /* Clear the stepping value so the mixer knows not to mix this
3031 * until the update gets applied.
3033 voice->Step = 0;
3036 voice->Moving = AL_FALSE;
3037 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
3039 ALsizei j;
3040 for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
3041 voice->Direct.Params[i].Hrtf.State.History[j] = 0.0f;
3042 for(j = 0;j < HRIR_LENGTH;j++)
3044 voice->Direct.Params[i].Hrtf.State.Values[j][0] = 0.0f;
3045 voice->Direct.Params[i].Hrtf.State.Values[j][1] = 0.0f;
3049 Source->NeedsUpdate = AL_FALSE;
3050 UpdateSourceProps(Source, device->NumAuxSends);
3052 else if(state == AL_PAUSED)
3054 ALenum playing = AL_PLAYING;
3055 ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum, &Source->state, &playing, AL_PAUSED);
3057 else if(state == AL_STOPPED)
3059 do_stop:
3060 if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL)
3062 ATOMIC_STORE(&Source->state, AL_STOPPED, almemory_order_relaxed);
3063 ATOMIC_STORE_SEQ(&Source->current_buffer, NULL);
3065 Source->OffsetType = AL_NONE;
3066 Source->Offset = 0.0;
3068 else if(state == AL_INITIAL)
3070 if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL)
3072 ATOMIC_STORE(&Source->state, AL_INITIAL, almemory_order_relaxed);
3073 ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD_SEQ(&Source->queue),
3074 almemory_order_relaxed);
3075 ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed);
3076 ATOMIC_STORE_SEQ(&Source->position_fraction, 0);
3078 Source->OffsetType = AL_NONE;
3079 Source->Offset = 0.0;
3081 WriteUnlock(&Source->queue_lock);
3084 /* GetSourceSampleOffset
3086 * Gets the current read offset for the given Source, in 32.32 fixed-point
3087 * samples. The offset is relative to the start of the queue (not the start of
3088 * the current buffer).
3090 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime)
3092 const ALbufferlistitem *BufferList;
3093 const ALbufferlistitem *Current;
3094 ALuint64 readPos;
3095 ALuint refcount;
3097 ReadLock(&Source->queue_lock);
3098 do {
3099 BufferList = Current = NULL;
3100 readPos = 0;
3101 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3102 althrd_yield();
3103 *clocktime = GetDeviceClockTime(device);
3105 if(IsPlayingOrPaused(Source))
3107 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3108 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3110 readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << 32;
3111 readPos |= ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed) <<
3112 (32-FRACTIONBITS);
3114 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3115 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3117 while(BufferList && BufferList != Current)
3119 if(BufferList->buffer)
3120 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
3121 BufferList = BufferList->next;
3124 ReadUnlock(&Source->queue_lock);
3125 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
3128 /* GetSourceSecOffset
3130 * Gets the current read offset for the given Source, in seconds. The offset is
3131 * relative to the start of the queue (not the start of the current buffer).
3133 static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime)
3135 const ALbufferlistitem *BufferList;
3136 const ALbufferlistitem *Current;
3137 ALuint64 readPos;
3138 ALuint refcount;
3139 ALdouble offset;
3141 ReadLock(&Source->queue_lock);
3142 do {
3143 BufferList = Current = NULL;
3144 readPos = 0;
3145 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3146 althrd_yield();
3147 *clocktime = GetDeviceClockTime(device);
3149 if(IsPlayingOrPaused(Source))
3151 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3152 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3154 readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) <<
3155 FRACTIONBITS;
3156 readPos |= ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed);
3158 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3159 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3161 if(!Current)
3162 offset = 0.0;
3163 else
3165 const ALbuffer *Buffer = NULL;
3166 while(BufferList && BufferList != Current)
3168 const ALbuffer *buffer = BufferList->buffer;
3169 if(buffer != NULL)
3171 if(!Buffer) Buffer = buffer;
3172 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
3174 BufferList = BufferList->next;
3177 while(BufferList && !Buffer)
3179 Buffer = BufferList->buffer;
3180 BufferList = BufferList->next;
3182 assert(Buffer != NULL);
3184 offset = (ALdouble)readPos / (ALdouble)FRACTIONONE /
3185 (ALdouble)Buffer->Frequency;
3188 ReadUnlock(&Source->queue_lock);
3189 return offset;
3192 /* GetSourceOffset
3194 * Gets the current read offset for the given Source, in the appropriate format
3195 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3196 * queue (not the start of the current buffer).
3198 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device)
3200 const ALbufferlistitem *BufferList;
3201 const ALbufferlistitem *Current;
3202 const ALbuffer *Buffer = NULL;
3203 ALboolean readFin = AL_FALSE;
3204 ALuint readPos, readPosFrac;
3205 ALuint totalBufferLen;
3206 ALboolean looping;
3207 ALuint refcount;
3208 ALdouble offset;
3209 ALenum state;
3211 ReadLock(&Source->queue_lock);
3212 do {
3213 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3214 althrd_yield();
3215 state = ATOMIC_LOAD(&Source->state, almemory_order_relaxed);
3217 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3218 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3220 readPos = ATOMIC_LOAD(&Source->position, almemory_order_relaxed);
3221 readPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed);
3223 looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed);
3224 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3225 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3227 if(state != AL_PLAYING && state != AL_PAUSED)
3229 ReadUnlock(&Source->queue_lock);
3230 return 0.0;
3233 totalBufferLen = 0;
3234 while(BufferList != NULL)
3236 const ALbuffer *buffer;
3237 readFin = readFin || (BufferList == Current);
3238 if((buffer=BufferList->buffer) != NULL)
3240 if(!Buffer) Buffer = buffer;
3241 totalBufferLen += buffer->SampleLen;
3242 if(!readFin) readPos += buffer->SampleLen;
3244 BufferList = BufferList->next;
3246 assert(Buffer != NULL);
3248 if(looping)
3249 readPos %= totalBufferLen;
3250 else
3252 /* Wrap back to 0 */
3253 if(readPos >= totalBufferLen)
3254 readPos = readPosFrac = 0;
3257 offset = 0.0;
3258 switch(name)
3260 case AL_SEC_OFFSET:
3261 offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
3262 break;
3264 case AL_SAMPLE_OFFSET:
3265 offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
3266 break;
3268 case AL_BYTE_OFFSET:
3269 if(Buffer->OriginalType == UserFmtIMA4)
3271 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3272 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3273 ALuint FrameBlockSize = Buffer->OriginalAlign;
3275 /* Round down to nearest ADPCM block */
3276 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3278 else if(Buffer->OriginalType == UserFmtMSADPCM)
3280 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3281 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3282 ALuint FrameBlockSize = Buffer->OriginalAlign;
3284 /* Round down to nearest ADPCM block */
3285 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3287 else
3289 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3290 offset = (ALdouble)(readPos * FrameSize);
3292 break;
3295 ReadUnlock(&Source->queue_lock);
3296 return offset;
3300 /* ApplyOffset
3302 * Apply the stored playback offset to the Source. This function will update
3303 * the number of buffers "played" given the stored offset.
3305 ALboolean ApplyOffset(ALsource *Source)
3307 ALbufferlistitem *BufferList;
3308 const ALbuffer *Buffer;
3309 ALuint bufferLen, totalBufferLen;
3310 ALuint offset=0, frac=0;
3312 /* Get sample frame offset */
3313 if(!GetSampleOffset(Source, &offset, &frac))
3314 return AL_FALSE;
3316 totalBufferLen = 0;
3317 BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
3318 while(BufferList && totalBufferLen <= offset)
3320 Buffer = BufferList->buffer;
3321 bufferLen = Buffer ? Buffer->SampleLen : 0;
3323 if(bufferLen > offset-totalBufferLen)
3325 /* Offset is in this buffer */
3326 ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed);
3328 ATOMIC_STORE(&Source->position, offset - totalBufferLen, almemory_order_relaxed);
3329 ATOMIC_STORE(&Source->position_fraction, frac, almemory_order_release);
3330 return AL_TRUE;
3333 totalBufferLen += bufferLen;
3335 BufferList = BufferList->next;
3338 /* Offset is out of range of the queue */
3339 return AL_FALSE;
3343 /* GetSampleOffset
3345 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3346 * or Second offset supplied by the application). This takes into account the
3347 * fact that the buffer format may have been modifed since.
3349 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
3351 const ALbuffer *Buffer = NULL;
3352 const ALbufferlistitem *BufferList;
3353 ALdouble dbloff, dblfrac;
3355 /* Find the first valid Buffer in the Queue */
3356 BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
3357 while(BufferList)
3359 if(BufferList->buffer)
3361 Buffer = BufferList->buffer;
3362 break;
3364 BufferList = BufferList->next;
3366 if(!Buffer)
3368 Source->OffsetType = AL_NONE;
3369 Source->Offset = 0.0;
3370 return AL_FALSE;
3373 switch(Source->OffsetType)
3375 case AL_BYTE_OFFSET:
3376 /* Determine the ByteOffset (and ensure it is block aligned) */
3377 *offset = (ALuint)Source->Offset;
3378 if(Buffer->OriginalType == UserFmtIMA4)
3380 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3381 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3382 *offset *= Buffer->OriginalAlign;
3384 else if(Buffer->OriginalType == UserFmtMSADPCM)
3386 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3387 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3388 *offset *= Buffer->OriginalAlign;
3390 else
3391 *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3392 *frac = 0;
3393 break;
3395 case AL_SAMPLE_OFFSET:
3396 dblfrac = modf(Source->Offset, &dbloff);
3397 *offset = (ALuint)mind(dbloff, UINT_MAX);
3398 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3399 break;
3401 case AL_SEC_OFFSET:
3402 dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
3403 *offset = (ALuint)mind(dbloff, UINT_MAX);
3404 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3405 break;
3407 Source->OffsetType = AL_NONE;
3408 Source->Offset = 0.0;
3410 return AL_TRUE;
3414 /* ReleaseALSources
3416 * Destroys all sources in the source map.
3418 ALvoid ReleaseALSources(ALCcontext *Context)
3420 ALCdevice *device = Context->Device;
3421 ALsizei pos;
3422 for(pos = 0;pos < Context->SourceMap.size;pos++)
3424 ALsource *temp = Context->SourceMap.values[pos];
3425 Context->SourceMap.values[pos] = NULL;
3427 DeinitSource(temp, device->NumAuxSends);
3429 FreeThunkEntry(temp->id);
3430 memset(temp, 0, sizeof(*temp));
3431 al_free(temp);