Don't force a fade-in when resuming a paused source
[openal-soft.git] / OpenAL32 / alSource.c
blobbe191fdb7bb403f1a62be356938770753dcc3484
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, ALvoice *voice, ALsizei num_sends);
53 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime);
54 static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime);
55 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context);
56 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac);
57 static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice);
59 typedef enum SourceProp {
60 srcPitch = AL_PITCH,
61 srcGain = AL_GAIN,
62 srcMinGain = AL_MIN_GAIN,
63 srcMaxGain = AL_MAX_GAIN,
64 srcMaxDistance = AL_MAX_DISTANCE,
65 srcRolloffFactor = AL_ROLLOFF_FACTOR,
66 srcDopplerFactor = AL_DOPPLER_FACTOR,
67 srcConeOuterGain = AL_CONE_OUTER_GAIN,
68 srcSecOffset = AL_SEC_OFFSET,
69 srcSampleOffset = AL_SAMPLE_OFFSET,
70 srcByteOffset = AL_BYTE_OFFSET,
71 srcConeInnerAngle = AL_CONE_INNER_ANGLE,
72 srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
73 srcRefDistance = AL_REFERENCE_DISTANCE,
75 srcPosition = AL_POSITION,
76 srcVelocity = AL_VELOCITY,
77 srcDirection = AL_DIRECTION,
79 srcSourceRelative = AL_SOURCE_RELATIVE,
80 srcLooping = AL_LOOPING,
81 srcBuffer = AL_BUFFER,
82 srcSourceState = AL_SOURCE_STATE,
83 srcBuffersQueued = AL_BUFFERS_QUEUED,
84 srcBuffersProcessed = AL_BUFFERS_PROCESSED,
85 srcSourceType = AL_SOURCE_TYPE,
87 /* ALC_EXT_EFX */
88 srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
89 srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
90 srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
91 srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
92 srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
93 srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
94 srcDirectFilter = AL_DIRECT_FILTER,
95 srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
97 /* AL_SOFT_direct_channels */
98 srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
100 /* AL_EXT_source_distance_model */
101 srcDistanceModel = AL_DISTANCE_MODEL,
103 srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
104 srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
105 srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
107 /* AL_SOFT_source_latency */
108 srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
109 srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
111 /* AL_EXT_STEREO_ANGLES */
112 srcAngles = AL_STEREO_ANGLES,
114 /* AL_EXT_SOURCE_RADIUS */
115 srcRadius = AL_SOURCE_RADIUS,
117 /* AL_EXT_BFORMAT */
118 srcOrientation = AL_ORIENTATION,
120 /* AL_SOFT_source_resampler */
121 srcResampler = AL_SOURCE_RESAMPLER_SOFT,
123 /* AL_SOFT_source_spatialize */
124 srcSpatialize = AL_SOURCE_SPATIALIZE_SOFT,
125 } SourceProp;
127 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
128 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
129 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
131 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
132 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
133 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
135 static inline ALvoice *GetSourceVoice(const ALsource *source, const ALCcontext *context)
137 ALvoice **voice = context->Voices;
138 ALvoice **voice_end = voice + context->VoiceCount;
139 while(voice != voice_end)
141 if(ATOMIC_LOAD(&(*voice)->Source, almemory_order_acquire) == source)
142 return *voice;
143 ++voice;
145 return NULL;
149 * Returns if the last known state for the source was playing or paused. Does
150 * not sync with the mixer voice.
152 static inline bool IsPlayingOrPaused(ALsource *source)
154 ALenum state = ATOMIC_LOAD(&source->state, almemory_order_acquire);
155 return state == AL_PLAYING || state == AL_PAUSED;
159 * Returns an updated source state using the matching voice's status (or lack
160 * thereof).
162 static inline ALenum GetSourceState(ALsource *source, ALvoice *voice)
164 if(!voice)
166 ALenum state = AL_PLAYING;
167 if(ATOMIC_COMPARE_EXCHANGE_STRONG(&source->state, &state, AL_STOPPED,
168 almemory_order_acq_rel, almemory_order_acquire))
169 return AL_STOPPED;
170 return state;
172 return ATOMIC_LOAD(&source->state, almemory_order_acquire);
176 * Returns if the source should specify an update, given the context's
177 * deferring state and the source's last known state.
179 static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context)
181 return !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) &&
182 IsPlayingOrPaused(source);
185 static ALint FloatValsByProp(ALenum prop)
187 if(prop != (ALenum)((SourceProp)prop))
188 return 0;
189 switch((SourceProp)prop)
191 case AL_PITCH:
192 case AL_GAIN:
193 case AL_MIN_GAIN:
194 case AL_MAX_GAIN:
195 case AL_MAX_DISTANCE:
196 case AL_ROLLOFF_FACTOR:
197 case AL_DOPPLER_FACTOR:
198 case AL_CONE_OUTER_GAIN:
199 case AL_SEC_OFFSET:
200 case AL_SAMPLE_OFFSET:
201 case AL_BYTE_OFFSET:
202 case AL_CONE_INNER_ANGLE:
203 case AL_CONE_OUTER_ANGLE:
204 case AL_REFERENCE_DISTANCE:
205 case AL_CONE_OUTER_GAINHF:
206 case AL_AIR_ABSORPTION_FACTOR:
207 case AL_ROOM_ROLLOFF_FACTOR:
208 case AL_DIRECT_FILTER_GAINHF_AUTO:
209 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
210 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
211 case AL_DIRECT_CHANNELS_SOFT:
212 case AL_DISTANCE_MODEL:
213 case AL_SOURCE_RELATIVE:
214 case AL_LOOPING:
215 case AL_SOURCE_STATE:
216 case AL_BUFFERS_QUEUED:
217 case AL_BUFFERS_PROCESSED:
218 case AL_SOURCE_TYPE:
219 case AL_BYTE_LENGTH_SOFT:
220 case AL_SAMPLE_LENGTH_SOFT:
221 case AL_SEC_LENGTH_SOFT:
222 case AL_SOURCE_RADIUS:
223 case AL_SOURCE_RESAMPLER_SOFT:
224 case AL_SOURCE_SPATIALIZE_SOFT:
225 return 1;
227 case AL_STEREO_ANGLES:
228 return 2;
230 case AL_POSITION:
231 case AL_VELOCITY:
232 case AL_DIRECTION:
233 return 3;
235 case AL_ORIENTATION:
236 return 6;
238 case AL_SEC_OFFSET_LATENCY_SOFT:
239 break; /* Double only */
241 case AL_BUFFER:
242 case AL_DIRECT_FILTER:
243 case AL_AUXILIARY_SEND_FILTER:
244 break; /* i/i64 only */
245 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
246 break; /* i64 only */
248 return 0;
250 static ALint DoubleValsByProp(ALenum prop)
252 if(prop != (ALenum)((SourceProp)prop))
253 return 0;
254 switch((SourceProp)prop)
256 case AL_PITCH:
257 case AL_GAIN:
258 case AL_MIN_GAIN:
259 case AL_MAX_GAIN:
260 case AL_MAX_DISTANCE:
261 case AL_ROLLOFF_FACTOR:
262 case AL_DOPPLER_FACTOR:
263 case AL_CONE_OUTER_GAIN:
264 case AL_SEC_OFFSET:
265 case AL_SAMPLE_OFFSET:
266 case AL_BYTE_OFFSET:
267 case AL_CONE_INNER_ANGLE:
268 case AL_CONE_OUTER_ANGLE:
269 case AL_REFERENCE_DISTANCE:
270 case AL_CONE_OUTER_GAINHF:
271 case AL_AIR_ABSORPTION_FACTOR:
272 case AL_ROOM_ROLLOFF_FACTOR:
273 case AL_DIRECT_FILTER_GAINHF_AUTO:
274 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
275 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
276 case AL_DIRECT_CHANNELS_SOFT:
277 case AL_DISTANCE_MODEL:
278 case AL_SOURCE_RELATIVE:
279 case AL_LOOPING:
280 case AL_SOURCE_STATE:
281 case AL_BUFFERS_QUEUED:
282 case AL_BUFFERS_PROCESSED:
283 case AL_SOURCE_TYPE:
284 case AL_BYTE_LENGTH_SOFT:
285 case AL_SAMPLE_LENGTH_SOFT:
286 case AL_SEC_LENGTH_SOFT:
287 case AL_SOURCE_RADIUS:
288 case AL_SOURCE_RESAMPLER_SOFT:
289 case AL_SOURCE_SPATIALIZE_SOFT:
290 return 1;
292 case AL_SEC_OFFSET_LATENCY_SOFT:
293 case AL_STEREO_ANGLES:
294 return 2;
296 case AL_POSITION:
297 case AL_VELOCITY:
298 case AL_DIRECTION:
299 return 3;
301 case AL_ORIENTATION:
302 return 6;
304 case AL_BUFFER:
305 case AL_DIRECT_FILTER:
306 case AL_AUXILIARY_SEND_FILTER:
307 break; /* i/i64 only */
308 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
309 break; /* i64 only */
311 return 0;
314 static ALint IntValsByProp(ALenum prop)
316 if(prop != (ALenum)((SourceProp)prop))
317 return 0;
318 switch((SourceProp)prop)
320 case AL_PITCH:
321 case AL_GAIN:
322 case AL_MIN_GAIN:
323 case AL_MAX_GAIN:
324 case AL_MAX_DISTANCE:
325 case AL_ROLLOFF_FACTOR:
326 case AL_DOPPLER_FACTOR:
327 case AL_CONE_OUTER_GAIN:
328 case AL_SEC_OFFSET:
329 case AL_SAMPLE_OFFSET:
330 case AL_BYTE_OFFSET:
331 case AL_CONE_INNER_ANGLE:
332 case AL_CONE_OUTER_ANGLE:
333 case AL_REFERENCE_DISTANCE:
334 case AL_CONE_OUTER_GAINHF:
335 case AL_AIR_ABSORPTION_FACTOR:
336 case AL_ROOM_ROLLOFF_FACTOR:
337 case AL_DIRECT_FILTER_GAINHF_AUTO:
338 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
339 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
340 case AL_DIRECT_CHANNELS_SOFT:
341 case AL_DISTANCE_MODEL:
342 case AL_SOURCE_RELATIVE:
343 case AL_LOOPING:
344 case AL_BUFFER:
345 case AL_SOURCE_STATE:
346 case AL_BUFFERS_QUEUED:
347 case AL_BUFFERS_PROCESSED:
348 case AL_SOURCE_TYPE:
349 case AL_DIRECT_FILTER:
350 case AL_BYTE_LENGTH_SOFT:
351 case AL_SAMPLE_LENGTH_SOFT:
352 case AL_SEC_LENGTH_SOFT:
353 case AL_SOURCE_RADIUS:
354 case AL_SOURCE_RESAMPLER_SOFT:
355 case AL_SOURCE_SPATIALIZE_SOFT:
356 return 1;
358 case AL_POSITION:
359 case AL_VELOCITY:
360 case AL_DIRECTION:
361 case AL_AUXILIARY_SEND_FILTER:
362 return 3;
364 case AL_ORIENTATION:
365 return 6;
367 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
368 break; /* i64 only */
369 case AL_SEC_OFFSET_LATENCY_SOFT:
370 break; /* Double only */
371 case AL_STEREO_ANGLES:
372 break; /* Float/double only */
374 return 0;
376 static ALint Int64ValsByProp(ALenum prop)
378 if(prop != (ALenum)((SourceProp)prop))
379 return 0;
380 switch((SourceProp)prop)
382 case AL_PITCH:
383 case AL_GAIN:
384 case AL_MIN_GAIN:
385 case AL_MAX_GAIN:
386 case AL_MAX_DISTANCE:
387 case AL_ROLLOFF_FACTOR:
388 case AL_DOPPLER_FACTOR:
389 case AL_CONE_OUTER_GAIN:
390 case AL_SEC_OFFSET:
391 case AL_SAMPLE_OFFSET:
392 case AL_BYTE_OFFSET:
393 case AL_CONE_INNER_ANGLE:
394 case AL_CONE_OUTER_ANGLE:
395 case AL_REFERENCE_DISTANCE:
396 case AL_CONE_OUTER_GAINHF:
397 case AL_AIR_ABSORPTION_FACTOR:
398 case AL_ROOM_ROLLOFF_FACTOR:
399 case AL_DIRECT_FILTER_GAINHF_AUTO:
400 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
401 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
402 case AL_DIRECT_CHANNELS_SOFT:
403 case AL_DISTANCE_MODEL:
404 case AL_SOURCE_RELATIVE:
405 case AL_LOOPING:
406 case AL_BUFFER:
407 case AL_SOURCE_STATE:
408 case AL_BUFFERS_QUEUED:
409 case AL_BUFFERS_PROCESSED:
410 case AL_SOURCE_TYPE:
411 case AL_DIRECT_FILTER:
412 case AL_BYTE_LENGTH_SOFT:
413 case AL_SAMPLE_LENGTH_SOFT:
414 case AL_SEC_LENGTH_SOFT:
415 case AL_SOURCE_RADIUS:
416 case AL_SOURCE_RESAMPLER_SOFT:
417 case AL_SOURCE_SPATIALIZE_SOFT:
418 return 1;
420 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
421 return 2;
423 case AL_POSITION:
424 case AL_VELOCITY:
425 case AL_DIRECTION:
426 case AL_AUXILIARY_SEND_FILTER:
427 return 3;
429 case AL_ORIENTATION:
430 return 6;
432 case AL_SEC_OFFSET_LATENCY_SOFT:
433 break; /* Double only */
434 case AL_STEREO_ANGLES:
435 break; /* Float/double only */
437 return 0;
441 #define CHECKVAL(x) do { \
442 if(!(x)) \
443 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
444 } while(0)
446 #define DO_UPDATEPROPS() do { \
447 ALvoice *voice; \
448 if(SourceShouldUpdate(Source, Context) && \
449 (voice=GetSourceVoice(Source, Context)) != NULL) \
450 UpdateSourceProps(Source, voice, device->NumAuxSends); \
451 else \
452 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \
453 } while(0)
455 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
457 ALCdevice *device = Context->Device;
458 ALint ival;
460 switch(prop)
462 case AL_BYTE_LENGTH_SOFT:
463 case AL_SAMPLE_LENGTH_SOFT:
464 case AL_SEC_LENGTH_SOFT:
465 case AL_SEC_OFFSET_LATENCY_SOFT:
466 /* Query only */
467 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
469 case AL_PITCH:
470 CHECKVAL(*values >= 0.0f);
472 Source->Pitch = *values;
473 DO_UPDATEPROPS();
474 return AL_TRUE;
476 case AL_CONE_INNER_ANGLE:
477 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
479 Source->InnerAngle = *values;
480 DO_UPDATEPROPS();
481 return AL_TRUE;
483 case AL_CONE_OUTER_ANGLE:
484 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
486 Source->OuterAngle = *values;
487 DO_UPDATEPROPS();
488 return AL_TRUE;
490 case AL_GAIN:
491 CHECKVAL(*values >= 0.0f);
493 Source->Gain = *values;
494 DO_UPDATEPROPS();
495 return AL_TRUE;
497 case AL_MAX_DISTANCE:
498 CHECKVAL(*values >= 0.0f);
500 Source->MaxDistance = *values;
501 DO_UPDATEPROPS();
502 return AL_TRUE;
504 case AL_ROLLOFF_FACTOR:
505 CHECKVAL(*values >= 0.0f);
507 Source->RolloffFactor = *values;
508 DO_UPDATEPROPS();
509 return AL_TRUE;
511 case AL_REFERENCE_DISTANCE:
512 CHECKVAL(*values >= 0.0f);
514 Source->RefDistance = *values;
515 DO_UPDATEPROPS();
516 return AL_TRUE;
518 case AL_MIN_GAIN:
519 CHECKVAL(*values >= 0.0f);
521 Source->MinGain = *values;
522 DO_UPDATEPROPS();
523 return AL_TRUE;
525 case AL_MAX_GAIN:
526 CHECKVAL(*values >= 0.0f);
528 Source->MaxGain = *values;
529 DO_UPDATEPROPS();
530 return AL_TRUE;
532 case AL_CONE_OUTER_GAIN:
533 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
535 Source->OuterGain = *values;
536 DO_UPDATEPROPS();
537 return AL_TRUE;
539 case AL_CONE_OUTER_GAINHF:
540 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
542 Source->OuterGainHF = *values;
543 DO_UPDATEPROPS();
544 return AL_TRUE;
546 case AL_AIR_ABSORPTION_FACTOR:
547 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
549 Source->AirAbsorptionFactor = *values;
550 DO_UPDATEPROPS();
551 return AL_TRUE;
553 case AL_ROOM_ROLLOFF_FACTOR:
554 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
556 Source->RoomRolloffFactor = *values;
557 DO_UPDATEPROPS();
558 return AL_TRUE;
560 case AL_DOPPLER_FACTOR:
561 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
563 Source->DopplerFactor = *values;
564 DO_UPDATEPROPS();
565 return AL_TRUE;
567 case AL_SEC_OFFSET:
568 case AL_SAMPLE_OFFSET:
569 case AL_BYTE_OFFSET:
570 CHECKVAL(*values >= 0.0f);
572 Source->OffsetType = prop;
573 Source->Offset = *values;
575 if(IsPlayingOrPaused(Source))
577 ALvoice *voice;
579 ALCdevice_Lock(Context->Device);
580 /* Double-check that the source is still playing while we have
581 * the lock.
583 voice = GetSourceVoice(Source, Context);
584 if(voice)
586 WriteLock(&Source->queue_lock);
587 if(ApplyOffset(Source, voice) == AL_FALSE)
589 WriteUnlock(&Source->queue_lock);
590 ALCdevice_Unlock(Context->Device);
591 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
593 WriteUnlock(&Source->queue_lock);
595 ALCdevice_Unlock(Context->Device);
597 return AL_TRUE;
599 case AL_SOURCE_RADIUS:
600 CHECKVAL(*values >= 0.0f && isfinite(*values));
602 Source->Radius = *values;
603 DO_UPDATEPROPS();
604 return AL_TRUE;
606 case AL_STEREO_ANGLES:
607 CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
609 Source->StereoPan[0] = values[0];
610 Source->StereoPan[1] = values[1];
611 DO_UPDATEPROPS();
612 return AL_TRUE;
615 case AL_POSITION:
616 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
618 Source->Position[0] = values[0];
619 Source->Position[1] = values[1];
620 Source->Position[2] = values[2];
621 DO_UPDATEPROPS();
622 return AL_TRUE;
624 case AL_VELOCITY:
625 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
627 Source->Velocity[0] = values[0];
628 Source->Velocity[1] = values[1];
629 Source->Velocity[2] = values[2];
630 DO_UPDATEPROPS();
631 return AL_TRUE;
633 case AL_DIRECTION:
634 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
636 Source->Direction[0] = values[0];
637 Source->Direction[1] = values[1];
638 Source->Direction[2] = values[2];
639 DO_UPDATEPROPS();
640 return AL_TRUE;
642 case AL_ORIENTATION:
643 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
644 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
646 Source->Orientation[0][0] = values[0];
647 Source->Orientation[0][1] = values[1];
648 Source->Orientation[0][2] = values[2];
649 Source->Orientation[1][0] = values[3];
650 Source->Orientation[1][1] = values[4];
651 Source->Orientation[1][2] = values[5];
652 DO_UPDATEPROPS();
653 return AL_TRUE;
656 case AL_SOURCE_RELATIVE:
657 case AL_LOOPING:
658 case AL_SOURCE_STATE:
659 case AL_SOURCE_TYPE:
660 case AL_DISTANCE_MODEL:
661 case AL_DIRECT_FILTER_GAINHF_AUTO:
662 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
663 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
664 case AL_DIRECT_CHANNELS_SOFT:
665 case AL_SOURCE_RESAMPLER_SOFT:
666 case AL_SOURCE_SPATIALIZE_SOFT:
667 ival = (ALint)values[0];
668 return SetSourceiv(Source, Context, prop, &ival);
670 case AL_BUFFERS_QUEUED:
671 case AL_BUFFERS_PROCESSED:
672 ival = (ALint)((ALuint)values[0]);
673 return SetSourceiv(Source, Context, prop, &ival);
675 case AL_BUFFER:
676 case AL_DIRECT_FILTER:
677 case AL_AUXILIARY_SEND_FILTER:
678 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
679 break;
682 ERR("Unexpected property: 0x%04x\n", prop);
683 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
686 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
688 ALCdevice *device = Context->Device;
689 ALbuffer *buffer = NULL;
690 ALfilter *filter = NULL;
691 ALeffectslot *slot = NULL;
692 ALbufferlistitem *oldlist;
693 ALfloat fvals[6];
695 switch(prop)
697 case AL_SOURCE_STATE:
698 case AL_SOURCE_TYPE:
699 case AL_BUFFERS_QUEUED:
700 case AL_BUFFERS_PROCESSED:
701 case AL_BYTE_LENGTH_SOFT:
702 case AL_SAMPLE_LENGTH_SOFT:
703 case AL_SEC_LENGTH_SOFT:
704 /* Query only */
705 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
707 case AL_SOURCE_RELATIVE:
708 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
710 Source->HeadRelative = (ALboolean)*values;
711 DO_UPDATEPROPS();
712 return AL_TRUE;
714 case AL_LOOPING:
715 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
717 WriteLock(&Source->queue_lock);
718 Source->Looping = (ALboolean)*values;
719 if(IsPlayingOrPaused(Source))
721 ALvoice *voice = GetSourceVoice(Source, Context);
722 if(voice)
724 if(Source->Looping)
725 ATOMIC_STORE(&voice->loop_buffer, Source->queue, almemory_order_release);
726 else
727 ATOMIC_STORE(&voice->loop_buffer, NULL, almemory_order_release);
729 /* If the source is playing, wait for the current mix to finish
730 * to ensure it isn't currently looping back or reaching the
731 * end.
733 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
734 althrd_yield();
737 WriteUnlock(&Source->queue_lock);
738 return AL_TRUE;
740 case AL_BUFFER:
741 LockBuffersRead(device);
742 if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
744 UnlockBuffersRead(device);
745 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
748 WriteLock(&Source->queue_lock);
750 ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context));
751 if(state == AL_PLAYING || state == AL_PAUSED)
753 WriteUnlock(&Source->queue_lock);
754 UnlockBuffersRead(device);
755 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
759 oldlist = Source->queue;
760 if(buffer != NULL)
762 /* Add the selected buffer to a one-item queue */
763 ALbufferlistitem *newlist = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
764 newlist->buffer = buffer;
765 ATOMIC_INIT(&newlist->next, NULL);
766 IncrementRef(&buffer->ref);
768 /* Source is now Static */
769 Source->SourceType = AL_STATIC;
770 Source->queue = newlist;
772 else
774 /* Source is now Undetermined */
775 Source->SourceType = AL_UNDETERMINED;
776 Source->queue = NULL;
778 WriteUnlock(&Source->queue_lock);
779 UnlockBuffersRead(device);
781 /* Delete all elements in the previous queue */
782 while(oldlist != NULL)
784 ALbufferlistitem *temp = oldlist;
785 oldlist = ATOMIC_LOAD(&temp->next, almemory_order_relaxed);
787 if(temp->buffer)
788 DecrementRef(&temp->buffer->ref);
789 al_free(temp);
791 return AL_TRUE;
793 case AL_SEC_OFFSET:
794 case AL_SAMPLE_OFFSET:
795 case AL_BYTE_OFFSET:
796 CHECKVAL(*values >= 0);
798 Source->OffsetType = prop;
799 Source->Offset = *values;
801 if(IsPlayingOrPaused(Source))
803 ALvoice *voice;
805 ALCdevice_Lock(Context->Device);
806 voice = GetSourceVoice(Source, Context);
807 if(voice)
809 WriteLock(&Source->queue_lock);
810 if(ApplyOffset(Source, voice) == AL_FALSE)
812 WriteUnlock(&Source->queue_lock);
813 ALCdevice_Unlock(Context->Device);
814 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
816 WriteUnlock(&Source->queue_lock);
818 ALCdevice_Unlock(Context->Device);
820 return AL_TRUE;
822 case AL_DIRECT_FILTER:
823 LockFiltersRead(device);
824 if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
826 UnlockFiltersRead(device);
827 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
830 if(!filter)
832 Source->Direct.Gain = 1.0f;
833 Source->Direct.GainHF = 1.0f;
834 Source->Direct.HFReference = LOWPASSFREQREF;
835 Source->Direct.GainLF = 1.0f;
836 Source->Direct.LFReference = HIGHPASSFREQREF;
838 else
840 Source->Direct.Gain = filter->Gain;
841 Source->Direct.GainHF = filter->GainHF;
842 Source->Direct.HFReference = filter->HFReference;
843 Source->Direct.GainLF = filter->GainLF;
844 Source->Direct.LFReference = filter->LFReference;
846 UnlockFiltersRead(device);
847 DO_UPDATEPROPS();
848 return AL_TRUE;
850 case AL_DIRECT_FILTER_GAINHF_AUTO:
851 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
853 Source->DryGainHFAuto = *values;
854 DO_UPDATEPROPS();
855 return AL_TRUE;
857 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
858 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
860 Source->WetGainAuto = *values;
861 DO_UPDATEPROPS();
862 return AL_TRUE;
864 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
865 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
867 Source->WetGainHFAuto = *values;
868 DO_UPDATEPROPS();
869 return AL_TRUE;
871 case AL_DIRECT_CHANNELS_SOFT:
872 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
874 Source->DirectChannels = *values;
875 DO_UPDATEPROPS();
876 return AL_TRUE;
878 case AL_DISTANCE_MODEL:
879 CHECKVAL(*values == AL_NONE ||
880 *values == AL_INVERSE_DISTANCE ||
881 *values == AL_INVERSE_DISTANCE_CLAMPED ||
882 *values == AL_LINEAR_DISTANCE ||
883 *values == AL_LINEAR_DISTANCE_CLAMPED ||
884 *values == AL_EXPONENT_DISTANCE ||
885 *values == AL_EXPONENT_DISTANCE_CLAMPED);
887 Source->DistanceModel = *values;
888 if(Context->SourceDistanceModel)
889 DO_UPDATEPROPS();
890 return AL_TRUE;
892 case AL_SOURCE_RESAMPLER_SOFT:
893 CHECKVAL(*values >= 0 && *values <= ResamplerMax);
895 Source->Resampler = *values;
896 DO_UPDATEPROPS();
897 return AL_TRUE;
899 case AL_SOURCE_SPATIALIZE_SOFT:
900 CHECKVAL(*values >= AL_FALSE && *values <= AL_AUTO_SOFT);
902 Source->Spatialize = *values;
903 DO_UPDATEPROPS();
904 return AL_TRUE;
907 case AL_AUXILIARY_SEND_FILTER:
908 LockEffectSlotsRead(Context);
909 LockFiltersRead(device);
910 if(!((ALuint)values[1] < (ALuint)device->NumAuxSends &&
911 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
912 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
914 UnlockFiltersRead(device);
915 UnlockEffectSlotsRead(Context);
916 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
919 if(!filter)
921 /* Disable filter */
922 Source->Send[values[1]].Gain = 1.0f;
923 Source->Send[values[1]].GainHF = 1.0f;
924 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
925 Source->Send[values[1]].GainLF = 1.0f;
926 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
928 else
930 Source->Send[values[1]].Gain = filter->Gain;
931 Source->Send[values[1]].GainHF = filter->GainHF;
932 Source->Send[values[1]].HFReference = filter->HFReference;
933 Source->Send[values[1]].GainLF = filter->GainLF;
934 Source->Send[values[1]].LFReference = filter->LFReference;
936 UnlockFiltersRead(device);
938 if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source))
940 ALvoice *voice;
941 /* Add refcount on the new slot, and release the previous slot */
942 if(slot) IncrementRef(&slot->ref);
943 if(Source->Send[values[1]].Slot)
944 DecrementRef(&Source->Send[values[1]].Slot->ref);
945 Source->Send[values[1]].Slot = slot;
947 /* We must force an update if the auxiliary slot changed on an
948 * active source, in case the slot is about to be deleted.
950 if((voice=GetSourceVoice(Source, Context)) != NULL)
951 UpdateSourceProps(Source, voice, device->NumAuxSends);
952 else
953 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release);
955 else
957 if(slot) IncrementRef(&slot->ref);
958 if(Source->Send[values[1]].Slot)
959 DecrementRef(&Source->Send[values[1]].Slot->ref);
960 Source->Send[values[1]].Slot = slot;
961 DO_UPDATEPROPS();
963 UnlockEffectSlotsRead(Context);
965 return AL_TRUE;
968 /* 1x float */
969 case AL_CONE_INNER_ANGLE:
970 case AL_CONE_OUTER_ANGLE:
971 case AL_PITCH:
972 case AL_GAIN:
973 case AL_MIN_GAIN:
974 case AL_MAX_GAIN:
975 case AL_REFERENCE_DISTANCE:
976 case AL_ROLLOFF_FACTOR:
977 case AL_CONE_OUTER_GAIN:
978 case AL_MAX_DISTANCE:
979 case AL_DOPPLER_FACTOR:
980 case AL_CONE_OUTER_GAINHF:
981 case AL_AIR_ABSORPTION_FACTOR:
982 case AL_ROOM_ROLLOFF_FACTOR:
983 case AL_SOURCE_RADIUS:
984 fvals[0] = (ALfloat)*values;
985 return SetSourcefv(Source, Context, (int)prop, fvals);
987 /* 3x float */
988 case AL_POSITION:
989 case AL_VELOCITY:
990 case AL_DIRECTION:
991 fvals[0] = (ALfloat)values[0];
992 fvals[1] = (ALfloat)values[1];
993 fvals[2] = (ALfloat)values[2];
994 return SetSourcefv(Source, Context, (int)prop, fvals);
996 /* 6x float */
997 case AL_ORIENTATION:
998 fvals[0] = (ALfloat)values[0];
999 fvals[1] = (ALfloat)values[1];
1000 fvals[2] = (ALfloat)values[2];
1001 fvals[3] = (ALfloat)values[3];
1002 fvals[4] = (ALfloat)values[4];
1003 fvals[5] = (ALfloat)values[5];
1004 return SetSourcefv(Source, Context, (int)prop, fvals);
1006 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1007 case AL_SEC_OFFSET_LATENCY_SOFT:
1008 case AL_STEREO_ANGLES:
1009 break;
1012 ERR("Unexpected property: 0x%04x\n", prop);
1013 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1016 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
1018 ALfloat fvals[6];
1019 ALint ivals[3];
1021 switch(prop)
1023 case AL_SOURCE_TYPE:
1024 case AL_BUFFERS_QUEUED:
1025 case AL_BUFFERS_PROCESSED:
1026 case AL_SOURCE_STATE:
1027 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1028 case AL_BYTE_LENGTH_SOFT:
1029 case AL_SAMPLE_LENGTH_SOFT:
1030 case AL_SEC_LENGTH_SOFT:
1031 /* Query only */
1032 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
1035 /* 1x int */
1036 case AL_SOURCE_RELATIVE:
1037 case AL_LOOPING:
1038 case AL_SEC_OFFSET:
1039 case AL_SAMPLE_OFFSET:
1040 case AL_BYTE_OFFSET:
1041 case AL_DIRECT_FILTER_GAINHF_AUTO:
1042 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1043 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1044 case AL_DIRECT_CHANNELS_SOFT:
1045 case AL_DISTANCE_MODEL:
1046 case AL_SOURCE_RESAMPLER_SOFT:
1047 case AL_SOURCE_SPATIALIZE_SOFT:
1048 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
1050 ivals[0] = (ALint)*values;
1051 return SetSourceiv(Source, Context, (int)prop, ivals);
1053 /* 1x uint */
1054 case AL_BUFFER:
1055 case AL_DIRECT_FILTER:
1056 CHECKVAL(*values <= UINT_MAX && *values >= 0);
1058 ivals[0] = (ALuint)*values;
1059 return SetSourceiv(Source, Context, (int)prop, ivals);
1061 /* 3x uint */
1062 case AL_AUXILIARY_SEND_FILTER:
1063 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
1064 values[1] <= UINT_MAX && values[1] >= 0 &&
1065 values[2] <= UINT_MAX && values[2] >= 0);
1067 ivals[0] = (ALuint)values[0];
1068 ivals[1] = (ALuint)values[1];
1069 ivals[2] = (ALuint)values[2];
1070 return SetSourceiv(Source, Context, (int)prop, ivals);
1072 /* 1x float */
1073 case AL_CONE_INNER_ANGLE:
1074 case AL_CONE_OUTER_ANGLE:
1075 case AL_PITCH:
1076 case AL_GAIN:
1077 case AL_MIN_GAIN:
1078 case AL_MAX_GAIN:
1079 case AL_REFERENCE_DISTANCE:
1080 case AL_ROLLOFF_FACTOR:
1081 case AL_CONE_OUTER_GAIN:
1082 case AL_MAX_DISTANCE:
1083 case AL_DOPPLER_FACTOR:
1084 case AL_CONE_OUTER_GAINHF:
1085 case AL_AIR_ABSORPTION_FACTOR:
1086 case AL_ROOM_ROLLOFF_FACTOR:
1087 case AL_SOURCE_RADIUS:
1088 fvals[0] = (ALfloat)*values;
1089 return SetSourcefv(Source, Context, (int)prop, fvals);
1091 /* 3x float */
1092 case AL_POSITION:
1093 case AL_VELOCITY:
1094 case AL_DIRECTION:
1095 fvals[0] = (ALfloat)values[0];
1096 fvals[1] = (ALfloat)values[1];
1097 fvals[2] = (ALfloat)values[2];
1098 return SetSourcefv(Source, Context, (int)prop, fvals);
1100 /* 6x float */
1101 case AL_ORIENTATION:
1102 fvals[0] = (ALfloat)values[0];
1103 fvals[1] = (ALfloat)values[1];
1104 fvals[2] = (ALfloat)values[2];
1105 fvals[3] = (ALfloat)values[3];
1106 fvals[4] = (ALfloat)values[4];
1107 fvals[5] = (ALfloat)values[5];
1108 return SetSourcefv(Source, Context, (int)prop, fvals);
1110 case AL_SEC_OFFSET_LATENCY_SOFT:
1111 case AL_STEREO_ANGLES:
1112 break;
1115 ERR("Unexpected property: 0x%04x\n", prop);
1116 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1119 #undef CHECKVAL
1122 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
1124 ALCdevice *device = Context->Device;
1125 ALbufferlistitem *BufferList;
1126 ClockLatency clocktime;
1127 ALuint64 srcclock;
1128 ALint ivals[3];
1129 ALboolean err;
1131 switch(prop)
1133 case AL_GAIN:
1134 *values = Source->Gain;
1135 return AL_TRUE;
1137 case AL_PITCH:
1138 *values = Source->Pitch;
1139 return AL_TRUE;
1141 case AL_MAX_DISTANCE:
1142 *values = Source->MaxDistance;
1143 return AL_TRUE;
1145 case AL_ROLLOFF_FACTOR:
1146 *values = Source->RolloffFactor;
1147 return AL_TRUE;
1149 case AL_REFERENCE_DISTANCE:
1150 *values = Source->RefDistance;
1151 return AL_TRUE;
1153 case AL_CONE_INNER_ANGLE:
1154 *values = Source->InnerAngle;
1155 return AL_TRUE;
1157 case AL_CONE_OUTER_ANGLE:
1158 *values = Source->OuterAngle;
1159 return AL_TRUE;
1161 case AL_MIN_GAIN:
1162 *values = Source->MinGain;
1163 return AL_TRUE;
1165 case AL_MAX_GAIN:
1166 *values = Source->MaxGain;
1167 return AL_TRUE;
1169 case AL_CONE_OUTER_GAIN:
1170 *values = Source->OuterGain;
1171 return AL_TRUE;
1173 case AL_SEC_OFFSET:
1174 case AL_SAMPLE_OFFSET:
1175 case AL_BYTE_OFFSET:
1176 *values = GetSourceOffset(Source, prop, Context);
1177 return AL_TRUE;
1179 case AL_CONE_OUTER_GAINHF:
1180 *values = Source->OuterGainHF;
1181 return AL_TRUE;
1183 case AL_AIR_ABSORPTION_FACTOR:
1184 *values = Source->AirAbsorptionFactor;
1185 return AL_TRUE;
1187 case AL_ROOM_ROLLOFF_FACTOR:
1188 *values = Source->RoomRolloffFactor;
1189 return AL_TRUE;
1191 case AL_DOPPLER_FACTOR:
1192 *values = Source->DopplerFactor;
1193 return AL_TRUE;
1195 case AL_SEC_LENGTH_SOFT:
1196 ReadLock(&Source->queue_lock);
1197 if(!(BufferList=Source->queue))
1198 *values = 0;
1199 else
1201 ALint length = 0;
1202 ALsizei freq = 1;
1203 do {
1204 ALbuffer *buffer = BufferList->buffer;
1205 if(buffer && buffer->SampleLen > 0)
1207 freq = buffer->Frequency;
1208 length += buffer->SampleLen;
1210 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
1211 } while(BufferList != NULL);
1212 *values = (ALdouble)length / (ALdouble)freq;
1214 ReadUnlock(&Source->queue_lock);
1215 return AL_TRUE;
1217 case AL_SOURCE_RADIUS:
1218 *values = Source->Radius;
1219 return AL_TRUE;
1221 case AL_STEREO_ANGLES:
1222 values[0] = Source->StereoPan[0];
1223 values[1] = Source->StereoPan[1];
1224 return AL_TRUE;
1226 case AL_SEC_OFFSET_LATENCY_SOFT:
1227 /* Get the source offset with the clock time first. Then get the
1228 * clock time with the device latency. Order is important.
1230 values[0] = GetSourceSecOffset(Source, Context, &srcclock);
1231 clocktime = V0(device->Backend,getClockLatency)();
1232 if(srcclock == (ALuint64)clocktime.ClockTime)
1233 values[1] = (ALdouble)clocktime.Latency / 1000000000.0;
1234 else
1236 /* If the clock time incremented, reduce the latency by that
1237 * much since it's that much closer to the source offset it got
1238 * earlier.
1240 ALuint64 diff = clocktime.ClockTime - srcclock;
1241 values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) /
1242 1000000000.0;
1244 return AL_TRUE;
1246 case AL_POSITION:
1247 values[0] = Source->Position[0];
1248 values[1] = Source->Position[1];
1249 values[2] = Source->Position[2];
1250 return AL_TRUE;
1252 case AL_VELOCITY:
1253 values[0] = Source->Velocity[0];
1254 values[1] = Source->Velocity[1];
1255 values[2] = Source->Velocity[2];
1256 return AL_TRUE;
1258 case AL_DIRECTION:
1259 values[0] = Source->Direction[0];
1260 values[1] = Source->Direction[1];
1261 values[2] = Source->Direction[2];
1262 return AL_TRUE;
1264 case AL_ORIENTATION:
1265 values[0] = Source->Orientation[0][0];
1266 values[1] = Source->Orientation[0][1];
1267 values[2] = Source->Orientation[0][2];
1268 values[3] = Source->Orientation[1][0];
1269 values[4] = Source->Orientation[1][1];
1270 values[5] = Source->Orientation[1][2];
1271 return AL_TRUE;
1273 /* 1x int */
1274 case AL_SOURCE_RELATIVE:
1275 case AL_LOOPING:
1276 case AL_SOURCE_STATE:
1277 case AL_BUFFERS_QUEUED:
1278 case AL_BUFFERS_PROCESSED:
1279 case AL_SOURCE_TYPE:
1280 case AL_DIRECT_FILTER_GAINHF_AUTO:
1281 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1282 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1283 case AL_DIRECT_CHANNELS_SOFT:
1284 case AL_BYTE_LENGTH_SOFT:
1285 case AL_SAMPLE_LENGTH_SOFT:
1286 case AL_DISTANCE_MODEL:
1287 case AL_SOURCE_RESAMPLER_SOFT:
1288 case AL_SOURCE_SPATIALIZE_SOFT:
1289 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1290 *values = (ALdouble)ivals[0];
1291 return err;
1293 case AL_BUFFER:
1294 case AL_DIRECT_FILTER:
1295 case AL_AUXILIARY_SEND_FILTER:
1296 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1297 break;
1300 ERR("Unexpected property: 0x%04x\n", prop);
1301 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1304 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1306 ALbufferlistitem *BufferList;
1307 ALdouble dvals[6];
1308 ALboolean err;
1310 switch(prop)
1312 case AL_SOURCE_RELATIVE:
1313 *values = Source->HeadRelative;
1314 return AL_TRUE;
1316 case AL_LOOPING:
1317 *values = Source->Looping;
1318 return AL_TRUE;
1320 case AL_BUFFER:
1321 ReadLock(&Source->queue_lock);
1322 BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : NULL;
1323 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1324 ReadUnlock(&Source->queue_lock);
1325 return AL_TRUE;
1327 case AL_SOURCE_STATE:
1328 *values = GetSourceState(Source, GetSourceVoice(Source, Context));
1329 return AL_TRUE;
1331 case AL_BYTE_LENGTH_SOFT:
1332 ReadLock(&Source->queue_lock);
1333 if(!(BufferList=Source->queue))
1334 *values = 0;
1335 else
1337 ALint length = 0;
1338 do {
1339 ALbuffer *buffer = BufferList->buffer;
1340 if(buffer && buffer->SampleLen > 0)
1342 ALuint byte_align, sample_align;
1343 if(buffer->OriginalType == UserFmtIMA4)
1345 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1346 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1347 sample_align = buffer->OriginalAlign;
1349 else if(buffer->OriginalType == UserFmtMSADPCM)
1351 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1352 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1353 sample_align = buffer->OriginalAlign;
1355 else
1357 ALsizei align = buffer->OriginalAlign;
1358 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1359 sample_align = buffer->OriginalAlign;
1362 length += buffer->SampleLen / sample_align * byte_align;
1364 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
1365 } while(BufferList != NULL);
1366 *values = length;
1368 ReadUnlock(&Source->queue_lock);
1369 return AL_TRUE;
1371 case AL_SAMPLE_LENGTH_SOFT:
1372 ReadLock(&Source->queue_lock);
1373 if(!(BufferList=Source->queue))
1374 *values = 0;
1375 else
1377 ALint length = 0;
1378 do {
1379 ALbuffer *buffer = BufferList->buffer;
1380 if(buffer) length += buffer->SampleLen;
1381 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
1382 } while(BufferList != NULL);
1383 *values = length;
1385 ReadUnlock(&Source->queue_lock);
1386 return AL_TRUE;
1388 case AL_BUFFERS_QUEUED:
1389 ReadLock(&Source->queue_lock);
1390 if(!(BufferList=Source->queue))
1391 *values = 0;
1392 else
1394 ALsizei count = 0;
1395 do {
1396 ++count;
1397 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
1398 } while(BufferList != NULL);
1399 *values = count;
1401 ReadUnlock(&Source->queue_lock);
1402 return AL_TRUE;
1404 case AL_BUFFERS_PROCESSED:
1405 ReadLock(&Source->queue_lock);
1406 if(Source->Looping || Source->SourceType != AL_STREAMING)
1408 /* Buffers on a looping source are in a perpetual state of
1409 * PENDING, so don't report any as PROCESSED */
1410 *values = 0;
1412 else
1414 const ALbufferlistitem *BufferList = Source->queue;
1415 const ALbufferlistitem *Current = NULL;
1416 ALsizei played = 0;
1417 ALvoice *voice;
1419 if((voice=GetSourceVoice(Source, Context)) != NULL)
1420 Current = ATOMIC_LOAD_SEQ(&voice->current_buffer);
1421 else if(ATOMIC_LOAD_SEQ(&Source->state) == AL_INITIAL)
1422 Current = BufferList;
1424 while(BufferList && BufferList != Current)
1426 played++;
1427 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
1428 almemory_order_relaxed);
1430 *values = played;
1432 ReadUnlock(&Source->queue_lock);
1433 return AL_TRUE;
1435 case AL_SOURCE_TYPE:
1436 *values = Source->SourceType;
1437 return AL_TRUE;
1439 case AL_DIRECT_FILTER_GAINHF_AUTO:
1440 *values = Source->DryGainHFAuto;
1441 return AL_TRUE;
1443 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1444 *values = Source->WetGainAuto;
1445 return AL_TRUE;
1447 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1448 *values = Source->WetGainHFAuto;
1449 return AL_TRUE;
1451 case AL_DIRECT_CHANNELS_SOFT:
1452 *values = Source->DirectChannels;
1453 return AL_TRUE;
1455 case AL_DISTANCE_MODEL:
1456 *values = Source->DistanceModel;
1457 return AL_TRUE;
1459 case AL_SOURCE_RESAMPLER_SOFT:
1460 *values = Source->Resampler;
1461 return AL_TRUE;
1463 case AL_SOURCE_SPATIALIZE_SOFT:
1464 *values = Source->Spatialize;
1465 return AL_TRUE;
1467 /* 1x float/double */
1468 case AL_CONE_INNER_ANGLE:
1469 case AL_CONE_OUTER_ANGLE:
1470 case AL_PITCH:
1471 case AL_GAIN:
1472 case AL_MIN_GAIN:
1473 case AL_MAX_GAIN:
1474 case AL_REFERENCE_DISTANCE:
1475 case AL_ROLLOFF_FACTOR:
1476 case AL_CONE_OUTER_GAIN:
1477 case AL_MAX_DISTANCE:
1478 case AL_SEC_OFFSET:
1479 case AL_SAMPLE_OFFSET:
1480 case AL_BYTE_OFFSET:
1481 case AL_DOPPLER_FACTOR:
1482 case AL_AIR_ABSORPTION_FACTOR:
1483 case AL_ROOM_ROLLOFF_FACTOR:
1484 case AL_CONE_OUTER_GAINHF:
1485 case AL_SEC_LENGTH_SOFT:
1486 case AL_SOURCE_RADIUS:
1487 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1488 *values = (ALint)dvals[0];
1489 return err;
1491 /* 3x float/double */
1492 case AL_POSITION:
1493 case AL_VELOCITY:
1494 case AL_DIRECTION:
1495 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1497 values[0] = (ALint)dvals[0];
1498 values[1] = (ALint)dvals[1];
1499 values[2] = (ALint)dvals[2];
1501 return err;
1503 /* 6x float/double */
1504 case AL_ORIENTATION:
1505 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1507 values[0] = (ALint)dvals[0];
1508 values[1] = (ALint)dvals[1];
1509 values[2] = (ALint)dvals[2];
1510 values[3] = (ALint)dvals[3];
1511 values[4] = (ALint)dvals[4];
1512 values[5] = (ALint)dvals[5];
1514 return err;
1516 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1517 break; /* i64 only */
1518 case AL_SEC_OFFSET_LATENCY_SOFT:
1519 break; /* Double only */
1520 case AL_STEREO_ANGLES:
1521 break; /* Float/double only */
1523 case AL_DIRECT_FILTER:
1524 case AL_AUXILIARY_SEND_FILTER:
1525 break; /* ??? */
1528 ERR("Unexpected property: 0x%04x\n", prop);
1529 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1532 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1534 ALCdevice *device = Context->Device;
1535 ClockLatency clocktime;
1536 ALuint64 srcclock;
1537 ALdouble dvals[6];
1538 ALint ivals[3];
1539 ALboolean err;
1541 switch(prop)
1543 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1544 /* Get the source offset with the clock time first. Then get the
1545 * clock time with the device latency. Order is important.
1547 values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
1548 clocktime = V0(device->Backend,getClockLatency)();
1549 if(srcclock == (ALuint64)clocktime.ClockTime)
1550 values[1] = clocktime.Latency;
1551 else
1553 /* If the clock time incremented, reduce the latency by that
1554 * much since it's that much closer to the source offset it got
1555 * earlier.
1557 ALuint64 diff = clocktime.ClockTime - srcclock;
1558 values[1] = clocktime.Latency - minu64(clocktime.Latency, diff);
1560 return AL_TRUE;
1562 /* 1x float/double */
1563 case AL_CONE_INNER_ANGLE:
1564 case AL_CONE_OUTER_ANGLE:
1565 case AL_PITCH:
1566 case AL_GAIN:
1567 case AL_MIN_GAIN:
1568 case AL_MAX_GAIN:
1569 case AL_REFERENCE_DISTANCE:
1570 case AL_ROLLOFF_FACTOR:
1571 case AL_CONE_OUTER_GAIN:
1572 case AL_MAX_DISTANCE:
1573 case AL_SEC_OFFSET:
1574 case AL_SAMPLE_OFFSET:
1575 case AL_BYTE_OFFSET:
1576 case AL_DOPPLER_FACTOR:
1577 case AL_AIR_ABSORPTION_FACTOR:
1578 case AL_ROOM_ROLLOFF_FACTOR:
1579 case AL_CONE_OUTER_GAINHF:
1580 case AL_SEC_LENGTH_SOFT:
1581 case AL_SOURCE_RADIUS:
1582 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1583 *values = (ALint64)dvals[0];
1584 return err;
1586 /* 3x float/double */
1587 case AL_POSITION:
1588 case AL_VELOCITY:
1589 case AL_DIRECTION:
1590 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1592 values[0] = (ALint64)dvals[0];
1593 values[1] = (ALint64)dvals[1];
1594 values[2] = (ALint64)dvals[2];
1596 return err;
1598 /* 6x float/double */
1599 case AL_ORIENTATION:
1600 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1602 values[0] = (ALint64)dvals[0];
1603 values[1] = (ALint64)dvals[1];
1604 values[2] = (ALint64)dvals[2];
1605 values[3] = (ALint64)dvals[3];
1606 values[4] = (ALint64)dvals[4];
1607 values[5] = (ALint64)dvals[5];
1609 return err;
1611 /* 1x int */
1612 case AL_SOURCE_RELATIVE:
1613 case AL_LOOPING:
1614 case AL_SOURCE_STATE:
1615 case AL_BUFFERS_QUEUED:
1616 case AL_BUFFERS_PROCESSED:
1617 case AL_BYTE_LENGTH_SOFT:
1618 case AL_SAMPLE_LENGTH_SOFT:
1619 case AL_SOURCE_TYPE:
1620 case AL_DIRECT_FILTER_GAINHF_AUTO:
1621 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1622 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1623 case AL_DIRECT_CHANNELS_SOFT:
1624 case AL_DISTANCE_MODEL:
1625 case AL_SOURCE_RESAMPLER_SOFT:
1626 case AL_SOURCE_SPATIALIZE_SOFT:
1627 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1628 *values = ivals[0];
1629 return err;
1631 /* 1x uint */
1632 case AL_BUFFER:
1633 case AL_DIRECT_FILTER:
1634 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1635 *values = (ALuint)ivals[0];
1636 return err;
1638 /* 3x uint */
1639 case AL_AUXILIARY_SEND_FILTER:
1640 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1642 values[0] = (ALuint)ivals[0];
1643 values[1] = (ALuint)ivals[1];
1644 values[2] = (ALuint)ivals[2];
1646 return err;
1648 case AL_SEC_OFFSET_LATENCY_SOFT:
1649 break; /* Double only */
1650 case AL_STEREO_ANGLES:
1651 break; /* Float/double only */
1654 ERR("Unexpected property: 0x%04x\n", prop);
1655 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1659 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1661 ALCdevice *device;
1662 ALCcontext *context;
1663 ALsizei cur = 0;
1664 ALenum err;
1666 context = GetContextRef();
1667 if(!context) return;
1669 if(!(n >= 0))
1670 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1671 device = context->Device;
1672 for(cur = 0;cur < n;cur++)
1674 ALsource *source = al_calloc(16, sizeof(ALsource));
1675 if(!source)
1677 alDeleteSources(cur, sources);
1678 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1680 InitSourceParams(source, device->NumAuxSends);
1682 err = NewThunkEntry(&source->id);
1683 if(err == AL_NO_ERROR)
1684 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1685 if(err != AL_NO_ERROR)
1687 FreeThunkEntry(source->id);
1688 memset(source, 0, sizeof(ALsource));
1689 al_free(source);
1691 alDeleteSources(cur, sources);
1692 SET_ERROR_AND_GOTO(context, err, done);
1695 sources[cur] = source->id;
1698 done:
1699 ALCcontext_DecRef(context);
1703 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1705 ALCdevice *device;
1706 ALCcontext *context;
1707 ALsource *Source;
1708 ALsizei i;
1710 context = GetContextRef();
1711 if(!context) return;
1713 LockSourcesWrite(context);
1714 if(!(n >= 0))
1715 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1717 /* Check that all Sources are valid */
1718 for(i = 0;i < n;i++)
1720 if(LookupSource(context, sources[i]) == NULL)
1721 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1723 device = context->Device;
1724 for(i = 0;i < n;i++)
1726 ALvoice *voice;
1728 if((Source=RemoveSource(context, sources[i])) == NULL)
1729 continue;
1730 FreeThunkEntry(Source->id);
1732 ALCdevice_Lock(device);
1733 if((voice=GetSourceVoice(Source, context)) != NULL)
1735 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
1736 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
1738 ALCdevice_Unlock(device);
1740 DeinitSource(Source, device->NumAuxSends);
1742 memset(Source, 0, sizeof(*Source));
1743 al_free(Source);
1746 done:
1747 UnlockSourcesWrite(context);
1748 ALCcontext_DecRef(context);
1752 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1754 ALCcontext *context;
1755 ALboolean ret;
1757 context = GetContextRef();
1758 if(!context) return AL_FALSE;
1760 LockSourcesRead(context);
1761 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1762 UnlockSourcesRead(context);
1764 ALCcontext_DecRef(context);
1766 return ret;
1770 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat 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(!(FloatValsByProp(param) == 1))
1783 alSetError(Context, AL_INVALID_ENUM);
1784 else
1785 SetSourcefv(Source, Context, param, &value);
1786 UnlockSourcesRead(Context);
1787 WriteUnlock(&Context->PropLock);
1789 ALCcontext_DecRef(Context);
1792 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1794 ALCcontext *Context;
1795 ALsource *Source;
1797 Context = GetContextRef();
1798 if(!Context) return;
1800 WriteLock(&Context->PropLock);
1801 LockSourcesRead(Context);
1802 if((Source=LookupSource(Context, source)) == NULL)
1803 alSetError(Context, AL_INVALID_NAME);
1804 else if(!(FloatValsByProp(param) == 3))
1805 alSetError(Context, AL_INVALID_ENUM);
1806 else
1808 ALfloat fvals[3] = { value1, value2, value3 };
1809 SetSourcefv(Source, Context, param, fvals);
1811 UnlockSourcesRead(Context);
1812 WriteUnlock(&Context->PropLock);
1814 ALCcontext_DecRef(Context);
1817 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1819 ALCcontext *Context;
1820 ALsource *Source;
1822 Context = GetContextRef();
1823 if(!Context) return;
1825 WriteLock(&Context->PropLock);
1826 LockSourcesRead(Context);
1827 if((Source=LookupSource(Context, source)) == NULL)
1828 alSetError(Context, AL_INVALID_NAME);
1829 else if(!values)
1830 alSetError(Context, AL_INVALID_VALUE);
1831 else if(!(FloatValsByProp(param) > 0))
1832 alSetError(Context, AL_INVALID_ENUM);
1833 else
1834 SetSourcefv(Source, Context, param, values);
1835 UnlockSourcesRead(Context);
1836 WriteUnlock(&Context->PropLock);
1838 ALCcontext_DecRef(Context);
1842 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1844 ALCcontext *Context;
1845 ALsource *Source;
1847 Context = GetContextRef();
1848 if(!Context) return;
1850 WriteLock(&Context->PropLock);
1851 LockSourcesRead(Context);
1852 if((Source=LookupSource(Context, source)) == NULL)
1853 alSetError(Context, AL_INVALID_NAME);
1854 else if(!(DoubleValsByProp(param) == 1))
1855 alSetError(Context, AL_INVALID_ENUM);
1856 else
1858 ALfloat fval = (ALfloat)value;
1859 SetSourcefv(Source, Context, param, &fval);
1861 UnlockSourcesRead(Context);
1862 WriteUnlock(&Context->PropLock);
1864 ALCcontext_DecRef(Context);
1867 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1869 ALCcontext *Context;
1870 ALsource *Source;
1872 Context = GetContextRef();
1873 if(!Context) return;
1875 WriteLock(&Context->PropLock);
1876 LockSourcesRead(Context);
1877 if((Source=LookupSource(Context, source)) == NULL)
1878 alSetError(Context, AL_INVALID_NAME);
1879 else if(!(DoubleValsByProp(param) == 3))
1880 alSetError(Context, AL_INVALID_ENUM);
1881 else
1883 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1884 SetSourcefv(Source, Context, param, fvals);
1886 UnlockSourcesRead(Context);
1887 WriteUnlock(&Context->PropLock);
1889 ALCcontext_DecRef(Context);
1892 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1894 ALCcontext *Context;
1895 ALsource *Source;
1896 ALint count;
1898 Context = GetContextRef();
1899 if(!Context) return;
1901 WriteLock(&Context->PropLock);
1902 LockSourcesRead(Context);
1903 if((Source=LookupSource(Context, source)) == NULL)
1904 alSetError(Context, AL_INVALID_NAME);
1905 else if(!values)
1906 alSetError(Context, AL_INVALID_VALUE);
1907 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1908 alSetError(Context, AL_INVALID_ENUM);
1909 else
1911 ALfloat fvals[6];
1912 ALint i;
1914 for(i = 0;i < count;i++)
1915 fvals[i] = (ALfloat)values[i];
1916 SetSourcefv(Source, Context, param, fvals);
1918 UnlockSourcesRead(Context);
1919 WriteUnlock(&Context->PropLock);
1921 ALCcontext_DecRef(Context);
1925 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint 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(!(IntValsByProp(param) == 1))
1938 alSetError(Context, AL_INVALID_ENUM);
1939 else
1940 SetSourceiv(Source, Context, param, &value);
1941 UnlockSourcesRead(Context);
1942 WriteUnlock(&Context->PropLock);
1944 ALCcontext_DecRef(Context);
1947 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint 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(!(IntValsByProp(param) == 3))
1960 alSetError(Context, AL_INVALID_ENUM);
1961 else
1963 ALint ivals[3] = { value1, value2, value3 };
1964 SetSourceiv(Source, Context, param, ivals);
1966 UnlockSourcesRead(Context);
1967 WriteUnlock(&Context->PropLock);
1969 ALCcontext_DecRef(Context);
1972 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *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(!(IntValsByProp(param) > 0))
1987 alSetError(Context, AL_INVALID_ENUM);
1988 else
1989 SetSourceiv(Source, Context, param, values);
1990 UnlockSourcesRead(Context);
1991 WriteUnlock(&Context->PropLock);
1993 ALCcontext_DecRef(Context);
1997 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1999 ALCcontext *Context;
2000 ALsource *Source;
2002 Context = GetContextRef();
2003 if(!Context) return;
2005 WriteLock(&Context->PropLock);
2006 LockSourcesRead(Context);
2007 if((Source=LookupSource(Context, source)) == NULL)
2008 alSetError(Context, AL_INVALID_NAME);
2009 else if(!(Int64ValsByProp(param) == 1))
2010 alSetError(Context, AL_INVALID_ENUM);
2011 else
2012 SetSourcei64v(Source, Context, param, &value);
2013 UnlockSourcesRead(Context);
2014 WriteUnlock(&Context->PropLock);
2016 ALCcontext_DecRef(Context);
2019 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
2021 ALCcontext *Context;
2022 ALsource *Source;
2024 Context = GetContextRef();
2025 if(!Context) return;
2027 WriteLock(&Context->PropLock);
2028 LockSourcesRead(Context);
2029 if((Source=LookupSource(Context, source)) == NULL)
2030 alSetError(Context, AL_INVALID_NAME);
2031 else if(!(Int64ValsByProp(param) == 3))
2032 alSetError(Context, AL_INVALID_ENUM);
2033 else
2035 ALint64SOFT i64vals[3] = { value1, value2, value3 };
2036 SetSourcei64v(Source, Context, param, i64vals);
2038 UnlockSourcesRead(Context);
2039 WriteUnlock(&Context->PropLock);
2041 ALCcontext_DecRef(Context);
2044 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
2046 ALCcontext *Context;
2047 ALsource *Source;
2049 Context = GetContextRef();
2050 if(!Context) return;
2052 WriteLock(&Context->PropLock);
2053 LockSourcesRead(Context);
2054 if((Source=LookupSource(Context, source)) == NULL)
2055 alSetError(Context, AL_INVALID_NAME);
2056 else if(!values)
2057 alSetError(Context, AL_INVALID_VALUE);
2058 else if(!(Int64ValsByProp(param) > 0))
2059 alSetError(Context, AL_INVALID_ENUM);
2060 else
2061 SetSourcei64v(Source, Context, param, values);
2062 UnlockSourcesRead(Context);
2063 WriteUnlock(&Context->PropLock);
2065 ALCcontext_DecRef(Context);
2069 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
2071 ALCcontext *Context;
2072 ALsource *Source;
2074 Context = GetContextRef();
2075 if(!Context) return;
2077 ReadLock(&Context->PropLock);
2078 LockSourcesRead(Context);
2079 if((Source=LookupSource(Context, source)) == NULL)
2080 alSetError(Context, AL_INVALID_NAME);
2081 else if(!value)
2082 alSetError(Context, AL_INVALID_VALUE);
2083 else if(!(FloatValsByProp(param) == 1))
2084 alSetError(Context, AL_INVALID_ENUM);
2085 else
2087 ALdouble dval;
2088 if(GetSourcedv(Source, Context, param, &dval))
2089 *value = (ALfloat)dval;
2091 UnlockSourcesRead(Context);
2092 ReadUnlock(&Context->PropLock);
2094 ALCcontext_DecRef(Context);
2098 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
2100 ALCcontext *Context;
2101 ALsource *Source;
2103 Context = GetContextRef();
2104 if(!Context) return;
2106 ReadLock(&Context->PropLock);
2107 LockSourcesRead(Context);
2108 if((Source=LookupSource(Context, source)) == NULL)
2109 alSetError(Context, AL_INVALID_NAME);
2110 else if(!(value1 && value2 && value3))
2111 alSetError(Context, AL_INVALID_VALUE);
2112 else if(!(FloatValsByProp(param) == 3))
2113 alSetError(Context, AL_INVALID_ENUM);
2114 else
2116 ALdouble dvals[3];
2117 if(GetSourcedv(Source, Context, param, dvals))
2119 *value1 = (ALfloat)dvals[0];
2120 *value2 = (ALfloat)dvals[1];
2121 *value3 = (ALfloat)dvals[2];
2124 UnlockSourcesRead(Context);
2125 ReadUnlock(&Context->PropLock);
2127 ALCcontext_DecRef(Context);
2131 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
2133 ALCcontext *Context;
2134 ALsource *Source;
2135 ALint count;
2137 Context = GetContextRef();
2138 if(!Context) return;
2140 ReadLock(&Context->PropLock);
2141 LockSourcesRead(Context);
2142 if((Source=LookupSource(Context, source)) == NULL)
2143 alSetError(Context, AL_INVALID_NAME);
2144 else if(!values)
2145 alSetError(Context, AL_INVALID_VALUE);
2146 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
2147 alSetError(Context, AL_INVALID_ENUM);
2148 else
2150 ALdouble dvals[6];
2151 if(GetSourcedv(Source, Context, param, dvals))
2153 ALint i;
2154 for(i = 0;i < count;i++)
2155 values[i] = (ALfloat)dvals[i];
2158 UnlockSourcesRead(Context);
2159 ReadUnlock(&Context->PropLock);
2161 ALCcontext_DecRef(Context);
2165 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
2167 ALCcontext *Context;
2168 ALsource *Source;
2170 Context = GetContextRef();
2171 if(!Context) return;
2173 ReadLock(&Context->PropLock);
2174 LockSourcesRead(Context);
2175 if((Source=LookupSource(Context, source)) == NULL)
2176 alSetError(Context, AL_INVALID_NAME);
2177 else if(!value)
2178 alSetError(Context, AL_INVALID_VALUE);
2179 else if(!(DoubleValsByProp(param) == 1))
2180 alSetError(Context, AL_INVALID_ENUM);
2181 else
2182 GetSourcedv(Source, Context, param, value);
2183 UnlockSourcesRead(Context);
2184 ReadUnlock(&Context->PropLock);
2186 ALCcontext_DecRef(Context);
2189 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
2191 ALCcontext *Context;
2192 ALsource *Source;
2194 Context = GetContextRef();
2195 if(!Context) return;
2197 ReadLock(&Context->PropLock);
2198 LockSourcesRead(Context);
2199 if((Source=LookupSource(Context, source)) == NULL)
2200 alSetError(Context, AL_INVALID_NAME);
2201 else if(!(value1 && value2 && value3))
2202 alSetError(Context, AL_INVALID_VALUE);
2203 else if(!(DoubleValsByProp(param) == 3))
2204 alSetError(Context, AL_INVALID_ENUM);
2205 else
2207 ALdouble dvals[3];
2208 if(GetSourcedv(Source, Context, param, dvals))
2210 *value1 = dvals[0];
2211 *value2 = dvals[1];
2212 *value3 = dvals[2];
2215 UnlockSourcesRead(Context);
2216 ReadUnlock(&Context->PropLock);
2218 ALCcontext_DecRef(Context);
2221 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
2223 ALCcontext *Context;
2224 ALsource *Source;
2226 Context = GetContextRef();
2227 if(!Context) return;
2229 ReadLock(&Context->PropLock);
2230 LockSourcesRead(Context);
2231 if((Source=LookupSource(Context, source)) == NULL)
2232 alSetError(Context, AL_INVALID_NAME);
2233 else if(!values)
2234 alSetError(Context, AL_INVALID_VALUE);
2235 else if(!(DoubleValsByProp(param) > 0))
2236 alSetError(Context, AL_INVALID_ENUM);
2237 else
2238 GetSourcedv(Source, Context, param, values);
2239 UnlockSourcesRead(Context);
2240 ReadUnlock(&Context->PropLock);
2242 ALCcontext_DecRef(Context);
2246 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2248 ALCcontext *Context;
2249 ALsource *Source;
2251 Context = GetContextRef();
2252 if(!Context) return;
2254 ReadLock(&Context->PropLock);
2255 LockSourcesRead(Context);
2256 if((Source=LookupSource(Context, source)) == NULL)
2257 alSetError(Context, AL_INVALID_NAME);
2258 else if(!value)
2259 alSetError(Context, AL_INVALID_VALUE);
2260 else if(!(IntValsByProp(param) == 1))
2261 alSetError(Context, AL_INVALID_ENUM);
2262 else
2263 GetSourceiv(Source, Context, param, value);
2264 UnlockSourcesRead(Context);
2265 ReadUnlock(&Context->PropLock);
2267 ALCcontext_DecRef(Context);
2271 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2273 ALCcontext *Context;
2274 ALsource *Source;
2276 Context = GetContextRef();
2277 if(!Context) return;
2279 ReadLock(&Context->PropLock);
2280 LockSourcesRead(Context);
2281 if((Source=LookupSource(Context, source)) == NULL)
2282 alSetError(Context, AL_INVALID_NAME);
2283 else if(!(value1 && value2 && value3))
2284 alSetError(Context, AL_INVALID_VALUE);
2285 else if(!(IntValsByProp(param) == 3))
2286 alSetError(Context, AL_INVALID_ENUM);
2287 else
2289 ALint ivals[3];
2290 if(GetSourceiv(Source, Context, param, ivals))
2292 *value1 = ivals[0];
2293 *value2 = ivals[1];
2294 *value3 = ivals[2];
2297 UnlockSourcesRead(Context);
2298 ReadUnlock(&Context->PropLock);
2300 ALCcontext_DecRef(Context);
2304 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2306 ALCcontext *Context;
2307 ALsource *Source;
2309 Context = GetContextRef();
2310 if(!Context) return;
2312 ReadLock(&Context->PropLock);
2313 LockSourcesRead(Context);
2314 if((Source=LookupSource(Context, source)) == NULL)
2315 alSetError(Context, AL_INVALID_NAME);
2316 else if(!values)
2317 alSetError(Context, AL_INVALID_VALUE);
2318 else if(!(IntValsByProp(param) > 0))
2319 alSetError(Context, AL_INVALID_ENUM);
2320 else
2321 GetSourceiv(Source, Context, param, values);
2322 UnlockSourcesRead(Context);
2323 ReadUnlock(&Context->PropLock);
2325 ALCcontext_DecRef(Context);
2329 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2331 ALCcontext *Context;
2332 ALsource *Source;
2334 Context = GetContextRef();
2335 if(!Context) return;
2337 ReadLock(&Context->PropLock);
2338 LockSourcesRead(Context);
2339 if((Source=LookupSource(Context, source)) == NULL)
2340 alSetError(Context, AL_INVALID_NAME);
2341 else if(!value)
2342 alSetError(Context, AL_INVALID_VALUE);
2343 else if(!(Int64ValsByProp(param) == 1))
2344 alSetError(Context, AL_INVALID_ENUM);
2345 else
2346 GetSourcei64v(Source, Context, param, value);
2347 UnlockSourcesRead(Context);
2348 ReadUnlock(&Context->PropLock);
2350 ALCcontext_DecRef(Context);
2353 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2355 ALCcontext *Context;
2356 ALsource *Source;
2358 Context = GetContextRef();
2359 if(!Context) return;
2361 ReadLock(&Context->PropLock);
2362 LockSourcesRead(Context);
2363 if((Source=LookupSource(Context, source)) == NULL)
2364 alSetError(Context, AL_INVALID_NAME);
2365 else if(!(value1 && value2 && value3))
2366 alSetError(Context, AL_INVALID_VALUE);
2367 else if(!(Int64ValsByProp(param) == 3))
2368 alSetError(Context, AL_INVALID_ENUM);
2369 else
2371 ALint64 i64vals[3];
2372 if(GetSourcei64v(Source, Context, param, i64vals))
2374 *value1 = i64vals[0];
2375 *value2 = i64vals[1];
2376 *value3 = i64vals[2];
2379 UnlockSourcesRead(Context);
2380 ReadUnlock(&Context->PropLock);
2382 ALCcontext_DecRef(Context);
2385 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2387 ALCcontext *Context;
2388 ALsource *Source;
2390 Context = GetContextRef();
2391 if(!Context) return;
2393 ReadLock(&Context->PropLock);
2394 LockSourcesRead(Context);
2395 if((Source=LookupSource(Context, source)) == NULL)
2396 alSetError(Context, AL_INVALID_NAME);
2397 else if(!values)
2398 alSetError(Context, AL_INVALID_VALUE);
2399 else if(!(Int64ValsByProp(param) > 0))
2400 alSetError(Context, AL_INVALID_ENUM);
2401 else
2402 GetSourcei64v(Source, Context, param, values);
2403 UnlockSourcesRead(Context);
2404 ReadUnlock(&Context->PropLock);
2406 ALCcontext_DecRef(Context);
2410 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2412 alSourcePlayv(1, &source);
2414 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2416 ALCcontext *context;
2417 ALCdevice *device;
2418 ALsource *source;
2419 ALvoice *voice;
2420 ALsizei i, j;
2422 context = GetContextRef();
2423 if(!context) return;
2425 LockSourcesRead(context);
2426 if(!(n >= 0))
2427 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2428 for(i = 0;i < n;i++)
2430 if(!LookupSource(context, sources[i]))
2431 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2434 device = context->Device;
2435 ALCdevice_Lock(device);
2436 /* If the device is disconnected, go right to stopped. */
2437 if(!device->Connected)
2439 for(i = 0;i < n;i++)
2441 source = LookupSource(context, sources[i]);
2442 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2444 ALCdevice_Unlock(device);
2445 goto done;
2448 while(n > context->MaxVoices-context->VoiceCount)
2450 ALsizei newcount = context->MaxVoices << 1;
2451 if(context->MaxVoices >= newcount)
2453 ALCdevice_Unlock(device);
2454 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2456 AllocateVoices(context, newcount, device->NumAuxSends);
2459 for(i = 0;i < n;i++)
2461 ALbufferlistitem *BufferList;
2462 ALbuffer *buffer = NULL;
2463 bool start_fading = false;
2464 ALsizei s;
2466 source = LookupSource(context, sources[i]);
2467 WriteLock(&source->queue_lock);
2468 /* Check that there is a queue containing at least one valid, non zero
2469 * length Buffer.
2471 BufferList = source->queue;
2472 while(BufferList)
2474 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2475 break;
2476 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
2479 /* If there's nothing to play, go right to stopped. */
2480 if(!BufferList)
2482 /* NOTE: A source without any playable buffers should not have an
2483 * ALvoice since it shouldn't be in a playing or paused state. So
2484 * there's no need to look up its voice and clear the source.
2486 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2487 source->OffsetType = AL_NONE;
2488 source->Offset = 0.0;
2489 goto finish_play;
2492 voice = GetSourceVoice(source, context);
2493 switch(GetSourceState(source, voice))
2495 case AL_PLAYING:
2496 assert(voice != NULL);
2497 /* A source that's already playing is restarted from the beginning. */
2498 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
2499 ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
2500 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release);
2501 goto finish_play;
2503 case AL_PAUSED:
2504 assert(voice != NULL);
2505 /* A source that's paused simply resumes. */
2506 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
2507 ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release);
2508 goto finish_play;
2510 default:
2511 break;
2514 /* Make sure this source isn't already active, and if not, look for an
2515 * unused voice to put it in.
2517 assert(voice == NULL);
2518 for(j = 0;j < context->VoiceCount;j++)
2520 if(ATOMIC_LOAD(&context->Voices[j]->Source, almemory_order_acquire) == NULL)
2522 voice = context->Voices[j];
2523 break;
2526 if(voice == NULL)
2527 voice = context->Voices[context->VoiceCount++];
2528 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2530 ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acquire);
2531 UpdateSourceProps(source, voice, device->NumAuxSends);
2533 /* A source that's not playing or paused has any offset applied when it
2534 * starts playing.
2536 if(source->Looping)
2537 ATOMIC_STORE(&voice->loop_buffer, source->queue, almemory_order_relaxed);
2538 else
2539 ATOMIC_STORE(&voice->loop_buffer, NULL, almemory_order_relaxed);
2540 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
2541 ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
2542 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed);
2543 if(source->OffsetType != AL_NONE)
2545 ApplyOffset(source, voice);
2546 start_fading = ATOMIC_LOAD(&voice->position, almemory_order_relaxed) != 0 ||
2547 ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) != 0 ||
2548 ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed) != BufferList;
2551 voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2552 voice->SampleSize = BytesFromFmt(buffer->FmtType);
2554 /* Clear previous samples. */
2555 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
2557 /* Clear the stepping value so the mixer knows not to mix this until
2558 * the update gets applied.
2560 voice->Step = 0;
2562 voice->Flags = start_fading ? VOICE_IS_FADING : 0;
2563 memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*voice->NumChannels);
2564 for(s = 0;s < device->NumAuxSends;s++)
2565 memset(voice->Send[s].Params, 0, sizeof(voice->Send[s].Params[0])*voice->NumChannels);
2566 if(device->AvgSpeakerDist > 0.0f)
2568 ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC /
2569 (device->AvgSpeakerDist * device->Frequency);
2570 for(j = 0;j < voice->NumChannels;j++)
2572 NfcFilterCreate1(&voice->Direct.Params[j].NFCtrlFilter[0], 0.0f, w1);
2573 NfcFilterCreate2(&voice->Direct.Params[j].NFCtrlFilter[1], 0.0f, w1);
2574 NfcFilterCreate3(&voice->Direct.Params[j].NFCtrlFilter[2], 0.0f, w1);
2578 ATOMIC_STORE(&voice->Source, source, almemory_order_relaxed);
2579 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
2580 ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release);
2581 finish_play:
2582 WriteUnlock(&source->queue_lock);
2584 ALCdevice_Unlock(device);
2586 done:
2587 UnlockSourcesRead(context);
2588 ALCcontext_DecRef(context);
2591 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2593 alSourcePausev(1, &source);
2595 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2597 ALCcontext *context;
2598 ALCdevice *device;
2599 ALsource *source;
2600 ALvoice *voice;
2601 ALsizei i;
2603 context = GetContextRef();
2604 if(!context) return;
2606 LockSourcesRead(context);
2607 if(!(n >= 0))
2608 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2609 for(i = 0;i < n;i++)
2611 if(!LookupSource(context, sources[i]))
2612 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2615 device = context->Device;
2616 ALCdevice_Lock(device);
2617 for(i = 0;i < n;i++)
2619 source = LookupSource(context, sources[i]);
2620 WriteLock(&source->queue_lock);
2621 if((voice=GetSourceVoice(source, context)) != NULL)
2623 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2624 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2625 althrd_yield();
2627 if(GetSourceState(source, voice) == AL_PLAYING)
2628 ATOMIC_STORE(&source->state, AL_PAUSED, almemory_order_release);
2629 WriteUnlock(&source->queue_lock);
2631 ALCdevice_Unlock(device);
2633 done:
2634 UnlockSourcesRead(context);
2635 ALCcontext_DecRef(context);
2638 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2640 alSourceStopv(1, &source);
2642 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2644 ALCcontext *context;
2645 ALCdevice *device;
2646 ALsource *source;
2647 ALvoice *voice;
2648 ALsizei i;
2650 context = GetContextRef();
2651 if(!context) return;
2653 LockSourcesRead(context);
2654 if(!(n >= 0))
2655 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2656 for(i = 0;i < n;i++)
2658 if(!LookupSource(context, sources[i]))
2659 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2662 device = context->Device;
2663 ALCdevice_Lock(device);
2664 for(i = 0;i < n;i++)
2666 source = LookupSource(context, sources[i]);
2667 WriteLock(&source->queue_lock);
2668 if((voice=GetSourceVoice(source, context)) != NULL)
2670 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
2671 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2672 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2673 althrd_yield();
2675 if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL)
2676 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2677 source->OffsetType = AL_NONE;
2678 source->Offset = 0.0;
2679 WriteUnlock(&source->queue_lock);
2681 ALCdevice_Unlock(device);
2683 done:
2684 UnlockSourcesRead(context);
2685 ALCcontext_DecRef(context);
2688 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2690 alSourceRewindv(1, &source);
2692 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2694 ALCcontext *context;
2695 ALCdevice *device;
2696 ALsource *source;
2697 ALvoice *voice;
2698 ALsizei i;
2700 context = GetContextRef();
2701 if(!context) return;
2703 LockSourcesRead(context);
2704 if(!(n >= 0))
2705 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2706 for(i = 0;i < n;i++)
2708 if(!LookupSource(context, sources[i]))
2709 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2712 device = context->Device;
2713 ALCdevice_Lock(device);
2714 for(i = 0;i < n;i++)
2716 source = LookupSource(context, sources[i]);
2717 WriteLock(&source->queue_lock);
2718 if((voice=GetSourceVoice(source, context)) != NULL)
2720 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
2721 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2722 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2723 althrd_yield();
2725 if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL)
2726 ATOMIC_STORE(&source->state, AL_INITIAL, almemory_order_relaxed);
2727 source->OffsetType = AL_NONE;
2728 source->Offset = 0.0;
2729 WriteUnlock(&source->queue_lock);
2731 ALCdevice_Unlock(device);
2733 done:
2734 UnlockSourcesRead(context);
2735 ALCcontext_DecRef(context);
2739 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2741 ALCdevice *device;
2742 ALCcontext *context;
2743 ALsource *source;
2744 ALsizei i;
2745 ALbufferlistitem *BufferListStart;
2746 ALbufferlistitem *BufferList;
2747 ALbuffer *BufferFmt = NULL;
2749 if(nb == 0)
2750 return;
2752 context = GetContextRef();
2753 if(!context) return;
2755 device = context->Device;
2757 LockSourcesRead(context);
2758 if(!(nb >= 0))
2759 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2760 if((source=LookupSource(context, src)) == NULL)
2761 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2763 WriteLock(&source->queue_lock);
2764 if(source->SourceType == AL_STATIC)
2766 WriteUnlock(&source->queue_lock);
2767 /* Can't queue on a Static Source */
2768 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2771 /* Check for a valid Buffer, for its frequency and format */
2772 BufferList = source->queue;
2773 while(BufferList)
2775 if(BufferList->buffer)
2777 BufferFmt = BufferList->buffer;
2778 break;
2780 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
2783 LockBuffersRead(device);
2784 BufferListStart = NULL;
2785 BufferList = NULL;
2786 for(i = 0;i < nb;i++)
2788 ALbuffer *buffer = NULL;
2789 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2791 WriteUnlock(&source->queue_lock);
2792 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2795 if(!BufferListStart)
2797 BufferListStart = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
2798 BufferList = BufferListStart;
2800 else
2802 ALbufferlistitem *item = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
2803 ATOMIC_STORE(&BufferList->next, item, almemory_order_relaxed);
2804 BufferList = item;
2806 BufferList->buffer = buffer;
2807 ATOMIC_INIT(&BufferList->next, NULL);
2808 if(!buffer) continue;
2810 /* Hold a read lock on each buffer being queued while checking all
2811 * provided buffers. This is done so other threads don't see an extra
2812 * reference on some buffers if this operation ends up failing. */
2813 ReadLock(&buffer->lock);
2814 IncrementRef(&buffer->ref);
2816 if(BufferFmt == NULL)
2817 BufferFmt = buffer;
2818 else if(BufferFmt->Frequency != buffer->Frequency ||
2819 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2820 BufferFmt->OriginalType != buffer->OriginalType)
2822 WriteUnlock(&source->queue_lock);
2823 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2825 buffer_error:
2826 /* A buffer failed (invalid ID or format), so unlock and release
2827 * each buffer we had. */
2828 while(BufferListStart)
2830 ALbufferlistitem *next = ATOMIC_LOAD(&BufferListStart->next,
2831 almemory_order_relaxed);
2832 if((buffer=BufferListStart->buffer) != NULL)
2834 DecrementRef(&buffer->ref);
2835 ReadUnlock(&buffer->lock);
2837 al_free(BufferListStart);
2838 BufferListStart = next;
2840 UnlockBuffersRead(device);
2841 goto done;
2844 /* All buffers good, unlock them now. */
2845 BufferList = BufferListStart;
2846 while(BufferList != NULL)
2848 ALbuffer *buffer = BufferList->buffer;
2849 if(buffer) ReadUnlock(&buffer->lock);
2850 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
2852 UnlockBuffersRead(device);
2854 /* Source is now streaming */
2855 source->SourceType = AL_STREAMING;
2857 if(!(BufferList=source->queue))
2858 source->queue = BufferListStart;
2859 else
2861 ALbufferlistitem *next;
2862 while((next=ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed)) != NULL)
2863 BufferList = next;
2864 ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release);
2866 WriteUnlock(&source->queue_lock);
2868 done:
2869 UnlockSourcesRead(context);
2870 ALCcontext_DecRef(context);
2873 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2875 ALCcontext *context;
2876 ALsource *source;
2877 ALbufferlistitem *OldHead;
2878 ALbufferlistitem *OldTail;
2879 ALbufferlistitem *Current;
2880 ALvoice *voice;
2881 ALsizei i = 0;
2883 context = GetContextRef();
2884 if(!context) return;
2886 LockSourcesRead(context);
2887 if(!(nb >= 0))
2888 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2890 if((source=LookupSource(context, src)) == NULL)
2891 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2893 /* Nothing to unqueue. */
2894 if(nb == 0) goto done;
2896 WriteLock(&source->queue_lock);
2897 if(source->Looping || source->SourceType != AL_STREAMING)
2899 WriteUnlock(&source->queue_lock);
2900 /* Trying to unqueue buffers on a looping or non-streaming source. */
2901 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2904 /* Find the new buffer queue head */
2905 OldTail = source->queue;
2906 Current = NULL;
2907 if((voice=GetSourceVoice(source, context)) != NULL)
2908 Current = ATOMIC_LOAD_SEQ(&voice->current_buffer);
2909 else if(ATOMIC_LOAD_SEQ(&source->state) == AL_INITIAL)
2910 Current = OldTail;
2911 if(OldTail != Current)
2913 for(i = 1;i < nb;i++)
2915 ALbufferlistitem *next = ATOMIC_LOAD(&OldTail->next, almemory_order_relaxed);
2916 if(!next || next == Current) break;
2917 OldTail = next;
2920 if(i != nb)
2922 WriteUnlock(&source->queue_lock);
2923 /* Trying to unqueue pending buffers. */
2924 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2927 /* Swap it, and cut the new head from the old. */
2928 OldHead = source->queue;
2929 source->queue = ATOMIC_EXCHANGE_PTR(&OldTail->next, NULL, almemory_order_acq_rel);
2930 WriteUnlock(&source->queue_lock);
2932 while(OldHead != NULL)
2934 ALbufferlistitem *next = ATOMIC_LOAD(&OldHead->next, almemory_order_relaxed);
2935 ALbuffer *buffer = OldHead->buffer;
2937 if(!buffer)
2938 *(buffers++) = 0;
2939 else
2941 *(buffers++) = buffer->id;
2942 DecrementRef(&buffer->ref);
2945 al_free(OldHead);
2946 OldHead = next;
2949 done:
2950 UnlockSourcesRead(context);
2951 ALCcontext_DecRef(context);
2955 static void InitSourceParams(ALsource *Source, ALsizei num_sends)
2957 ALsizei i;
2959 RWLockInit(&Source->queue_lock);
2961 Source->InnerAngle = 360.0f;
2962 Source->OuterAngle = 360.0f;
2963 Source->Pitch = 1.0f;
2964 Source->Position[0] = 0.0f;
2965 Source->Position[1] = 0.0f;
2966 Source->Position[2] = 0.0f;
2967 Source->Velocity[0] = 0.0f;
2968 Source->Velocity[1] = 0.0f;
2969 Source->Velocity[2] = 0.0f;
2970 Source->Direction[0] = 0.0f;
2971 Source->Direction[1] = 0.0f;
2972 Source->Direction[2] = 0.0f;
2973 Source->Orientation[0][0] = 0.0f;
2974 Source->Orientation[0][1] = 0.0f;
2975 Source->Orientation[0][2] = -1.0f;
2976 Source->Orientation[1][0] = 0.0f;
2977 Source->Orientation[1][1] = 1.0f;
2978 Source->Orientation[1][2] = 0.0f;
2979 Source->RefDistance = 1.0f;
2980 Source->MaxDistance = FLT_MAX;
2981 Source->RolloffFactor = 1.0f;
2982 Source->Gain = 1.0f;
2983 Source->MinGain = 0.0f;
2984 Source->MaxGain = 1.0f;
2985 Source->OuterGain = 0.0f;
2986 Source->OuterGainHF = 1.0f;
2988 Source->DryGainHFAuto = AL_TRUE;
2989 Source->WetGainAuto = AL_TRUE;
2990 Source->WetGainHFAuto = AL_TRUE;
2991 Source->AirAbsorptionFactor = 0.0f;
2992 Source->RoomRolloffFactor = 0.0f;
2993 Source->DopplerFactor = 1.0f;
2994 Source->HeadRelative = AL_FALSE;
2995 Source->Looping = AL_FALSE;
2996 Source->DistanceModel = DefaultDistanceModel;
2997 Source->Resampler = ResamplerDefault;
2998 Source->DirectChannels = AL_FALSE;
2999 Source->Spatialize = SpatializeAuto;
3001 Source->StereoPan[0] = DEG2RAD( 30.0f);
3002 Source->StereoPan[1] = DEG2RAD(-30.0f);
3004 Source->Radius = 0.0f;
3006 Source->Direct.Gain = 1.0f;
3007 Source->Direct.GainHF = 1.0f;
3008 Source->Direct.HFReference = LOWPASSFREQREF;
3009 Source->Direct.GainLF = 1.0f;
3010 Source->Direct.LFReference = HIGHPASSFREQREF;
3011 Source->Send = al_calloc(16, num_sends*sizeof(Source->Send[0]));
3012 for(i = 0;i < num_sends;i++)
3014 Source->Send[i].Slot = NULL;
3015 Source->Send[i].Gain = 1.0f;
3016 Source->Send[i].GainHF = 1.0f;
3017 Source->Send[i].HFReference = LOWPASSFREQREF;
3018 Source->Send[i].GainLF = 1.0f;
3019 Source->Send[i].LFReference = HIGHPASSFREQREF;
3022 Source->Offset = 0.0;
3023 Source->OffsetType = AL_NONE;
3024 Source->SourceType = AL_UNDETERMINED;
3025 ATOMIC_INIT(&Source->state, AL_INITIAL);
3027 Source->queue = NULL;
3029 /* No way to do an 'init' here, so just test+set with relaxed ordering and
3030 * ignore the test.
3032 ATOMIC_FLAG_TEST_AND_SET(&Source->PropsClean, almemory_order_relaxed);
3035 static void DeinitSource(ALsource *source, ALsizei num_sends)
3037 ALbufferlistitem *BufferList;
3038 ALsizei i;
3040 BufferList = source->queue;
3041 while(BufferList != NULL)
3043 ALbufferlistitem *next = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
3044 if(BufferList->buffer != NULL)
3045 DecrementRef(&BufferList->buffer->ref);
3046 al_free(BufferList);
3047 BufferList = next;
3049 source->queue = NULL;
3051 if(source->Send)
3053 for(i = 0;i < num_sends;i++)
3055 if(source->Send[i].Slot)
3056 DecrementRef(&source->Send[i].Slot->ref);
3057 source->Send[i].Slot = NULL;
3059 al_free(source->Send);
3060 source->Send = NULL;
3064 static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends)
3066 struct ALvoiceProps *props;
3067 ALsizei i;
3069 /* Get an unused property container, or allocate a new one as needed. */
3070 props = ATOMIC_LOAD(&voice->FreeList, almemory_order_acquire);
3071 if(!props)
3072 props = al_calloc(16, FAM_SIZE(struct ALvoiceProps, Send, num_sends));
3073 else
3075 struct ALvoiceProps *next;
3076 do {
3077 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
3078 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&voice->FreeList, &props, next,
3079 almemory_order_acq_rel, almemory_order_acquire) == 0);
3082 /* Copy in current property values. */
3083 props->Pitch = source->Pitch;
3084 props->Gain = source->Gain;
3085 props->OuterGain = source->OuterGain;
3086 props->MinGain = source->MinGain;
3087 props->MaxGain = source->MaxGain;
3088 props->InnerAngle = source->InnerAngle;
3089 props->OuterAngle = source->OuterAngle;
3090 props->RefDistance = source->RefDistance;
3091 props->MaxDistance = source->MaxDistance;
3092 props->RolloffFactor = source->RolloffFactor;
3093 for(i = 0;i < 3;i++)
3094 props->Position[i] = source->Position[i];
3095 for(i = 0;i < 3;i++)
3096 props->Velocity[i] = source->Velocity[i];
3097 for(i = 0;i < 3;i++)
3098 props->Direction[i] = source->Direction[i];
3099 for(i = 0;i < 2;i++)
3101 ALsizei j;
3102 for(j = 0;j < 3;j++)
3103 props->Orientation[i][j] = source->Orientation[i][j];
3105 props->HeadRelative = source->HeadRelative;
3106 props->DistanceModel = source->DistanceModel;
3107 props->Resampler = source->Resampler;
3108 props->DirectChannels = source->DirectChannels;
3109 props->SpatializeMode = source->Spatialize;
3111 props->DryGainHFAuto = source->DryGainHFAuto;
3112 props->WetGainAuto = source->WetGainAuto;
3113 props->WetGainHFAuto = source->WetGainHFAuto;
3114 props->OuterGainHF = source->OuterGainHF;
3116 props->AirAbsorptionFactor = source->AirAbsorptionFactor;
3117 props->RoomRolloffFactor = source->RoomRolloffFactor;
3118 props->DopplerFactor = source->DopplerFactor;
3120 props->StereoPan[0] = source->StereoPan[0];
3121 props->StereoPan[1] = source->StereoPan[1];
3123 props->Radius = source->Radius;
3125 props->Direct.Gain = source->Direct.Gain;
3126 props->Direct.GainHF = source->Direct.GainHF;
3127 props->Direct.HFReference = source->Direct.HFReference;
3128 props->Direct.GainLF = source->Direct.GainLF;
3129 props->Direct.LFReference = source->Direct.LFReference;
3131 for(i = 0;i < num_sends;i++)
3133 props->Send[i].Slot = source->Send[i].Slot;
3134 props->Send[i].Gain = source->Send[i].Gain;
3135 props->Send[i].GainHF = source->Send[i].GainHF;
3136 props->Send[i].HFReference = source->Send[i].HFReference;
3137 props->Send[i].GainLF = source->Send[i].GainLF;
3138 props->Send[i].LFReference = source->Send[i].LFReference;
3141 /* Set the new container for updating internal parameters. */
3142 props = ATOMIC_EXCHANGE_PTR(&voice->Update, props, almemory_order_acq_rel);
3143 if(props)
3145 /* If there was an unused update container, put it back in the
3146 * freelist.
3148 ATOMIC_REPLACE_HEAD(struct ALvoiceProps*, &voice->FreeList, props);
3152 void UpdateAllSourceProps(ALCcontext *context)
3154 ALsizei num_sends = context->Device->NumAuxSends;
3155 ALsizei pos;
3157 for(pos = 0;pos < context->VoiceCount;pos++)
3159 ALvoice *voice = context->Voices[pos];
3160 ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire);
3161 if(source && !ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acq_rel))
3162 UpdateSourceProps(source, voice, num_sends);
3167 /* GetSourceSampleOffset
3169 * Gets the current read offset for the given Source, in 32.32 fixed-point
3170 * samples. The offset is relative to the start of the queue (not the start of
3171 * the current buffer).
3173 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3175 ALCdevice *device = context->Device;
3176 const ALbufferlistitem *Current;
3177 ALuint64 readPos;
3178 ALuint refcount;
3179 ALvoice *voice;
3181 ReadLock(&Source->queue_lock);
3182 do {
3183 Current = NULL;
3184 readPos = 0;
3185 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3186 althrd_yield();
3187 *clocktime = GetDeviceClockTime(device);
3189 voice = GetSourceVoice(Source, context);
3190 if(voice)
3192 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3194 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << 32;
3195 readPos |= (ALuint64)ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) <<
3196 (32-FRACTIONBITS);
3198 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3199 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3201 if(voice)
3203 const ALbufferlistitem *BufferList = Source->queue;
3204 while(BufferList && BufferList != Current)
3206 if(BufferList->buffer)
3207 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
3208 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3209 almemory_order_relaxed);
3211 readPos = minu64(readPos, U64(0x7fffffffffffffff));
3214 ReadUnlock(&Source->queue_lock);
3215 return (ALint64)readPos;
3218 /* GetSourceSecOffset
3220 * Gets the current read offset for the given Source, in seconds. The offset is
3221 * relative to the start of the queue (not the start of the current buffer).
3223 static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3225 ALCdevice *device = context->Device;
3226 const ALbufferlistitem *Current;
3227 ALuint64 readPos;
3228 ALuint refcount;
3229 ALdouble offset;
3230 ALvoice *voice;
3232 ReadLock(&Source->queue_lock);
3233 do {
3234 Current = NULL;
3235 readPos = 0;
3236 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3237 althrd_yield();
3238 *clocktime = GetDeviceClockTime(device);
3240 voice = GetSourceVoice(Source, context);
3241 if(voice)
3243 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3245 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) <<
3246 FRACTIONBITS;
3247 readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3249 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3250 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3252 offset = 0.0;
3253 if(voice)
3255 const ALbufferlistitem *BufferList = Source->queue;
3256 const ALbuffer *BufferFmt = NULL;
3257 while(BufferList && BufferList != Current)
3259 const ALbuffer *buffer = BufferList->buffer;
3260 if(buffer != NULL)
3262 if(!BufferFmt) BufferFmt = buffer;
3263 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
3265 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3266 almemory_order_relaxed);
3269 while(BufferList && !BufferFmt)
3271 BufferFmt = BufferList->buffer;
3272 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3273 almemory_order_relaxed);
3275 assert(BufferFmt != NULL);
3277 offset = (ALdouble)readPos / (ALdouble)FRACTIONONE /
3278 (ALdouble)BufferFmt->Frequency;
3281 ReadUnlock(&Source->queue_lock);
3282 return offset;
3285 /* GetSourceOffset
3287 * Gets the current read offset for the given Source, in the appropriate format
3288 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3289 * queue (not the start of the current buffer).
3291 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context)
3293 ALCdevice *device = context->Device;
3294 const ALbufferlistitem *Current;
3295 ALuint readPos;
3296 ALsizei readPosFrac;
3297 ALuint refcount;
3298 ALdouble offset;
3299 ALvoice *voice;
3301 ReadLock(&Source->queue_lock);
3302 do {
3303 Current = NULL;
3304 readPos = readPosFrac = 0;
3305 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3306 althrd_yield();
3307 voice = GetSourceVoice(Source, context);
3308 if(voice)
3310 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3312 readPos = ATOMIC_LOAD(&voice->position, almemory_order_relaxed);
3313 readPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3315 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3316 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3318 offset = 0.0;
3319 if(voice)
3321 const ALbufferlistitem *BufferList = Source->queue;
3322 const ALbuffer *BufferFmt = NULL;
3323 ALboolean readFin = AL_FALSE;
3324 ALuint totalBufferLen = 0;
3326 while(BufferList != NULL)
3328 const ALbuffer *buffer;
3329 readFin = readFin || (BufferList == Current);
3330 if((buffer=BufferList->buffer) != NULL)
3332 if(!BufferFmt) BufferFmt = buffer;
3333 totalBufferLen += buffer->SampleLen;
3334 if(!readFin) readPos += buffer->SampleLen;
3336 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3337 almemory_order_relaxed);
3339 assert(BufferFmt != NULL);
3341 if(Source->Looping)
3342 readPos %= totalBufferLen;
3343 else
3345 /* Wrap back to 0 */
3346 if(readPos >= totalBufferLen)
3347 readPos = readPosFrac = 0;
3350 offset = 0.0;
3351 switch(name)
3353 case AL_SEC_OFFSET:
3354 offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE) / BufferFmt->Frequency;
3355 break;
3357 case AL_SAMPLE_OFFSET:
3358 offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
3359 break;
3361 case AL_BYTE_OFFSET:
3362 if(BufferFmt->OriginalType == UserFmtIMA4)
3364 ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
3365 ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels);
3366 ALuint FrameBlockSize = BufferFmt->OriginalAlign;
3368 /* Round down to nearest ADPCM block */
3369 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3371 else if(BufferFmt->OriginalType == UserFmtMSADPCM)
3373 ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
3374 ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels);
3375 ALuint FrameBlockSize = BufferFmt->OriginalAlign;
3377 /* Round down to nearest ADPCM block */
3378 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3380 else
3382 ALuint FrameSize = FrameSizeFromUserFmt(BufferFmt->OriginalChannels,
3383 BufferFmt->OriginalType);
3384 offset = (ALdouble)(readPos * FrameSize);
3386 break;
3390 ReadUnlock(&Source->queue_lock);
3391 return offset;
3395 /* ApplyOffset
3397 * Apply the stored playback offset to the Source. This function will update
3398 * the number of buffers "played" given the stored offset.
3400 static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice)
3402 ALbufferlistitem *BufferList;
3403 const ALbuffer *Buffer;
3404 ALuint bufferLen, totalBufferLen;
3405 ALuint offset = 0;
3406 ALsizei frac = 0;
3408 /* Get sample frame offset */
3409 if(!GetSampleOffset(Source, &offset, &frac))
3410 return AL_FALSE;
3412 totalBufferLen = 0;
3413 BufferList = Source->queue;
3414 while(BufferList && totalBufferLen <= offset)
3416 Buffer = BufferList->buffer;
3417 bufferLen = Buffer ? Buffer->SampleLen : 0;
3419 if(bufferLen > offset-totalBufferLen)
3421 /* Offset is in this buffer */
3422 ATOMIC_STORE(&voice->position, offset - totalBufferLen, almemory_order_relaxed);
3423 ATOMIC_STORE(&voice->position_fraction, frac, almemory_order_relaxed);
3424 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_release);
3425 return AL_TRUE;
3428 totalBufferLen += bufferLen;
3430 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
3433 /* Offset is out of range of the queue */
3434 return AL_FALSE;
3438 /* GetSampleOffset
3440 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3441 * or Second offset supplied by the application). This takes into account the
3442 * fact that the buffer format may have been modifed since.
3444 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac)
3446 const ALbuffer *BufferFmt = NULL;
3447 const ALbufferlistitem *BufferList;
3448 ALdouble dbloff, dblfrac;
3450 /* Find the first valid Buffer in the Queue */
3451 BufferList = Source->queue;
3452 while(BufferList)
3454 if((BufferFmt=BufferList->buffer) != NULL)
3455 break;
3456 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3457 almemory_order_relaxed);
3459 if(!BufferFmt)
3461 Source->OffsetType = AL_NONE;
3462 Source->Offset = 0.0;
3463 return AL_FALSE;
3466 switch(Source->OffsetType)
3468 case AL_BYTE_OFFSET:
3469 /* Determine the ByteOffset (and ensure it is block aligned) */
3470 *offset = (ALuint)Source->Offset;
3471 if(BufferFmt->OriginalType == UserFmtIMA4)
3473 ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
3474 *offset /= align * ChannelsFromUserFmt(BufferFmt->OriginalChannels);
3475 *offset *= BufferFmt->OriginalAlign;
3477 else if(BufferFmt->OriginalType == UserFmtMSADPCM)
3479 ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
3480 *offset /= align * ChannelsFromUserFmt(BufferFmt->OriginalChannels);
3481 *offset *= BufferFmt->OriginalAlign;
3483 else
3484 *offset /= FrameSizeFromUserFmt(BufferFmt->OriginalChannels,
3485 BufferFmt->OriginalType);
3486 *frac = 0;
3487 break;
3489 case AL_SAMPLE_OFFSET:
3490 dblfrac = modf(Source->Offset, &dbloff);
3491 *offset = (ALuint)mind(dbloff, UINT_MAX);
3492 *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3493 break;
3495 case AL_SEC_OFFSET:
3496 dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff);
3497 *offset = (ALuint)mind(dbloff, UINT_MAX);
3498 *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3499 break;
3501 Source->OffsetType = AL_NONE;
3502 Source->Offset = 0.0;
3504 return AL_TRUE;
3508 /* ReleaseALSources
3510 * Destroys all sources in the source map.
3512 ALvoid ReleaseALSources(ALCcontext *Context)
3514 ALCdevice *device = Context->Device;
3515 ALsizei pos;
3516 for(pos = 0;pos < Context->SourceMap.size;pos++)
3518 ALsource *temp = Context->SourceMap.values[pos];
3519 Context->SourceMap.values[pos] = NULL;
3521 DeinitSource(temp, device->NumAuxSends);
3523 FreeThunkEntry(temp->id);
3524 memset(temp, 0, sizeof(*temp));
3525 al_free(temp);