Add some comments for ALsource functions
[openal-soft.git] / OpenAL32 / alSource.c
bloba882cb83d1c04ebd61817389b71f7d9d6d0990e3
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <math.h>
26 #include <float.h>
28 #include "AL/al.h"
29 #include "AL/alc.h"
30 #include "alMain.h"
31 #include "alError.h"
32 #include "alSource.h"
33 #include "alBuffer.h"
34 #include "alThunk.h"
35 #include "alAuxEffectSlot.h"
37 #include "backends/base.h"
39 #include "threads.h"
40 #include "almalloc.h"
43 extern inline void LockSourcesRead(ALCcontext *context);
44 extern inline void UnlockSourcesRead(ALCcontext *context);
45 extern inline void LockSourcesWrite(ALCcontext *context);
46 extern inline void UnlockSourcesWrite(ALCcontext *context);
47 extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
48 extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
50 static void InitSourceParams(ALsource *Source, ALsizei num_sends);
51 static void DeinitSource(ALsource *source, ALsizei num_sends);
52 static void UpdateSourceProps(ALsource *source, ALsizei num_sends);
53 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime);
54 static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime);
55 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context);
56 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac);
57 static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice);
59 typedef enum SourceProp {
60 srcPitch = AL_PITCH,
61 srcGain = AL_GAIN,
62 srcMinGain = AL_MIN_GAIN,
63 srcMaxGain = AL_MAX_GAIN,
64 srcMaxDistance = AL_MAX_DISTANCE,
65 srcRolloffFactor = AL_ROLLOFF_FACTOR,
66 srcDopplerFactor = AL_DOPPLER_FACTOR,
67 srcConeOuterGain = AL_CONE_OUTER_GAIN,
68 srcSecOffset = AL_SEC_OFFSET,
69 srcSampleOffset = AL_SAMPLE_OFFSET,
70 srcByteOffset = AL_BYTE_OFFSET,
71 srcConeInnerAngle = AL_CONE_INNER_ANGLE,
72 srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
73 srcRefDistance = AL_REFERENCE_DISTANCE,
75 srcPosition = AL_POSITION,
76 srcVelocity = AL_VELOCITY,
77 srcDirection = AL_DIRECTION,
79 srcSourceRelative = AL_SOURCE_RELATIVE,
80 srcLooping = AL_LOOPING,
81 srcBuffer = AL_BUFFER,
82 srcSourceState = AL_SOURCE_STATE,
83 srcBuffersQueued = AL_BUFFERS_QUEUED,
84 srcBuffersProcessed = AL_BUFFERS_PROCESSED,
85 srcSourceType = AL_SOURCE_TYPE,
87 /* ALC_EXT_EFX */
88 srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
89 srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
90 srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
91 srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
92 srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
93 srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
94 srcDirectFilter = AL_DIRECT_FILTER,
95 srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
97 /* AL_SOFT_direct_channels */
98 srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
100 /* AL_EXT_source_distance_model */
101 srcDistanceModel = AL_DISTANCE_MODEL,
103 srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
104 srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
105 srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
107 /* AL_SOFT_source_latency */
108 srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
109 srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
111 /* AL_EXT_STEREO_ANGLES */
112 srcAngles = AL_STEREO_ANGLES,
114 /* AL_EXT_SOURCE_RADIUS */
115 srcRadius = AL_SOURCE_RADIUS,
117 /* AL_EXT_BFORMAT */
118 srcOrientation = AL_ORIENTATION,
119 } SourceProp;
121 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
122 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
123 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
125 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
126 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
127 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
129 static inline ALvoice *GetSourceVoice(const ALsource *source, const ALCcontext *context)
131 ALvoice **voice = context->Voices;
132 ALvoice **voice_end = voice + context->VoiceCount;
133 while(voice != voice_end)
135 if(ATOMIC_LOAD(&(*voice)->Source, almemory_order_acquire) == source)
136 return *voice;
137 ++voice;
139 return NULL;
143 * Returns if the last known state for the source was playing or paused. Does
144 * not sync with the mixer voice.
146 static inline bool IsPlayingOrPaused(ALsource *source)
148 ALenum state = ATOMIC_LOAD(&source->state, almemory_order_acquire);
149 return state == AL_PLAYING || state == AL_PAUSED;
153 * Returns an updated source state using the matching voice's status (or lack
154 * thereof).
156 static inline ALenum GetSourceState(ALsource *source, ALvoice *voice)
158 if(!voice)
160 ALenum state = AL_PLAYING;
161 if(ATOMIC_COMPARE_EXCHANGE_STRONG(ALenum, &source->state, &state, AL_STOPPED,
162 almemory_order_acq_rel, almemory_order_acquire))
163 return AL_STOPPED;
164 return state;
166 return ATOMIC_LOAD(&source->state, almemory_order_acquire);
170 * Returns if the source should specify an update, given the context's
171 * deferring state and the source's last known state.
173 static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context)
175 return !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) &&
176 IsPlayingOrPaused(source);
179 static ALint FloatValsByProp(ALenum prop)
181 if(prop != (ALenum)((SourceProp)prop))
182 return 0;
183 switch((SourceProp)prop)
185 case AL_PITCH:
186 case AL_GAIN:
187 case AL_MIN_GAIN:
188 case AL_MAX_GAIN:
189 case AL_MAX_DISTANCE:
190 case AL_ROLLOFF_FACTOR:
191 case AL_DOPPLER_FACTOR:
192 case AL_CONE_OUTER_GAIN:
193 case AL_SEC_OFFSET:
194 case AL_SAMPLE_OFFSET:
195 case AL_BYTE_OFFSET:
196 case AL_CONE_INNER_ANGLE:
197 case AL_CONE_OUTER_ANGLE:
198 case AL_REFERENCE_DISTANCE:
199 case AL_CONE_OUTER_GAINHF:
200 case AL_AIR_ABSORPTION_FACTOR:
201 case AL_ROOM_ROLLOFF_FACTOR:
202 case AL_DIRECT_FILTER_GAINHF_AUTO:
203 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
204 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
205 case AL_DIRECT_CHANNELS_SOFT:
206 case AL_DISTANCE_MODEL:
207 case AL_SOURCE_RELATIVE:
208 case AL_LOOPING:
209 case AL_SOURCE_STATE:
210 case AL_BUFFERS_QUEUED:
211 case AL_BUFFERS_PROCESSED:
212 case AL_SOURCE_TYPE:
213 case AL_BYTE_LENGTH_SOFT:
214 case AL_SAMPLE_LENGTH_SOFT:
215 case AL_SEC_LENGTH_SOFT:
216 case AL_SOURCE_RADIUS:
217 return 1;
219 case AL_STEREO_ANGLES:
220 return 2;
222 case AL_POSITION:
223 case AL_VELOCITY:
224 case AL_DIRECTION:
225 return 3;
227 case AL_ORIENTATION:
228 return 6;
230 case AL_SEC_OFFSET_LATENCY_SOFT:
231 break; /* Double only */
233 case AL_BUFFER:
234 case AL_DIRECT_FILTER:
235 case AL_AUXILIARY_SEND_FILTER:
236 break; /* i/i64 only */
237 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
238 break; /* i64 only */
240 return 0;
242 static ALint DoubleValsByProp(ALenum prop)
244 if(prop != (ALenum)((SourceProp)prop))
245 return 0;
246 switch((SourceProp)prop)
248 case AL_PITCH:
249 case AL_GAIN:
250 case AL_MIN_GAIN:
251 case AL_MAX_GAIN:
252 case AL_MAX_DISTANCE:
253 case AL_ROLLOFF_FACTOR:
254 case AL_DOPPLER_FACTOR:
255 case AL_CONE_OUTER_GAIN:
256 case AL_SEC_OFFSET:
257 case AL_SAMPLE_OFFSET:
258 case AL_BYTE_OFFSET:
259 case AL_CONE_INNER_ANGLE:
260 case AL_CONE_OUTER_ANGLE:
261 case AL_REFERENCE_DISTANCE:
262 case AL_CONE_OUTER_GAINHF:
263 case AL_AIR_ABSORPTION_FACTOR:
264 case AL_ROOM_ROLLOFF_FACTOR:
265 case AL_DIRECT_FILTER_GAINHF_AUTO:
266 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
267 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
268 case AL_DIRECT_CHANNELS_SOFT:
269 case AL_DISTANCE_MODEL:
270 case AL_SOURCE_RELATIVE:
271 case AL_LOOPING:
272 case AL_SOURCE_STATE:
273 case AL_BUFFERS_QUEUED:
274 case AL_BUFFERS_PROCESSED:
275 case AL_SOURCE_TYPE:
276 case AL_BYTE_LENGTH_SOFT:
277 case AL_SAMPLE_LENGTH_SOFT:
278 case AL_SEC_LENGTH_SOFT:
279 case AL_SOURCE_RADIUS:
280 return 1;
282 case AL_SEC_OFFSET_LATENCY_SOFT:
283 case AL_STEREO_ANGLES:
284 return 2;
286 case AL_POSITION:
287 case AL_VELOCITY:
288 case AL_DIRECTION:
289 return 3;
291 case AL_ORIENTATION:
292 return 6;
294 case AL_BUFFER:
295 case AL_DIRECT_FILTER:
296 case AL_AUXILIARY_SEND_FILTER:
297 break; /* i/i64 only */
298 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
299 break; /* i64 only */
301 return 0;
304 static ALint IntValsByProp(ALenum prop)
306 if(prop != (ALenum)((SourceProp)prop))
307 return 0;
308 switch((SourceProp)prop)
310 case AL_PITCH:
311 case AL_GAIN:
312 case AL_MIN_GAIN:
313 case AL_MAX_GAIN:
314 case AL_MAX_DISTANCE:
315 case AL_ROLLOFF_FACTOR:
316 case AL_DOPPLER_FACTOR:
317 case AL_CONE_OUTER_GAIN:
318 case AL_SEC_OFFSET:
319 case AL_SAMPLE_OFFSET:
320 case AL_BYTE_OFFSET:
321 case AL_CONE_INNER_ANGLE:
322 case AL_CONE_OUTER_ANGLE:
323 case AL_REFERENCE_DISTANCE:
324 case AL_CONE_OUTER_GAINHF:
325 case AL_AIR_ABSORPTION_FACTOR:
326 case AL_ROOM_ROLLOFF_FACTOR:
327 case AL_DIRECT_FILTER_GAINHF_AUTO:
328 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
329 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
330 case AL_DIRECT_CHANNELS_SOFT:
331 case AL_DISTANCE_MODEL:
332 case AL_SOURCE_RELATIVE:
333 case AL_LOOPING:
334 case AL_BUFFER:
335 case AL_SOURCE_STATE:
336 case AL_BUFFERS_QUEUED:
337 case AL_BUFFERS_PROCESSED:
338 case AL_SOURCE_TYPE:
339 case AL_DIRECT_FILTER:
340 case AL_BYTE_LENGTH_SOFT:
341 case AL_SAMPLE_LENGTH_SOFT:
342 case AL_SEC_LENGTH_SOFT:
343 case AL_SOURCE_RADIUS:
344 return 1;
346 case AL_POSITION:
347 case AL_VELOCITY:
348 case AL_DIRECTION:
349 case AL_AUXILIARY_SEND_FILTER:
350 return 3;
352 case AL_ORIENTATION:
353 return 6;
355 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
356 break; /* i64 only */
357 case AL_SEC_OFFSET_LATENCY_SOFT:
358 break; /* Double only */
359 case AL_STEREO_ANGLES:
360 break; /* Float/double only */
362 return 0;
364 static ALint Int64ValsByProp(ALenum prop)
366 if(prop != (ALenum)((SourceProp)prop))
367 return 0;
368 switch((SourceProp)prop)
370 case AL_PITCH:
371 case AL_GAIN:
372 case AL_MIN_GAIN:
373 case AL_MAX_GAIN:
374 case AL_MAX_DISTANCE:
375 case AL_ROLLOFF_FACTOR:
376 case AL_DOPPLER_FACTOR:
377 case AL_CONE_OUTER_GAIN:
378 case AL_SEC_OFFSET:
379 case AL_SAMPLE_OFFSET:
380 case AL_BYTE_OFFSET:
381 case AL_CONE_INNER_ANGLE:
382 case AL_CONE_OUTER_ANGLE:
383 case AL_REFERENCE_DISTANCE:
384 case AL_CONE_OUTER_GAINHF:
385 case AL_AIR_ABSORPTION_FACTOR:
386 case AL_ROOM_ROLLOFF_FACTOR:
387 case AL_DIRECT_FILTER_GAINHF_AUTO:
388 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
389 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
390 case AL_DIRECT_CHANNELS_SOFT:
391 case AL_DISTANCE_MODEL:
392 case AL_SOURCE_RELATIVE:
393 case AL_LOOPING:
394 case AL_BUFFER:
395 case AL_SOURCE_STATE:
396 case AL_BUFFERS_QUEUED:
397 case AL_BUFFERS_PROCESSED:
398 case AL_SOURCE_TYPE:
399 case AL_DIRECT_FILTER:
400 case AL_BYTE_LENGTH_SOFT:
401 case AL_SAMPLE_LENGTH_SOFT:
402 case AL_SEC_LENGTH_SOFT:
403 case AL_SOURCE_RADIUS:
404 return 1;
406 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
407 return 2;
409 case AL_POSITION:
410 case AL_VELOCITY:
411 case AL_DIRECTION:
412 case AL_AUXILIARY_SEND_FILTER:
413 return 3;
415 case AL_ORIENTATION:
416 return 6;
418 case AL_SEC_OFFSET_LATENCY_SOFT:
419 break; /* Double only */
420 case AL_STEREO_ANGLES:
421 break; /* Float/double only */
423 return 0;
427 #define CHECKVAL(x) do { \
428 if(!(x)) \
429 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
430 } while(0)
432 #define DO_UPDATEPROPS() do { \
433 if(SourceShouldUpdate(Source, Context)) \
434 UpdateSourceProps(Source, device->NumAuxSends); \
435 else \
436 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \
437 } while(0)
439 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
441 ALCdevice *device = Context->Device;
442 ALint ival;
444 switch(prop)
446 case AL_BYTE_LENGTH_SOFT:
447 case AL_SAMPLE_LENGTH_SOFT:
448 case AL_SEC_LENGTH_SOFT:
449 case AL_SEC_OFFSET_LATENCY_SOFT:
450 /* Query only */
451 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
453 case AL_PITCH:
454 CHECKVAL(*values >= 0.0f);
456 Source->Pitch = *values;
457 DO_UPDATEPROPS();
458 return AL_TRUE;
460 case AL_CONE_INNER_ANGLE:
461 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
463 Source->InnerAngle = *values;
464 DO_UPDATEPROPS();
465 return AL_TRUE;
467 case AL_CONE_OUTER_ANGLE:
468 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
470 Source->OuterAngle = *values;
471 DO_UPDATEPROPS();
472 return AL_TRUE;
474 case AL_GAIN:
475 CHECKVAL(*values >= 0.0f);
477 Source->Gain = *values;
478 DO_UPDATEPROPS();
479 return AL_TRUE;
481 case AL_MAX_DISTANCE:
482 CHECKVAL(*values >= 0.0f);
484 Source->MaxDistance = *values;
485 DO_UPDATEPROPS();
486 return AL_TRUE;
488 case AL_ROLLOFF_FACTOR:
489 CHECKVAL(*values >= 0.0f);
491 Source->RollOffFactor = *values;
492 DO_UPDATEPROPS();
493 return AL_TRUE;
495 case AL_REFERENCE_DISTANCE:
496 CHECKVAL(*values >= 0.0f);
498 Source->RefDistance = *values;
499 DO_UPDATEPROPS();
500 return AL_TRUE;
502 case AL_MIN_GAIN:
503 CHECKVAL(*values >= 0.0f);
505 Source->MinGain = *values;
506 DO_UPDATEPROPS();
507 return AL_TRUE;
509 case AL_MAX_GAIN:
510 CHECKVAL(*values >= 0.0f);
512 Source->MaxGain = *values;
513 DO_UPDATEPROPS();
514 return AL_TRUE;
516 case AL_CONE_OUTER_GAIN:
517 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
519 Source->OuterGain = *values;
520 DO_UPDATEPROPS();
521 return AL_TRUE;
523 case AL_CONE_OUTER_GAINHF:
524 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
526 Source->OuterGainHF = *values;
527 DO_UPDATEPROPS();
528 return AL_TRUE;
530 case AL_AIR_ABSORPTION_FACTOR:
531 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
533 Source->AirAbsorptionFactor = *values;
534 DO_UPDATEPROPS();
535 return AL_TRUE;
537 case AL_ROOM_ROLLOFF_FACTOR:
538 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
540 Source->RoomRolloffFactor = *values;
541 DO_UPDATEPROPS();
542 return AL_TRUE;
544 case AL_DOPPLER_FACTOR:
545 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
547 Source->DopplerFactor = *values;
548 DO_UPDATEPROPS();
549 return AL_TRUE;
551 case AL_SEC_OFFSET:
552 case AL_SAMPLE_OFFSET:
553 case AL_BYTE_OFFSET:
554 CHECKVAL(*values >= 0.0f);
556 Source->OffsetType = prop;
557 Source->Offset = *values;
559 if(IsPlayingOrPaused(Source))
561 ALvoice *voice;
563 ALCdevice_Lock(Context->Device);
564 /* Double-check that the source is still playing while we have
565 * the lock.
567 voice = GetSourceVoice(Source, Context);
568 if(voice)
570 WriteLock(&Source->queue_lock);
571 if(ApplyOffset(Source, voice) == AL_FALSE)
573 WriteUnlock(&Source->queue_lock);
574 ALCdevice_Unlock(Context->Device);
575 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
577 WriteUnlock(&Source->queue_lock);
579 ALCdevice_Unlock(Context->Device);
581 return AL_TRUE;
583 case AL_SOURCE_RADIUS:
584 CHECKVAL(*values >= 0.0f && isfinite(*values));
586 Source->Radius = *values;
587 DO_UPDATEPROPS();
588 return AL_TRUE;
590 case AL_STEREO_ANGLES:
591 CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
593 Source->StereoPan[0] = values[0];
594 Source->StereoPan[1] = values[1];
595 DO_UPDATEPROPS();
596 return AL_TRUE;
599 case AL_POSITION:
600 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
602 Source->Position[0] = values[0];
603 Source->Position[1] = values[1];
604 Source->Position[2] = values[2];
605 DO_UPDATEPROPS();
606 return AL_TRUE;
608 case AL_VELOCITY:
609 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
611 Source->Velocity[0] = values[0];
612 Source->Velocity[1] = values[1];
613 Source->Velocity[2] = values[2];
614 DO_UPDATEPROPS();
615 return AL_TRUE;
617 case AL_DIRECTION:
618 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
620 Source->Direction[0] = values[0];
621 Source->Direction[1] = values[1];
622 Source->Direction[2] = values[2];
623 DO_UPDATEPROPS();
624 return AL_TRUE;
626 case AL_ORIENTATION:
627 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
628 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
630 Source->Orientation[0][0] = values[0];
631 Source->Orientation[0][1] = values[1];
632 Source->Orientation[0][2] = values[2];
633 Source->Orientation[1][0] = values[3];
634 Source->Orientation[1][1] = values[4];
635 Source->Orientation[1][2] = values[5];
636 DO_UPDATEPROPS();
637 return AL_TRUE;
640 case AL_SOURCE_RELATIVE:
641 case AL_LOOPING:
642 case AL_SOURCE_STATE:
643 case AL_SOURCE_TYPE:
644 case AL_DISTANCE_MODEL:
645 case AL_DIRECT_FILTER_GAINHF_AUTO:
646 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
647 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
648 case AL_DIRECT_CHANNELS_SOFT:
649 ival = (ALint)values[0];
650 return SetSourceiv(Source, Context, prop, &ival);
652 case AL_BUFFERS_QUEUED:
653 case AL_BUFFERS_PROCESSED:
654 ival = (ALint)((ALuint)values[0]);
655 return SetSourceiv(Source, Context, prop, &ival);
657 case AL_BUFFER:
658 case AL_DIRECT_FILTER:
659 case AL_AUXILIARY_SEND_FILTER:
660 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
661 break;
664 ERR("Unexpected property: 0x%04x\n", prop);
665 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
668 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
670 ALCdevice *device = Context->Device;
671 ALbuffer *buffer = NULL;
672 ALfilter *filter = NULL;
673 ALeffectslot *slot = NULL;
674 ALbufferlistitem *oldlist;
675 ALbufferlistitem *newlist;
676 ALfloat fvals[6];
678 switch(prop)
680 case AL_SOURCE_STATE:
681 case AL_SOURCE_TYPE:
682 case AL_BUFFERS_QUEUED:
683 case AL_BUFFERS_PROCESSED:
684 case AL_BYTE_LENGTH_SOFT:
685 case AL_SAMPLE_LENGTH_SOFT:
686 case AL_SEC_LENGTH_SOFT:
687 /* Query only */
688 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
690 case AL_SOURCE_RELATIVE:
691 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
693 Source->HeadRelative = (ALboolean)*values;
694 DO_UPDATEPROPS();
695 return AL_TRUE;
697 case AL_LOOPING:
698 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
700 WriteLock(&Source->queue_lock);
701 ATOMIC_STORE_SEQ(&Source->looping, *values);
702 WriteUnlock(&Source->queue_lock);
703 return AL_TRUE;
705 case AL_BUFFER:
706 LockBuffersRead(device);
707 if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
709 UnlockBuffersRead(device);
710 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
713 WriteLock(&Source->queue_lock);
715 ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context));
716 if(state == AL_PLAYING || state == AL_PAUSED)
718 WriteUnlock(&Source->queue_lock);
719 UnlockBuffersRead(device);
720 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
724 if(buffer != NULL)
726 /* Add the selected buffer to a one-item queue */
727 newlist = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
728 newlist->buffer = buffer;
729 newlist->next = NULL;
730 IncrementRef(&buffer->ref);
732 /* Source is now Static */
733 Source->SourceType = AL_STATIC;
735 else
737 /* Source is now Undetermined */
738 Source->SourceType = AL_UNDETERMINED;
739 newlist = NULL;
741 oldlist = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &Source->queue, newlist);
742 WriteUnlock(&Source->queue_lock);
743 UnlockBuffersRead(device);
745 /* Delete all elements in the previous queue */
746 while(oldlist != NULL)
748 ALbufferlistitem *temp = oldlist;
749 oldlist = temp->next;
751 if(temp->buffer)
752 DecrementRef(&temp->buffer->ref);
753 al_free(temp);
755 return AL_TRUE;
757 case AL_SEC_OFFSET:
758 case AL_SAMPLE_OFFSET:
759 case AL_BYTE_OFFSET:
760 CHECKVAL(*values >= 0);
762 Source->OffsetType = prop;
763 Source->Offset = *values;
765 if(IsPlayingOrPaused(Source))
767 ALvoice *voice;
769 ALCdevice_Lock(Context->Device);
770 voice = GetSourceVoice(Source, Context);
771 if(voice)
773 WriteLock(&Source->queue_lock);
774 if(ApplyOffset(Source, voice) == AL_FALSE)
776 WriteUnlock(&Source->queue_lock);
777 ALCdevice_Unlock(Context->Device);
778 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
780 WriteUnlock(&Source->queue_lock);
782 ALCdevice_Unlock(Context->Device);
784 return AL_TRUE;
786 case AL_DIRECT_FILTER:
787 LockFiltersRead(device);
788 if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
790 UnlockFiltersRead(device);
791 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
794 if(!filter)
796 Source->Direct.Gain = 1.0f;
797 Source->Direct.GainHF = 1.0f;
798 Source->Direct.HFReference = LOWPASSFREQREF;
799 Source->Direct.GainLF = 1.0f;
800 Source->Direct.LFReference = HIGHPASSFREQREF;
802 else
804 Source->Direct.Gain = filter->Gain;
805 Source->Direct.GainHF = filter->GainHF;
806 Source->Direct.HFReference = filter->HFReference;
807 Source->Direct.GainLF = filter->GainLF;
808 Source->Direct.LFReference = filter->LFReference;
810 UnlockFiltersRead(device);
811 DO_UPDATEPROPS();
812 return AL_TRUE;
814 case AL_DIRECT_FILTER_GAINHF_AUTO:
815 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
817 Source->DryGainHFAuto = *values;
818 DO_UPDATEPROPS();
819 return AL_TRUE;
821 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
822 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
824 Source->WetGainAuto = *values;
825 DO_UPDATEPROPS();
826 return AL_TRUE;
828 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
829 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
831 Source->WetGainHFAuto = *values;
832 DO_UPDATEPROPS();
833 return AL_TRUE;
835 case AL_DIRECT_CHANNELS_SOFT:
836 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
838 Source->DirectChannels = *values;
839 DO_UPDATEPROPS();
840 return AL_TRUE;
842 case AL_DISTANCE_MODEL:
843 CHECKVAL(*values == AL_NONE ||
844 *values == AL_INVERSE_DISTANCE ||
845 *values == AL_INVERSE_DISTANCE_CLAMPED ||
846 *values == AL_LINEAR_DISTANCE ||
847 *values == AL_LINEAR_DISTANCE_CLAMPED ||
848 *values == AL_EXPONENT_DISTANCE ||
849 *values == AL_EXPONENT_DISTANCE_CLAMPED);
851 Source->DistanceModel = *values;
852 if(Context->SourceDistanceModel)
853 DO_UPDATEPROPS();
854 return AL_TRUE;
857 case AL_AUXILIARY_SEND_FILTER:
858 LockEffectSlotsRead(Context);
859 LockFiltersRead(device);
860 if(!((ALuint)values[1] < (ALuint)device->NumAuxSends &&
861 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
862 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
864 UnlockFiltersRead(device);
865 UnlockEffectSlotsRead(Context);
866 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
869 if(!filter)
871 /* Disable filter */
872 Source->Send[values[1]].Gain = 1.0f;
873 Source->Send[values[1]].GainHF = 1.0f;
874 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
875 Source->Send[values[1]].GainLF = 1.0f;
876 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
878 else
880 Source->Send[values[1]].Gain = filter->Gain;
881 Source->Send[values[1]].GainHF = filter->GainHF;
882 Source->Send[values[1]].HFReference = filter->HFReference;
883 Source->Send[values[1]].GainLF = filter->GainLF;
884 Source->Send[values[1]].LFReference = filter->LFReference;
886 UnlockFiltersRead(device);
888 if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source))
890 /* Add refcount on the new slot, and release the previous slot */
891 if(slot) IncrementRef(&slot->ref);
892 if(Source->Send[values[1]].Slot)
893 DecrementRef(&Source->Send[values[1]].Slot->ref);
894 Source->Send[values[1]].Slot = slot;
896 /* We must force an update if the auxiliary slot changed on a
897 * playing source, in case the slot is about to be deleted.
899 UpdateSourceProps(Source, device->NumAuxSends);
901 else
903 if(slot) IncrementRef(&slot->ref);
904 if(Source->Send[values[1]].Slot)
905 DecrementRef(&Source->Send[values[1]].Slot->ref);
906 Source->Send[values[1]].Slot = slot;
907 DO_UPDATEPROPS();
909 UnlockEffectSlotsRead(Context);
911 return AL_TRUE;
914 /* 1x float */
915 case AL_CONE_INNER_ANGLE:
916 case AL_CONE_OUTER_ANGLE:
917 case AL_PITCH:
918 case AL_GAIN:
919 case AL_MIN_GAIN:
920 case AL_MAX_GAIN:
921 case AL_REFERENCE_DISTANCE:
922 case AL_ROLLOFF_FACTOR:
923 case AL_CONE_OUTER_GAIN:
924 case AL_MAX_DISTANCE:
925 case AL_DOPPLER_FACTOR:
926 case AL_CONE_OUTER_GAINHF:
927 case AL_AIR_ABSORPTION_FACTOR:
928 case AL_ROOM_ROLLOFF_FACTOR:
929 case AL_SOURCE_RADIUS:
930 fvals[0] = (ALfloat)*values;
931 return SetSourcefv(Source, Context, (int)prop, fvals);
933 /* 3x float */
934 case AL_POSITION:
935 case AL_VELOCITY:
936 case AL_DIRECTION:
937 fvals[0] = (ALfloat)values[0];
938 fvals[1] = (ALfloat)values[1];
939 fvals[2] = (ALfloat)values[2];
940 return SetSourcefv(Source, Context, (int)prop, fvals);
942 /* 6x float */
943 case AL_ORIENTATION:
944 fvals[0] = (ALfloat)values[0];
945 fvals[1] = (ALfloat)values[1];
946 fvals[2] = (ALfloat)values[2];
947 fvals[3] = (ALfloat)values[3];
948 fvals[4] = (ALfloat)values[4];
949 fvals[5] = (ALfloat)values[5];
950 return SetSourcefv(Source, Context, (int)prop, fvals);
952 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
953 case AL_SEC_OFFSET_LATENCY_SOFT:
954 case AL_STEREO_ANGLES:
955 break;
958 ERR("Unexpected property: 0x%04x\n", prop);
959 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
962 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
964 ALfloat fvals[6];
965 ALint ivals[3];
967 switch(prop)
969 case AL_SOURCE_TYPE:
970 case AL_BUFFERS_QUEUED:
971 case AL_BUFFERS_PROCESSED:
972 case AL_SOURCE_STATE:
973 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
974 case AL_BYTE_LENGTH_SOFT:
975 case AL_SAMPLE_LENGTH_SOFT:
976 case AL_SEC_LENGTH_SOFT:
977 /* Query only */
978 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
981 /* 1x int */
982 case AL_SOURCE_RELATIVE:
983 case AL_LOOPING:
984 case AL_SEC_OFFSET:
985 case AL_SAMPLE_OFFSET:
986 case AL_BYTE_OFFSET:
987 case AL_DIRECT_FILTER_GAINHF_AUTO:
988 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
989 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
990 case AL_DIRECT_CHANNELS_SOFT:
991 case AL_DISTANCE_MODEL:
992 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
994 ivals[0] = (ALint)*values;
995 return SetSourceiv(Source, Context, (int)prop, ivals);
997 /* 1x uint */
998 case AL_BUFFER:
999 case AL_DIRECT_FILTER:
1000 CHECKVAL(*values <= UINT_MAX && *values >= 0);
1002 ivals[0] = (ALuint)*values;
1003 return SetSourceiv(Source, Context, (int)prop, ivals);
1005 /* 3x uint */
1006 case AL_AUXILIARY_SEND_FILTER:
1007 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
1008 values[1] <= UINT_MAX && values[1] >= 0 &&
1009 values[2] <= UINT_MAX && values[2] >= 0);
1011 ivals[0] = (ALuint)values[0];
1012 ivals[1] = (ALuint)values[1];
1013 ivals[2] = (ALuint)values[2];
1014 return SetSourceiv(Source, Context, (int)prop, ivals);
1016 /* 1x float */
1017 case AL_CONE_INNER_ANGLE:
1018 case AL_CONE_OUTER_ANGLE:
1019 case AL_PITCH:
1020 case AL_GAIN:
1021 case AL_MIN_GAIN:
1022 case AL_MAX_GAIN:
1023 case AL_REFERENCE_DISTANCE:
1024 case AL_ROLLOFF_FACTOR:
1025 case AL_CONE_OUTER_GAIN:
1026 case AL_MAX_DISTANCE:
1027 case AL_DOPPLER_FACTOR:
1028 case AL_CONE_OUTER_GAINHF:
1029 case AL_AIR_ABSORPTION_FACTOR:
1030 case AL_ROOM_ROLLOFF_FACTOR:
1031 case AL_SOURCE_RADIUS:
1032 fvals[0] = (ALfloat)*values;
1033 return SetSourcefv(Source, Context, (int)prop, fvals);
1035 /* 3x float */
1036 case AL_POSITION:
1037 case AL_VELOCITY:
1038 case AL_DIRECTION:
1039 fvals[0] = (ALfloat)values[0];
1040 fvals[1] = (ALfloat)values[1];
1041 fvals[2] = (ALfloat)values[2];
1042 return SetSourcefv(Source, Context, (int)prop, fvals);
1044 /* 6x float */
1045 case AL_ORIENTATION:
1046 fvals[0] = (ALfloat)values[0];
1047 fvals[1] = (ALfloat)values[1];
1048 fvals[2] = (ALfloat)values[2];
1049 fvals[3] = (ALfloat)values[3];
1050 fvals[4] = (ALfloat)values[4];
1051 fvals[5] = (ALfloat)values[5];
1052 return SetSourcefv(Source, Context, (int)prop, fvals);
1054 case AL_SEC_OFFSET_LATENCY_SOFT:
1055 case AL_STEREO_ANGLES:
1056 break;
1059 ERR("Unexpected property: 0x%04x\n", prop);
1060 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1063 #undef CHECKVAL
1066 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
1068 ALCdevice *device = Context->Device;
1069 ALbufferlistitem *BufferList;
1070 ClockLatency clocktime;
1071 ALuint64 srcclock;
1072 ALint ivals[3];
1073 ALboolean err;
1075 switch(prop)
1077 case AL_GAIN:
1078 *values = Source->Gain;
1079 return AL_TRUE;
1081 case AL_PITCH:
1082 *values = Source->Pitch;
1083 return AL_TRUE;
1085 case AL_MAX_DISTANCE:
1086 *values = Source->MaxDistance;
1087 return AL_TRUE;
1089 case AL_ROLLOFF_FACTOR:
1090 *values = Source->RollOffFactor;
1091 return AL_TRUE;
1093 case AL_REFERENCE_DISTANCE:
1094 *values = Source->RefDistance;
1095 return AL_TRUE;
1097 case AL_CONE_INNER_ANGLE:
1098 *values = Source->InnerAngle;
1099 return AL_TRUE;
1101 case AL_CONE_OUTER_ANGLE:
1102 *values = Source->OuterAngle;
1103 return AL_TRUE;
1105 case AL_MIN_GAIN:
1106 *values = Source->MinGain;
1107 return AL_TRUE;
1109 case AL_MAX_GAIN:
1110 *values = Source->MaxGain;
1111 return AL_TRUE;
1113 case AL_CONE_OUTER_GAIN:
1114 *values = Source->OuterGain;
1115 return AL_TRUE;
1117 case AL_SEC_OFFSET:
1118 case AL_SAMPLE_OFFSET:
1119 case AL_BYTE_OFFSET:
1120 *values = GetSourceOffset(Source, prop, Context);
1121 return AL_TRUE;
1123 case AL_CONE_OUTER_GAINHF:
1124 *values = Source->OuterGainHF;
1125 return AL_TRUE;
1127 case AL_AIR_ABSORPTION_FACTOR:
1128 *values = Source->AirAbsorptionFactor;
1129 return AL_TRUE;
1131 case AL_ROOM_ROLLOFF_FACTOR:
1132 *values = Source->RoomRolloffFactor;
1133 return AL_TRUE;
1135 case AL_DOPPLER_FACTOR:
1136 *values = Source->DopplerFactor;
1137 return AL_TRUE;
1139 case AL_SEC_LENGTH_SOFT:
1140 ReadLock(&Source->queue_lock);
1141 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1142 *values = 0;
1143 else
1145 ALint length = 0;
1146 ALsizei freq = 1;
1147 do {
1148 ALbuffer *buffer = BufferList->buffer;
1149 if(buffer && buffer->SampleLen > 0)
1151 freq = buffer->Frequency;
1152 length += buffer->SampleLen;
1154 } while((BufferList=BufferList->next) != NULL);
1155 *values = (ALdouble)length / (ALdouble)freq;
1157 ReadUnlock(&Source->queue_lock);
1158 return AL_TRUE;
1160 case AL_SOURCE_RADIUS:
1161 *values = Source->Radius;
1162 return AL_TRUE;
1164 case AL_STEREO_ANGLES:
1165 values[0] = Source->StereoPan[0];
1166 values[1] = Source->StereoPan[1];
1167 return AL_TRUE;
1169 case AL_SEC_OFFSET_LATENCY_SOFT:
1170 /* Get the source offset with the clock time first. Then get the
1171 * clock time with the device latency. Order is important.
1173 values[0] = GetSourceSecOffset(Source, Context, &srcclock);
1174 clocktime = V0(device->Backend,getClockLatency)();
1175 if(srcclock == (ALuint64)clocktime.ClockTime)
1176 values[1] = (ALdouble)clocktime.Latency / 1000000000.0;
1177 else
1179 /* If the clock time incremented, reduce the latency by that
1180 * much since it's that much closer to the source offset it got
1181 * earlier.
1183 ALuint64 diff = clocktime.ClockTime - srcclock;
1184 values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) /
1185 1000000000.0;
1187 return AL_TRUE;
1189 case AL_POSITION:
1190 values[0] = Source->Position[0];
1191 values[1] = Source->Position[1];
1192 values[2] = Source->Position[2];
1193 return AL_TRUE;
1195 case AL_VELOCITY:
1196 values[0] = Source->Velocity[0];
1197 values[1] = Source->Velocity[1];
1198 values[2] = Source->Velocity[2];
1199 return AL_TRUE;
1201 case AL_DIRECTION:
1202 values[0] = Source->Direction[0];
1203 values[1] = Source->Direction[1];
1204 values[2] = Source->Direction[2];
1205 return AL_TRUE;
1207 case AL_ORIENTATION:
1208 values[0] = Source->Orientation[0][0];
1209 values[1] = Source->Orientation[0][1];
1210 values[2] = Source->Orientation[0][2];
1211 values[3] = Source->Orientation[1][0];
1212 values[4] = Source->Orientation[1][1];
1213 values[5] = Source->Orientation[1][2];
1214 return AL_TRUE;
1216 /* 1x int */
1217 case AL_SOURCE_RELATIVE:
1218 case AL_LOOPING:
1219 case AL_SOURCE_STATE:
1220 case AL_BUFFERS_QUEUED:
1221 case AL_BUFFERS_PROCESSED:
1222 case AL_SOURCE_TYPE:
1223 case AL_DIRECT_FILTER_GAINHF_AUTO:
1224 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1225 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1226 case AL_DIRECT_CHANNELS_SOFT:
1227 case AL_BYTE_LENGTH_SOFT:
1228 case AL_SAMPLE_LENGTH_SOFT:
1229 case AL_DISTANCE_MODEL:
1230 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1231 *values = (ALdouble)ivals[0];
1232 return err;
1234 case AL_BUFFER:
1235 case AL_DIRECT_FILTER:
1236 case AL_AUXILIARY_SEND_FILTER:
1237 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1238 break;
1241 ERR("Unexpected property: 0x%04x\n", prop);
1242 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1245 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1247 ALbufferlistitem *BufferList;
1248 ALdouble dvals[6];
1249 ALboolean err;
1251 switch(prop)
1253 case AL_SOURCE_RELATIVE:
1254 *values = Source->HeadRelative;
1255 return AL_TRUE;
1257 case AL_LOOPING:
1258 *values = ATOMIC_LOAD_SEQ(&Source->looping);
1259 return AL_TRUE;
1261 case AL_BUFFER:
1262 ReadLock(&Source->queue_lock);
1263 BufferList = (Source->SourceType == AL_STATIC) ?
1264 ATOMIC_LOAD_SEQ(&Source->queue) : NULL;
1265 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1266 ReadUnlock(&Source->queue_lock);
1267 return AL_TRUE;
1269 case AL_SOURCE_STATE:
1270 *values = GetSourceState(Source, GetSourceVoice(Source, Context));
1271 return AL_TRUE;
1273 case AL_BYTE_LENGTH_SOFT:
1274 ReadLock(&Source->queue_lock);
1275 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1276 *values = 0;
1277 else
1279 ALint length = 0;
1280 do {
1281 ALbuffer *buffer = BufferList->buffer;
1282 if(buffer && buffer->SampleLen > 0)
1284 ALuint byte_align, sample_align;
1285 if(buffer->OriginalType == UserFmtIMA4)
1287 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1288 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1289 sample_align = buffer->OriginalAlign;
1291 else if(buffer->OriginalType == UserFmtMSADPCM)
1293 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1294 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1295 sample_align = buffer->OriginalAlign;
1297 else
1299 ALsizei align = buffer->OriginalAlign;
1300 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1301 sample_align = buffer->OriginalAlign;
1304 length += buffer->SampleLen / sample_align * byte_align;
1306 } while((BufferList=BufferList->next) != NULL);
1307 *values = length;
1309 ReadUnlock(&Source->queue_lock);
1310 return AL_TRUE;
1312 case AL_SAMPLE_LENGTH_SOFT:
1313 ReadLock(&Source->queue_lock);
1314 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1315 *values = 0;
1316 else
1318 ALint length = 0;
1319 do {
1320 ALbuffer *buffer = BufferList->buffer;
1321 if(buffer) length += buffer->SampleLen;
1322 } while((BufferList=BufferList->next) != NULL);
1323 *values = length;
1325 ReadUnlock(&Source->queue_lock);
1326 return AL_TRUE;
1328 case AL_BUFFERS_QUEUED:
1329 ReadLock(&Source->queue_lock);
1330 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1331 *values = 0;
1332 else
1334 ALsizei count = 0;
1335 do {
1336 ++count;
1337 } while((BufferList=BufferList->next) != NULL);
1338 *values = count;
1340 ReadUnlock(&Source->queue_lock);
1341 return AL_TRUE;
1343 case AL_BUFFERS_PROCESSED:
1344 ReadLock(&Source->queue_lock);
1345 if(ATOMIC_LOAD_SEQ(&Source->looping) || Source->SourceType != AL_STREAMING)
1347 /* Buffers on a looping source are in a perpetual state of
1348 * PENDING, so don't report any as PROCESSED */
1349 *values = 0;
1351 else
1353 const ALbufferlistitem *BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
1354 const ALbufferlistitem *Current = NULL;
1355 ALsizei played = 0;
1356 ALvoice *voice;
1358 if((voice=GetSourceVoice(Source, Context)) != NULL)
1359 Current = ATOMIC_LOAD_SEQ(&voice->current_buffer);
1360 else if(ATOMIC_LOAD_SEQ(&Source->state) == AL_INITIAL)
1361 Current = BufferList;
1363 while(BufferList && BufferList != Current)
1365 played++;
1366 BufferList = BufferList->next;
1368 *values = played;
1370 ReadUnlock(&Source->queue_lock);
1371 return AL_TRUE;
1373 case AL_SOURCE_TYPE:
1374 *values = Source->SourceType;
1375 return AL_TRUE;
1377 case AL_DIRECT_FILTER_GAINHF_AUTO:
1378 *values = Source->DryGainHFAuto;
1379 return AL_TRUE;
1381 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1382 *values = Source->WetGainAuto;
1383 return AL_TRUE;
1385 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1386 *values = Source->WetGainHFAuto;
1387 return AL_TRUE;
1389 case AL_DIRECT_CHANNELS_SOFT:
1390 *values = Source->DirectChannels;
1391 return AL_TRUE;
1393 case AL_DISTANCE_MODEL:
1394 *values = Source->DistanceModel;
1395 return AL_TRUE;
1397 /* 1x float/double */
1398 case AL_CONE_INNER_ANGLE:
1399 case AL_CONE_OUTER_ANGLE:
1400 case AL_PITCH:
1401 case AL_GAIN:
1402 case AL_MIN_GAIN:
1403 case AL_MAX_GAIN:
1404 case AL_REFERENCE_DISTANCE:
1405 case AL_ROLLOFF_FACTOR:
1406 case AL_CONE_OUTER_GAIN:
1407 case AL_MAX_DISTANCE:
1408 case AL_SEC_OFFSET:
1409 case AL_SAMPLE_OFFSET:
1410 case AL_BYTE_OFFSET:
1411 case AL_DOPPLER_FACTOR:
1412 case AL_AIR_ABSORPTION_FACTOR:
1413 case AL_ROOM_ROLLOFF_FACTOR:
1414 case AL_CONE_OUTER_GAINHF:
1415 case AL_SEC_LENGTH_SOFT:
1416 case AL_SOURCE_RADIUS:
1417 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1418 *values = (ALint)dvals[0];
1419 return err;
1421 /* 3x float/double */
1422 case AL_POSITION:
1423 case AL_VELOCITY:
1424 case AL_DIRECTION:
1425 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1427 values[0] = (ALint)dvals[0];
1428 values[1] = (ALint)dvals[1];
1429 values[2] = (ALint)dvals[2];
1431 return err;
1433 /* 6x float/double */
1434 case AL_ORIENTATION:
1435 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1437 values[0] = (ALint)dvals[0];
1438 values[1] = (ALint)dvals[1];
1439 values[2] = (ALint)dvals[2];
1440 values[3] = (ALint)dvals[3];
1441 values[4] = (ALint)dvals[4];
1442 values[5] = (ALint)dvals[5];
1444 return err;
1446 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1447 break; /* i64 only */
1448 case AL_SEC_OFFSET_LATENCY_SOFT:
1449 break; /* Double only */
1450 case AL_STEREO_ANGLES:
1451 break; /* Float/double only */
1453 case AL_DIRECT_FILTER:
1454 case AL_AUXILIARY_SEND_FILTER:
1455 break; /* ??? */
1458 ERR("Unexpected property: 0x%04x\n", prop);
1459 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1462 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1464 ALCdevice *device = Context->Device;
1465 ClockLatency clocktime;
1466 ALuint64 srcclock;
1467 ALdouble dvals[6];
1468 ALint ivals[3];
1469 ALboolean err;
1471 switch(prop)
1473 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1474 /* Get the source offset with the clock time first. Then get the
1475 * clock time with the device latency. Order is important.
1477 values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
1478 clocktime = V0(device->Backend,getClockLatency)();
1479 if(srcclock == (ALuint64)clocktime.ClockTime)
1480 values[1] = clocktime.Latency;
1481 else
1483 /* If the clock time incremented, reduce the latency by that
1484 * much since it's that much closer to the source offset it got
1485 * earlier.
1487 ALuint64 diff = clocktime.ClockTime - srcclock;
1488 values[1] = clocktime.Latency - minu64(clocktime.Latency, diff);
1490 return AL_TRUE;
1492 /* 1x float/double */
1493 case AL_CONE_INNER_ANGLE:
1494 case AL_CONE_OUTER_ANGLE:
1495 case AL_PITCH:
1496 case AL_GAIN:
1497 case AL_MIN_GAIN:
1498 case AL_MAX_GAIN:
1499 case AL_REFERENCE_DISTANCE:
1500 case AL_ROLLOFF_FACTOR:
1501 case AL_CONE_OUTER_GAIN:
1502 case AL_MAX_DISTANCE:
1503 case AL_SEC_OFFSET:
1504 case AL_SAMPLE_OFFSET:
1505 case AL_BYTE_OFFSET:
1506 case AL_DOPPLER_FACTOR:
1507 case AL_AIR_ABSORPTION_FACTOR:
1508 case AL_ROOM_ROLLOFF_FACTOR:
1509 case AL_CONE_OUTER_GAINHF:
1510 case AL_SEC_LENGTH_SOFT:
1511 case AL_SOURCE_RADIUS:
1512 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1513 *values = (ALint64)dvals[0];
1514 return err;
1516 /* 3x float/double */
1517 case AL_POSITION:
1518 case AL_VELOCITY:
1519 case AL_DIRECTION:
1520 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1522 values[0] = (ALint64)dvals[0];
1523 values[1] = (ALint64)dvals[1];
1524 values[2] = (ALint64)dvals[2];
1526 return err;
1528 /* 6x float/double */
1529 case AL_ORIENTATION:
1530 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1532 values[0] = (ALint64)dvals[0];
1533 values[1] = (ALint64)dvals[1];
1534 values[2] = (ALint64)dvals[2];
1535 values[3] = (ALint64)dvals[3];
1536 values[4] = (ALint64)dvals[4];
1537 values[5] = (ALint64)dvals[5];
1539 return err;
1541 /* 1x int */
1542 case AL_SOURCE_RELATIVE:
1543 case AL_LOOPING:
1544 case AL_SOURCE_STATE:
1545 case AL_BUFFERS_QUEUED:
1546 case AL_BUFFERS_PROCESSED:
1547 case AL_BYTE_LENGTH_SOFT:
1548 case AL_SAMPLE_LENGTH_SOFT:
1549 case AL_SOURCE_TYPE:
1550 case AL_DIRECT_FILTER_GAINHF_AUTO:
1551 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1552 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1553 case AL_DIRECT_CHANNELS_SOFT:
1554 case AL_DISTANCE_MODEL:
1555 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1556 *values = ivals[0];
1557 return err;
1559 /* 1x uint */
1560 case AL_BUFFER:
1561 case AL_DIRECT_FILTER:
1562 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1563 *values = (ALuint)ivals[0];
1564 return err;
1566 /* 3x uint */
1567 case AL_AUXILIARY_SEND_FILTER:
1568 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1570 values[0] = (ALuint)ivals[0];
1571 values[1] = (ALuint)ivals[1];
1572 values[2] = (ALuint)ivals[2];
1574 return err;
1576 case AL_SEC_OFFSET_LATENCY_SOFT:
1577 break; /* Double only */
1578 case AL_STEREO_ANGLES:
1579 break; /* Float/double only */
1582 ERR("Unexpected property: 0x%04x\n", prop);
1583 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1587 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1589 ALCdevice *device;
1590 ALCcontext *context;
1591 ALsizei cur = 0;
1592 ALenum err;
1594 context = GetContextRef();
1595 if(!context) return;
1597 if(!(n >= 0))
1598 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1599 device = context->Device;
1600 for(cur = 0;cur < n;cur++)
1602 ALsource *source = al_calloc(16, sizeof(ALsource));
1603 if(!source)
1605 alDeleteSources(cur, sources);
1606 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1608 InitSourceParams(source, device->NumAuxSends);
1610 err = NewThunkEntry(&source->id);
1611 if(err == AL_NO_ERROR)
1612 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1613 if(err != AL_NO_ERROR)
1615 FreeThunkEntry(source->id);
1616 memset(source, 0, sizeof(ALsource));
1617 al_free(source);
1619 alDeleteSources(cur, sources);
1620 SET_ERROR_AND_GOTO(context, err, done);
1623 sources[cur] = source->id;
1626 done:
1627 ALCcontext_DecRef(context);
1631 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1633 ALCdevice *device;
1634 ALCcontext *context;
1635 ALsource *Source;
1636 ALsizei i;
1638 context = GetContextRef();
1639 if(!context) return;
1641 LockSourcesWrite(context);
1642 if(!(n >= 0))
1643 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1645 /* Check that all Sources are valid */
1646 for(i = 0;i < n;i++)
1648 if(LookupSource(context, sources[i]) == NULL)
1649 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1651 device = context->Device;
1652 for(i = 0;i < n;i++)
1654 ALvoice *voice;
1656 if((Source=RemoveSource(context, sources[i])) == NULL)
1657 continue;
1658 FreeThunkEntry(Source->id);
1660 ALCdevice_Lock(device);
1661 if((voice=GetSourceVoice(Source, context)) != NULL)
1663 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
1664 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
1666 ALCdevice_Unlock(device);
1668 DeinitSource(Source, device->NumAuxSends);
1670 memset(Source, 0, sizeof(*Source));
1671 al_free(Source);
1674 done:
1675 UnlockSourcesWrite(context);
1676 ALCcontext_DecRef(context);
1680 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1682 ALCcontext *context;
1683 ALboolean ret;
1685 context = GetContextRef();
1686 if(!context) return AL_FALSE;
1688 LockSourcesRead(context);
1689 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1690 UnlockSourcesRead(context);
1692 ALCcontext_DecRef(context);
1694 return ret;
1698 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1700 ALCcontext *Context;
1701 ALsource *Source;
1703 Context = GetContextRef();
1704 if(!Context) return;
1706 WriteLock(&Context->PropLock);
1707 LockSourcesRead(Context);
1708 if((Source=LookupSource(Context, source)) == NULL)
1709 alSetError(Context, AL_INVALID_NAME);
1710 else if(!(FloatValsByProp(param) == 1))
1711 alSetError(Context, AL_INVALID_ENUM);
1712 else
1713 SetSourcefv(Source, Context, param, &value);
1714 UnlockSourcesRead(Context);
1715 WriteUnlock(&Context->PropLock);
1717 ALCcontext_DecRef(Context);
1720 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
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(!(FloatValsByProp(param) == 3))
1733 alSetError(Context, AL_INVALID_ENUM);
1734 else
1736 ALfloat fvals[3] = { value1, value2, value3 };
1737 SetSourcefv(Source, Context, param, fvals);
1739 UnlockSourcesRead(Context);
1740 WriteUnlock(&Context->PropLock);
1742 ALCcontext_DecRef(Context);
1745 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
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(!values)
1758 alSetError(Context, AL_INVALID_VALUE);
1759 else if(!(FloatValsByProp(param) > 0))
1760 alSetError(Context, AL_INVALID_ENUM);
1761 else
1762 SetSourcefv(Source, Context, param, values);
1763 UnlockSourcesRead(Context);
1764 WriteUnlock(&Context->PropLock);
1766 ALCcontext_DecRef(Context);
1770 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1772 ALCcontext *Context;
1773 ALsource *Source;
1775 Context = GetContextRef();
1776 if(!Context) return;
1778 WriteLock(&Context->PropLock);
1779 LockSourcesRead(Context);
1780 if((Source=LookupSource(Context, source)) == NULL)
1781 alSetError(Context, AL_INVALID_NAME);
1782 else if(!(DoubleValsByProp(param) == 1))
1783 alSetError(Context, AL_INVALID_ENUM);
1784 else
1786 ALfloat fval = (ALfloat)value;
1787 SetSourcefv(Source, Context, param, &fval);
1789 UnlockSourcesRead(Context);
1790 WriteUnlock(&Context->PropLock);
1792 ALCcontext_DecRef(Context);
1795 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1797 ALCcontext *Context;
1798 ALsource *Source;
1800 Context = GetContextRef();
1801 if(!Context) return;
1803 WriteLock(&Context->PropLock);
1804 LockSourcesRead(Context);
1805 if((Source=LookupSource(Context, source)) == NULL)
1806 alSetError(Context, AL_INVALID_NAME);
1807 else if(!(DoubleValsByProp(param) == 3))
1808 alSetError(Context, AL_INVALID_ENUM);
1809 else
1811 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1812 SetSourcefv(Source, Context, param, fvals);
1814 UnlockSourcesRead(Context);
1815 WriteUnlock(&Context->PropLock);
1817 ALCcontext_DecRef(Context);
1820 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1822 ALCcontext *Context;
1823 ALsource *Source;
1824 ALint count;
1826 Context = GetContextRef();
1827 if(!Context) return;
1829 WriteLock(&Context->PropLock);
1830 LockSourcesRead(Context);
1831 if((Source=LookupSource(Context, source)) == NULL)
1832 alSetError(Context, AL_INVALID_NAME);
1833 else if(!values)
1834 alSetError(Context, AL_INVALID_VALUE);
1835 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1836 alSetError(Context, AL_INVALID_ENUM);
1837 else
1839 ALfloat fvals[6];
1840 ALint i;
1842 for(i = 0;i < count;i++)
1843 fvals[i] = (ALfloat)values[i];
1844 SetSourcefv(Source, Context, param, fvals);
1846 UnlockSourcesRead(Context);
1847 WriteUnlock(&Context->PropLock);
1849 ALCcontext_DecRef(Context);
1853 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1855 ALCcontext *Context;
1856 ALsource *Source;
1858 Context = GetContextRef();
1859 if(!Context) return;
1861 WriteLock(&Context->PropLock);
1862 LockSourcesRead(Context);
1863 if((Source=LookupSource(Context, source)) == NULL)
1864 alSetError(Context, AL_INVALID_NAME);
1865 else if(!(IntValsByProp(param) == 1))
1866 alSetError(Context, AL_INVALID_ENUM);
1867 else
1868 SetSourceiv(Source, Context, param, &value);
1869 UnlockSourcesRead(Context);
1870 WriteUnlock(&Context->PropLock);
1872 ALCcontext_DecRef(Context);
1875 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
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(!(IntValsByProp(param) == 3))
1888 alSetError(Context, AL_INVALID_ENUM);
1889 else
1891 ALint ivals[3] = { value1, value2, value3 };
1892 SetSourceiv(Source, Context, param, ivals);
1894 UnlockSourcesRead(Context);
1895 WriteUnlock(&Context->PropLock);
1897 ALCcontext_DecRef(Context);
1900 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1902 ALCcontext *Context;
1903 ALsource *Source;
1905 Context = GetContextRef();
1906 if(!Context) return;
1908 WriteLock(&Context->PropLock);
1909 LockSourcesRead(Context);
1910 if((Source=LookupSource(Context, source)) == NULL)
1911 alSetError(Context, AL_INVALID_NAME);
1912 else if(!values)
1913 alSetError(Context, AL_INVALID_VALUE);
1914 else if(!(IntValsByProp(param) > 0))
1915 alSetError(Context, AL_INVALID_ENUM);
1916 else
1917 SetSourceiv(Source, Context, param, values);
1918 UnlockSourcesRead(Context);
1919 WriteUnlock(&Context->PropLock);
1921 ALCcontext_DecRef(Context);
1925 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1927 ALCcontext *Context;
1928 ALsource *Source;
1930 Context = GetContextRef();
1931 if(!Context) return;
1933 WriteLock(&Context->PropLock);
1934 LockSourcesRead(Context);
1935 if((Source=LookupSource(Context, source)) == NULL)
1936 alSetError(Context, AL_INVALID_NAME);
1937 else if(!(Int64ValsByProp(param) == 1))
1938 alSetError(Context, AL_INVALID_ENUM);
1939 else
1940 SetSourcei64v(Source, Context, param, &value);
1941 UnlockSourcesRead(Context);
1942 WriteUnlock(&Context->PropLock);
1944 ALCcontext_DecRef(Context);
1947 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1949 ALCcontext *Context;
1950 ALsource *Source;
1952 Context = GetContextRef();
1953 if(!Context) return;
1955 WriteLock(&Context->PropLock);
1956 LockSourcesRead(Context);
1957 if((Source=LookupSource(Context, source)) == NULL)
1958 alSetError(Context, AL_INVALID_NAME);
1959 else if(!(Int64ValsByProp(param) == 3))
1960 alSetError(Context, AL_INVALID_ENUM);
1961 else
1963 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1964 SetSourcei64v(Source, Context, param, i64vals);
1966 UnlockSourcesRead(Context);
1967 WriteUnlock(&Context->PropLock);
1969 ALCcontext_DecRef(Context);
1972 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1974 ALCcontext *Context;
1975 ALsource *Source;
1977 Context = GetContextRef();
1978 if(!Context) return;
1980 WriteLock(&Context->PropLock);
1981 LockSourcesRead(Context);
1982 if((Source=LookupSource(Context, source)) == NULL)
1983 alSetError(Context, AL_INVALID_NAME);
1984 else if(!values)
1985 alSetError(Context, AL_INVALID_VALUE);
1986 else if(!(Int64ValsByProp(param) > 0))
1987 alSetError(Context, AL_INVALID_ENUM);
1988 else
1989 SetSourcei64v(Source, Context, param, values);
1990 UnlockSourcesRead(Context);
1991 WriteUnlock(&Context->PropLock);
1993 ALCcontext_DecRef(Context);
1997 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1999 ALCcontext *Context;
2000 ALsource *Source;
2002 Context = GetContextRef();
2003 if(!Context) return;
2005 ReadLock(&Context->PropLock);
2006 LockSourcesRead(Context);
2007 if((Source=LookupSource(Context, source)) == NULL)
2008 alSetError(Context, AL_INVALID_NAME);
2009 else if(!value)
2010 alSetError(Context, AL_INVALID_VALUE);
2011 else if(!(FloatValsByProp(param) == 1))
2012 alSetError(Context, AL_INVALID_ENUM);
2013 else
2015 ALdouble dval;
2016 if(GetSourcedv(Source, Context, param, &dval))
2017 *value = (ALfloat)dval;
2019 UnlockSourcesRead(Context);
2020 ReadUnlock(&Context->PropLock);
2022 ALCcontext_DecRef(Context);
2026 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
2028 ALCcontext *Context;
2029 ALsource *Source;
2031 Context = GetContextRef();
2032 if(!Context) return;
2034 ReadLock(&Context->PropLock);
2035 LockSourcesRead(Context);
2036 if((Source=LookupSource(Context, source)) == NULL)
2037 alSetError(Context, AL_INVALID_NAME);
2038 else if(!(value1 && value2 && value3))
2039 alSetError(Context, AL_INVALID_VALUE);
2040 else if(!(FloatValsByProp(param) == 3))
2041 alSetError(Context, AL_INVALID_ENUM);
2042 else
2044 ALdouble dvals[3];
2045 if(GetSourcedv(Source, Context, param, dvals))
2047 *value1 = (ALfloat)dvals[0];
2048 *value2 = (ALfloat)dvals[1];
2049 *value3 = (ALfloat)dvals[2];
2052 UnlockSourcesRead(Context);
2053 ReadUnlock(&Context->PropLock);
2055 ALCcontext_DecRef(Context);
2059 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
2061 ALCcontext *Context;
2062 ALsource *Source;
2063 ALint count;
2065 Context = GetContextRef();
2066 if(!Context) return;
2068 ReadLock(&Context->PropLock);
2069 LockSourcesRead(Context);
2070 if((Source=LookupSource(Context, source)) == NULL)
2071 alSetError(Context, AL_INVALID_NAME);
2072 else if(!values)
2073 alSetError(Context, AL_INVALID_VALUE);
2074 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
2075 alSetError(Context, AL_INVALID_ENUM);
2076 else
2078 ALdouble dvals[6];
2079 if(GetSourcedv(Source, Context, param, dvals))
2081 ALint i;
2082 for(i = 0;i < count;i++)
2083 values[i] = (ALfloat)dvals[i];
2086 UnlockSourcesRead(Context);
2087 ReadUnlock(&Context->PropLock);
2089 ALCcontext_DecRef(Context);
2093 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
2095 ALCcontext *Context;
2096 ALsource *Source;
2098 Context = GetContextRef();
2099 if(!Context) return;
2101 ReadLock(&Context->PropLock);
2102 LockSourcesRead(Context);
2103 if((Source=LookupSource(Context, source)) == NULL)
2104 alSetError(Context, AL_INVALID_NAME);
2105 else if(!value)
2106 alSetError(Context, AL_INVALID_VALUE);
2107 else if(!(DoubleValsByProp(param) == 1))
2108 alSetError(Context, AL_INVALID_ENUM);
2109 else
2110 GetSourcedv(Source, Context, param, value);
2111 UnlockSourcesRead(Context);
2112 ReadUnlock(&Context->PropLock);
2114 ALCcontext_DecRef(Context);
2117 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
2119 ALCcontext *Context;
2120 ALsource *Source;
2122 Context = GetContextRef();
2123 if(!Context) return;
2125 ReadLock(&Context->PropLock);
2126 LockSourcesRead(Context);
2127 if((Source=LookupSource(Context, source)) == NULL)
2128 alSetError(Context, AL_INVALID_NAME);
2129 else if(!(value1 && value2 && value3))
2130 alSetError(Context, AL_INVALID_VALUE);
2131 else if(!(DoubleValsByProp(param) == 3))
2132 alSetError(Context, AL_INVALID_ENUM);
2133 else
2135 ALdouble dvals[3];
2136 if(GetSourcedv(Source, Context, param, dvals))
2138 *value1 = dvals[0];
2139 *value2 = dvals[1];
2140 *value3 = dvals[2];
2143 UnlockSourcesRead(Context);
2144 ReadUnlock(&Context->PropLock);
2146 ALCcontext_DecRef(Context);
2149 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
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(!values)
2162 alSetError(Context, AL_INVALID_VALUE);
2163 else if(!(DoubleValsByProp(param) > 0))
2164 alSetError(Context, AL_INVALID_ENUM);
2165 else
2166 GetSourcedv(Source, Context, param, values);
2167 UnlockSourcesRead(Context);
2168 ReadUnlock(&Context->PropLock);
2170 ALCcontext_DecRef(Context);
2174 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2176 ALCcontext *Context;
2177 ALsource *Source;
2179 Context = GetContextRef();
2180 if(!Context) return;
2182 ReadLock(&Context->PropLock);
2183 LockSourcesRead(Context);
2184 if((Source=LookupSource(Context, source)) == NULL)
2185 alSetError(Context, AL_INVALID_NAME);
2186 else if(!value)
2187 alSetError(Context, AL_INVALID_VALUE);
2188 else if(!(IntValsByProp(param) == 1))
2189 alSetError(Context, AL_INVALID_ENUM);
2190 else
2191 GetSourceiv(Source, Context, param, value);
2192 UnlockSourcesRead(Context);
2193 ReadUnlock(&Context->PropLock);
2195 ALCcontext_DecRef(Context);
2199 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2201 ALCcontext *Context;
2202 ALsource *Source;
2204 Context = GetContextRef();
2205 if(!Context) return;
2207 ReadLock(&Context->PropLock);
2208 LockSourcesRead(Context);
2209 if((Source=LookupSource(Context, source)) == NULL)
2210 alSetError(Context, AL_INVALID_NAME);
2211 else if(!(value1 && value2 && value3))
2212 alSetError(Context, AL_INVALID_VALUE);
2213 else if(!(IntValsByProp(param) == 3))
2214 alSetError(Context, AL_INVALID_ENUM);
2215 else
2217 ALint ivals[3];
2218 if(GetSourceiv(Source, Context, param, ivals))
2220 *value1 = ivals[0];
2221 *value2 = ivals[1];
2222 *value3 = ivals[2];
2225 UnlockSourcesRead(Context);
2226 ReadUnlock(&Context->PropLock);
2228 ALCcontext_DecRef(Context);
2232 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2234 ALCcontext *Context;
2235 ALsource *Source;
2237 Context = GetContextRef();
2238 if(!Context) return;
2240 ReadLock(&Context->PropLock);
2241 LockSourcesRead(Context);
2242 if((Source=LookupSource(Context, source)) == NULL)
2243 alSetError(Context, AL_INVALID_NAME);
2244 else if(!values)
2245 alSetError(Context, AL_INVALID_VALUE);
2246 else if(!(IntValsByProp(param) > 0))
2247 alSetError(Context, AL_INVALID_ENUM);
2248 else
2249 GetSourceiv(Source, Context, param, values);
2250 UnlockSourcesRead(Context);
2251 ReadUnlock(&Context->PropLock);
2253 ALCcontext_DecRef(Context);
2257 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2259 ALCcontext *Context;
2260 ALsource *Source;
2262 Context = GetContextRef();
2263 if(!Context) return;
2265 ReadLock(&Context->PropLock);
2266 LockSourcesRead(Context);
2267 if((Source=LookupSource(Context, source)) == NULL)
2268 alSetError(Context, AL_INVALID_NAME);
2269 else if(!value)
2270 alSetError(Context, AL_INVALID_VALUE);
2271 else if(!(Int64ValsByProp(param) == 1))
2272 alSetError(Context, AL_INVALID_ENUM);
2273 else
2274 GetSourcei64v(Source, Context, param, value);
2275 UnlockSourcesRead(Context);
2276 ReadUnlock(&Context->PropLock);
2278 ALCcontext_DecRef(Context);
2281 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2283 ALCcontext *Context;
2284 ALsource *Source;
2286 Context = GetContextRef();
2287 if(!Context) return;
2289 ReadLock(&Context->PropLock);
2290 LockSourcesRead(Context);
2291 if((Source=LookupSource(Context, source)) == NULL)
2292 alSetError(Context, AL_INVALID_NAME);
2293 else if(!(value1 && value2 && value3))
2294 alSetError(Context, AL_INVALID_VALUE);
2295 else if(!(Int64ValsByProp(param) == 3))
2296 alSetError(Context, AL_INVALID_ENUM);
2297 else
2299 ALint64 i64vals[3];
2300 if(GetSourcei64v(Source, Context, param, i64vals))
2302 *value1 = i64vals[0];
2303 *value2 = i64vals[1];
2304 *value3 = i64vals[2];
2307 UnlockSourcesRead(Context);
2308 ReadUnlock(&Context->PropLock);
2310 ALCcontext_DecRef(Context);
2313 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2315 ALCcontext *Context;
2316 ALsource *Source;
2318 Context = GetContextRef();
2319 if(!Context) return;
2321 ReadLock(&Context->PropLock);
2322 LockSourcesRead(Context);
2323 if((Source=LookupSource(Context, source)) == NULL)
2324 alSetError(Context, AL_INVALID_NAME);
2325 else if(!values)
2326 alSetError(Context, AL_INVALID_VALUE);
2327 else if(!(Int64ValsByProp(param) > 0))
2328 alSetError(Context, AL_INVALID_ENUM);
2329 else
2330 GetSourcei64v(Source, Context, param, values);
2331 UnlockSourcesRead(Context);
2332 ReadUnlock(&Context->PropLock);
2334 ALCcontext_DecRef(Context);
2338 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2340 alSourcePlayv(1, &source);
2342 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2344 ALCcontext *context;
2345 ALCdevice *device;
2346 ALsource *source;
2347 ALvoice *voice;
2348 ALsizei i, j;
2350 context = GetContextRef();
2351 if(!context) return;
2353 LockSourcesRead(context);
2354 if(!(n >= 0))
2355 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2356 for(i = 0;i < n;i++)
2358 if(!LookupSource(context, sources[i]))
2359 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2362 device = context->Device;
2363 ALCdevice_Lock(device);
2364 /* If the device is disconnected, go right to stopped. */
2365 if(!device->Connected)
2367 for(i = 0;i < n;i++)
2369 source = LookupSource(context, sources[i]);
2370 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2372 ALCdevice_Unlock(device);
2373 goto done;
2376 while(n > context->MaxVoices-context->VoiceCount)
2378 ALsizei newcount = context->MaxVoices << 1;
2379 if(context->MaxVoices >= newcount)
2381 ALCdevice_Unlock(device);
2382 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2384 AllocateVoices(context, newcount, device->NumAuxSends);
2387 for(i = 0;i < n;i++)
2389 ALbufferlistitem *BufferList;
2390 ALbuffer *buffer = NULL;
2392 source = LookupSource(context, sources[i]);
2393 WriteLock(&source->queue_lock);
2394 /* Check that there is a queue containing at least one valid, non zero
2395 * length Buffer.
2397 BufferList = ATOMIC_LOAD_SEQ(&source->queue);
2398 while(BufferList)
2400 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2401 break;
2402 BufferList = BufferList->next;
2405 /* If there's nothing to play, go right to stopped. */
2406 if(!BufferList)
2408 /* NOTE: A source without any playable buffers should not have an
2409 * ALvoice since it shouldn't be in a playing or paused state. So
2410 * there's no need to look up its voice and clear the source.
2412 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2413 source->OffsetType = AL_NONE;
2414 source->Offset = 0.0;
2415 goto finish_play;
2418 voice = GetSourceVoice(source, context);
2419 switch(GetSourceState(source, voice))
2421 case AL_PLAYING:
2422 assert(voice != NULL);
2423 /* A source that's already playing is restarted from the beginning. */
2424 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
2425 ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
2426 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release);
2427 goto finish_play;
2429 case AL_PAUSED:
2430 assert(voice != NULL);
2431 /* A source that's paused simply resumes. Make sure it uses the
2432 * volume last specified; there's no reason to fade from where
2433 * it stopped at.
2435 voice->Flags &= ~VOICE_IS_MOVING;
2436 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
2437 ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release);
2438 goto finish_play;
2440 default:
2441 break;
2444 ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acquire);
2445 UpdateSourceProps(source, device->NumAuxSends);
2447 /* Make sure this source isn't already active, and if not, look for an
2448 * unused voice to put it in.
2450 assert(voice == NULL);
2451 for(j = 0;j < context->VoiceCount;j++)
2453 if(ATOMIC_LOAD(&context->Voices[j]->Source, almemory_order_acquire) == NULL)
2455 voice = context->Voices[j];
2456 break;
2459 if(voice == NULL)
2460 voice = context->Voices[context->VoiceCount++];
2461 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2462 ATOMIC_THREAD_FENCE(almemory_order_acquire);
2464 /* A source that's not playing or paused has any offset applied when it
2465 * starts playing.
2467 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
2468 ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
2469 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed);
2470 if(source->OffsetType != AL_NONE)
2471 ApplyOffset(source, voice);
2473 voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2474 voice->SampleSize = BytesFromFmt(buffer->FmtType);
2476 /* Clear previous samples. */
2477 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
2479 /* Clear the stepping value so the mixer knows not to mix this until
2480 * the update gets applied.
2482 voice->Step = 0;
2484 voice->Flags = 0;
2485 for(j = 0;j < voice->NumChannels;j++)
2486 memset(&voice->Direct.Params[j].Hrtf.State, 0,
2487 sizeof(voice->Direct.Params[j].Hrtf.State));
2488 if(device->AvgSpeakerDist > 0.0f)
2490 ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC /
2491 (device->AvgSpeakerDist * device->Frequency);
2492 for(j = 0;j < voice->NumChannels;j++)
2494 NfcFilterCreate1(&voice->Direct.Params[j].NFCtrlFilter[0], 0.0f, w1);
2495 NfcFilterCreate2(&voice->Direct.Params[j].NFCtrlFilter[1], 0.0f, w1);
2496 NfcFilterCreate3(&voice->Direct.Params[j].NFCtrlFilter[2], 0.0f, w1);
2500 ATOMIC_STORE(&voice->Source, source, almemory_order_relaxed);
2501 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
2502 ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release);
2503 finish_play:
2504 WriteUnlock(&source->queue_lock);
2506 ALCdevice_Unlock(device);
2508 done:
2509 UnlockSourcesRead(context);
2510 ALCcontext_DecRef(context);
2513 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2515 alSourcePausev(1, &source);
2517 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2519 ALCcontext *context;
2520 ALCdevice *device;
2521 ALsource *source;
2522 ALvoice *voice;
2523 ALsizei i;
2525 context = GetContextRef();
2526 if(!context) return;
2528 LockSourcesRead(context);
2529 if(!(n >= 0))
2530 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2531 for(i = 0;i < n;i++)
2533 if(!LookupSource(context, sources[i]))
2534 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2537 device = context->Device;
2538 ALCdevice_Lock(device);
2539 for(i = 0;i < n;i++)
2541 source = LookupSource(context, sources[i]);
2542 WriteLock(&source->queue_lock);
2543 if((voice=GetSourceVoice(source, context)) != NULL)
2545 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2546 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2547 althrd_yield();
2549 if(GetSourceState(source, voice) == AL_PLAYING)
2550 ATOMIC_STORE(&source->state, AL_PAUSED, almemory_order_release);
2551 WriteUnlock(&source->queue_lock);
2553 ALCdevice_Unlock(device);
2555 done:
2556 UnlockSourcesRead(context);
2557 ALCcontext_DecRef(context);
2560 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2562 alSourceStopv(1, &source);
2564 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2566 ALCcontext *context;
2567 ALCdevice *device;
2568 ALsource *source;
2569 ALvoice *voice;
2570 ALsizei i;
2572 context = GetContextRef();
2573 if(!context) return;
2575 LockSourcesRead(context);
2576 if(!(n >= 0))
2577 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2578 for(i = 0;i < n;i++)
2580 if(!LookupSource(context, sources[i]))
2581 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2584 device = context->Device;
2585 ALCdevice_Lock(device);
2586 for(i = 0;i < n;i++)
2588 source = LookupSource(context, sources[i]);
2589 WriteLock(&source->queue_lock);
2590 if((voice=GetSourceVoice(source, context)) != NULL)
2592 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
2593 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2594 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2595 althrd_yield();
2597 if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL)
2598 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2599 source->OffsetType = AL_NONE;
2600 source->Offset = 0.0;
2601 WriteUnlock(&source->queue_lock);
2603 ALCdevice_Unlock(device);
2605 done:
2606 UnlockSourcesRead(context);
2607 ALCcontext_DecRef(context);
2610 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2612 alSourceRewindv(1, &source);
2614 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2616 ALCcontext *context;
2617 ALCdevice *device;
2618 ALsource *source;
2619 ALvoice *voice;
2620 ALsizei i;
2622 context = GetContextRef();
2623 if(!context) return;
2625 LockSourcesRead(context);
2626 if(!(n >= 0))
2627 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2628 for(i = 0;i < n;i++)
2630 if(!LookupSource(context, sources[i]))
2631 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2634 device = context->Device;
2635 ALCdevice_Lock(device);
2636 for(i = 0;i < n;i++)
2638 source = LookupSource(context, sources[i]);
2639 WriteLock(&source->queue_lock);
2640 if((voice=GetSourceVoice(source, context)) != NULL)
2642 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
2643 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2644 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2645 althrd_yield();
2647 if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL)
2648 ATOMIC_STORE(&source->state, AL_INITIAL, almemory_order_relaxed);
2649 source->OffsetType = AL_NONE;
2650 source->Offset = 0.0;
2651 WriteUnlock(&source->queue_lock);
2653 ALCdevice_Unlock(device);
2655 done:
2656 UnlockSourcesRead(context);
2657 ALCcontext_DecRef(context);
2661 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2663 ALCdevice *device;
2664 ALCcontext *context;
2665 ALsource *source;
2666 ALsizei i;
2667 ALbufferlistitem *BufferListStart;
2668 ALbufferlistitem *BufferList;
2669 ALbuffer *BufferFmt = NULL;
2671 if(nb == 0)
2672 return;
2674 context = GetContextRef();
2675 if(!context) return;
2677 device = context->Device;
2679 LockSourcesRead(context);
2680 if(!(nb >= 0))
2681 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2682 if((source=LookupSource(context, src)) == NULL)
2683 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2685 WriteLock(&source->queue_lock);
2686 if(source->SourceType == AL_STATIC)
2688 WriteUnlock(&source->queue_lock);
2689 /* Can't queue on a Static Source */
2690 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2693 /* Check for a valid Buffer, for its frequency and format */
2694 BufferList = ATOMIC_LOAD_SEQ(&source->queue);
2695 while(BufferList)
2697 if(BufferList->buffer)
2699 BufferFmt = BufferList->buffer;
2700 break;
2702 BufferList = BufferList->next;
2705 LockBuffersRead(device);
2706 BufferListStart = NULL;
2707 BufferList = NULL;
2708 for(i = 0;i < nb;i++)
2710 ALbuffer *buffer = NULL;
2711 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2713 WriteUnlock(&source->queue_lock);
2714 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2717 if(!BufferListStart)
2719 BufferListStart = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
2720 BufferList = BufferListStart;
2722 else
2724 BufferList->next = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
2725 BufferList = BufferList->next;
2727 BufferList->buffer = buffer;
2728 BufferList->next = NULL;
2729 if(!buffer) continue;
2731 /* Hold a read lock on each buffer being queued while checking all
2732 * provided buffers. This is done so other threads don't see an extra
2733 * reference on some buffers if this operation ends up failing. */
2734 ReadLock(&buffer->lock);
2735 IncrementRef(&buffer->ref);
2737 if(BufferFmt == NULL)
2738 BufferFmt = buffer;
2739 else if(BufferFmt->Frequency != buffer->Frequency ||
2740 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2741 BufferFmt->OriginalType != buffer->OriginalType)
2743 WriteUnlock(&source->queue_lock);
2744 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2746 buffer_error:
2747 /* A buffer failed (invalid ID or format), so unlock and release
2748 * each buffer we had. */
2749 while(BufferListStart)
2751 ALbufferlistitem *next = BufferListStart->next;
2752 if((buffer=BufferListStart->buffer) != NULL)
2754 DecrementRef(&buffer->ref);
2755 ReadUnlock(&buffer->lock);
2757 al_free(BufferListStart);
2758 BufferListStart = next;
2760 UnlockBuffersRead(device);
2761 goto done;
2764 /* All buffers good, unlock them now. */
2765 BufferList = BufferListStart;
2766 while(BufferList != NULL)
2768 ALbuffer *buffer = BufferList->buffer;
2769 if(buffer) ReadUnlock(&buffer->lock);
2770 BufferList = BufferList->next;
2772 UnlockBuffersRead(device);
2774 /* Source is now streaming */
2775 source->SourceType = AL_STREAMING;
2777 BufferList = NULL;
2778 if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem*, &source->queue,
2779 &BufferList, BufferListStart))
2781 /* Queue head is not NULL, append to the end of the queue */
2782 while(BufferList->next != NULL)
2783 BufferList = BufferList->next;
2784 BufferList->next = BufferListStart;
2786 WriteUnlock(&source->queue_lock);
2788 done:
2789 UnlockSourcesRead(context);
2790 ALCcontext_DecRef(context);
2793 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2795 ALCcontext *context;
2796 ALsource *source;
2797 ALbufferlistitem *OldHead;
2798 ALbufferlistitem *OldTail;
2799 ALbufferlistitem *Current;
2800 ALvoice *voice;
2801 ALsizei i = 0;
2803 context = GetContextRef();
2804 if(!context) return;
2806 LockSourcesRead(context);
2807 if(!(nb >= 0))
2808 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2810 if((source=LookupSource(context, src)) == NULL)
2811 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2813 /* Nothing to unqueue. */
2814 if(nb == 0) goto done;
2816 WriteLock(&source->queue_lock);
2817 if(ATOMIC_LOAD_SEQ(&source->looping) || source->SourceType != AL_STREAMING)
2819 WriteUnlock(&source->queue_lock);
2820 /* Trying to unqueue buffers on a looping or non-streaming source. */
2821 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2824 /* Find the new buffer queue head */
2825 OldTail = ATOMIC_LOAD_SEQ(&source->queue);
2826 Current = NULL;
2827 if((voice=GetSourceVoice(source, context)) != NULL)
2828 Current = ATOMIC_LOAD_SEQ(&voice->current_buffer);
2829 else if(ATOMIC_LOAD_SEQ(&source->state) == AL_INITIAL)
2830 Current = OldTail;
2831 if(OldTail != Current)
2833 for(i = 1;i < nb;i++)
2835 ALbufferlistitem *next = OldTail->next;
2836 if(!next || next == Current) break;
2837 OldTail = next;
2840 if(i != nb)
2842 WriteUnlock(&source->queue_lock);
2843 /* Trying to unqueue pending buffers. */
2844 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2847 /* Swap it, and cut the new head from the old. */
2848 OldHead = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &source->queue, OldTail->next);
2849 if(OldTail->next)
2851 ALCdevice *device = context->Device;
2852 uint count;
2854 /* Once the active mix (if any) is done, it's safe to cut the old tail
2855 * from the new head.
2857 if(((count=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
2859 while(count == ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))
2860 althrd_yield();
2862 ATOMIC_THREAD_FENCE(almemory_order_acq_rel);
2863 OldTail->next = NULL;
2865 WriteUnlock(&source->queue_lock);
2867 while(OldHead != NULL)
2869 ALbufferlistitem *next = OldHead->next;
2870 ALbuffer *buffer = OldHead->buffer;
2872 if(!buffer)
2873 *(buffers++) = 0;
2874 else
2876 *(buffers++) = buffer->id;
2877 DecrementRef(&buffer->ref);
2880 al_free(OldHead);
2881 OldHead = next;
2884 done:
2885 UnlockSourcesRead(context);
2886 ALCcontext_DecRef(context);
2890 static void InitSourceParams(ALsource *Source, ALsizei num_sends)
2892 ALsizei i;
2894 RWLockInit(&Source->queue_lock);
2896 Source->InnerAngle = 360.0f;
2897 Source->OuterAngle = 360.0f;
2898 Source->Pitch = 1.0f;
2899 Source->Position[0] = 0.0f;
2900 Source->Position[1] = 0.0f;
2901 Source->Position[2] = 0.0f;
2902 Source->Velocity[0] = 0.0f;
2903 Source->Velocity[1] = 0.0f;
2904 Source->Velocity[2] = 0.0f;
2905 Source->Direction[0] = 0.0f;
2906 Source->Direction[1] = 0.0f;
2907 Source->Direction[2] = 0.0f;
2908 Source->Orientation[0][0] = 0.0f;
2909 Source->Orientation[0][1] = 0.0f;
2910 Source->Orientation[0][2] = -1.0f;
2911 Source->Orientation[1][0] = 0.0f;
2912 Source->Orientation[1][1] = 1.0f;
2913 Source->Orientation[1][2] = 0.0f;
2914 Source->RefDistance = 1.0f;
2915 Source->MaxDistance = FLT_MAX;
2916 Source->RollOffFactor = 1.0f;
2917 Source->Gain = 1.0f;
2918 Source->MinGain = 0.0f;
2919 Source->MaxGain = 1.0f;
2920 Source->OuterGain = 0.0f;
2921 Source->OuterGainHF = 1.0f;
2923 Source->DryGainHFAuto = AL_TRUE;
2924 Source->WetGainAuto = AL_TRUE;
2925 Source->WetGainHFAuto = AL_TRUE;
2926 Source->AirAbsorptionFactor = 0.0f;
2927 Source->RoomRolloffFactor = 0.0f;
2928 Source->DopplerFactor = 1.0f;
2929 Source->DirectChannels = AL_FALSE;
2931 Source->StereoPan[0] = DEG2RAD( 30.0f);
2932 Source->StereoPan[1] = DEG2RAD(-30.0f);
2934 Source->Radius = 0.0f;
2936 Source->DistanceModel = DefaultDistanceModel;
2938 Source->Direct.Gain = 1.0f;
2939 Source->Direct.GainHF = 1.0f;
2940 Source->Direct.HFReference = LOWPASSFREQREF;
2941 Source->Direct.GainLF = 1.0f;
2942 Source->Direct.LFReference = HIGHPASSFREQREF;
2943 Source->Send = al_calloc(16, num_sends*sizeof(Source->Send[0]));
2944 for(i = 0;i < num_sends;i++)
2946 Source->Send[i].Slot = NULL;
2947 Source->Send[i].Gain = 1.0f;
2948 Source->Send[i].GainHF = 1.0f;
2949 Source->Send[i].HFReference = LOWPASSFREQREF;
2950 Source->Send[i].GainLF = 1.0f;
2951 Source->Send[i].LFReference = HIGHPASSFREQREF;
2954 Source->Offset = 0.0;
2955 Source->OffsetType = AL_NONE;
2956 Source->SourceType = AL_UNDETERMINED;
2957 ATOMIC_INIT(&Source->state, AL_INITIAL);
2959 ATOMIC_INIT(&Source->queue, NULL);
2961 ATOMIC_INIT(&Source->looping, AL_FALSE);
2963 /* No way to do an 'init' here, so just test+set with relaxed ordering and
2964 * ignore the test.
2966 ATOMIC_FLAG_TEST_AND_SET(&Source->PropsClean, almemory_order_relaxed);
2968 ATOMIC_INIT(&Source->Update, NULL);
2969 ATOMIC_INIT(&Source->FreeList, NULL);
2972 static void DeinitSource(ALsource *source, ALsizei num_sends)
2974 ALbufferlistitem *BufferList;
2975 struct ALsourceProps *props;
2976 size_t count = 0;
2977 ALsizei i;
2979 props = ATOMIC_LOAD_SEQ(&source->Update);
2980 if(props) al_free(props);
2982 props = ATOMIC_LOAD(&source->FreeList, almemory_order_relaxed);
2983 while(props)
2985 struct ALsourceProps *next;
2986 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2987 al_free(props);
2988 props = next;
2989 ++count;
2991 /* This is excessively spammy if it traces every source destruction, so
2992 * just warn if it was unexpectedly large.
2994 if(count > 3)
2995 WARN("Freed "SZFMT" Source property objects\n", count);
2997 BufferList = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &source->queue, NULL);
2998 while(BufferList != NULL)
3000 ALbufferlistitem *next = BufferList->next;
3001 if(BufferList->buffer != NULL)
3002 DecrementRef(&BufferList->buffer->ref);
3003 al_free(BufferList);
3004 BufferList = next;
3007 if(source->Send)
3009 for(i = 0;i < num_sends;i++)
3011 if(source->Send[i].Slot)
3012 DecrementRef(&source->Send[i].Slot->ref);
3013 source->Send[i].Slot = NULL;
3015 al_free(source->Send);
3016 source->Send = NULL;
3020 static void UpdateSourceProps(ALsource *source, ALsizei num_sends)
3022 struct ALsourceProps *props;
3023 ALsizei i;
3025 /* Get an unused property container, or allocate a new one as needed. */
3026 props = ATOMIC_LOAD(&source->FreeList, almemory_order_acquire);
3027 if(!props)
3028 props = al_calloc(16, offsetof(struct ALsourceProps, Send[num_sends]));
3029 else
3031 struct ALsourceProps *next;
3032 do {
3033 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
3034 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*,
3035 &source->FreeList, &props, next, almemory_order_acq_rel,
3036 almemory_order_acquire) == 0);
3039 /* Copy in current property values. */
3040 props->Pitch = source->Pitch;
3041 props->Gain = source->Gain;
3042 props->OuterGain = source->OuterGain;
3043 props->MinGain = source->MinGain;
3044 props->MaxGain = source->MaxGain;
3045 props->InnerAngle = source->InnerAngle;
3046 props->OuterAngle = source->OuterAngle;
3047 props->RefDistance = source->RefDistance;
3048 props->MaxDistance = source->MaxDistance;
3049 props->RollOffFactor = source->RollOffFactor;
3050 for(i = 0;i < 3;i++)
3051 props->Position[i] = source->Position[i];
3052 for(i = 0;i < 3;i++)
3053 props->Velocity[i] = source->Velocity[i];
3054 for(i = 0;i < 3;i++)
3055 props->Direction[i] = source->Direction[i];
3056 for(i = 0;i < 2;i++)
3058 ALsizei j;
3059 for(j = 0;j < 3;j++)
3060 props->Orientation[i][j] = source->Orientation[i][j];
3062 props->HeadRelative = source->HeadRelative;
3063 props->DistanceModel = source->DistanceModel;
3064 props->DirectChannels = source->DirectChannels;
3066 props->DryGainHFAuto = source->DryGainHFAuto;
3067 props->WetGainAuto = source->WetGainAuto;
3068 props->WetGainHFAuto = source->WetGainHFAuto;
3069 props->OuterGainHF = source->OuterGainHF;
3071 props->AirAbsorptionFactor = source->AirAbsorptionFactor;
3072 props->RoomRolloffFactor = source->RoomRolloffFactor;
3073 props->DopplerFactor = source->DopplerFactor;
3075 props->StereoPan[0] = source->StereoPan[0];
3076 props->StereoPan[1] = source->StereoPan[1];
3078 props->Radius = source->Radius;
3080 props->Direct.Gain = source->Direct.Gain;
3081 props->Direct.GainHF = source->Direct.GainHF;
3082 props->Direct.HFReference = source->Direct.HFReference;
3083 props->Direct.GainLF = source->Direct.GainLF;
3084 props->Direct.LFReference = source->Direct.LFReference;
3086 for(i = 0;i < num_sends;i++)
3088 props->Send[i].Slot = source->Send[i].Slot;
3089 props->Send[i].Gain = source->Send[i].Gain;
3090 props->Send[i].GainHF = source->Send[i].GainHF;
3091 props->Send[i].HFReference = source->Send[i].HFReference;
3092 props->Send[i].GainLF = source->Send[i].GainLF;
3093 props->Send[i].LFReference = source->Send[i].LFReference;
3096 /* Set the new container for updating internal parameters. */
3097 props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, props, almemory_order_acq_rel);
3098 if(props)
3100 /* If there was an unused update container, put it back in the
3101 * freelist.
3103 ATOMIC_REPLACE_HEAD(struct ALsourceProps*, &source->FreeList, props);
3107 void UpdateAllSourceProps(ALCcontext *context)
3109 ALsizei num_sends = context->Device->NumAuxSends;
3110 ALsizei pos;
3112 for(pos = 0;pos < context->VoiceCount;pos++)
3114 ALvoice *voice = context->Voices[pos];
3115 ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire);
3116 if(source != NULL && ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acq_rel))
3117 UpdateSourceProps(source, num_sends);
3122 /* GetSourceSampleOffset
3124 * Gets the current read offset for the given Source, in 32.32 fixed-point
3125 * samples. The offset is relative to the start of the queue (not the start of
3126 * the current buffer).
3128 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3130 ALCdevice *device = context->Device;
3131 const ALbufferlistitem *BufferList;
3132 const ALbufferlistitem *Current;
3133 ALuint64 readPos;
3134 ALuint refcount;
3135 ALvoice *voice;
3137 ReadLock(&Source->queue_lock);
3138 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3139 do {
3140 Current = NULL;
3141 readPos = 0;
3142 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3143 althrd_yield();
3144 *clocktime = GetDeviceClockTime(device);
3146 voice = GetSourceVoice(Source, context);
3147 if(voice)
3149 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3151 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << 32;
3152 readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) <<
3153 (32-FRACTIONBITS);
3155 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3156 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3158 if(voice)
3160 while(BufferList && BufferList != Current)
3162 if(BufferList->buffer)
3163 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
3164 BufferList = BufferList->next;
3166 readPos = minu64(readPos, U64(0x7fffffffffffffff));
3169 ReadUnlock(&Source->queue_lock);
3170 return (ALint64)readPos;
3173 /* GetSourceSecOffset
3175 * Gets the current read offset for the given Source, in seconds. The offset is
3176 * relative to the start of the queue (not the start of the current buffer).
3178 static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3180 ALCdevice *device = context->Device;
3181 const ALbufferlistitem *BufferList;
3182 const ALbufferlistitem *Current;
3183 ALuint64 readPos;
3184 ALuint refcount;
3185 ALdouble offset;
3186 ALvoice *voice;
3188 ReadLock(&Source->queue_lock);
3189 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3190 do {
3191 Current = NULL;
3192 readPos = 0;
3193 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3194 althrd_yield();
3195 *clocktime = GetDeviceClockTime(device);
3197 voice = GetSourceVoice(Source, context);
3198 if(voice)
3200 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3202 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) <<
3203 FRACTIONBITS;
3204 readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3206 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3207 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3209 offset = 0.0;
3210 if(voice)
3212 const ALbuffer *Buffer = NULL;
3213 while(BufferList && BufferList != Current)
3215 const ALbuffer *buffer = BufferList->buffer;
3216 if(buffer != NULL)
3218 if(!Buffer) Buffer = buffer;
3219 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
3221 BufferList = BufferList->next;
3224 while(BufferList && !Buffer)
3226 Buffer = BufferList->buffer;
3227 BufferList = BufferList->next;
3229 assert(Buffer != NULL);
3231 offset = (ALdouble)readPos / (ALdouble)FRACTIONONE /
3232 (ALdouble)Buffer->Frequency;
3235 ReadUnlock(&Source->queue_lock);
3236 return offset;
3239 /* GetSourceOffset
3241 * Gets the current read offset for the given Source, in the appropriate format
3242 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3243 * queue (not the start of the current buffer).
3245 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context)
3247 ALCdevice *device = context->Device;
3248 const ALbufferlistitem *BufferList;
3249 const ALbufferlistitem *Current;
3250 const ALbuffer *Buffer = NULL;
3251 ALboolean readFin = AL_FALSE;
3252 ALuint readPos, readPosFrac;
3253 ALuint totalBufferLen;
3254 ALboolean looping;
3255 ALuint refcount;
3256 ALdouble offset;
3257 ALvoice *voice;
3259 ReadLock(&Source->queue_lock);
3260 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3261 looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed);
3262 do {
3263 Current = NULL;
3264 readPos = readPosFrac = 0;
3265 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3266 althrd_yield();
3267 voice = GetSourceVoice(Source, context);
3268 if(voice)
3270 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3272 readPos = ATOMIC_LOAD(&voice->position, almemory_order_relaxed);
3273 readPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3275 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3276 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3278 if(!voice)
3280 ReadUnlock(&Source->queue_lock);
3281 return 0.0;
3284 totalBufferLen = 0;
3285 while(BufferList != NULL)
3287 const ALbuffer *buffer;
3288 readFin = readFin || (BufferList == Current);
3289 if((buffer=BufferList->buffer) != NULL)
3291 if(!Buffer) Buffer = buffer;
3292 totalBufferLen += buffer->SampleLen;
3293 if(!readFin) readPos += buffer->SampleLen;
3295 BufferList = BufferList->next;
3297 assert(Buffer != NULL);
3299 if(looping)
3300 readPos %= totalBufferLen;
3301 else
3303 /* Wrap back to 0 */
3304 if(readPos >= totalBufferLen)
3305 readPos = readPosFrac = 0;
3308 offset = 0.0;
3309 switch(name)
3311 case AL_SEC_OFFSET:
3312 offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
3313 break;
3315 case AL_SAMPLE_OFFSET:
3316 offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
3317 break;
3319 case AL_BYTE_OFFSET:
3320 if(Buffer->OriginalType == UserFmtIMA4)
3322 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3323 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3324 ALuint FrameBlockSize = Buffer->OriginalAlign;
3326 /* Round down to nearest ADPCM block */
3327 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3329 else if(Buffer->OriginalType == UserFmtMSADPCM)
3331 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3332 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3333 ALuint FrameBlockSize = Buffer->OriginalAlign;
3335 /* Round down to nearest ADPCM block */
3336 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3338 else
3340 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3341 offset = (ALdouble)(readPos * FrameSize);
3343 break;
3346 ReadUnlock(&Source->queue_lock);
3347 return offset;
3351 /* ApplyOffset
3353 * Apply the stored playback offset to the Source. This function will update
3354 * the number of buffers "played" given the stored offset.
3356 static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice)
3358 ALbufferlistitem *BufferList;
3359 const ALbuffer *Buffer;
3360 ALuint bufferLen, totalBufferLen;
3361 ALuint offset=0, frac=0;
3363 /* Get sample frame offset */
3364 if(!GetSampleOffset(Source, &offset, &frac))
3365 return AL_FALSE;
3367 totalBufferLen = 0;
3368 BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
3369 while(BufferList && totalBufferLen <= offset)
3371 Buffer = BufferList->buffer;
3372 bufferLen = Buffer ? Buffer->SampleLen : 0;
3374 if(bufferLen > offset-totalBufferLen)
3376 /* Offset is in this buffer */
3377 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
3378 ATOMIC_STORE(&voice->position, offset - totalBufferLen, almemory_order_relaxed);
3379 ATOMIC_STORE(&voice->position_fraction, frac, almemory_order_release);
3380 return AL_TRUE;
3383 totalBufferLen += bufferLen;
3385 BufferList = BufferList->next;
3388 /* Offset is out of range of the queue */
3389 return AL_FALSE;
3393 /* GetSampleOffset
3395 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3396 * or Second offset supplied by the application). This takes into account the
3397 * fact that the buffer format may have been modifed since.
3399 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
3401 const ALbuffer *Buffer = NULL;
3402 const ALbufferlistitem *BufferList;
3403 ALdouble dbloff, dblfrac;
3405 /* Find the first valid Buffer in the Queue */
3406 BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
3407 while(BufferList)
3409 if(BufferList->buffer)
3411 Buffer = BufferList->buffer;
3412 break;
3414 BufferList = BufferList->next;
3416 if(!Buffer)
3418 Source->OffsetType = AL_NONE;
3419 Source->Offset = 0.0;
3420 return AL_FALSE;
3423 switch(Source->OffsetType)
3425 case AL_BYTE_OFFSET:
3426 /* Determine the ByteOffset (and ensure it is block aligned) */
3427 *offset = (ALuint)Source->Offset;
3428 if(Buffer->OriginalType == UserFmtIMA4)
3430 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3431 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3432 *offset *= Buffer->OriginalAlign;
3434 else if(Buffer->OriginalType == UserFmtMSADPCM)
3436 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3437 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3438 *offset *= Buffer->OriginalAlign;
3440 else
3441 *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3442 *frac = 0;
3443 break;
3445 case AL_SAMPLE_OFFSET:
3446 dblfrac = modf(Source->Offset, &dbloff);
3447 *offset = (ALuint)mind(dbloff, UINT_MAX);
3448 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3449 break;
3451 case AL_SEC_OFFSET:
3452 dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
3453 *offset = (ALuint)mind(dbloff, UINT_MAX);
3454 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3455 break;
3457 Source->OffsetType = AL_NONE;
3458 Source->Offset = 0.0;
3460 return AL_TRUE;
3464 /* ReleaseALSources
3466 * Destroys all sources in the source map.
3468 ALvoid ReleaseALSources(ALCcontext *Context)
3470 ALCdevice *device = Context->Device;
3471 ALsizei pos;
3472 for(pos = 0;pos < Context->SourceMap.size;pos++)
3474 ALsource *temp = Context->SourceMap.values[pos];
3475 Context->SourceMap.values[pos] = NULL;
3477 DeinitSource(temp, device->NumAuxSends);
3479 FreeThunkEntry(temp->id);
3480 memset(temp, 0, sizeof(*temp));
3481 al_free(temp);