Update ChangeLog
[openal-soft.git] / OpenAL32 / alSource.c
blob1b3f4c563fb29741255ca7959c617bf502efdd38
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 SourceShouldUpdate(const ALsource *source, const ALCcontext *context)
144 return IsPlayingOrPaused(source) &&
145 !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire);
148 static ALint FloatValsByProp(ALenum prop)
150 if(prop != (ALenum)((SourceProp)prop))
151 return 0;
152 switch((SourceProp)prop)
154 case AL_PITCH:
155 case AL_GAIN:
156 case AL_MIN_GAIN:
157 case AL_MAX_GAIN:
158 case AL_MAX_DISTANCE:
159 case AL_ROLLOFF_FACTOR:
160 case AL_DOPPLER_FACTOR:
161 case AL_CONE_OUTER_GAIN:
162 case AL_SEC_OFFSET:
163 case AL_SAMPLE_OFFSET:
164 case AL_BYTE_OFFSET:
165 case AL_CONE_INNER_ANGLE:
166 case AL_CONE_OUTER_ANGLE:
167 case AL_REFERENCE_DISTANCE:
168 case AL_CONE_OUTER_GAINHF:
169 case AL_AIR_ABSORPTION_FACTOR:
170 case AL_ROOM_ROLLOFF_FACTOR:
171 case AL_DIRECT_FILTER_GAINHF_AUTO:
172 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
173 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
174 case AL_DIRECT_CHANNELS_SOFT:
175 case AL_DISTANCE_MODEL:
176 case AL_SOURCE_RELATIVE:
177 case AL_LOOPING:
178 case AL_SOURCE_STATE:
179 case AL_BUFFERS_QUEUED:
180 case AL_BUFFERS_PROCESSED:
181 case AL_SOURCE_TYPE:
182 case AL_BYTE_LENGTH_SOFT:
183 case AL_SAMPLE_LENGTH_SOFT:
184 case AL_SEC_LENGTH_SOFT:
185 case AL_SOURCE_RADIUS:
186 return 1;
188 case AL_STEREO_ANGLES:
189 return 2;
191 case AL_POSITION:
192 case AL_VELOCITY:
193 case AL_DIRECTION:
194 return 3;
196 case AL_ORIENTATION:
197 return 6;
199 case AL_SEC_OFFSET_LATENCY_SOFT:
200 break; /* Double only */
202 case AL_BUFFER:
203 case AL_DIRECT_FILTER:
204 case AL_AUXILIARY_SEND_FILTER:
205 break; /* i/i64 only */
206 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
207 break; /* i64 only */
209 return 0;
211 static ALint DoubleValsByProp(ALenum prop)
213 if(prop != (ALenum)((SourceProp)prop))
214 return 0;
215 switch((SourceProp)prop)
217 case AL_PITCH:
218 case AL_GAIN:
219 case AL_MIN_GAIN:
220 case AL_MAX_GAIN:
221 case AL_MAX_DISTANCE:
222 case AL_ROLLOFF_FACTOR:
223 case AL_DOPPLER_FACTOR:
224 case AL_CONE_OUTER_GAIN:
225 case AL_SEC_OFFSET:
226 case AL_SAMPLE_OFFSET:
227 case AL_BYTE_OFFSET:
228 case AL_CONE_INNER_ANGLE:
229 case AL_CONE_OUTER_ANGLE:
230 case AL_REFERENCE_DISTANCE:
231 case AL_CONE_OUTER_GAINHF:
232 case AL_AIR_ABSORPTION_FACTOR:
233 case AL_ROOM_ROLLOFF_FACTOR:
234 case AL_DIRECT_FILTER_GAINHF_AUTO:
235 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
236 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
237 case AL_DIRECT_CHANNELS_SOFT:
238 case AL_DISTANCE_MODEL:
239 case AL_SOURCE_RELATIVE:
240 case AL_LOOPING:
241 case AL_SOURCE_STATE:
242 case AL_BUFFERS_QUEUED:
243 case AL_BUFFERS_PROCESSED:
244 case AL_SOURCE_TYPE:
245 case AL_BYTE_LENGTH_SOFT:
246 case AL_SAMPLE_LENGTH_SOFT:
247 case AL_SEC_LENGTH_SOFT:
248 case AL_SOURCE_RADIUS:
249 return 1;
251 case AL_SEC_OFFSET_LATENCY_SOFT:
252 case AL_STEREO_ANGLES:
253 return 2;
255 case AL_POSITION:
256 case AL_VELOCITY:
257 case AL_DIRECTION:
258 return 3;
260 case AL_ORIENTATION:
261 return 6;
263 case AL_BUFFER:
264 case AL_DIRECT_FILTER:
265 case AL_AUXILIARY_SEND_FILTER:
266 break; /* i/i64 only */
267 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
268 break; /* i64 only */
270 return 0;
273 static ALint IntValsByProp(ALenum prop)
275 if(prop != (ALenum)((SourceProp)prop))
276 return 0;
277 switch((SourceProp)prop)
279 case AL_PITCH:
280 case AL_GAIN:
281 case AL_MIN_GAIN:
282 case AL_MAX_GAIN:
283 case AL_MAX_DISTANCE:
284 case AL_ROLLOFF_FACTOR:
285 case AL_DOPPLER_FACTOR:
286 case AL_CONE_OUTER_GAIN:
287 case AL_SEC_OFFSET:
288 case AL_SAMPLE_OFFSET:
289 case AL_BYTE_OFFSET:
290 case AL_CONE_INNER_ANGLE:
291 case AL_CONE_OUTER_ANGLE:
292 case AL_REFERENCE_DISTANCE:
293 case AL_CONE_OUTER_GAINHF:
294 case AL_AIR_ABSORPTION_FACTOR:
295 case AL_ROOM_ROLLOFF_FACTOR:
296 case AL_DIRECT_FILTER_GAINHF_AUTO:
297 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
298 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
299 case AL_DIRECT_CHANNELS_SOFT:
300 case AL_DISTANCE_MODEL:
301 case AL_SOURCE_RELATIVE:
302 case AL_LOOPING:
303 case AL_BUFFER:
304 case AL_SOURCE_STATE:
305 case AL_BUFFERS_QUEUED:
306 case AL_BUFFERS_PROCESSED:
307 case AL_SOURCE_TYPE:
308 case AL_DIRECT_FILTER:
309 case AL_BYTE_LENGTH_SOFT:
310 case AL_SAMPLE_LENGTH_SOFT:
311 case AL_SEC_LENGTH_SOFT:
312 case AL_SOURCE_RADIUS:
313 return 1;
315 case AL_POSITION:
316 case AL_VELOCITY:
317 case AL_DIRECTION:
318 case AL_AUXILIARY_SEND_FILTER:
319 return 3;
321 case AL_ORIENTATION:
322 return 6;
324 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
325 break; /* i64 only */
326 case AL_SEC_OFFSET_LATENCY_SOFT:
327 break; /* Double only */
328 case AL_STEREO_ANGLES:
329 break; /* Float/double only */
331 return 0;
333 static ALint Int64ValsByProp(ALenum prop)
335 if(prop != (ALenum)((SourceProp)prop))
336 return 0;
337 switch((SourceProp)prop)
339 case AL_PITCH:
340 case AL_GAIN:
341 case AL_MIN_GAIN:
342 case AL_MAX_GAIN:
343 case AL_MAX_DISTANCE:
344 case AL_ROLLOFF_FACTOR:
345 case AL_DOPPLER_FACTOR:
346 case AL_CONE_OUTER_GAIN:
347 case AL_SEC_OFFSET:
348 case AL_SAMPLE_OFFSET:
349 case AL_BYTE_OFFSET:
350 case AL_CONE_INNER_ANGLE:
351 case AL_CONE_OUTER_ANGLE:
352 case AL_REFERENCE_DISTANCE:
353 case AL_CONE_OUTER_GAINHF:
354 case AL_AIR_ABSORPTION_FACTOR:
355 case AL_ROOM_ROLLOFF_FACTOR:
356 case AL_DIRECT_FILTER_GAINHF_AUTO:
357 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
358 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
359 case AL_DIRECT_CHANNELS_SOFT:
360 case AL_DISTANCE_MODEL:
361 case AL_SOURCE_RELATIVE:
362 case AL_LOOPING:
363 case AL_BUFFER:
364 case AL_SOURCE_STATE:
365 case AL_BUFFERS_QUEUED:
366 case AL_BUFFERS_PROCESSED:
367 case AL_SOURCE_TYPE:
368 case AL_DIRECT_FILTER:
369 case AL_BYTE_LENGTH_SOFT:
370 case AL_SAMPLE_LENGTH_SOFT:
371 case AL_SEC_LENGTH_SOFT:
372 case AL_SOURCE_RADIUS:
373 return 1;
375 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
376 return 2;
378 case AL_POSITION:
379 case AL_VELOCITY:
380 case AL_DIRECTION:
381 case AL_AUXILIARY_SEND_FILTER:
382 return 3;
384 case AL_ORIENTATION:
385 return 6;
387 case AL_SEC_OFFSET_LATENCY_SOFT:
388 break; /* Double only */
389 case AL_STEREO_ANGLES:
390 break; /* Float/double only */
392 return 0;
396 #define CHECKVAL(x) do { \
397 if(!(x)) \
398 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
399 } while(0)
401 #define DO_UPDATEPROPS() do { \
402 if(SourceShouldUpdate(Source, Context)) \
403 UpdateSourceProps(Source, device->NumAuxSends); \
404 else \
405 Source->NeedsUpdate = AL_TRUE; \
406 } while(0)
408 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
410 ALCdevice *device = Context->Device;
411 ALint ival;
413 switch(prop)
415 case AL_BYTE_LENGTH_SOFT:
416 case AL_SAMPLE_LENGTH_SOFT:
417 case AL_SEC_LENGTH_SOFT:
418 case AL_SEC_OFFSET_LATENCY_SOFT:
419 /* Query only */
420 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
422 case AL_PITCH:
423 CHECKVAL(*values >= 0.0f);
425 Source->Pitch = *values;
426 DO_UPDATEPROPS();
427 return AL_TRUE;
429 case AL_CONE_INNER_ANGLE:
430 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
432 Source->InnerAngle = *values;
433 DO_UPDATEPROPS();
434 return AL_TRUE;
436 case AL_CONE_OUTER_ANGLE:
437 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
439 Source->OuterAngle = *values;
440 DO_UPDATEPROPS();
441 return AL_TRUE;
443 case AL_GAIN:
444 CHECKVAL(*values >= 0.0f);
446 Source->Gain = *values;
447 DO_UPDATEPROPS();
448 return AL_TRUE;
450 case AL_MAX_DISTANCE:
451 CHECKVAL(*values >= 0.0f);
453 Source->MaxDistance = *values;
454 DO_UPDATEPROPS();
455 return AL_TRUE;
457 case AL_ROLLOFF_FACTOR:
458 CHECKVAL(*values >= 0.0f);
460 Source->RollOffFactor = *values;
461 DO_UPDATEPROPS();
462 return AL_TRUE;
464 case AL_REFERENCE_DISTANCE:
465 CHECKVAL(*values >= 0.0f);
467 Source->RefDistance = *values;
468 DO_UPDATEPROPS();
469 return AL_TRUE;
471 case AL_MIN_GAIN:
472 CHECKVAL(*values >= 0.0f);
474 Source->MinGain = *values;
475 DO_UPDATEPROPS();
476 return AL_TRUE;
478 case AL_MAX_GAIN:
479 CHECKVAL(*values >= 0.0f);
481 Source->MaxGain = *values;
482 DO_UPDATEPROPS();
483 return AL_TRUE;
485 case AL_CONE_OUTER_GAIN:
486 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
488 Source->OuterGain = *values;
489 DO_UPDATEPROPS();
490 return AL_TRUE;
492 case AL_CONE_OUTER_GAINHF:
493 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
495 Source->OuterGainHF = *values;
496 DO_UPDATEPROPS();
497 return AL_TRUE;
499 case AL_AIR_ABSORPTION_FACTOR:
500 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
502 Source->AirAbsorptionFactor = *values;
503 DO_UPDATEPROPS();
504 return AL_TRUE;
506 case AL_ROOM_ROLLOFF_FACTOR:
507 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
509 Source->RoomRolloffFactor = *values;
510 DO_UPDATEPROPS();
511 return AL_TRUE;
513 case AL_DOPPLER_FACTOR:
514 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
516 Source->DopplerFactor = *values;
517 DO_UPDATEPROPS();
518 return AL_TRUE;
520 case AL_SEC_OFFSET:
521 case AL_SAMPLE_OFFSET:
522 case AL_BYTE_OFFSET:
523 CHECKVAL(*values >= 0.0f);
525 Source->OffsetType = prop;
526 Source->Offset = *values;
528 if(IsPlayingOrPaused(Source) &&
529 !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire))
531 ALCdevice_Lock(Context->Device);
532 WriteLock(&Source->queue_lock);
533 if(ApplyOffset(Source) == AL_FALSE)
535 WriteUnlock(&Source->queue_lock);
536 ALCdevice_Unlock(Context->Device);
537 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
539 WriteUnlock(&Source->queue_lock);
540 ALCdevice_Unlock(Context->Device);
542 return AL_TRUE;
544 case AL_SOURCE_RADIUS:
545 CHECKVAL(*values >= 0.0f && isfinite(*values));
547 Source->Radius = *values;
548 DO_UPDATEPROPS();
549 return AL_TRUE;
551 case AL_STEREO_ANGLES:
552 CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
554 Source->StereoPan[0] = values[0];
555 Source->StereoPan[1] = values[1];
556 DO_UPDATEPROPS();
557 return AL_TRUE;
560 case AL_POSITION:
561 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
563 Source->Position[0] = values[0];
564 Source->Position[1] = values[1];
565 Source->Position[2] = values[2];
566 DO_UPDATEPROPS();
567 return AL_TRUE;
569 case AL_VELOCITY:
570 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
572 Source->Velocity[0] = values[0];
573 Source->Velocity[1] = values[1];
574 Source->Velocity[2] = values[2];
575 DO_UPDATEPROPS();
576 return AL_TRUE;
578 case AL_DIRECTION:
579 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
581 Source->Direction[0] = values[0];
582 Source->Direction[1] = values[1];
583 Source->Direction[2] = values[2];
584 DO_UPDATEPROPS();
585 return AL_TRUE;
587 case AL_ORIENTATION:
588 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
589 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
591 Source->Orientation[0][0] = values[0];
592 Source->Orientation[0][1] = values[1];
593 Source->Orientation[0][2] = values[2];
594 Source->Orientation[1][0] = values[3];
595 Source->Orientation[1][1] = values[4];
596 Source->Orientation[1][2] = values[5];
597 DO_UPDATEPROPS();
598 return AL_TRUE;
601 case AL_SOURCE_RELATIVE:
602 case AL_LOOPING:
603 case AL_SOURCE_STATE:
604 case AL_SOURCE_TYPE:
605 case AL_DISTANCE_MODEL:
606 case AL_DIRECT_FILTER_GAINHF_AUTO:
607 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
608 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
609 case AL_DIRECT_CHANNELS_SOFT:
610 ival = (ALint)values[0];
611 return SetSourceiv(Source, Context, prop, &ival);
613 case AL_BUFFERS_QUEUED:
614 case AL_BUFFERS_PROCESSED:
615 ival = (ALint)((ALuint)values[0]);
616 return SetSourceiv(Source, Context, prop, &ival);
618 case AL_BUFFER:
619 case AL_DIRECT_FILTER:
620 case AL_AUXILIARY_SEND_FILTER:
621 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
622 break;
625 ERR("Unexpected property: 0x%04x\n", prop);
626 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
629 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
631 ALCdevice *device = Context->Device;
632 ALbuffer *buffer = NULL;
633 ALfilter *filter = NULL;
634 ALeffectslot *slot = NULL;
635 ALbufferlistitem *oldlist;
636 ALbufferlistitem *newlist;
637 ALfloat fvals[6];
639 switch(prop)
641 case AL_SOURCE_STATE:
642 case AL_SOURCE_TYPE:
643 case AL_BUFFERS_QUEUED:
644 case AL_BUFFERS_PROCESSED:
645 case AL_BYTE_LENGTH_SOFT:
646 case AL_SAMPLE_LENGTH_SOFT:
647 case AL_SEC_LENGTH_SOFT:
648 /* Query only */
649 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
651 case AL_SOURCE_RELATIVE:
652 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
654 Source->HeadRelative = (ALboolean)*values;
655 DO_UPDATEPROPS();
656 return AL_TRUE;
658 case AL_LOOPING:
659 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
661 WriteLock(&Source->queue_lock);
662 ATOMIC_STORE_SEQ(&Source->looping, *values);
663 WriteUnlock(&Source->queue_lock);
664 return AL_TRUE;
666 case AL_BUFFER:
667 LockBuffersRead(device);
668 if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
670 UnlockBuffersRead(device);
671 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
674 WriteLock(&Source->queue_lock);
675 if(IsPlayingOrPaused(Source))
677 WriteUnlock(&Source->queue_lock);
678 UnlockBuffersRead(device);
679 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
682 if(buffer != NULL)
684 /* Add the selected buffer to a one-item queue */
685 newlist = malloc(sizeof(ALbufferlistitem));
686 newlist->buffer = buffer;
687 newlist->next = NULL;
688 IncrementRef(&buffer->ref);
690 /* Source is now Static */
691 Source->SourceType = AL_STATIC;
693 ReadLock(&buffer->lock);
694 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
695 Source->SampleSize = BytesFromFmt(buffer->FmtType);
696 ReadUnlock(&buffer->lock);
698 else
700 /* Source is now Undetermined */
701 Source->SourceType = AL_UNDETERMINED;
702 newlist = NULL;
704 oldlist = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &Source->queue, newlist);
705 ATOMIC_STORE_SEQ(&Source->current_buffer, newlist);
706 WriteUnlock(&Source->queue_lock);
707 UnlockBuffersRead(device);
709 /* Delete all elements in the previous queue */
710 while(oldlist != NULL)
712 ALbufferlistitem *temp = oldlist;
713 oldlist = temp->next;
715 if(temp->buffer)
716 DecrementRef(&temp->buffer->ref);
717 free(temp);
719 return AL_TRUE;
721 case AL_SEC_OFFSET:
722 case AL_SAMPLE_OFFSET:
723 case AL_BYTE_OFFSET:
724 CHECKVAL(*values >= 0);
726 Source->OffsetType = prop;
727 Source->Offset = *values;
729 if(IsPlayingOrPaused(Source) &&
730 !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire))
732 ALCdevice_Lock(Context->Device);
733 WriteLock(&Source->queue_lock);
734 if(ApplyOffset(Source) == AL_FALSE)
736 WriteUnlock(&Source->queue_lock);
737 ALCdevice_Unlock(Context->Device);
738 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
740 WriteUnlock(&Source->queue_lock);
741 ALCdevice_Unlock(Context->Device);
743 return AL_TRUE;
745 case AL_DIRECT_FILTER:
746 LockFiltersRead(device);
747 if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
749 UnlockFiltersRead(device);
750 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
753 if(!filter)
755 Source->Direct.Gain = 1.0f;
756 Source->Direct.GainHF = 1.0f;
757 Source->Direct.HFReference = LOWPASSFREQREF;
758 Source->Direct.GainLF = 1.0f;
759 Source->Direct.LFReference = HIGHPASSFREQREF;
761 else
763 Source->Direct.Gain = filter->Gain;
764 Source->Direct.GainHF = filter->GainHF;
765 Source->Direct.HFReference = filter->HFReference;
766 Source->Direct.GainLF = filter->GainLF;
767 Source->Direct.LFReference = filter->LFReference;
769 UnlockFiltersRead(device);
770 DO_UPDATEPROPS();
771 return AL_TRUE;
773 case AL_DIRECT_FILTER_GAINHF_AUTO:
774 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
776 Source->DryGainHFAuto = *values;
777 DO_UPDATEPROPS();
778 return AL_TRUE;
780 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
781 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
783 Source->WetGainAuto = *values;
784 DO_UPDATEPROPS();
785 return AL_TRUE;
787 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
788 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
790 Source->WetGainHFAuto = *values;
791 DO_UPDATEPROPS();
792 return AL_TRUE;
794 case AL_DIRECT_CHANNELS_SOFT:
795 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
797 Source->DirectChannels = *values;
798 DO_UPDATEPROPS();
799 return AL_TRUE;
801 case AL_DISTANCE_MODEL:
802 CHECKVAL(*values == AL_NONE ||
803 *values == AL_INVERSE_DISTANCE ||
804 *values == AL_INVERSE_DISTANCE_CLAMPED ||
805 *values == AL_LINEAR_DISTANCE ||
806 *values == AL_LINEAR_DISTANCE_CLAMPED ||
807 *values == AL_EXPONENT_DISTANCE ||
808 *values == AL_EXPONENT_DISTANCE_CLAMPED);
810 Source->DistanceModel = *values;
811 if(Context->SourceDistanceModel)
812 DO_UPDATEPROPS();
813 return AL_TRUE;
816 case AL_AUXILIARY_SEND_FILTER:
817 LockEffectSlotsRead(Context);
818 LockFiltersRead(device);
819 if(!((ALuint)values[1] < (ALuint)device->NumAuxSends &&
820 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
821 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
823 UnlockFiltersRead(device);
824 UnlockEffectSlotsRead(Context);
825 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
828 if(!filter)
830 /* Disable filter */
831 Source->Send[values[1]].Gain = 1.0f;
832 Source->Send[values[1]].GainHF = 1.0f;
833 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
834 Source->Send[values[1]].GainLF = 1.0f;
835 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
837 else
839 Source->Send[values[1]].Gain = filter->Gain;
840 Source->Send[values[1]].GainHF = filter->GainHF;
841 Source->Send[values[1]].HFReference = filter->HFReference;
842 Source->Send[values[1]].GainLF = filter->GainLF;
843 Source->Send[values[1]].LFReference = filter->LFReference;
845 UnlockFiltersRead(device);
847 if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source))
849 /* Add refcount on the new slot, and release the previous slot */
850 if(slot) IncrementRef(&slot->ref);
851 if(Source->Send[values[1]].Slot)
852 DecrementRef(&Source->Send[values[1]].Slot->ref);
853 Source->Send[values[1]].Slot = slot;
855 /* We must force an update if the auxiliary slot changed on a
856 * playing source, in case the slot is about to be deleted.
858 UpdateSourceProps(Source, device->NumAuxSends);
860 else
862 if(slot) IncrementRef(&slot->ref);
863 if(Source->Send[values[1]].Slot)
864 DecrementRef(&Source->Send[values[1]].Slot->ref);
865 Source->Send[values[1]].Slot = slot;
866 DO_UPDATEPROPS();
868 UnlockEffectSlotsRead(Context);
870 return AL_TRUE;
873 /* 1x float */
874 case AL_CONE_INNER_ANGLE:
875 case AL_CONE_OUTER_ANGLE:
876 case AL_PITCH:
877 case AL_GAIN:
878 case AL_MIN_GAIN:
879 case AL_MAX_GAIN:
880 case AL_REFERENCE_DISTANCE:
881 case AL_ROLLOFF_FACTOR:
882 case AL_CONE_OUTER_GAIN:
883 case AL_MAX_DISTANCE:
884 case AL_DOPPLER_FACTOR:
885 case AL_CONE_OUTER_GAINHF:
886 case AL_AIR_ABSORPTION_FACTOR:
887 case AL_ROOM_ROLLOFF_FACTOR:
888 case AL_SOURCE_RADIUS:
889 fvals[0] = (ALfloat)*values;
890 return SetSourcefv(Source, Context, (int)prop, fvals);
892 /* 3x float */
893 case AL_POSITION:
894 case AL_VELOCITY:
895 case AL_DIRECTION:
896 fvals[0] = (ALfloat)values[0];
897 fvals[1] = (ALfloat)values[1];
898 fvals[2] = (ALfloat)values[2];
899 return SetSourcefv(Source, Context, (int)prop, fvals);
901 /* 6x float */
902 case AL_ORIENTATION:
903 fvals[0] = (ALfloat)values[0];
904 fvals[1] = (ALfloat)values[1];
905 fvals[2] = (ALfloat)values[2];
906 fvals[3] = (ALfloat)values[3];
907 fvals[4] = (ALfloat)values[4];
908 fvals[5] = (ALfloat)values[5];
909 return SetSourcefv(Source, Context, (int)prop, fvals);
911 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
912 case AL_SEC_OFFSET_LATENCY_SOFT:
913 case AL_STEREO_ANGLES:
914 break;
917 ERR("Unexpected property: 0x%04x\n", prop);
918 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
921 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
923 ALfloat fvals[6];
924 ALint ivals[3];
926 switch(prop)
928 case AL_SOURCE_TYPE:
929 case AL_BUFFERS_QUEUED:
930 case AL_BUFFERS_PROCESSED:
931 case AL_SOURCE_STATE:
932 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
933 case AL_BYTE_LENGTH_SOFT:
934 case AL_SAMPLE_LENGTH_SOFT:
935 case AL_SEC_LENGTH_SOFT:
936 /* Query only */
937 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
940 /* 1x int */
941 case AL_SOURCE_RELATIVE:
942 case AL_LOOPING:
943 case AL_SEC_OFFSET:
944 case AL_SAMPLE_OFFSET:
945 case AL_BYTE_OFFSET:
946 case AL_DIRECT_FILTER_GAINHF_AUTO:
947 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
948 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
949 case AL_DIRECT_CHANNELS_SOFT:
950 case AL_DISTANCE_MODEL:
951 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
953 ivals[0] = (ALint)*values;
954 return SetSourceiv(Source, Context, (int)prop, ivals);
956 /* 1x uint */
957 case AL_BUFFER:
958 case AL_DIRECT_FILTER:
959 CHECKVAL(*values <= UINT_MAX && *values >= 0);
961 ivals[0] = (ALuint)*values;
962 return SetSourceiv(Source, Context, (int)prop, ivals);
964 /* 3x uint */
965 case AL_AUXILIARY_SEND_FILTER:
966 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
967 values[1] <= UINT_MAX && values[1] >= 0 &&
968 values[2] <= UINT_MAX && values[2] >= 0);
970 ivals[0] = (ALuint)values[0];
971 ivals[1] = (ALuint)values[1];
972 ivals[2] = (ALuint)values[2];
973 return SetSourceiv(Source, Context, (int)prop, ivals);
975 /* 1x float */
976 case AL_CONE_INNER_ANGLE:
977 case AL_CONE_OUTER_ANGLE:
978 case AL_PITCH:
979 case AL_GAIN:
980 case AL_MIN_GAIN:
981 case AL_MAX_GAIN:
982 case AL_REFERENCE_DISTANCE:
983 case AL_ROLLOFF_FACTOR:
984 case AL_CONE_OUTER_GAIN:
985 case AL_MAX_DISTANCE:
986 case AL_DOPPLER_FACTOR:
987 case AL_CONE_OUTER_GAINHF:
988 case AL_AIR_ABSORPTION_FACTOR:
989 case AL_ROOM_ROLLOFF_FACTOR:
990 case AL_SOURCE_RADIUS:
991 fvals[0] = (ALfloat)*values;
992 return SetSourcefv(Source, Context, (int)prop, fvals);
994 /* 3x float */
995 case AL_POSITION:
996 case AL_VELOCITY:
997 case AL_DIRECTION:
998 fvals[0] = (ALfloat)values[0];
999 fvals[1] = (ALfloat)values[1];
1000 fvals[2] = (ALfloat)values[2];
1001 return SetSourcefv(Source, Context, (int)prop, fvals);
1003 /* 6x float */
1004 case AL_ORIENTATION:
1005 fvals[0] = (ALfloat)values[0];
1006 fvals[1] = (ALfloat)values[1];
1007 fvals[2] = (ALfloat)values[2];
1008 fvals[3] = (ALfloat)values[3];
1009 fvals[4] = (ALfloat)values[4];
1010 fvals[5] = (ALfloat)values[5];
1011 return SetSourcefv(Source, Context, (int)prop, fvals);
1013 case AL_SEC_OFFSET_LATENCY_SOFT:
1014 case AL_STEREO_ANGLES:
1015 break;
1018 ERR("Unexpected property: 0x%04x\n", prop);
1019 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1022 #undef CHECKVAL
1025 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
1027 ALCdevice *device = Context->Device;
1028 ALbufferlistitem *BufferList;
1029 ClockLatency clocktime;
1030 ALuint64 srcclock;
1031 ALint ivals[3];
1032 ALboolean err;
1034 switch(prop)
1036 case AL_GAIN:
1037 *values = Source->Gain;
1038 return AL_TRUE;
1040 case AL_PITCH:
1041 *values = Source->Pitch;
1042 return AL_TRUE;
1044 case AL_MAX_DISTANCE:
1045 *values = Source->MaxDistance;
1046 return AL_TRUE;
1048 case AL_ROLLOFF_FACTOR:
1049 *values = Source->RollOffFactor;
1050 return AL_TRUE;
1052 case AL_REFERENCE_DISTANCE:
1053 *values = Source->RefDistance;
1054 return AL_TRUE;
1056 case AL_CONE_INNER_ANGLE:
1057 *values = Source->InnerAngle;
1058 return AL_TRUE;
1060 case AL_CONE_OUTER_ANGLE:
1061 *values = Source->OuterAngle;
1062 return AL_TRUE;
1064 case AL_MIN_GAIN:
1065 *values = Source->MinGain;
1066 return AL_TRUE;
1068 case AL_MAX_GAIN:
1069 *values = Source->MaxGain;
1070 return AL_TRUE;
1072 case AL_CONE_OUTER_GAIN:
1073 *values = Source->OuterGain;
1074 return AL_TRUE;
1076 case AL_SEC_OFFSET:
1077 case AL_SAMPLE_OFFSET:
1078 case AL_BYTE_OFFSET:
1079 *values = GetSourceOffset(Source, prop, device);
1080 return AL_TRUE;
1082 case AL_CONE_OUTER_GAINHF:
1083 *values = Source->OuterGainHF;
1084 return AL_TRUE;
1086 case AL_AIR_ABSORPTION_FACTOR:
1087 *values = Source->AirAbsorptionFactor;
1088 return AL_TRUE;
1090 case AL_ROOM_ROLLOFF_FACTOR:
1091 *values = Source->RoomRolloffFactor;
1092 return AL_TRUE;
1094 case AL_DOPPLER_FACTOR:
1095 *values = Source->DopplerFactor;
1096 return AL_TRUE;
1098 case AL_SEC_LENGTH_SOFT:
1099 ReadLock(&Source->queue_lock);
1100 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1101 *values = 0;
1102 else
1104 ALint length = 0;
1105 ALsizei freq = 1;
1106 do {
1107 ALbuffer *buffer = BufferList->buffer;
1108 if(buffer && buffer->SampleLen > 0)
1110 freq = buffer->Frequency;
1111 length += buffer->SampleLen;
1113 } while((BufferList=BufferList->next) != NULL);
1114 *values = (ALdouble)length / (ALdouble)freq;
1116 ReadUnlock(&Source->queue_lock);
1117 return AL_TRUE;
1119 case AL_SOURCE_RADIUS:
1120 *values = Source->Radius;
1121 return AL_TRUE;
1123 case AL_STEREO_ANGLES:
1124 values[0] = Source->StereoPan[0];
1125 values[1] = Source->StereoPan[1];
1126 return AL_TRUE;
1128 case AL_SEC_OFFSET_LATENCY_SOFT:
1129 /* Get the source offset with the clock time first. Then get the
1130 * clock time with the device latency. Order is important.
1132 values[0] = GetSourceSecOffset(Source, device, &srcclock);
1133 clocktime = V0(device->Backend,getClockLatency)();
1134 if(srcclock == (ALuint64)clocktime.ClockTime)
1135 values[1] = (ALdouble)clocktime.Latency / 1000000000.0;
1136 else
1138 /* If the clock time incremented, reduce the latency by that
1139 * much since it's that much closer to the source offset it got
1140 * earlier.
1142 ALuint64 diff = clocktime.ClockTime - srcclock;
1143 values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) /
1144 1000000000.0;
1146 return AL_TRUE;
1148 case AL_POSITION:
1149 values[0] = Source->Position[0];
1150 values[1] = Source->Position[1];
1151 values[2] = Source->Position[2];
1152 return AL_TRUE;
1154 case AL_VELOCITY:
1155 values[0] = Source->Velocity[0];
1156 values[1] = Source->Velocity[1];
1157 values[2] = Source->Velocity[2];
1158 return AL_TRUE;
1160 case AL_DIRECTION:
1161 values[0] = Source->Direction[0];
1162 values[1] = Source->Direction[1];
1163 values[2] = Source->Direction[2];
1164 return AL_TRUE;
1166 case AL_ORIENTATION:
1167 values[0] = Source->Orientation[0][0];
1168 values[1] = Source->Orientation[0][1];
1169 values[2] = Source->Orientation[0][2];
1170 values[3] = Source->Orientation[1][0];
1171 values[4] = Source->Orientation[1][1];
1172 values[5] = Source->Orientation[1][2];
1173 return AL_TRUE;
1175 /* 1x int */
1176 case AL_SOURCE_RELATIVE:
1177 case AL_LOOPING:
1178 case AL_SOURCE_STATE:
1179 case AL_BUFFERS_QUEUED:
1180 case AL_BUFFERS_PROCESSED:
1181 case AL_SOURCE_TYPE:
1182 case AL_DIRECT_FILTER_GAINHF_AUTO:
1183 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1184 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1185 case AL_DIRECT_CHANNELS_SOFT:
1186 case AL_BYTE_LENGTH_SOFT:
1187 case AL_SAMPLE_LENGTH_SOFT:
1188 case AL_DISTANCE_MODEL:
1189 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1190 *values = (ALdouble)ivals[0];
1191 return err;
1193 case AL_BUFFER:
1194 case AL_DIRECT_FILTER:
1195 case AL_AUXILIARY_SEND_FILTER:
1196 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1197 break;
1200 ERR("Unexpected property: 0x%04x\n", prop);
1201 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1204 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1206 ALbufferlistitem *BufferList;
1207 ALdouble dvals[6];
1208 ALboolean err;
1210 switch(prop)
1212 case AL_SOURCE_RELATIVE:
1213 *values = Source->HeadRelative;
1214 return AL_TRUE;
1216 case AL_LOOPING:
1217 *values = ATOMIC_LOAD_SEQ(&Source->looping);
1218 return AL_TRUE;
1220 case AL_BUFFER:
1221 ReadLock(&Source->queue_lock);
1222 BufferList = (Source->SourceType == AL_STATIC) ?
1223 ATOMIC_LOAD_SEQ(&Source->queue) :
1224 ATOMIC_LOAD_SEQ(&Source->current_buffer);
1225 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1226 ReadUnlock(&Source->queue_lock);
1227 return AL_TRUE;
1229 case AL_SOURCE_STATE:
1230 *values = ATOMIC_LOAD_SEQ(&Source->state);
1231 return AL_TRUE;
1233 case AL_BYTE_LENGTH_SOFT:
1234 ReadLock(&Source->queue_lock);
1235 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1236 *values = 0;
1237 else
1239 ALint length = 0;
1240 do {
1241 ALbuffer *buffer = BufferList->buffer;
1242 if(buffer && buffer->SampleLen > 0)
1244 ALuint byte_align, sample_align;
1245 if(buffer->OriginalType == UserFmtIMA4)
1247 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1248 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1249 sample_align = buffer->OriginalAlign;
1251 else if(buffer->OriginalType == UserFmtMSADPCM)
1253 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1254 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1255 sample_align = buffer->OriginalAlign;
1257 else
1259 ALsizei align = buffer->OriginalAlign;
1260 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1261 sample_align = buffer->OriginalAlign;
1264 length += buffer->SampleLen / sample_align * byte_align;
1266 } while((BufferList=BufferList->next) != NULL);
1267 *values = length;
1269 ReadUnlock(&Source->queue_lock);
1270 return AL_TRUE;
1272 case AL_SAMPLE_LENGTH_SOFT:
1273 ReadLock(&Source->queue_lock);
1274 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1275 *values = 0;
1276 else
1278 ALint length = 0;
1279 do {
1280 ALbuffer *buffer = BufferList->buffer;
1281 if(buffer) length += buffer->SampleLen;
1282 } while((BufferList=BufferList->next) != NULL);
1283 *values = length;
1285 ReadUnlock(&Source->queue_lock);
1286 return AL_TRUE;
1288 case AL_BUFFERS_QUEUED:
1289 ReadLock(&Source->queue_lock);
1290 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1291 *values = 0;
1292 else
1294 ALsizei count = 0;
1295 do {
1296 ++count;
1297 } while((BufferList=BufferList->next) != NULL);
1298 *values = count;
1300 ReadUnlock(&Source->queue_lock);
1301 return AL_TRUE;
1303 case AL_BUFFERS_PROCESSED:
1304 ReadLock(&Source->queue_lock);
1305 if(ATOMIC_LOAD_SEQ(&Source->looping) || Source->SourceType != AL_STREAMING)
1307 /* Buffers on a looping source are in a perpetual state of
1308 * PENDING, so don't report any as PROCESSED */
1309 *values = 0;
1311 else
1313 const ALbufferlistitem *BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
1314 const ALbufferlistitem *Current = ATOMIC_LOAD_SEQ(&Source->current_buffer);
1315 ALsizei played = 0;
1316 while(BufferList && BufferList != Current)
1318 played++;
1319 BufferList = BufferList->next;
1321 *values = played;
1323 ReadUnlock(&Source->queue_lock);
1324 return AL_TRUE;
1326 case AL_SOURCE_TYPE:
1327 *values = Source->SourceType;
1328 return AL_TRUE;
1330 case AL_DIRECT_FILTER_GAINHF_AUTO:
1331 *values = Source->DryGainHFAuto;
1332 return AL_TRUE;
1334 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1335 *values = Source->WetGainAuto;
1336 return AL_TRUE;
1338 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1339 *values = Source->WetGainHFAuto;
1340 return AL_TRUE;
1342 case AL_DIRECT_CHANNELS_SOFT:
1343 *values = Source->DirectChannels;
1344 return AL_TRUE;
1346 case AL_DISTANCE_MODEL:
1347 *values = Source->DistanceModel;
1348 return AL_TRUE;
1350 /* 1x float/double */
1351 case AL_CONE_INNER_ANGLE:
1352 case AL_CONE_OUTER_ANGLE:
1353 case AL_PITCH:
1354 case AL_GAIN:
1355 case AL_MIN_GAIN:
1356 case AL_MAX_GAIN:
1357 case AL_REFERENCE_DISTANCE:
1358 case AL_ROLLOFF_FACTOR:
1359 case AL_CONE_OUTER_GAIN:
1360 case AL_MAX_DISTANCE:
1361 case AL_SEC_OFFSET:
1362 case AL_SAMPLE_OFFSET:
1363 case AL_BYTE_OFFSET:
1364 case AL_DOPPLER_FACTOR:
1365 case AL_AIR_ABSORPTION_FACTOR:
1366 case AL_ROOM_ROLLOFF_FACTOR:
1367 case AL_CONE_OUTER_GAINHF:
1368 case AL_SEC_LENGTH_SOFT:
1369 case AL_SOURCE_RADIUS:
1370 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1371 *values = (ALint)dvals[0];
1372 return err;
1374 /* 3x float/double */
1375 case AL_POSITION:
1376 case AL_VELOCITY:
1377 case AL_DIRECTION:
1378 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1380 values[0] = (ALint)dvals[0];
1381 values[1] = (ALint)dvals[1];
1382 values[2] = (ALint)dvals[2];
1384 return err;
1386 /* 6x float/double */
1387 case AL_ORIENTATION:
1388 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1390 values[0] = (ALint)dvals[0];
1391 values[1] = (ALint)dvals[1];
1392 values[2] = (ALint)dvals[2];
1393 values[3] = (ALint)dvals[3];
1394 values[4] = (ALint)dvals[4];
1395 values[5] = (ALint)dvals[5];
1397 return err;
1399 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1400 break; /* i64 only */
1401 case AL_SEC_OFFSET_LATENCY_SOFT:
1402 break; /* Double only */
1403 case AL_STEREO_ANGLES:
1404 break; /* Float/double only */
1406 case AL_DIRECT_FILTER:
1407 case AL_AUXILIARY_SEND_FILTER:
1408 break; /* ??? */
1411 ERR("Unexpected property: 0x%04x\n", prop);
1412 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1415 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1417 ALCdevice *device = Context->Device;
1418 ClockLatency clocktime;
1419 ALuint64 srcclock;
1420 ALdouble dvals[6];
1421 ALint ivals[3];
1422 ALboolean err;
1424 switch(prop)
1426 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1427 /* Get the source offset with the clock time first. Then get the
1428 * clock time with the device latency. Order is important.
1430 values[0] = GetSourceSampleOffset(Source, device, &srcclock);
1431 clocktime = V0(device->Backend,getClockLatency)();
1432 if(srcclock == (ALuint64)clocktime.ClockTime)
1433 values[1] = clocktime.Latency;
1434 else
1436 /* If the clock time incremented, reduce the latency by that
1437 * much since it's that much closer to the source offset it got
1438 * earlier.
1440 ALuint64 diff = clocktime.ClockTime - srcclock;
1441 values[1] = clocktime.Latency - minu64(clocktime.Latency, diff);
1443 return AL_TRUE;
1445 /* 1x float/double */
1446 case AL_CONE_INNER_ANGLE:
1447 case AL_CONE_OUTER_ANGLE:
1448 case AL_PITCH:
1449 case AL_GAIN:
1450 case AL_MIN_GAIN:
1451 case AL_MAX_GAIN:
1452 case AL_REFERENCE_DISTANCE:
1453 case AL_ROLLOFF_FACTOR:
1454 case AL_CONE_OUTER_GAIN:
1455 case AL_MAX_DISTANCE:
1456 case AL_SEC_OFFSET:
1457 case AL_SAMPLE_OFFSET:
1458 case AL_BYTE_OFFSET:
1459 case AL_DOPPLER_FACTOR:
1460 case AL_AIR_ABSORPTION_FACTOR:
1461 case AL_ROOM_ROLLOFF_FACTOR:
1462 case AL_CONE_OUTER_GAINHF:
1463 case AL_SEC_LENGTH_SOFT:
1464 case AL_SOURCE_RADIUS:
1465 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1466 *values = (ALint64)dvals[0];
1467 return err;
1469 /* 3x float/double */
1470 case AL_POSITION:
1471 case AL_VELOCITY:
1472 case AL_DIRECTION:
1473 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1475 values[0] = (ALint64)dvals[0];
1476 values[1] = (ALint64)dvals[1];
1477 values[2] = (ALint64)dvals[2];
1479 return err;
1481 /* 6x float/double */
1482 case AL_ORIENTATION:
1483 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1485 values[0] = (ALint64)dvals[0];
1486 values[1] = (ALint64)dvals[1];
1487 values[2] = (ALint64)dvals[2];
1488 values[3] = (ALint64)dvals[3];
1489 values[4] = (ALint64)dvals[4];
1490 values[5] = (ALint64)dvals[5];
1492 return err;
1494 /* 1x int */
1495 case AL_SOURCE_RELATIVE:
1496 case AL_LOOPING:
1497 case AL_SOURCE_STATE:
1498 case AL_BUFFERS_QUEUED:
1499 case AL_BUFFERS_PROCESSED:
1500 case AL_BYTE_LENGTH_SOFT:
1501 case AL_SAMPLE_LENGTH_SOFT:
1502 case AL_SOURCE_TYPE:
1503 case AL_DIRECT_FILTER_GAINHF_AUTO:
1504 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1505 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1506 case AL_DIRECT_CHANNELS_SOFT:
1507 case AL_DISTANCE_MODEL:
1508 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1509 *values = ivals[0];
1510 return err;
1512 /* 1x uint */
1513 case AL_BUFFER:
1514 case AL_DIRECT_FILTER:
1515 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1516 *values = (ALuint)ivals[0];
1517 return err;
1519 /* 3x uint */
1520 case AL_AUXILIARY_SEND_FILTER:
1521 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1523 values[0] = (ALuint)ivals[0];
1524 values[1] = (ALuint)ivals[1];
1525 values[2] = (ALuint)ivals[2];
1527 return err;
1529 case AL_SEC_OFFSET_LATENCY_SOFT:
1530 break; /* Double only */
1531 case AL_STEREO_ANGLES:
1532 break; /* Float/double only */
1535 ERR("Unexpected property: 0x%04x\n", prop);
1536 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1540 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1542 ALCdevice *device;
1543 ALCcontext *context;
1544 ALsizei cur = 0;
1545 ALenum err;
1547 context = GetContextRef();
1548 if(!context) return;
1550 if(!(n >= 0))
1551 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1552 device = context->Device;
1553 for(cur = 0;cur < n;cur++)
1555 ALsource *source = al_calloc(16, sizeof(ALsource));
1556 if(!source)
1558 alDeleteSources(cur, sources);
1559 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1561 InitSourceParams(source, device->NumAuxSends);
1563 err = NewThunkEntry(&source->id);
1564 if(err == AL_NO_ERROR)
1565 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1566 if(err != AL_NO_ERROR)
1568 FreeThunkEntry(source->id);
1569 memset(source, 0, sizeof(ALsource));
1570 al_free(source);
1572 alDeleteSources(cur, sources);
1573 SET_ERROR_AND_GOTO(context, err, done);
1576 sources[cur] = source->id;
1579 done:
1580 ALCcontext_DecRef(context);
1584 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1586 ALCdevice *device;
1587 ALCcontext *context;
1588 ALsource *Source;
1589 ALsizei i;
1591 context = GetContextRef();
1592 if(!context) return;
1594 LockSourcesWrite(context);
1595 if(!(n >= 0))
1596 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1598 /* Check that all Sources are valid */
1599 for(i = 0;i < n;i++)
1601 if(LookupSource(context, sources[i]) == NULL)
1602 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1604 device = context->Device;
1605 for(i = 0;i < n;i++)
1607 ALvoice *voice;
1609 if((Source=RemoveSource(context, sources[i])) == NULL)
1610 continue;
1611 FreeThunkEntry(Source->id);
1613 ALCdevice_Lock(device);
1614 voice = GetSourceVoice(Source, context);
1615 if(voice) voice->Source = NULL;
1616 ALCdevice_Unlock(device);
1618 DeinitSource(Source, device->NumAuxSends);
1620 memset(Source, 0, sizeof(*Source));
1621 al_free(Source);
1624 done:
1625 UnlockSourcesWrite(context);
1626 ALCcontext_DecRef(context);
1630 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1632 ALCcontext *context;
1633 ALboolean ret;
1635 context = GetContextRef();
1636 if(!context) return AL_FALSE;
1638 LockSourcesRead(context);
1639 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1640 UnlockSourcesRead(context);
1642 ALCcontext_DecRef(context);
1644 return ret;
1648 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1650 ALCcontext *Context;
1651 ALsource *Source;
1653 Context = GetContextRef();
1654 if(!Context) return;
1656 WriteLock(&Context->PropLock);
1657 LockSourcesRead(Context);
1658 if((Source=LookupSource(Context, source)) == NULL)
1659 alSetError(Context, AL_INVALID_NAME);
1660 else if(!(FloatValsByProp(param) == 1))
1661 alSetError(Context, AL_INVALID_ENUM);
1662 else
1663 SetSourcefv(Source, Context, param, &value);
1664 UnlockSourcesRead(Context);
1665 WriteUnlock(&Context->PropLock);
1667 ALCcontext_DecRef(Context);
1670 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1672 ALCcontext *Context;
1673 ALsource *Source;
1675 Context = GetContextRef();
1676 if(!Context) return;
1678 WriteLock(&Context->PropLock);
1679 LockSourcesRead(Context);
1680 if((Source=LookupSource(Context, source)) == NULL)
1681 alSetError(Context, AL_INVALID_NAME);
1682 else if(!(FloatValsByProp(param) == 3))
1683 alSetError(Context, AL_INVALID_ENUM);
1684 else
1686 ALfloat fvals[3] = { value1, value2, value3 };
1687 SetSourcefv(Source, Context, param, fvals);
1689 UnlockSourcesRead(Context);
1690 WriteUnlock(&Context->PropLock);
1692 ALCcontext_DecRef(Context);
1695 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1697 ALCcontext *Context;
1698 ALsource *Source;
1700 Context = GetContextRef();
1701 if(!Context) return;
1703 WriteLock(&Context->PropLock);
1704 LockSourcesRead(Context);
1705 if((Source=LookupSource(Context, source)) == NULL)
1706 alSetError(Context, AL_INVALID_NAME);
1707 else if(!values)
1708 alSetError(Context, AL_INVALID_VALUE);
1709 else if(!(FloatValsByProp(param) > 0))
1710 alSetError(Context, AL_INVALID_ENUM);
1711 else
1712 SetSourcefv(Source, Context, param, values);
1713 UnlockSourcesRead(Context);
1714 WriteUnlock(&Context->PropLock);
1716 ALCcontext_DecRef(Context);
1720 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1722 ALCcontext *Context;
1723 ALsource *Source;
1725 Context = GetContextRef();
1726 if(!Context) return;
1728 WriteLock(&Context->PropLock);
1729 LockSourcesRead(Context);
1730 if((Source=LookupSource(Context, source)) == NULL)
1731 alSetError(Context, AL_INVALID_NAME);
1732 else if(!(DoubleValsByProp(param) == 1))
1733 alSetError(Context, AL_INVALID_ENUM);
1734 else
1736 ALfloat fval = (ALfloat)value;
1737 SetSourcefv(Source, Context, param, &fval);
1739 UnlockSourcesRead(Context);
1740 WriteUnlock(&Context->PropLock);
1742 ALCcontext_DecRef(Context);
1745 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1747 ALCcontext *Context;
1748 ALsource *Source;
1750 Context = GetContextRef();
1751 if(!Context) return;
1753 WriteLock(&Context->PropLock);
1754 LockSourcesRead(Context);
1755 if((Source=LookupSource(Context, source)) == NULL)
1756 alSetError(Context, AL_INVALID_NAME);
1757 else if(!(DoubleValsByProp(param) == 3))
1758 alSetError(Context, AL_INVALID_ENUM);
1759 else
1761 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1762 SetSourcefv(Source, Context, param, fvals);
1764 UnlockSourcesRead(Context);
1765 WriteUnlock(&Context->PropLock);
1767 ALCcontext_DecRef(Context);
1770 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1772 ALCcontext *Context;
1773 ALsource *Source;
1774 ALint count;
1776 Context = GetContextRef();
1777 if(!Context) return;
1779 WriteLock(&Context->PropLock);
1780 LockSourcesRead(Context);
1781 if((Source=LookupSource(Context, source)) == NULL)
1782 alSetError(Context, AL_INVALID_NAME);
1783 else if(!values)
1784 alSetError(Context, AL_INVALID_VALUE);
1785 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1786 alSetError(Context, AL_INVALID_ENUM);
1787 else
1789 ALfloat fvals[6];
1790 ALint i;
1792 for(i = 0;i < count;i++)
1793 fvals[i] = (ALfloat)values[i];
1794 SetSourcefv(Source, Context, param, fvals);
1796 UnlockSourcesRead(Context);
1797 WriteUnlock(&Context->PropLock);
1799 ALCcontext_DecRef(Context);
1803 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1805 ALCcontext *Context;
1806 ALsource *Source;
1808 Context = GetContextRef();
1809 if(!Context) return;
1811 WriteLock(&Context->PropLock);
1812 LockSourcesRead(Context);
1813 if((Source=LookupSource(Context, source)) == NULL)
1814 alSetError(Context, AL_INVALID_NAME);
1815 else if(!(IntValsByProp(param) == 1))
1816 alSetError(Context, AL_INVALID_ENUM);
1817 else
1818 SetSourceiv(Source, Context, param, &value);
1819 UnlockSourcesRead(Context);
1820 WriteUnlock(&Context->PropLock);
1822 ALCcontext_DecRef(Context);
1825 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1827 ALCcontext *Context;
1828 ALsource *Source;
1830 Context = GetContextRef();
1831 if(!Context) return;
1833 WriteLock(&Context->PropLock);
1834 LockSourcesRead(Context);
1835 if((Source=LookupSource(Context, source)) == NULL)
1836 alSetError(Context, AL_INVALID_NAME);
1837 else if(!(IntValsByProp(param) == 3))
1838 alSetError(Context, AL_INVALID_ENUM);
1839 else
1841 ALint ivals[3] = { value1, value2, value3 };
1842 SetSourceiv(Source, Context, param, ivals);
1844 UnlockSourcesRead(Context);
1845 WriteUnlock(&Context->PropLock);
1847 ALCcontext_DecRef(Context);
1850 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1852 ALCcontext *Context;
1853 ALsource *Source;
1855 Context = GetContextRef();
1856 if(!Context) return;
1858 WriteLock(&Context->PropLock);
1859 LockSourcesRead(Context);
1860 if((Source=LookupSource(Context, source)) == NULL)
1861 alSetError(Context, AL_INVALID_NAME);
1862 else if(!values)
1863 alSetError(Context, AL_INVALID_VALUE);
1864 else if(!(IntValsByProp(param) > 0))
1865 alSetError(Context, AL_INVALID_ENUM);
1866 else
1867 SetSourceiv(Source, Context, param, values);
1868 UnlockSourcesRead(Context);
1869 WriteUnlock(&Context->PropLock);
1871 ALCcontext_DecRef(Context);
1875 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1877 ALCcontext *Context;
1878 ALsource *Source;
1880 Context = GetContextRef();
1881 if(!Context) return;
1883 WriteLock(&Context->PropLock);
1884 LockSourcesRead(Context);
1885 if((Source=LookupSource(Context, source)) == NULL)
1886 alSetError(Context, AL_INVALID_NAME);
1887 else if(!(Int64ValsByProp(param) == 1))
1888 alSetError(Context, AL_INVALID_ENUM);
1889 else
1890 SetSourcei64v(Source, Context, param, &value);
1891 UnlockSourcesRead(Context);
1892 WriteUnlock(&Context->PropLock);
1894 ALCcontext_DecRef(Context);
1897 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1899 ALCcontext *Context;
1900 ALsource *Source;
1902 Context = GetContextRef();
1903 if(!Context) return;
1905 WriteLock(&Context->PropLock);
1906 LockSourcesRead(Context);
1907 if((Source=LookupSource(Context, source)) == NULL)
1908 alSetError(Context, AL_INVALID_NAME);
1909 else if(!(Int64ValsByProp(param) == 3))
1910 alSetError(Context, AL_INVALID_ENUM);
1911 else
1913 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1914 SetSourcei64v(Source, Context, param, i64vals);
1916 UnlockSourcesRead(Context);
1917 WriteUnlock(&Context->PropLock);
1919 ALCcontext_DecRef(Context);
1922 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1924 ALCcontext *Context;
1925 ALsource *Source;
1927 Context = GetContextRef();
1928 if(!Context) return;
1930 WriteLock(&Context->PropLock);
1931 LockSourcesRead(Context);
1932 if((Source=LookupSource(Context, source)) == NULL)
1933 alSetError(Context, AL_INVALID_NAME);
1934 else if(!values)
1935 alSetError(Context, AL_INVALID_VALUE);
1936 else if(!(Int64ValsByProp(param) > 0))
1937 alSetError(Context, AL_INVALID_ENUM);
1938 else
1939 SetSourcei64v(Source, Context, param, values);
1940 UnlockSourcesRead(Context);
1941 WriteUnlock(&Context->PropLock);
1943 ALCcontext_DecRef(Context);
1947 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1949 ALCcontext *Context;
1950 ALsource *Source;
1952 Context = GetContextRef();
1953 if(!Context) return;
1955 ReadLock(&Context->PropLock);
1956 LockSourcesRead(Context);
1957 if((Source=LookupSource(Context, source)) == NULL)
1958 alSetError(Context, AL_INVALID_NAME);
1959 else if(!value)
1960 alSetError(Context, AL_INVALID_VALUE);
1961 else if(!(FloatValsByProp(param) == 1))
1962 alSetError(Context, AL_INVALID_ENUM);
1963 else
1965 ALdouble dval;
1966 if(GetSourcedv(Source, Context, param, &dval))
1967 *value = (ALfloat)dval;
1969 UnlockSourcesRead(Context);
1970 ReadUnlock(&Context->PropLock);
1972 ALCcontext_DecRef(Context);
1976 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1978 ALCcontext *Context;
1979 ALsource *Source;
1981 Context = GetContextRef();
1982 if(!Context) return;
1984 ReadLock(&Context->PropLock);
1985 LockSourcesRead(Context);
1986 if((Source=LookupSource(Context, source)) == NULL)
1987 alSetError(Context, AL_INVALID_NAME);
1988 else if(!(value1 && value2 && value3))
1989 alSetError(Context, AL_INVALID_VALUE);
1990 else if(!(FloatValsByProp(param) == 3))
1991 alSetError(Context, AL_INVALID_ENUM);
1992 else
1994 ALdouble dvals[3];
1995 if(GetSourcedv(Source, Context, param, dvals))
1997 *value1 = (ALfloat)dvals[0];
1998 *value2 = (ALfloat)dvals[1];
1999 *value3 = (ALfloat)dvals[2];
2002 UnlockSourcesRead(Context);
2003 ReadUnlock(&Context->PropLock);
2005 ALCcontext_DecRef(Context);
2009 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
2011 ALCcontext *Context;
2012 ALsource *Source;
2013 ALint count;
2015 Context = GetContextRef();
2016 if(!Context) return;
2018 ReadLock(&Context->PropLock);
2019 LockSourcesRead(Context);
2020 if((Source=LookupSource(Context, source)) == NULL)
2021 alSetError(Context, AL_INVALID_NAME);
2022 else if(!values)
2023 alSetError(Context, AL_INVALID_VALUE);
2024 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
2025 alSetError(Context, AL_INVALID_ENUM);
2026 else
2028 ALdouble dvals[6];
2029 if(GetSourcedv(Source, Context, param, dvals))
2031 ALint i;
2032 for(i = 0;i < count;i++)
2033 values[i] = (ALfloat)dvals[i];
2036 UnlockSourcesRead(Context);
2037 ReadUnlock(&Context->PropLock);
2039 ALCcontext_DecRef(Context);
2043 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
2045 ALCcontext *Context;
2046 ALsource *Source;
2048 Context = GetContextRef();
2049 if(!Context) return;
2051 ReadLock(&Context->PropLock);
2052 LockSourcesRead(Context);
2053 if((Source=LookupSource(Context, source)) == NULL)
2054 alSetError(Context, AL_INVALID_NAME);
2055 else if(!value)
2056 alSetError(Context, AL_INVALID_VALUE);
2057 else if(!(DoubleValsByProp(param) == 1))
2058 alSetError(Context, AL_INVALID_ENUM);
2059 else
2060 GetSourcedv(Source, Context, param, value);
2061 UnlockSourcesRead(Context);
2062 ReadUnlock(&Context->PropLock);
2064 ALCcontext_DecRef(Context);
2067 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
2069 ALCcontext *Context;
2070 ALsource *Source;
2072 Context = GetContextRef();
2073 if(!Context) return;
2075 ReadLock(&Context->PropLock);
2076 LockSourcesRead(Context);
2077 if((Source=LookupSource(Context, source)) == NULL)
2078 alSetError(Context, AL_INVALID_NAME);
2079 else if(!(value1 && value2 && value3))
2080 alSetError(Context, AL_INVALID_VALUE);
2081 else if(!(DoubleValsByProp(param) == 3))
2082 alSetError(Context, AL_INVALID_ENUM);
2083 else
2085 ALdouble dvals[3];
2086 if(GetSourcedv(Source, Context, param, dvals))
2088 *value1 = dvals[0];
2089 *value2 = dvals[1];
2090 *value3 = dvals[2];
2093 UnlockSourcesRead(Context);
2094 ReadUnlock(&Context->PropLock);
2096 ALCcontext_DecRef(Context);
2099 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
2101 ALCcontext *Context;
2102 ALsource *Source;
2104 Context = GetContextRef();
2105 if(!Context) return;
2107 ReadLock(&Context->PropLock);
2108 LockSourcesRead(Context);
2109 if((Source=LookupSource(Context, source)) == NULL)
2110 alSetError(Context, AL_INVALID_NAME);
2111 else if(!values)
2112 alSetError(Context, AL_INVALID_VALUE);
2113 else if(!(DoubleValsByProp(param) > 0))
2114 alSetError(Context, AL_INVALID_ENUM);
2115 else
2116 GetSourcedv(Source, Context, param, values);
2117 UnlockSourcesRead(Context);
2118 ReadUnlock(&Context->PropLock);
2120 ALCcontext_DecRef(Context);
2124 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2126 ALCcontext *Context;
2127 ALsource *Source;
2129 Context = GetContextRef();
2130 if(!Context) return;
2132 ReadLock(&Context->PropLock);
2133 LockSourcesRead(Context);
2134 if((Source=LookupSource(Context, source)) == NULL)
2135 alSetError(Context, AL_INVALID_NAME);
2136 else if(!value)
2137 alSetError(Context, AL_INVALID_VALUE);
2138 else if(!(IntValsByProp(param) == 1))
2139 alSetError(Context, AL_INVALID_ENUM);
2140 else
2141 GetSourceiv(Source, Context, param, value);
2142 UnlockSourcesRead(Context);
2143 ReadUnlock(&Context->PropLock);
2145 ALCcontext_DecRef(Context);
2149 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2151 ALCcontext *Context;
2152 ALsource *Source;
2154 Context = GetContextRef();
2155 if(!Context) return;
2157 ReadLock(&Context->PropLock);
2158 LockSourcesRead(Context);
2159 if((Source=LookupSource(Context, source)) == NULL)
2160 alSetError(Context, AL_INVALID_NAME);
2161 else if(!(value1 && value2 && value3))
2162 alSetError(Context, AL_INVALID_VALUE);
2163 else if(!(IntValsByProp(param) == 3))
2164 alSetError(Context, AL_INVALID_ENUM);
2165 else
2167 ALint ivals[3];
2168 if(GetSourceiv(Source, Context, param, ivals))
2170 *value1 = ivals[0];
2171 *value2 = ivals[1];
2172 *value3 = ivals[2];
2175 UnlockSourcesRead(Context);
2176 ReadUnlock(&Context->PropLock);
2178 ALCcontext_DecRef(Context);
2182 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2184 ALCcontext *Context;
2185 ALsource *Source;
2187 Context = GetContextRef();
2188 if(!Context) return;
2190 ReadLock(&Context->PropLock);
2191 LockSourcesRead(Context);
2192 if((Source=LookupSource(Context, source)) == NULL)
2193 alSetError(Context, AL_INVALID_NAME);
2194 else if(!values)
2195 alSetError(Context, AL_INVALID_VALUE);
2196 else if(!(IntValsByProp(param) > 0))
2197 alSetError(Context, AL_INVALID_ENUM);
2198 else
2199 GetSourceiv(Source, Context, param, values);
2200 UnlockSourcesRead(Context);
2201 ReadUnlock(&Context->PropLock);
2203 ALCcontext_DecRef(Context);
2207 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2209 ALCcontext *Context;
2210 ALsource *Source;
2212 Context = GetContextRef();
2213 if(!Context) return;
2215 ReadLock(&Context->PropLock);
2216 LockSourcesRead(Context);
2217 if((Source=LookupSource(Context, source)) == NULL)
2218 alSetError(Context, AL_INVALID_NAME);
2219 else if(!value)
2220 alSetError(Context, AL_INVALID_VALUE);
2221 else if(!(Int64ValsByProp(param) == 1))
2222 alSetError(Context, AL_INVALID_ENUM);
2223 else
2224 GetSourcei64v(Source, Context, param, value);
2225 UnlockSourcesRead(Context);
2226 ReadUnlock(&Context->PropLock);
2228 ALCcontext_DecRef(Context);
2231 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2233 ALCcontext *Context;
2234 ALsource *Source;
2236 Context = GetContextRef();
2237 if(!Context) return;
2239 ReadLock(&Context->PropLock);
2240 LockSourcesRead(Context);
2241 if((Source=LookupSource(Context, source)) == NULL)
2242 alSetError(Context, AL_INVALID_NAME);
2243 else if(!(value1 && value2 && value3))
2244 alSetError(Context, AL_INVALID_VALUE);
2245 else if(!(Int64ValsByProp(param) == 3))
2246 alSetError(Context, AL_INVALID_ENUM);
2247 else
2249 ALint64 i64vals[3];
2250 if(GetSourcei64v(Source, Context, param, i64vals))
2252 *value1 = i64vals[0];
2253 *value2 = i64vals[1];
2254 *value3 = i64vals[2];
2257 UnlockSourcesRead(Context);
2258 ReadUnlock(&Context->PropLock);
2260 ALCcontext_DecRef(Context);
2263 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2265 ALCcontext *Context;
2266 ALsource *Source;
2268 Context = GetContextRef();
2269 if(!Context) return;
2271 ReadLock(&Context->PropLock);
2272 LockSourcesRead(Context);
2273 if((Source=LookupSource(Context, source)) == NULL)
2274 alSetError(Context, AL_INVALID_NAME);
2275 else if(!values)
2276 alSetError(Context, AL_INVALID_VALUE);
2277 else if(!(Int64ValsByProp(param) > 0))
2278 alSetError(Context, AL_INVALID_ENUM);
2279 else
2280 GetSourcei64v(Source, Context, param, values);
2281 UnlockSourcesRead(Context);
2282 ReadUnlock(&Context->PropLock);
2284 ALCcontext_DecRef(Context);
2288 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2290 alSourcePlayv(1, &source);
2292 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2294 ALCcontext *context;
2295 ALsource *source;
2296 ALsizei i;
2298 context = GetContextRef();
2299 if(!context) return;
2301 LockSourcesRead(context);
2302 if(!(n >= 0))
2303 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2304 for(i = 0;i < n;i++)
2306 if(!LookupSource(context, sources[i]))
2307 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2310 ALCdevice_Lock(context->Device);
2311 while(n > context->MaxVoices-context->VoiceCount)
2313 ALsizei newcount = context->MaxVoices << 1;
2314 if(context->MaxVoices >= newcount)
2316 ALCdevice_Unlock(context->Device);
2317 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2319 AllocateVoices(context, newcount, context->Device->NumAuxSends);
2322 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll)
2324 for(i = 0;i < n;i++)
2326 source = LookupSource(context, sources[i]);
2327 source->new_state = AL_PLAYING;
2330 else
2332 for(i = 0;i < n;i++)
2334 source = LookupSource(context, sources[i]);
2335 SetSourceState(source, context, AL_PLAYING);
2338 ALCdevice_Unlock(context->Device);
2340 done:
2341 UnlockSourcesRead(context);
2342 ALCcontext_DecRef(context);
2345 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2347 alSourcePausev(1, &source);
2349 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2351 ALCcontext *context;
2352 ALsource *source;
2353 ALsizei i;
2355 context = GetContextRef();
2356 if(!context) return;
2358 LockSourcesRead(context);
2359 if(!(n >= 0))
2360 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2361 for(i = 0;i < n;i++)
2363 if(!LookupSource(context, sources[i]))
2364 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2367 ALCdevice_Lock(context->Device);
2368 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
2370 for(i = 0;i < n;i++)
2372 source = LookupSource(context, sources[i]);
2373 source->new_state = AL_PAUSED;
2376 else
2378 for(i = 0;i < n;i++)
2380 source = LookupSource(context, sources[i]);
2381 SetSourceState(source, context, AL_PAUSED);
2384 ALCdevice_Unlock(context->Device);
2386 done:
2387 UnlockSourcesRead(context);
2388 ALCcontext_DecRef(context);
2391 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2393 alSourceStopv(1, &source);
2395 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2397 ALCcontext *context;
2398 ALsource *source;
2399 ALsizei i;
2401 context = GetContextRef();
2402 if(!context) return;
2404 LockSourcesRead(context);
2405 if(!(n >= 0))
2406 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2407 for(i = 0;i < n;i++)
2409 if(!LookupSource(context, sources[i]))
2410 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2413 ALCdevice_Lock(context->Device);
2414 for(i = 0;i < n;i++)
2416 source = LookupSource(context, sources[i]);
2417 source->new_state = AL_NONE;
2418 SetSourceState(source, context, AL_STOPPED);
2420 ALCdevice_Unlock(context->Device);
2422 done:
2423 UnlockSourcesRead(context);
2424 ALCcontext_DecRef(context);
2427 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2429 alSourceRewindv(1, &source);
2431 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2433 ALCcontext *context;
2434 ALsource *source;
2435 ALsizei i;
2437 context = GetContextRef();
2438 if(!context) return;
2440 LockSourcesRead(context);
2441 if(!(n >= 0))
2442 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2443 for(i = 0;i < n;i++)
2445 if(!LookupSource(context, sources[i]))
2446 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2449 ALCdevice_Lock(context->Device);
2450 for(i = 0;i < n;i++)
2452 source = LookupSource(context, sources[i]);
2453 source->new_state = AL_NONE;
2454 SetSourceState(source, context, AL_INITIAL);
2456 ALCdevice_Unlock(context->Device);
2458 done:
2459 UnlockSourcesRead(context);
2460 ALCcontext_DecRef(context);
2464 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2466 ALCdevice *device;
2467 ALCcontext *context;
2468 ALsource *source;
2469 ALsizei i;
2470 ALbufferlistitem *BufferListStart;
2471 ALbufferlistitem *BufferList;
2472 ALbuffer *BufferFmt = NULL;
2474 if(nb == 0)
2475 return;
2477 context = GetContextRef();
2478 if(!context) return;
2480 device = context->Device;
2482 LockSourcesRead(context);
2483 if(!(nb >= 0))
2484 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2485 if((source=LookupSource(context, src)) == NULL)
2486 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2488 WriteLock(&source->queue_lock);
2489 if(source->SourceType == AL_STATIC)
2491 WriteUnlock(&source->queue_lock);
2492 /* Can't queue on a Static Source */
2493 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2496 /* Check for a valid Buffer, for its frequency and format */
2497 BufferList = ATOMIC_LOAD_SEQ(&source->queue);
2498 while(BufferList)
2500 if(BufferList->buffer)
2502 BufferFmt = BufferList->buffer;
2503 break;
2505 BufferList = BufferList->next;
2508 LockBuffersRead(device);
2509 BufferListStart = NULL;
2510 BufferList = NULL;
2511 for(i = 0;i < nb;i++)
2513 ALbuffer *buffer = NULL;
2514 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2516 WriteUnlock(&source->queue_lock);
2517 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2520 if(!BufferListStart)
2522 BufferListStart = malloc(sizeof(ALbufferlistitem));
2523 BufferList = BufferListStart;
2525 else
2527 BufferList->next = malloc(sizeof(ALbufferlistitem));
2528 BufferList = BufferList->next;
2530 BufferList->buffer = buffer;
2531 BufferList->next = NULL;
2532 if(!buffer) continue;
2534 /* Hold a read lock on each buffer being queued while checking all
2535 * provided buffers. This is done so other threads don't see an extra
2536 * reference on some buffers if this operation ends up failing. */
2537 ReadLock(&buffer->lock);
2538 IncrementRef(&buffer->ref);
2540 if(BufferFmt == NULL)
2542 BufferFmt = buffer;
2544 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2545 source->SampleSize = BytesFromFmt(buffer->FmtType);
2547 else if(BufferFmt->Frequency != buffer->Frequency ||
2548 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2549 BufferFmt->OriginalType != buffer->OriginalType)
2551 WriteUnlock(&source->queue_lock);
2552 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2554 buffer_error:
2555 /* A buffer failed (invalid ID or format), so unlock and release
2556 * each buffer we had. */
2557 while(BufferListStart)
2559 ALbufferlistitem *next = BufferListStart->next;
2560 if((buffer=BufferListStart->buffer) != NULL)
2562 DecrementRef(&buffer->ref);
2563 ReadUnlock(&buffer->lock);
2565 free(BufferListStart);
2566 BufferListStart = next;
2568 UnlockBuffersRead(device);
2569 goto done;
2572 /* All buffers good, unlock them now. */
2573 BufferList = BufferListStart;
2574 while(BufferList != NULL)
2576 ALbuffer *buffer = BufferList->buffer;
2577 if(buffer) ReadUnlock(&buffer->lock);
2578 BufferList = BufferList->next;
2580 UnlockBuffersRead(device);
2582 /* Source is now streaming */
2583 source->SourceType = AL_STREAMING;
2585 BufferList = NULL;
2586 if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem*, &source->queue,
2587 &BufferList, BufferListStart))
2589 /* Queue head is not NULL, append to the end of the queue */
2590 while(BufferList->next != NULL)
2591 BufferList = BufferList->next;
2592 BufferList->next = BufferListStart;
2594 /* If the current buffer was at the end (NULL), put it at the start of the newly queued
2595 * buffers.
2597 BufferList = NULL;
2598 ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem*, &source->current_buffer,
2599 &BufferList, BufferListStart);
2600 WriteUnlock(&source->queue_lock);
2602 done:
2603 UnlockSourcesRead(context);
2604 ALCcontext_DecRef(context);
2607 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2609 ALCcontext *context;
2610 ALsource *source;
2611 ALbufferlistitem *OldHead;
2612 ALbufferlistitem *OldTail;
2613 ALbufferlistitem *Current;
2614 ALsizei i = 0;
2616 if(nb == 0)
2617 return;
2619 context = GetContextRef();
2620 if(!context) return;
2622 LockSourcesRead(context);
2623 if(!(nb >= 0))
2624 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2626 if((source=LookupSource(context, src)) == NULL)
2627 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2629 WriteLock(&source->queue_lock);
2630 if(ATOMIC_LOAD_SEQ(&source->looping) || source->SourceType != AL_STREAMING)
2632 WriteUnlock(&source->queue_lock);
2633 /* Trying to unqueue buffers on a looping or non-streaming source. */
2634 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2637 /* Find the new buffer queue head */
2638 OldTail = ATOMIC_LOAD_SEQ(&source->queue);
2639 Current = ATOMIC_LOAD_SEQ(&source->current_buffer);
2640 if(OldTail != Current)
2642 for(i = 1;i < nb;i++)
2644 ALbufferlistitem *next = OldTail->next;
2645 if(!next || next == Current) break;
2646 OldTail = next;
2649 if(i != nb)
2651 WriteUnlock(&source->queue_lock);
2652 /* Trying to unqueue pending buffers. */
2653 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2656 /* Swap it, and cut the new head from the old. */
2657 OldHead = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &source->queue, OldTail->next);
2658 if(OldTail->next)
2660 ALCdevice *device = context->Device;
2661 uint count;
2663 /* Once the active mix (if any) is done, it's safe to cut the old tail
2664 * from the new head.
2666 if(((count=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
2668 while(count == ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))
2669 althrd_yield();
2671 ATOMIC_THREAD_FENCE(almemory_order_acq_rel);
2672 OldTail->next = NULL;
2674 WriteUnlock(&source->queue_lock);
2676 while(OldHead != NULL)
2678 ALbufferlistitem *next = OldHead->next;
2679 ALbuffer *buffer = OldHead->buffer;
2681 if(!buffer)
2682 *(buffers++) = 0;
2683 else
2685 *(buffers++) = buffer->id;
2686 DecrementRef(&buffer->ref);
2689 free(OldHead);
2690 OldHead = next;
2693 done:
2694 UnlockSourcesRead(context);
2695 ALCcontext_DecRef(context);
2699 static void InitSourceParams(ALsource *Source, ALsizei num_sends)
2701 ALsizei i;
2703 RWLockInit(&Source->queue_lock);
2705 Source->InnerAngle = 360.0f;
2706 Source->OuterAngle = 360.0f;
2707 Source->Pitch = 1.0f;
2708 Source->Position[0] = 0.0f;
2709 Source->Position[1] = 0.0f;
2710 Source->Position[2] = 0.0f;
2711 Source->Velocity[0] = 0.0f;
2712 Source->Velocity[1] = 0.0f;
2713 Source->Velocity[2] = 0.0f;
2714 Source->Direction[0] = 0.0f;
2715 Source->Direction[1] = 0.0f;
2716 Source->Direction[2] = 0.0f;
2717 Source->Orientation[0][0] = 0.0f;
2718 Source->Orientation[0][1] = 0.0f;
2719 Source->Orientation[0][2] = -1.0f;
2720 Source->Orientation[1][0] = 0.0f;
2721 Source->Orientation[1][1] = 1.0f;
2722 Source->Orientation[1][2] = 0.0f;
2723 Source->RefDistance = 1.0f;
2724 Source->MaxDistance = FLT_MAX;
2725 Source->RollOffFactor = 1.0f;
2726 Source->Gain = 1.0f;
2727 Source->MinGain = 0.0f;
2728 Source->MaxGain = 1.0f;
2729 Source->OuterGain = 0.0f;
2730 Source->OuterGainHF = 1.0f;
2732 Source->DryGainHFAuto = AL_TRUE;
2733 Source->WetGainAuto = AL_TRUE;
2734 Source->WetGainHFAuto = AL_TRUE;
2735 Source->AirAbsorptionFactor = 0.0f;
2736 Source->RoomRolloffFactor = 0.0f;
2737 Source->DopplerFactor = 1.0f;
2738 Source->DirectChannels = AL_FALSE;
2740 Source->StereoPan[0] = DEG2RAD( 30.0f);
2741 Source->StereoPan[1] = DEG2RAD(-30.0f);
2743 Source->Radius = 0.0f;
2745 Source->DistanceModel = DefaultDistanceModel;
2747 Source->Direct.Gain = 1.0f;
2748 Source->Direct.GainHF = 1.0f;
2749 Source->Direct.HFReference = LOWPASSFREQREF;
2750 Source->Direct.GainLF = 1.0f;
2751 Source->Direct.LFReference = HIGHPASSFREQREF;
2752 Source->Send = al_calloc(16, num_sends*sizeof(Source->Send[0]));
2753 for(i = 0;i < num_sends;i++)
2755 Source->Send[i].Slot = NULL;
2756 Source->Send[i].Gain = 1.0f;
2757 Source->Send[i].GainHF = 1.0f;
2758 Source->Send[i].HFReference = LOWPASSFREQREF;
2759 Source->Send[i].GainLF = 1.0f;
2760 Source->Send[i].LFReference = HIGHPASSFREQREF;
2763 Source->Offset = 0.0;
2764 Source->OffsetType = AL_NONE;
2765 Source->SourceType = AL_UNDETERMINED;
2766 ATOMIC_INIT(&Source->state, AL_INITIAL);
2767 Source->new_state = AL_NONE;
2769 ATOMIC_INIT(&Source->queue, NULL);
2770 ATOMIC_INIT(&Source->current_buffer, NULL);
2772 ATOMIC_INIT(&Source->position, 0);
2773 ATOMIC_INIT(&Source->position_fraction, 0);
2775 ATOMIC_INIT(&Source->looping, AL_FALSE);
2777 Source->NeedsUpdate = AL_TRUE;
2779 ATOMIC_INIT(&Source->Update, NULL);
2780 ATOMIC_INIT(&Source->FreeList, NULL);
2783 static void DeinitSource(ALsource *source, ALsizei num_sends)
2785 ALbufferlistitem *BufferList;
2786 struct ALsourceProps *props;
2787 size_t count = 0;
2788 ALsizei i;
2790 props = ATOMIC_LOAD_SEQ(&source->Update);
2791 if(props) al_free(props);
2793 props = ATOMIC_LOAD(&source->FreeList, almemory_order_relaxed);
2794 while(props)
2796 struct ALsourceProps *next;
2797 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2798 al_free(props);
2799 props = next;
2800 ++count;
2802 /* This is excessively spammy if it traces every source destruction, so
2803 * just warn if it was unexpectedly large.
2805 if(count > 3)
2806 WARN("Freed "SZFMT" Source property objects\n", count);
2808 BufferList = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &source->queue, NULL);
2809 while(BufferList != NULL)
2811 ALbufferlistitem *next = BufferList->next;
2812 if(BufferList->buffer != NULL)
2813 DecrementRef(&BufferList->buffer->ref);
2814 free(BufferList);
2815 BufferList = next;
2818 if(source->Send)
2820 for(i = 0;i < num_sends;i++)
2822 if(source->Send[i].Slot)
2823 DecrementRef(&source->Send[i].Slot->ref);
2824 source->Send[i].Slot = NULL;
2826 al_free(source->Send);
2827 source->Send = NULL;
2831 static void UpdateSourceProps(ALsource *source, ALsizei num_sends)
2833 struct ALsourceProps *props;
2834 ALsizei i;
2836 /* Get an unused property container, or allocate a new one as needed. */
2837 props = ATOMIC_LOAD(&source->FreeList, almemory_order_acquire);
2838 if(!props)
2839 props = al_calloc(16, offsetof(struct ALsourceProps, Send[num_sends]));
2840 else
2842 struct ALsourceProps *next;
2843 do {
2844 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2845 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*,
2846 &source->FreeList, &props, next, almemory_order_acq_rel,
2847 almemory_order_acquire) == 0);
2850 /* Copy in current property values. */
2851 ATOMIC_STORE(&props->Pitch, source->Pitch, almemory_order_relaxed);
2852 ATOMIC_STORE(&props->Gain, source->Gain, almemory_order_relaxed);
2853 ATOMIC_STORE(&props->OuterGain, source->OuterGain, almemory_order_relaxed);
2854 ATOMIC_STORE(&props->MinGain, source->MinGain, almemory_order_relaxed);
2855 ATOMIC_STORE(&props->MaxGain, source->MaxGain, almemory_order_relaxed);
2856 ATOMIC_STORE(&props->InnerAngle, source->InnerAngle, almemory_order_relaxed);
2857 ATOMIC_STORE(&props->OuterAngle, source->OuterAngle, almemory_order_relaxed);
2858 ATOMIC_STORE(&props->RefDistance, source->RefDistance, almemory_order_relaxed);
2859 ATOMIC_STORE(&props->MaxDistance, source->MaxDistance, almemory_order_relaxed);
2860 ATOMIC_STORE(&props->RollOffFactor, source->RollOffFactor, almemory_order_relaxed);
2861 for(i = 0;i < 3;i++)
2862 ATOMIC_STORE(&props->Position[i], source->Position[i], almemory_order_relaxed);
2863 for(i = 0;i < 3;i++)
2864 ATOMIC_STORE(&props->Velocity[i], source->Velocity[i], almemory_order_relaxed);
2865 for(i = 0;i < 3;i++)
2866 ATOMIC_STORE(&props->Direction[i], source->Direction[i], almemory_order_relaxed);
2867 for(i = 0;i < 2;i++)
2869 ALsizei j;
2870 for(j = 0;j < 3;j++)
2871 ATOMIC_STORE(&props->Orientation[i][j], source->Orientation[i][j],
2872 almemory_order_relaxed);
2874 ATOMIC_STORE(&props->HeadRelative, source->HeadRelative, almemory_order_relaxed);
2875 ATOMIC_STORE(&props->DistanceModel, source->DistanceModel, almemory_order_relaxed);
2876 ATOMIC_STORE(&props->DirectChannels, source->DirectChannels, almemory_order_relaxed);
2878 ATOMIC_STORE(&props->DryGainHFAuto, source->DryGainHFAuto, almemory_order_relaxed);
2879 ATOMIC_STORE(&props->WetGainAuto, source->WetGainAuto, almemory_order_relaxed);
2880 ATOMIC_STORE(&props->WetGainHFAuto, source->WetGainHFAuto, almemory_order_relaxed);
2881 ATOMIC_STORE(&props->OuterGainHF, source->OuterGainHF, almemory_order_relaxed);
2883 ATOMIC_STORE(&props->AirAbsorptionFactor, source->AirAbsorptionFactor, almemory_order_relaxed);
2884 ATOMIC_STORE(&props->RoomRolloffFactor, source->RoomRolloffFactor, almemory_order_relaxed);
2885 ATOMIC_STORE(&props->DopplerFactor, source->DopplerFactor, almemory_order_relaxed);
2887 ATOMIC_STORE(&props->StereoPan[0], source->StereoPan[0], almemory_order_relaxed);
2888 ATOMIC_STORE(&props->StereoPan[1], source->StereoPan[1], almemory_order_relaxed);
2890 ATOMIC_STORE(&props->Radius, source->Radius, almemory_order_relaxed);
2892 ATOMIC_STORE(&props->Direct.Gain, source->Direct.Gain, almemory_order_relaxed);
2893 ATOMIC_STORE(&props->Direct.GainHF, source->Direct.GainHF, almemory_order_relaxed);
2894 ATOMIC_STORE(&props->Direct.HFReference, source->Direct.HFReference, almemory_order_relaxed);
2895 ATOMIC_STORE(&props->Direct.GainLF, source->Direct.GainLF, almemory_order_relaxed);
2896 ATOMIC_STORE(&props->Direct.LFReference, source->Direct.LFReference, almemory_order_relaxed);
2898 for(i = 0;i < num_sends;i++)
2900 ATOMIC_STORE(&props->Send[i].Slot, source->Send[i].Slot, almemory_order_relaxed);
2901 ATOMIC_STORE(&props->Send[i].Gain, source->Send[i].Gain, almemory_order_relaxed);
2902 ATOMIC_STORE(&props->Send[i].GainHF, source->Send[i].GainHF, almemory_order_relaxed);
2903 ATOMIC_STORE(&props->Send[i].HFReference, source->Send[i].HFReference,
2904 almemory_order_relaxed);
2905 ATOMIC_STORE(&props->Send[i].GainLF, source->Send[i].GainLF, almemory_order_relaxed);
2906 ATOMIC_STORE(&props->Send[i].LFReference, source->Send[i].LFReference,
2907 almemory_order_relaxed);
2910 /* Set the new container for updating internal parameters. */
2911 props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, props, almemory_order_acq_rel);
2912 if(props)
2914 /* If there was an unused update container, put it back in the
2915 * freelist.
2917 ATOMIC_REPLACE_HEAD(struct ALsourceProps*, &source->FreeList, props);
2921 void UpdateAllSourceProps(ALCcontext *context)
2923 ALsizei num_sends = context->Device->NumAuxSends;
2924 ALsizei pos;
2926 for(pos = 0;pos < context->VoiceCount;pos++)
2928 ALvoice *voice = context->Voices[pos];
2929 ALsource *source = voice->Source;
2930 if(source != NULL && source->NeedsUpdate && IsPlayingOrPaused(source))
2932 source->NeedsUpdate = AL_FALSE;
2933 UpdateSourceProps(source, num_sends);
2939 /* SetSourceState
2941 * Sets the source's new play state given its current state.
2943 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2945 WriteLock(&Source->queue_lock);
2946 if(state == AL_PLAYING)
2948 ALCdevice *device = Context->Device;
2949 ALbufferlistitem *BufferList;
2950 ALboolean discontinuity;
2951 ALvoice *voice = NULL;
2952 ALsizei i;
2954 /* Check that there is a queue containing at least one valid, non zero
2955 * length Buffer. */
2956 BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
2957 while(BufferList)
2959 ALbuffer *buffer;
2960 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2961 break;
2962 BufferList = BufferList->next;
2965 if(ATOMIC_EXCHANGE(ALenum, &Source->state, AL_PLAYING, almemory_order_acq_rel) == AL_PAUSED)
2966 discontinuity = AL_FALSE;
2967 else
2969 ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed);
2970 ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed);
2971 ATOMIC_STORE(&Source->position_fraction, 0, almemory_order_release);
2972 discontinuity = AL_TRUE;
2975 // Check if an Offset has been set
2976 if(Source->OffsetType != AL_NONE)
2978 ApplyOffset(Source);
2979 /* discontinuity = AL_TRUE;??? */
2982 /* If there's nothing to play, or device is disconnected, go right to
2983 * stopped */
2984 if(!BufferList || !device->Connected)
2985 goto do_stop;
2987 /* Make sure this source isn't already active, and if not, look for an
2988 * unused voice to put it in.
2990 voice = GetSourceVoice(Source, Context);
2991 if(voice == NULL)
2993 for(i = 0;i < Context->VoiceCount;i++)
2995 if(Context->Voices[i]->Source == NULL)
2997 voice = Context->Voices[i];
2998 voice->Source = Source;
2999 break;
3002 if(voice == NULL)
3004 voice = Context->Voices[Context->VoiceCount++];
3005 voice->Source = Source;
3007 discontinuity = AL_TRUE;
3010 if(discontinuity)
3012 /* Clear previous samples if playback is discontinuous. */
3013 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
3015 /* Clear the stepping value so the mixer knows not to mix this
3016 * until the update gets applied.
3018 voice->Step = 0;
3021 voice->Moving = AL_FALSE;
3022 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
3024 ALsizei j;
3025 for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
3026 voice->Direct.Params[i].Hrtf.State.History[j] = 0.0f;
3027 for(j = 0;j < HRIR_LENGTH;j++)
3029 voice->Direct.Params[i].Hrtf.State.Values[j][0] = 0.0f;
3030 voice->Direct.Params[i].Hrtf.State.Values[j][1] = 0.0f;
3034 Source->NeedsUpdate = AL_FALSE;
3035 UpdateSourceProps(Source, device->NumAuxSends);
3037 else if(state == AL_PAUSED)
3039 ALenum playing = AL_PLAYING;
3040 ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum, &Source->state, &playing, AL_PAUSED);
3042 else if(state == AL_STOPPED)
3044 do_stop:
3045 if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL)
3047 ATOMIC_STORE(&Source->state, AL_STOPPED, almemory_order_relaxed);
3048 ATOMIC_STORE_SEQ(&Source->current_buffer, NULL);
3050 Source->OffsetType = AL_NONE;
3051 Source->Offset = 0.0;
3053 else if(state == AL_INITIAL)
3055 if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL)
3057 ATOMIC_STORE(&Source->state, AL_INITIAL, almemory_order_relaxed);
3058 ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD_SEQ(&Source->queue),
3059 almemory_order_relaxed);
3060 ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed);
3061 ATOMIC_STORE_SEQ(&Source->position_fraction, 0);
3063 Source->OffsetType = AL_NONE;
3064 Source->Offset = 0.0;
3066 WriteUnlock(&Source->queue_lock);
3069 /* GetSourceSampleOffset
3071 * Gets the current read offset for the given Source, in 32.32 fixed-point
3072 * samples. The offset is relative to the start of the queue (not the start of
3073 * the current buffer).
3075 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime)
3077 const ALbufferlistitem *BufferList;
3078 const ALbufferlistitem *Current;
3079 ALuint64 readPos;
3080 ALuint refcount;
3082 ReadLock(&Source->queue_lock);
3083 if(!IsPlayingOrPaused(Source))
3085 ReadUnlock(&Source->queue_lock);
3086 do {
3087 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3088 althrd_yield();
3089 *clocktime = GetDeviceClockTime(device);
3090 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3091 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3092 return 0;
3095 do {
3096 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3097 althrd_yield();
3098 *clocktime = GetDeviceClockTime(device);
3100 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3101 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3103 readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << 32;
3104 readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed) <<
3105 (32-FRACTIONBITS);
3106 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3107 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3108 while(BufferList && BufferList != Current)
3110 if(BufferList->buffer)
3111 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
3112 BufferList = BufferList->next;
3115 ReadUnlock(&Source->queue_lock);
3116 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
3119 /* GetSourceSecOffset
3121 * Gets the current read offset for the given Source, in seconds. The offset is
3122 * relative to the start of the queue (not the start of the current buffer).
3124 static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime)
3126 const ALbufferlistitem *BufferList;
3127 const ALbufferlistitem *Current;
3128 const ALbuffer *Buffer = NULL;
3129 ALuint64 readPos;
3130 ALuint refcount;
3132 ReadLock(&Source->queue_lock);
3133 if(!IsPlayingOrPaused(Source))
3135 ReadUnlock(&Source->queue_lock);
3136 do {
3137 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3138 althrd_yield();
3139 *clocktime = GetDeviceClockTime(device);
3140 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3141 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3142 return 0.0;
3145 do {
3146 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3147 althrd_yield();
3148 *clocktime = GetDeviceClockTime(device);
3150 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3151 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3153 readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed)<<FRACTIONBITS;
3154 readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed);
3155 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3156 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3157 while(BufferList && BufferList != Current)
3159 const ALbuffer *buffer = BufferList->buffer;
3160 if(buffer != NULL)
3162 if(!Buffer) Buffer = buffer;
3163 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
3165 BufferList = BufferList->next;
3168 while(BufferList && !Buffer)
3170 Buffer = BufferList->buffer;
3171 BufferList = BufferList->next;
3173 assert(Buffer != NULL);
3175 ReadUnlock(&Source->queue_lock);
3176 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
3179 /* GetSourceOffset
3181 * Gets the current read offset for the given Source, in the appropriate format
3182 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3183 * queue (not the start of the current buffer).
3185 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device)
3187 const ALbufferlistitem *BufferList;
3188 const ALbufferlistitem *Current;
3189 const ALbuffer *Buffer = NULL;
3190 ALboolean readFin = AL_FALSE;
3191 ALuint readPos, readPosFrac;
3192 ALuint totalBufferLen;
3193 ALdouble offset = 0.0;
3194 ALboolean looping;
3195 ALuint refcount;
3197 ReadLock(&Source->queue_lock);
3198 if(!IsPlayingOrPaused(Source))
3200 ReadUnlock(&Source->queue_lock);
3201 return 0.0;
3204 totalBufferLen = 0;
3205 do {
3206 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3207 althrd_yield();
3208 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3209 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3211 readPos = ATOMIC_LOAD(&Source->position, almemory_order_relaxed);
3212 readPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed);
3214 looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed);
3215 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3216 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3218 while(BufferList != NULL)
3220 const ALbuffer *buffer;
3221 readFin = readFin || (BufferList == Current);
3222 if((buffer=BufferList->buffer) != NULL)
3224 if(!Buffer) Buffer = buffer;
3225 totalBufferLen += buffer->SampleLen;
3226 if(!readFin) readPos += buffer->SampleLen;
3228 BufferList = BufferList->next;
3230 assert(Buffer != NULL);
3232 if(looping)
3233 readPos %= totalBufferLen;
3234 else
3236 /* Wrap back to 0 */
3237 if(readPos >= totalBufferLen)
3238 readPos = readPosFrac = 0;
3241 switch(name)
3243 case AL_SEC_OFFSET:
3244 offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
3245 break;
3247 case AL_SAMPLE_OFFSET:
3248 offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
3249 break;
3251 case AL_BYTE_OFFSET:
3252 if(Buffer->OriginalType == UserFmtIMA4)
3254 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3255 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3256 ALuint FrameBlockSize = Buffer->OriginalAlign;
3258 /* Round down to nearest ADPCM block */
3259 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3261 else if(Buffer->OriginalType == UserFmtMSADPCM)
3263 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3264 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3265 ALuint FrameBlockSize = Buffer->OriginalAlign;
3267 /* Round down to nearest ADPCM block */
3268 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3270 else
3272 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3273 offset = (ALdouble)(readPos * FrameSize);
3275 break;
3278 ReadUnlock(&Source->queue_lock);
3279 return offset;
3283 /* ApplyOffset
3285 * Apply the stored playback offset to the Source. This function will update
3286 * the number of buffers "played" given the stored offset.
3288 ALboolean ApplyOffset(ALsource *Source)
3290 ALbufferlistitem *BufferList;
3291 const ALbuffer *Buffer;
3292 ALuint bufferLen, totalBufferLen;
3293 ALuint offset=0, frac=0;
3295 /* Get sample frame offset */
3296 if(!GetSampleOffset(Source, &offset, &frac))
3297 return AL_FALSE;
3299 totalBufferLen = 0;
3300 BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
3301 while(BufferList && totalBufferLen <= offset)
3303 Buffer = BufferList->buffer;
3304 bufferLen = Buffer ? Buffer->SampleLen : 0;
3306 if(bufferLen > offset-totalBufferLen)
3308 /* Offset is in this buffer */
3309 ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed);
3311 ATOMIC_STORE(&Source->position, offset - totalBufferLen, almemory_order_relaxed);
3312 ATOMIC_STORE(&Source->position_fraction, frac, almemory_order_release);
3313 return AL_TRUE;
3316 totalBufferLen += bufferLen;
3318 BufferList = BufferList->next;
3321 /* Offset is out of range of the queue */
3322 return AL_FALSE;
3326 /* GetSampleOffset
3328 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3329 * or Second offset supplied by the application). This takes into account the
3330 * fact that the buffer format may have been modifed since.
3332 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
3334 const ALbuffer *Buffer = NULL;
3335 const ALbufferlistitem *BufferList;
3336 ALdouble dbloff, dblfrac;
3338 /* Find the first valid Buffer in the Queue */
3339 BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
3340 while(BufferList)
3342 if(BufferList->buffer)
3344 Buffer = BufferList->buffer;
3345 break;
3347 BufferList = BufferList->next;
3349 if(!Buffer)
3351 Source->OffsetType = AL_NONE;
3352 Source->Offset = 0.0;
3353 return AL_FALSE;
3356 switch(Source->OffsetType)
3358 case AL_BYTE_OFFSET:
3359 /* Determine the ByteOffset (and ensure it is block aligned) */
3360 *offset = (ALuint)Source->Offset;
3361 if(Buffer->OriginalType == UserFmtIMA4)
3363 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3364 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3365 *offset *= Buffer->OriginalAlign;
3367 else if(Buffer->OriginalType == UserFmtMSADPCM)
3369 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3370 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3371 *offset *= Buffer->OriginalAlign;
3373 else
3374 *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3375 *frac = 0;
3376 break;
3378 case AL_SAMPLE_OFFSET:
3379 dblfrac = modf(Source->Offset, &dbloff);
3380 *offset = (ALuint)mind(dbloff, UINT_MAX);
3381 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3382 break;
3384 case AL_SEC_OFFSET:
3385 dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
3386 *offset = (ALuint)mind(dbloff, UINT_MAX);
3387 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3388 break;
3390 Source->OffsetType = AL_NONE;
3391 Source->Offset = 0.0;
3393 return AL_TRUE;
3397 /* ReleaseALSources
3399 * Destroys all sources in the source map.
3401 ALvoid ReleaseALSources(ALCcontext *Context)
3403 ALCdevice *device = Context->Device;
3404 ALsizei pos;
3405 for(pos = 0;pos < Context->SourceMap.size;pos++)
3407 ALsource *temp = Context->SourceMap.values[pos];
3408 Context->SourceMap.values[pos] = NULL;
3410 DeinitSource(temp, device->NumAuxSends);
3412 FreeThunkEntry(temp->id);
3413 memset(temp, 0, sizeof(*temp));
3414 al_free(temp);