Fix a mixed-sign-comparison warning on MSVC
[openal-soft.git] / OpenAL32 / alSource.c
blob9fc2220552c49b0583b1a6e1f3b82916167fc540
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,
119 } SourceProp;
121 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
122 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
123 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
125 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
126 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
127 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
129 static inline ALvoice *GetSourceVoice(const ALsource *source, const ALCcontext *context)
131 ALvoice **voice = context->Voices;
132 ALvoice **voice_end = voice + context->VoiceCount;
133 while(voice != voice_end)
135 if(ATOMIC_LOAD(&(*voice)->Source, almemory_order_acquire) == source)
136 return *voice;
137 ++voice;
139 return NULL;
143 * Returns if the last known state for the source was playing or paused. Does
144 * not sync with the mixer voice.
146 static inline bool IsPlayingOrPaused(ALsource *source)
148 ALenum state = ATOMIC_LOAD(&source->state, almemory_order_acquire);
149 return state == AL_PLAYING || state == AL_PAUSED;
153 * Returns an updated source state using the matching voice's status (or lack
154 * thereof).
156 static inline ALenum GetSourceState(ALsource *source, ALvoice *voice)
158 if(!voice)
160 ALenum state = AL_PLAYING;
161 if(ATOMIC_COMPARE_EXCHANGE_STRONG(&source->state, &state, AL_STOPPED,
162 almemory_order_acq_rel, almemory_order_acquire))
163 return AL_STOPPED;
164 return state;
166 return ATOMIC_LOAD(&source->state, almemory_order_acquire);
170 * Returns if the source should specify an update, given the context's
171 * deferring state and the source's last known state.
173 static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context)
175 return !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) &&
176 IsPlayingOrPaused(source);
179 static ALint FloatValsByProp(ALenum prop)
181 if(prop != (ALenum)((SourceProp)prop))
182 return 0;
183 switch((SourceProp)prop)
185 case AL_PITCH:
186 case AL_GAIN:
187 case AL_MIN_GAIN:
188 case AL_MAX_GAIN:
189 case AL_MAX_DISTANCE:
190 case AL_ROLLOFF_FACTOR:
191 case AL_DOPPLER_FACTOR:
192 case AL_CONE_OUTER_GAIN:
193 case AL_SEC_OFFSET:
194 case AL_SAMPLE_OFFSET:
195 case AL_BYTE_OFFSET:
196 case AL_CONE_INNER_ANGLE:
197 case AL_CONE_OUTER_ANGLE:
198 case AL_REFERENCE_DISTANCE:
199 case AL_CONE_OUTER_GAINHF:
200 case AL_AIR_ABSORPTION_FACTOR:
201 case AL_ROOM_ROLLOFF_FACTOR:
202 case AL_DIRECT_FILTER_GAINHF_AUTO:
203 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
204 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
205 case AL_DIRECT_CHANNELS_SOFT:
206 case AL_DISTANCE_MODEL:
207 case AL_SOURCE_RELATIVE:
208 case AL_LOOPING:
209 case AL_SOURCE_STATE:
210 case AL_BUFFERS_QUEUED:
211 case AL_BUFFERS_PROCESSED:
212 case AL_SOURCE_TYPE:
213 case AL_BYTE_LENGTH_SOFT:
214 case AL_SAMPLE_LENGTH_SOFT:
215 case AL_SEC_LENGTH_SOFT:
216 case AL_SOURCE_RADIUS:
217 return 1;
219 case AL_STEREO_ANGLES:
220 return 2;
222 case AL_POSITION:
223 case AL_VELOCITY:
224 case AL_DIRECTION:
225 return 3;
227 case AL_ORIENTATION:
228 return 6;
230 case AL_SEC_OFFSET_LATENCY_SOFT:
231 break; /* Double only */
233 case AL_BUFFER:
234 case AL_DIRECT_FILTER:
235 case AL_AUXILIARY_SEND_FILTER:
236 break; /* i/i64 only */
237 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
238 break; /* i64 only */
240 return 0;
242 static ALint DoubleValsByProp(ALenum prop)
244 if(prop != (ALenum)((SourceProp)prop))
245 return 0;
246 switch((SourceProp)prop)
248 case AL_PITCH:
249 case AL_GAIN:
250 case AL_MIN_GAIN:
251 case AL_MAX_GAIN:
252 case AL_MAX_DISTANCE:
253 case AL_ROLLOFF_FACTOR:
254 case AL_DOPPLER_FACTOR:
255 case AL_CONE_OUTER_GAIN:
256 case AL_SEC_OFFSET:
257 case AL_SAMPLE_OFFSET:
258 case AL_BYTE_OFFSET:
259 case AL_CONE_INNER_ANGLE:
260 case AL_CONE_OUTER_ANGLE:
261 case AL_REFERENCE_DISTANCE:
262 case AL_CONE_OUTER_GAINHF:
263 case AL_AIR_ABSORPTION_FACTOR:
264 case AL_ROOM_ROLLOFF_FACTOR:
265 case AL_DIRECT_FILTER_GAINHF_AUTO:
266 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
267 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
268 case AL_DIRECT_CHANNELS_SOFT:
269 case AL_DISTANCE_MODEL:
270 case AL_SOURCE_RELATIVE:
271 case AL_LOOPING:
272 case AL_SOURCE_STATE:
273 case AL_BUFFERS_QUEUED:
274 case AL_BUFFERS_PROCESSED:
275 case AL_SOURCE_TYPE:
276 case AL_BYTE_LENGTH_SOFT:
277 case AL_SAMPLE_LENGTH_SOFT:
278 case AL_SEC_LENGTH_SOFT:
279 case AL_SOURCE_RADIUS:
280 return 1;
282 case AL_SEC_OFFSET_LATENCY_SOFT:
283 case AL_STEREO_ANGLES:
284 return 2;
286 case AL_POSITION:
287 case AL_VELOCITY:
288 case AL_DIRECTION:
289 return 3;
291 case AL_ORIENTATION:
292 return 6;
294 case AL_BUFFER:
295 case AL_DIRECT_FILTER:
296 case AL_AUXILIARY_SEND_FILTER:
297 break; /* i/i64 only */
298 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
299 break; /* i64 only */
301 return 0;
304 static ALint IntValsByProp(ALenum prop)
306 if(prop != (ALenum)((SourceProp)prop))
307 return 0;
308 switch((SourceProp)prop)
310 case AL_PITCH:
311 case AL_GAIN:
312 case AL_MIN_GAIN:
313 case AL_MAX_GAIN:
314 case AL_MAX_DISTANCE:
315 case AL_ROLLOFF_FACTOR:
316 case AL_DOPPLER_FACTOR:
317 case AL_CONE_OUTER_GAIN:
318 case AL_SEC_OFFSET:
319 case AL_SAMPLE_OFFSET:
320 case AL_BYTE_OFFSET:
321 case AL_CONE_INNER_ANGLE:
322 case AL_CONE_OUTER_ANGLE:
323 case AL_REFERENCE_DISTANCE:
324 case AL_CONE_OUTER_GAINHF:
325 case AL_AIR_ABSORPTION_FACTOR:
326 case AL_ROOM_ROLLOFF_FACTOR:
327 case AL_DIRECT_FILTER_GAINHF_AUTO:
328 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
329 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
330 case AL_DIRECT_CHANNELS_SOFT:
331 case AL_DISTANCE_MODEL:
332 case AL_SOURCE_RELATIVE:
333 case AL_LOOPING:
334 case AL_BUFFER:
335 case AL_SOURCE_STATE:
336 case AL_BUFFERS_QUEUED:
337 case AL_BUFFERS_PROCESSED:
338 case AL_SOURCE_TYPE:
339 case AL_DIRECT_FILTER:
340 case AL_BYTE_LENGTH_SOFT:
341 case AL_SAMPLE_LENGTH_SOFT:
342 case AL_SEC_LENGTH_SOFT:
343 case AL_SOURCE_RADIUS:
344 return 1;
346 case AL_POSITION:
347 case AL_VELOCITY:
348 case AL_DIRECTION:
349 case AL_AUXILIARY_SEND_FILTER:
350 return 3;
352 case AL_ORIENTATION:
353 return 6;
355 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
356 break; /* i64 only */
357 case AL_SEC_OFFSET_LATENCY_SOFT:
358 break; /* Double only */
359 case AL_STEREO_ANGLES:
360 break; /* Float/double only */
362 return 0;
364 static ALint Int64ValsByProp(ALenum prop)
366 if(prop != (ALenum)((SourceProp)prop))
367 return 0;
368 switch((SourceProp)prop)
370 case AL_PITCH:
371 case AL_GAIN:
372 case AL_MIN_GAIN:
373 case AL_MAX_GAIN:
374 case AL_MAX_DISTANCE:
375 case AL_ROLLOFF_FACTOR:
376 case AL_DOPPLER_FACTOR:
377 case AL_CONE_OUTER_GAIN:
378 case AL_SEC_OFFSET:
379 case AL_SAMPLE_OFFSET:
380 case AL_BYTE_OFFSET:
381 case AL_CONE_INNER_ANGLE:
382 case AL_CONE_OUTER_ANGLE:
383 case AL_REFERENCE_DISTANCE:
384 case AL_CONE_OUTER_GAINHF:
385 case AL_AIR_ABSORPTION_FACTOR:
386 case AL_ROOM_ROLLOFF_FACTOR:
387 case AL_DIRECT_FILTER_GAINHF_AUTO:
388 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
389 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
390 case AL_DIRECT_CHANNELS_SOFT:
391 case AL_DISTANCE_MODEL:
392 case AL_SOURCE_RELATIVE:
393 case AL_LOOPING:
394 case AL_BUFFER:
395 case AL_SOURCE_STATE:
396 case AL_BUFFERS_QUEUED:
397 case AL_BUFFERS_PROCESSED:
398 case AL_SOURCE_TYPE:
399 case AL_DIRECT_FILTER:
400 case AL_BYTE_LENGTH_SOFT:
401 case AL_SAMPLE_LENGTH_SOFT:
402 case AL_SEC_LENGTH_SOFT:
403 case AL_SOURCE_RADIUS:
404 return 1;
406 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
407 return 2;
409 case AL_POSITION:
410 case AL_VELOCITY:
411 case AL_DIRECTION:
412 case AL_AUXILIARY_SEND_FILTER:
413 return 3;
415 case AL_ORIENTATION:
416 return 6;
418 case AL_SEC_OFFSET_LATENCY_SOFT:
419 break; /* Double only */
420 case AL_STEREO_ANGLES:
421 break; /* Float/double only */
423 return 0;
427 #define CHECKVAL(x) do { \
428 if(!(x)) \
429 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
430 } while(0)
432 #define DO_UPDATEPROPS() do { \
433 ALvoice *voice; \
434 if(SourceShouldUpdate(Source, Context) && \
435 (voice=GetSourceVoice(Source, Context)) != NULL) \
436 UpdateSourceProps(Source, voice, device->NumAuxSends); \
437 else \
438 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \
439 } while(0)
441 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
443 ALCdevice *device = Context->Device;
444 ALint ival;
446 switch(prop)
448 case AL_BYTE_LENGTH_SOFT:
449 case AL_SAMPLE_LENGTH_SOFT:
450 case AL_SEC_LENGTH_SOFT:
451 case AL_SEC_OFFSET_LATENCY_SOFT:
452 /* Query only */
453 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
455 case AL_PITCH:
456 CHECKVAL(*values >= 0.0f);
458 Source->Pitch = *values;
459 DO_UPDATEPROPS();
460 return AL_TRUE;
462 case AL_CONE_INNER_ANGLE:
463 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
465 Source->InnerAngle = *values;
466 DO_UPDATEPROPS();
467 return AL_TRUE;
469 case AL_CONE_OUTER_ANGLE:
470 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
472 Source->OuterAngle = *values;
473 DO_UPDATEPROPS();
474 return AL_TRUE;
476 case AL_GAIN:
477 CHECKVAL(*values >= 0.0f);
479 Source->Gain = *values;
480 DO_UPDATEPROPS();
481 return AL_TRUE;
483 case AL_MAX_DISTANCE:
484 CHECKVAL(*values >= 0.0f);
486 Source->MaxDistance = *values;
487 DO_UPDATEPROPS();
488 return AL_TRUE;
490 case AL_ROLLOFF_FACTOR:
491 CHECKVAL(*values >= 0.0f);
493 Source->RollOffFactor = *values;
494 DO_UPDATEPROPS();
495 return AL_TRUE;
497 case AL_REFERENCE_DISTANCE:
498 CHECKVAL(*values >= 0.0f);
500 Source->RefDistance = *values;
501 DO_UPDATEPROPS();
502 return AL_TRUE;
504 case AL_MIN_GAIN:
505 CHECKVAL(*values >= 0.0f);
507 Source->MinGain = *values;
508 DO_UPDATEPROPS();
509 return AL_TRUE;
511 case AL_MAX_GAIN:
512 CHECKVAL(*values >= 0.0f);
514 Source->MaxGain = *values;
515 DO_UPDATEPROPS();
516 return AL_TRUE;
518 case AL_CONE_OUTER_GAIN:
519 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
521 Source->OuterGain = *values;
522 DO_UPDATEPROPS();
523 return AL_TRUE;
525 case AL_CONE_OUTER_GAINHF:
526 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
528 Source->OuterGainHF = *values;
529 DO_UPDATEPROPS();
530 return AL_TRUE;
532 case AL_AIR_ABSORPTION_FACTOR:
533 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
535 Source->AirAbsorptionFactor = *values;
536 DO_UPDATEPROPS();
537 return AL_TRUE;
539 case AL_ROOM_ROLLOFF_FACTOR:
540 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
542 Source->RoomRolloffFactor = *values;
543 DO_UPDATEPROPS();
544 return AL_TRUE;
546 case AL_DOPPLER_FACTOR:
547 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
549 Source->DopplerFactor = *values;
550 DO_UPDATEPROPS();
551 return AL_TRUE;
553 case AL_SEC_OFFSET:
554 case AL_SAMPLE_OFFSET:
555 case AL_BYTE_OFFSET:
556 CHECKVAL(*values >= 0.0f);
558 Source->OffsetType = prop;
559 Source->Offset = *values;
561 if(IsPlayingOrPaused(Source))
563 ALvoice *voice;
565 ALCdevice_Lock(Context->Device);
566 /* Double-check that the source is still playing while we have
567 * the lock.
569 voice = GetSourceVoice(Source, Context);
570 if(voice)
572 WriteLock(&Source->queue_lock);
573 if(ApplyOffset(Source, voice) == AL_FALSE)
575 WriteUnlock(&Source->queue_lock);
576 ALCdevice_Unlock(Context->Device);
577 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
579 WriteUnlock(&Source->queue_lock);
581 ALCdevice_Unlock(Context->Device);
583 return AL_TRUE;
585 case AL_SOURCE_RADIUS:
586 CHECKVAL(*values >= 0.0f && isfinite(*values));
588 Source->Radius = *values;
589 DO_UPDATEPROPS();
590 return AL_TRUE;
592 case AL_STEREO_ANGLES:
593 CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
595 Source->StereoPan[0] = values[0];
596 Source->StereoPan[1] = values[1];
597 DO_UPDATEPROPS();
598 return AL_TRUE;
601 case AL_POSITION:
602 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
604 Source->Position[0] = values[0];
605 Source->Position[1] = values[1];
606 Source->Position[2] = values[2];
607 DO_UPDATEPROPS();
608 return AL_TRUE;
610 case AL_VELOCITY:
611 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
613 Source->Velocity[0] = values[0];
614 Source->Velocity[1] = values[1];
615 Source->Velocity[2] = values[2];
616 DO_UPDATEPROPS();
617 return AL_TRUE;
619 case AL_DIRECTION:
620 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
622 Source->Direction[0] = values[0];
623 Source->Direction[1] = values[1];
624 Source->Direction[2] = values[2];
625 DO_UPDATEPROPS();
626 return AL_TRUE;
628 case AL_ORIENTATION:
629 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
630 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
632 Source->Orientation[0][0] = values[0];
633 Source->Orientation[0][1] = values[1];
634 Source->Orientation[0][2] = values[2];
635 Source->Orientation[1][0] = values[3];
636 Source->Orientation[1][1] = values[4];
637 Source->Orientation[1][2] = values[5];
638 DO_UPDATEPROPS();
639 return AL_TRUE;
642 case AL_SOURCE_RELATIVE:
643 case AL_LOOPING:
644 case AL_SOURCE_STATE:
645 case AL_SOURCE_TYPE:
646 case AL_DISTANCE_MODEL:
647 case AL_DIRECT_FILTER_GAINHF_AUTO:
648 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
649 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
650 case AL_DIRECT_CHANNELS_SOFT:
651 ival = (ALint)values[0];
652 return SetSourceiv(Source, Context, prop, &ival);
654 case AL_BUFFERS_QUEUED:
655 case AL_BUFFERS_PROCESSED:
656 ival = (ALint)((ALuint)values[0]);
657 return SetSourceiv(Source, Context, prop, &ival);
659 case AL_BUFFER:
660 case AL_DIRECT_FILTER:
661 case AL_AUXILIARY_SEND_FILTER:
662 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
663 break;
666 ERR("Unexpected property: 0x%04x\n", prop);
667 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
670 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
672 ALCdevice *device = Context->Device;
673 ALbuffer *buffer = NULL;
674 ALfilter *filter = NULL;
675 ALeffectslot *slot = NULL;
676 ALbufferlistitem *oldlist;
677 ALfloat fvals[6];
679 switch(prop)
681 case AL_SOURCE_STATE:
682 case AL_SOURCE_TYPE:
683 case AL_BUFFERS_QUEUED:
684 case AL_BUFFERS_PROCESSED:
685 case AL_BYTE_LENGTH_SOFT:
686 case AL_SAMPLE_LENGTH_SOFT:
687 case AL_SEC_LENGTH_SOFT:
688 /* Query only */
689 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
691 case AL_SOURCE_RELATIVE:
692 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
694 Source->HeadRelative = (ALboolean)*values;
695 DO_UPDATEPROPS();
696 return AL_TRUE;
698 case AL_LOOPING:
699 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
701 WriteLock(&Source->queue_lock);
702 Source->Looping = (ALboolean)*values;
703 if(IsPlayingOrPaused(Source))
705 ALvoice *voice = GetSourceVoice(Source, Context);
706 if(voice)
708 if(Source->Looping)
709 ATOMIC_STORE(&voice->loop_buffer, Source->queue, almemory_order_release);
710 else
711 ATOMIC_STORE(&voice->loop_buffer, NULL, almemory_order_release);
713 /* If the source is playing, wait for the current mix to finish
714 * to ensure it isn't currently looping back or reaching the
715 * end.
717 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
718 althrd_yield();
721 WriteUnlock(&Source->queue_lock);
722 return AL_TRUE;
724 case AL_BUFFER:
725 LockBuffersRead(device);
726 if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
728 UnlockBuffersRead(device);
729 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
732 WriteLock(&Source->queue_lock);
734 ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context));
735 if(state == AL_PLAYING || state == AL_PAUSED)
737 WriteUnlock(&Source->queue_lock);
738 UnlockBuffersRead(device);
739 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
743 oldlist = Source->queue;
744 if(buffer != NULL)
746 /* Add the selected buffer to a one-item queue */
747 ALbufferlistitem *newlist = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
748 newlist->buffer = buffer;
749 newlist->next = NULL;
750 IncrementRef(&buffer->ref);
752 /* Source is now Static */
753 Source->SourceType = AL_STATIC;
754 Source->queue = newlist;
756 else
758 /* Source is now Undetermined */
759 Source->SourceType = AL_UNDETERMINED;
760 Source->queue = NULL;
762 WriteUnlock(&Source->queue_lock);
763 UnlockBuffersRead(device);
765 /* Delete all elements in the previous queue */
766 while(oldlist != NULL)
768 ALbufferlistitem *temp = oldlist;
769 oldlist = temp->next;
771 if(temp->buffer)
772 DecrementRef(&temp->buffer->ref);
773 al_free(temp);
775 return AL_TRUE;
777 case AL_SEC_OFFSET:
778 case AL_SAMPLE_OFFSET:
779 case AL_BYTE_OFFSET:
780 CHECKVAL(*values >= 0);
782 Source->OffsetType = prop;
783 Source->Offset = *values;
785 if(IsPlayingOrPaused(Source))
787 ALvoice *voice;
789 ALCdevice_Lock(Context->Device);
790 voice = GetSourceVoice(Source, Context);
791 if(voice)
793 WriteLock(&Source->queue_lock);
794 if(ApplyOffset(Source, voice) == AL_FALSE)
796 WriteUnlock(&Source->queue_lock);
797 ALCdevice_Unlock(Context->Device);
798 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
800 WriteUnlock(&Source->queue_lock);
802 ALCdevice_Unlock(Context->Device);
804 return AL_TRUE;
806 case AL_DIRECT_FILTER:
807 LockFiltersRead(device);
808 if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
810 UnlockFiltersRead(device);
811 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
814 if(!filter)
816 Source->Direct.Gain = 1.0f;
817 Source->Direct.GainHF = 1.0f;
818 Source->Direct.HFReference = LOWPASSFREQREF;
819 Source->Direct.GainLF = 1.0f;
820 Source->Direct.LFReference = HIGHPASSFREQREF;
822 else
824 Source->Direct.Gain = filter->Gain;
825 Source->Direct.GainHF = filter->GainHF;
826 Source->Direct.HFReference = filter->HFReference;
827 Source->Direct.GainLF = filter->GainLF;
828 Source->Direct.LFReference = filter->LFReference;
830 UnlockFiltersRead(device);
831 DO_UPDATEPROPS();
832 return AL_TRUE;
834 case AL_DIRECT_FILTER_GAINHF_AUTO:
835 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
837 Source->DryGainHFAuto = *values;
838 DO_UPDATEPROPS();
839 return AL_TRUE;
841 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
842 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
844 Source->WetGainAuto = *values;
845 DO_UPDATEPROPS();
846 return AL_TRUE;
848 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
849 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
851 Source->WetGainHFAuto = *values;
852 DO_UPDATEPROPS();
853 return AL_TRUE;
855 case AL_DIRECT_CHANNELS_SOFT:
856 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
858 Source->DirectChannels = *values;
859 DO_UPDATEPROPS();
860 return AL_TRUE;
862 case AL_DISTANCE_MODEL:
863 CHECKVAL(*values == AL_NONE ||
864 *values == AL_INVERSE_DISTANCE ||
865 *values == AL_INVERSE_DISTANCE_CLAMPED ||
866 *values == AL_LINEAR_DISTANCE ||
867 *values == AL_LINEAR_DISTANCE_CLAMPED ||
868 *values == AL_EXPONENT_DISTANCE ||
869 *values == AL_EXPONENT_DISTANCE_CLAMPED);
871 Source->DistanceModel = *values;
872 if(Context->SourceDistanceModel)
873 DO_UPDATEPROPS();
874 return AL_TRUE;
877 case AL_AUXILIARY_SEND_FILTER:
878 LockEffectSlotsRead(Context);
879 LockFiltersRead(device);
880 if(!((ALuint)values[1] < (ALuint)device->NumAuxSends &&
881 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
882 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
884 UnlockFiltersRead(device);
885 UnlockEffectSlotsRead(Context);
886 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
889 if(!filter)
891 /* Disable filter */
892 Source->Send[values[1]].Gain = 1.0f;
893 Source->Send[values[1]].GainHF = 1.0f;
894 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
895 Source->Send[values[1]].GainLF = 1.0f;
896 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
898 else
900 Source->Send[values[1]].Gain = filter->Gain;
901 Source->Send[values[1]].GainHF = filter->GainHF;
902 Source->Send[values[1]].HFReference = filter->HFReference;
903 Source->Send[values[1]].GainLF = filter->GainLF;
904 Source->Send[values[1]].LFReference = filter->LFReference;
906 UnlockFiltersRead(device);
908 if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source))
910 ALvoice *voice;
911 /* Add refcount on the new slot, and release the previous slot */
912 if(slot) IncrementRef(&slot->ref);
913 if(Source->Send[values[1]].Slot)
914 DecrementRef(&Source->Send[values[1]].Slot->ref);
915 Source->Send[values[1]].Slot = slot;
917 /* We must force an update if the auxiliary slot changed on an
918 * active source, in case the slot is about to be deleted.
920 if((voice=GetSourceVoice(Source, Context)) != NULL)
921 UpdateSourceProps(Source, voice, device->NumAuxSends);
922 else
923 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release);
925 else
927 if(slot) IncrementRef(&slot->ref);
928 if(Source->Send[values[1]].Slot)
929 DecrementRef(&Source->Send[values[1]].Slot->ref);
930 Source->Send[values[1]].Slot = slot;
931 DO_UPDATEPROPS();
933 UnlockEffectSlotsRead(Context);
935 return AL_TRUE;
938 /* 1x float */
939 case AL_CONE_INNER_ANGLE:
940 case AL_CONE_OUTER_ANGLE:
941 case AL_PITCH:
942 case AL_GAIN:
943 case AL_MIN_GAIN:
944 case AL_MAX_GAIN:
945 case AL_REFERENCE_DISTANCE:
946 case AL_ROLLOFF_FACTOR:
947 case AL_CONE_OUTER_GAIN:
948 case AL_MAX_DISTANCE:
949 case AL_DOPPLER_FACTOR:
950 case AL_CONE_OUTER_GAINHF:
951 case AL_AIR_ABSORPTION_FACTOR:
952 case AL_ROOM_ROLLOFF_FACTOR:
953 case AL_SOURCE_RADIUS:
954 fvals[0] = (ALfloat)*values;
955 return SetSourcefv(Source, Context, (int)prop, fvals);
957 /* 3x float */
958 case AL_POSITION:
959 case AL_VELOCITY:
960 case AL_DIRECTION:
961 fvals[0] = (ALfloat)values[0];
962 fvals[1] = (ALfloat)values[1];
963 fvals[2] = (ALfloat)values[2];
964 return SetSourcefv(Source, Context, (int)prop, fvals);
966 /* 6x float */
967 case AL_ORIENTATION:
968 fvals[0] = (ALfloat)values[0];
969 fvals[1] = (ALfloat)values[1];
970 fvals[2] = (ALfloat)values[2];
971 fvals[3] = (ALfloat)values[3];
972 fvals[4] = (ALfloat)values[4];
973 fvals[5] = (ALfloat)values[5];
974 return SetSourcefv(Source, Context, (int)prop, fvals);
976 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
977 case AL_SEC_OFFSET_LATENCY_SOFT:
978 case AL_STEREO_ANGLES:
979 break;
982 ERR("Unexpected property: 0x%04x\n", prop);
983 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
986 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
988 ALfloat fvals[6];
989 ALint ivals[3];
991 switch(prop)
993 case AL_SOURCE_TYPE:
994 case AL_BUFFERS_QUEUED:
995 case AL_BUFFERS_PROCESSED:
996 case AL_SOURCE_STATE:
997 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
998 case AL_BYTE_LENGTH_SOFT:
999 case AL_SAMPLE_LENGTH_SOFT:
1000 case AL_SEC_LENGTH_SOFT:
1001 /* Query only */
1002 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
1005 /* 1x int */
1006 case AL_SOURCE_RELATIVE:
1007 case AL_LOOPING:
1008 case AL_SEC_OFFSET:
1009 case AL_SAMPLE_OFFSET:
1010 case AL_BYTE_OFFSET:
1011 case AL_DIRECT_FILTER_GAINHF_AUTO:
1012 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1013 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1014 case AL_DIRECT_CHANNELS_SOFT:
1015 case AL_DISTANCE_MODEL:
1016 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
1018 ivals[0] = (ALint)*values;
1019 return SetSourceiv(Source, Context, (int)prop, ivals);
1021 /* 1x uint */
1022 case AL_BUFFER:
1023 case AL_DIRECT_FILTER:
1024 CHECKVAL(*values <= UINT_MAX && *values >= 0);
1026 ivals[0] = (ALuint)*values;
1027 return SetSourceiv(Source, Context, (int)prop, ivals);
1029 /* 3x uint */
1030 case AL_AUXILIARY_SEND_FILTER:
1031 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
1032 values[1] <= UINT_MAX && values[1] >= 0 &&
1033 values[2] <= UINT_MAX && values[2] >= 0);
1035 ivals[0] = (ALuint)values[0];
1036 ivals[1] = (ALuint)values[1];
1037 ivals[2] = (ALuint)values[2];
1038 return SetSourceiv(Source, Context, (int)prop, ivals);
1040 /* 1x float */
1041 case AL_CONE_INNER_ANGLE:
1042 case AL_CONE_OUTER_ANGLE:
1043 case AL_PITCH:
1044 case AL_GAIN:
1045 case AL_MIN_GAIN:
1046 case AL_MAX_GAIN:
1047 case AL_REFERENCE_DISTANCE:
1048 case AL_ROLLOFF_FACTOR:
1049 case AL_CONE_OUTER_GAIN:
1050 case AL_MAX_DISTANCE:
1051 case AL_DOPPLER_FACTOR:
1052 case AL_CONE_OUTER_GAINHF:
1053 case AL_AIR_ABSORPTION_FACTOR:
1054 case AL_ROOM_ROLLOFF_FACTOR:
1055 case AL_SOURCE_RADIUS:
1056 fvals[0] = (ALfloat)*values;
1057 return SetSourcefv(Source, Context, (int)prop, fvals);
1059 /* 3x float */
1060 case AL_POSITION:
1061 case AL_VELOCITY:
1062 case AL_DIRECTION:
1063 fvals[0] = (ALfloat)values[0];
1064 fvals[1] = (ALfloat)values[1];
1065 fvals[2] = (ALfloat)values[2];
1066 return SetSourcefv(Source, Context, (int)prop, fvals);
1068 /* 6x float */
1069 case AL_ORIENTATION:
1070 fvals[0] = (ALfloat)values[0];
1071 fvals[1] = (ALfloat)values[1];
1072 fvals[2] = (ALfloat)values[2];
1073 fvals[3] = (ALfloat)values[3];
1074 fvals[4] = (ALfloat)values[4];
1075 fvals[5] = (ALfloat)values[5];
1076 return SetSourcefv(Source, Context, (int)prop, fvals);
1078 case AL_SEC_OFFSET_LATENCY_SOFT:
1079 case AL_STEREO_ANGLES:
1080 break;
1083 ERR("Unexpected property: 0x%04x\n", prop);
1084 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1087 #undef CHECKVAL
1090 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
1092 ALCdevice *device = Context->Device;
1093 ALbufferlistitem *BufferList;
1094 ClockLatency clocktime;
1095 ALuint64 srcclock;
1096 ALint ivals[3];
1097 ALboolean err;
1099 switch(prop)
1101 case AL_GAIN:
1102 *values = Source->Gain;
1103 return AL_TRUE;
1105 case AL_PITCH:
1106 *values = Source->Pitch;
1107 return AL_TRUE;
1109 case AL_MAX_DISTANCE:
1110 *values = Source->MaxDistance;
1111 return AL_TRUE;
1113 case AL_ROLLOFF_FACTOR:
1114 *values = Source->RollOffFactor;
1115 return AL_TRUE;
1117 case AL_REFERENCE_DISTANCE:
1118 *values = Source->RefDistance;
1119 return AL_TRUE;
1121 case AL_CONE_INNER_ANGLE:
1122 *values = Source->InnerAngle;
1123 return AL_TRUE;
1125 case AL_CONE_OUTER_ANGLE:
1126 *values = Source->OuterAngle;
1127 return AL_TRUE;
1129 case AL_MIN_GAIN:
1130 *values = Source->MinGain;
1131 return AL_TRUE;
1133 case AL_MAX_GAIN:
1134 *values = Source->MaxGain;
1135 return AL_TRUE;
1137 case AL_CONE_OUTER_GAIN:
1138 *values = Source->OuterGain;
1139 return AL_TRUE;
1141 case AL_SEC_OFFSET:
1142 case AL_SAMPLE_OFFSET:
1143 case AL_BYTE_OFFSET:
1144 *values = GetSourceOffset(Source, prop, Context);
1145 return AL_TRUE;
1147 case AL_CONE_OUTER_GAINHF:
1148 *values = Source->OuterGainHF;
1149 return AL_TRUE;
1151 case AL_AIR_ABSORPTION_FACTOR:
1152 *values = Source->AirAbsorptionFactor;
1153 return AL_TRUE;
1155 case AL_ROOM_ROLLOFF_FACTOR:
1156 *values = Source->RoomRolloffFactor;
1157 return AL_TRUE;
1159 case AL_DOPPLER_FACTOR:
1160 *values = Source->DopplerFactor;
1161 return AL_TRUE;
1163 case AL_SEC_LENGTH_SOFT:
1164 ReadLock(&Source->queue_lock);
1165 if(!(BufferList=Source->queue))
1166 *values = 0;
1167 else
1169 ALint length = 0;
1170 ALsizei freq = 1;
1171 do {
1172 ALbuffer *buffer = BufferList->buffer;
1173 if(buffer && buffer->SampleLen > 0)
1175 freq = buffer->Frequency;
1176 length += buffer->SampleLen;
1178 } while((BufferList=BufferList->next) != NULL);
1179 *values = (ALdouble)length / (ALdouble)freq;
1181 ReadUnlock(&Source->queue_lock);
1182 return AL_TRUE;
1184 case AL_SOURCE_RADIUS:
1185 *values = Source->Radius;
1186 return AL_TRUE;
1188 case AL_STEREO_ANGLES:
1189 values[0] = Source->StereoPan[0];
1190 values[1] = Source->StereoPan[1];
1191 return AL_TRUE;
1193 case AL_SEC_OFFSET_LATENCY_SOFT:
1194 /* Get the source offset with the clock time first. Then get the
1195 * clock time with the device latency. Order is important.
1197 values[0] = GetSourceSecOffset(Source, Context, &srcclock);
1198 clocktime = V0(device->Backend,getClockLatency)();
1199 if(srcclock == (ALuint64)clocktime.ClockTime)
1200 values[1] = (ALdouble)clocktime.Latency / 1000000000.0;
1201 else
1203 /* If the clock time incremented, reduce the latency by that
1204 * much since it's that much closer to the source offset it got
1205 * earlier.
1207 ALuint64 diff = clocktime.ClockTime - srcclock;
1208 values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) /
1209 1000000000.0;
1211 return AL_TRUE;
1213 case AL_POSITION:
1214 values[0] = Source->Position[0];
1215 values[1] = Source->Position[1];
1216 values[2] = Source->Position[2];
1217 return AL_TRUE;
1219 case AL_VELOCITY:
1220 values[0] = Source->Velocity[0];
1221 values[1] = Source->Velocity[1];
1222 values[2] = Source->Velocity[2];
1223 return AL_TRUE;
1225 case AL_DIRECTION:
1226 values[0] = Source->Direction[0];
1227 values[1] = Source->Direction[1];
1228 values[2] = Source->Direction[2];
1229 return AL_TRUE;
1231 case AL_ORIENTATION:
1232 values[0] = Source->Orientation[0][0];
1233 values[1] = Source->Orientation[0][1];
1234 values[2] = Source->Orientation[0][2];
1235 values[3] = Source->Orientation[1][0];
1236 values[4] = Source->Orientation[1][1];
1237 values[5] = Source->Orientation[1][2];
1238 return AL_TRUE;
1240 /* 1x int */
1241 case AL_SOURCE_RELATIVE:
1242 case AL_LOOPING:
1243 case AL_SOURCE_STATE:
1244 case AL_BUFFERS_QUEUED:
1245 case AL_BUFFERS_PROCESSED:
1246 case AL_SOURCE_TYPE:
1247 case AL_DIRECT_FILTER_GAINHF_AUTO:
1248 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1249 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1250 case AL_DIRECT_CHANNELS_SOFT:
1251 case AL_BYTE_LENGTH_SOFT:
1252 case AL_SAMPLE_LENGTH_SOFT:
1253 case AL_DISTANCE_MODEL:
1254 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1255 *values = (ALdouble)ivals[0];
1256 return err;
1258 case AL_BUFFER:
1259 case AL_DIRECT_FILTER:
1260 case AL_AUXILIARY_SEND_FILTER:
1261 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1262 break;
1265 ERR("Unexpected property: 0x%04x\n", prop);
1266 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1269 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1271 ALbufferlistitem *BufferList;
1272 ALdouble dvals[6];
1273 ALboolean err;
1275 switch(prop)
1277 case AL_SOURCE_RELATIVE:
1278 *values = Source->HeadRelative;
1279 return AL_TRUE;
1281 case AL_LOOPING:
1282 *values = Source->Looping;
1283 return AL_TRUE;
1285 case AL_BUFFER:
1286 ReadLock(&Source->queue_lock);
1287 BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : NULL;
1288 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1289 ReadUnlock(&Source->queue_lock);
1290 return AL_TRUE;
1292 case AL_SOURCE_STATE:
1293 *values = GetSourceState(Source, GetSourceVoice(Source, Context));
1294 return AL_TRUE;
1296 case AL_BYTE_LENGTH_SOFT:
1297 ReadLock(&Source->queue_lock);
1298 if(!(BufferList=Source->queue))
1299 *values = 0;
1300 else
1302 ALint length = 0;
1303 do {
1304 ALbuffer *buffer = BufferList->buffer;
1305 if(buffer && buffer->SampleLen > 0)
1307 ALuint byte_align, sample_align;
1308 if(buffer->OriginalType == UserFmtIMA4)
1310 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1311 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1312 sample_align = buffer->OriginalAlign;
1314 else if(buffer->OriginalType == UserFmtMSADPCM)
1316 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1317 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1318 sample_align = buffer->OriginalAlign;
1320 else
1322 ALsizei align = buffer->OriginalAlign;
1323 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1324 sample_align = buffer->OriginalAlign;
1327 length += buffer->SampleLen / sample_align * byte_align;
1329 } while((BufferList=BufferList->next) != NULL);
1330 *values = length;
1332 ReadUnlock(&Source->queue_lock);
1333 return AL_TRUE;
1335 case AL_SAMPLE_LENGTH_SOFT:
1336 ReadLock(&Source->queue_lock);
1337 if(!(BufferList=Source->queue))
1338 *values = 0;
1339 else
1341 ALint length = 0;
1342 do {
1343 ALbuffer *buffer = BufferList->buffer;
1344 if(buffer) length += buffer->SampleLen;
1345 } while((BufferList=BufferList->next) != NULL);
1346 *values = length;
1348 ReadUnlock(&Source->queue_lock);
1349 return AL_TRUE;
1351 case AL_BUFFERS_QUEUED:
1352 ReadLock(&Source->queue_lock);
1353 if(!(BufferList=Source->queue))
1354 *values = 0;
1355 else
1357 ALsizei count = 0;
1358 do {
1359 ++count;
1360 } while((BufferList=BufferList->next) != NULL);
1361 *values = count;
1363 ReadUnlock(&Source->queue_lock);
1364 return AL_TRUE;
1366 case AL_BUFFERS_PROCESSED:
1367 ReadLock(&Source->queue_lock);
1368 if(Source->Looping || Source->SourceType != AL_STREAMING)
1370 /* Buffers on a looping source are in a perpetual state of
1371 * PENDING, so don't report any as PROCESSED */
1372 *values = 0;
1374 else
1376 const ALbufferlistitem *BufferList = Source->queue;
1377 const ALbufferlistitem *Current = NULL;
1378 ALsizei played = 0;
1379 ALvoice *voice;
1381 if((voice=GetSourceVoice(Source, Context)) != NULL)
1382 Current = ATOMIC_LOAD_SEQ(&voice->current_buffer);
1383 else if(ATOMIC_LOAD_SEQ(&Source->state) == AL_INITIAL)
1384 Current = BufferList;
1386 while(BufferList && BufferList != Current)
1388 played++;
1389 BufferList = BufferList->next;
1391 *values = played;
1393 ReadUnlock(&Source->queue_lock);
1394 return AL_TRUE;
1396 case AL_SOURCE_TYPE:
1397 *values = Source->SourceType;
1398 return AL_TRUE;
1400 case AL_DIRECT_FILTER_GAINHF_AUTO:
1401 *values = Source->DryGainHFAuto;
1402 return AL_TRUE;
1404 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1405 *values = Source->WetGainAuto;
1406 return AL_TRUE;
1408 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1409 *values = Source->WetGainHFAuto;
1410 return AL_TRUE;
1412 case AL_DIRECT_CHANNELS_SOFT:
1413 *values = Source->DirectChannels;
1414 return AL_TRUE;
1416 case AL_DISTANCE_MODEL:
1417 *values = Source->DistanceModel;
1418 return AL_TRUE;
1420 /* 1x float/double */
1421 case AL_CONE_INNER_ANGLE:
1422 case AL_CONE_OUTER_ANGLE:
1423 case AL_PITCH:
1424 case AL_GAIN:
1425 case AL_MIN_GAIN:
1426 case AL_MAX_GAIN:
1427 case AL_REFERENCE_DISTANCE:
1428 case AL_ROLLOFF_FACTOR:
1429 case AL_CONE_OUTER_GAIN:
1430 case AL_MAX_DISTANCE:
1431 case AL_SEC_OFFSET:
1432 case AL_SAMPLE_OFFSET:
1433 case AL_BYTE_OFFSET:
1434 case AL_DOPPLER_FACTOR:
1435 case AL_AIR_ABSORPTION_FACTOR:
1436 case AL_ROOM_ROLLOFF_FACTOR:
1437 case AL_CONE_OUTER_GAINHF:
1438 case AL_SEC_LENGTH_SOFT:
1439 case AL_SOURCE_RADIUS:
1440 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1441 *values = (ALint)dvals[0];
1442 return err;
1444 /* 3x float/double */
1445 case AL_POSITION:
1446 case AL_VELOCITY:
1447 case AL_DIRECTION:
1448 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1450 values[0] = (ALint)dvals[0];
1451 values[1] = (ALint)dvals[1];
1452 values[2] = (ALint)dvals[2];
1454 return err;
1456 /* 6x float/double */
1457 case AL_ORIENTATION:
1458 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1460 values[0] = (ALint)dvals[0];
1461 values[1] = (ALint)dvals[1];
1462 values[2] = (ALint)dvals[2];
1463 values[3] = (ALint)dvals[3];
1464 values[4] = (ALint)dvals[4];
1465 values[5] = (ALint)dvals[5];
1467 return err;
1469 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1470 break; /* i64 only */
1471 case AL_SEC_OFFSET_LATENCY_SOFT:
1472 break; /* Double only */
1473 case AL_STEREO_ANGLES:
1474 break; /* Float/double only */
1476 case AL_DIRECT_FILTER:
1477 case AL_AUXILIARY_SEND_FILTER:
1478 break; /* ??? */
1481 ERR("Unexpected property: 0x%04x\n", prop);
1482 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1485 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1487 ALCdevice *device = Context->Device;
1488 ClockLatency clocktime;
1489 ALuint64 srcclock;
1490 ALdouble dvals[6];
1491 ALint ivals[3];
1492 ALboolean err;
1494 switch(prop)
1496 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1497 /* Get the source offset with the clock time first. Then get the
1498 * clock time with the device latency. Order is important.
1500 values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
1501 clocktime = V0(device->Backend,getClockLatency)();
1502 if(srcclock == (ALuint64)clocktime.ClockTime)
1503 values[1] = clocktime.Latency;
1504 else
1506 /* If the clock time incremented, reduce the latency by that
1507 * much since it's that much closer to the source offset it got
1508 * earlier.
1510 ALuint64 diff = clocktime.ClockTime - srcclock;
1511 values[1] = clocktime.Latency - minu64(clocktime.Latency, diff);
1513 return AL_TRUE;
1515 /* 1x float/double */
1516 case AL_CONE_INNER_ANGLE:
1517 case AL_CONE_OUTER_ANGLE:
1518 case AL_PITCH:
1519 case AL_GAIN:
1520 case AL_MIN_GAIN:
1521 case AL_MAX_GAIN:
1522 case AL_REFERENCE_DISTANCE:
1523 case AL_ROLLOFF_FACTOR:
1524 case AL_CONE_OUTER_GAIN:
1525 case AL_MAX_DISTANCE:
1526 case AL_SEC_OFFSET:
1527 case AL_SAMPLE_OFFSET:
1528 case AL_BYTE_OFFSET:
1529 case AL_DOPPLER_FACTOR:
1530 case AL_AIR_ABSORPTION_FACTOR:
1531 case AL_ROOM_ROLLOFF_FACTOR:
1532 case AL_CONE_OUTER_GAINHF:
1533 case AL_SEC_LENGTH_SOFT:
1534 case AL_SOURCE_RADIUS:
1535 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1536 *values = (ALint64)dvals[0];
1537 return err;
1539 /* 3x float/double */
1540 case AL_POSITION:
1541 case AL_VELOCITY:
1542 case AL_DIRECTION:
1543 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1545 values[0] = (ALint64)dvals[0];
1546 values[1] = (ALint64)dvals[1];
1547 values[2] = (ALint64)dvals[2];
1549 return err;
1551 /* 6x float/double */
1552 case AL_ORIENTATION:
1553 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1555 values[0] = (ALint64)dvals[0];
1556 values[1] = (ALint64)dvals[1];
1557 values[2] = (ALint64)dvals[2];
1558 values[3] = (ALint64)dvals[3];
1559 values[4] = (ALint64)dvals[4];
1560 values[5] = (ALint64)dvals[5];
1562 return err;
1564 /* 1x int */
1565 case AL_SOURCE_RELATIVE:
1566 case AL_LOOPING:
1567 case AL_SOURCE_STATE:
1568 case AL_BUFFERS_QUEUED:
1569 case AL_BUFFERS_PROCESSED:
1570 case AL_BYTE_LENGTH_SOFT:
1571 case AL_SAMPLE_LENGTH_SOFT:
1572 case AL_SOURCE_TYPE:
1573 case AL_DIRECT_FILTER_GAINHF_AUTO:
1574 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1575 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1576 case AL_DIRECT_CHANNELS_SOFT:
1577 case AL_DISTANCE_MODEL:
1578 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1579 *values = ivals[0];
1580 return err;
1582 /* 1x uint */
1583 case AL_BUFFER:
1584 case AL_DIRECT_FILTER:
1585 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1586 *values = (ALuint)ivals[0];
1587 return err;
1589 /* 3x uint */
1590 case AL_AUXILIARY_SEND_FILTER:
1591 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1593 values[0] = (ALuint)ivals[0];
1594 values[1] = (ALuint)ivals[1];
1595 values[2] = (ALuint)ivals[2];
1597 return err;
1599 case AL_SEC_OFFSET_LATENCY_SOFT:
1600 break; /* Double only */
1601 case AL_STEREO_ANGLES:
1602 break; /* Float/double only */
1605 ERR("Unexpected property: 0x%04x\n", prop);
1606 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1610 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1612 ALCdevice *device;
1613 ALCcontext *context;
1614 ALsizei cur = 0;
1615 ALenum err;
1617 context = GetContextRef();
1618 if(!context) return;
1620 if(!(n >= 0))
1621 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1622 device = context->Device;
1623 for(cur = 0;cur < n;cur++)
1625 ALsource *source = al_calloc(16, sizeof(ALsource));
1626 if(!source)
1628 alDeleteSources(cur, sources);
1629 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1631 InitSourceParams(source, device->NumAuxSends);
1633 err = NewThunkEntry(&source->id);
1634 if(err == AL_NO_ERROR)
1635 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1636 if(err != AL_NO_ERROR)
1638 FreeThunkEntry(source->id);
1639 memset(source, 0, sizeof(ALsource));
1640 al_free(source);
1642 alDeleteSources(cur, sources);
1643 SET_ERROR_AND_GOTO(context, err, done);
1646 sources[cur] = source->id;
1649 done:
1650 ALCcontext_DecRef(context);
1654 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1656 ALCdevice *device;
1657 ALCcontext *context;
1658 ALsource *Source;
1659 ALsizei i;
1661 context = GetContextRef();
1662 if(!context) return;
1664 LockSourcesWrite(context);
1665 if(!(n >= 0))
1666 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1668 /* Check that all Sources are valid */
1669 for(i = 0;i < n;i++)
1671 if(LookupSource(context, sources[i]) == NULL)
1672 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1674 device = context->Device;
1675 for(i = 0;i < n;i++)
1677 ALvoice *voice;
1679 if((Source=RemoveSource(context, sources[i])) == NULL)
1680 continue;
1681 FreeThunkEntry(Source->id);
1683 ALCdevice_Lock(device);
1684 if((voice=GetSourceVoice(Source, context)) != NULL)
1686 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
1687 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
1689 ALCdevice_Unlock(device);
1691 DeinitSource(Source, device->NumAuxSends);
1693 memset(Source, 0, sizeof(*Source));
1694 al_free(Source);
1697 done:
1698 UnlockSourcesWrite(context);
1699 ALCcontext_DecRef(context);
1703 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1705 ALCcontext *context;
1706 ALboolean ret;
1708 context = GetContextRef();
1709 if(!context) return AL_FALSE;
1711 LockSourcesRead(context);
1712 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1713 UnlockSourcesRead(context);
1715 ALCcontext_DecRef(context);
1717 return ret;
1721 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1723 ALCcontext *Context;
1724 ALsource *Source;
1726 Context = GetContextRef();
1727 if(!Context) return;
1729 WriteLock(&Context->PropLock);
1730 LockSourcesRead(Context);
1731 if((Source=LookupSource(Context, source)) == NULL)
1732 alSetError(Context, AL_INVALID_NAME);
1733 else if(!(FloatValsByProp(param) == 1))
1734 alSetError(Context, AL_INVALID_ENUM);
1735 else
1736 SetSourcefv(Source, Context, param, &value);
1737 UnlockSourcesRead(Context);
1738 WriteUnlock(&Context->PropLock);
1740 ALCcontext_DecRef(Context);
1743 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1745 ALCcontext *Context;
1746 ALsource *Source;
1748 Context = GetContextRef();
1749 if(!Context) return;
1751 WriteLock(&Context->PropLock);
1752 LockSourcesRead(Context);
1753 if((Source=LookupSource(Context, source)) == NULL)
1754 alSetError(Context, AL_INVALID_NAME);
1755 else if(!(FloatValsByProp(param) == 3))
1756 alSetError(Context, AL_INVALID_ENUM);
1757 else
1759 ALfloat fvals[3] = { value1, value2, value3 };
1760 SetSourcefv(Source, Context, param, fvals);
1762 UnlockSourcesRead(Context);
1763 WriteUnlock(&Context->PropLock);
1765 ALCcontext_DecRef(Context);
1768 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1770 ALCcontext *Context;
1771 ALsource *Source;
1773 Context = GetContextRef();
1774 if(!Context) return;
1776 WriteLock(&Context->PropLock);
1777 LockSourcesRead(Context);
1778 if((Source=LookupSource(Context, source)) == NULL)
1779 alSetError(Context, AL_INVALID_NAME);
1780 else if(!values)
1781 alSetError(Context, AL_INVALID_VALUE);
1782 else if(!(FloatValsByProp(param) > 0))
1783 alSetError(Context, AL_INVALID_ENUM);
1784 else
1785 SetSourcefv(Source, Context, param, values);
1786 UnlockSourcesRead(Context);
1787 WriteUnlock(&Context->PropLock);
1789 ALCcontext_DecRef(Context);
1793 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1795 ALCcontext *Context;
1796 ALsource *Source;
1798 Context = GetContextRef();
1799 if(!Context) return;
1801 WriteLock(&Context->PropLock);
1802 LockSourcesRead(Context);
1803 if((Source=LookupSource(Context, source)) == NULL)
1804 alSetError(Context, AL_INVALID_NAME);
1805 else if(!(DoubleValsByProp(param) == 1))
1806 alSetError(Context, AL_INVALID_ENUM);
1807 else
1809 ALfloat fval = (ALfloat)value;
1810 SetSourcefv(Source, Context, param, &fval);
1812 UnlockSourcesRead(Context);
1813 WriteUnlock(&Context->PropLock);
1815 ALCcontext_DecRef(Context);
1818 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1820 ALCcontext *Context;
1821 ALsource *Source;
1823 Context = GetContextRef();
1824 if(!Context) return;
1826 WriteLock(&Context->PropLock);
1827 LockSourcesRead(Context);
1828 if((Source=LookupSource(Context, source)) == NULL)
1829 alSetError(Context, AL_INVALID_NAME);
1830 else if(!(DoubleValsByProp(param) == 3))
1831 alSetError(Context, AL_INVALID_ENUM);
1832 else
1834 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1835 SetSourcefv(Source, Context, param, fvals);
1837 UnlockSourcesRead(Context);
1838 WriteUnlock(&Context->PropLock);
1840 ALCcontext_DecRef(Context);
1843 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1845 ALCcontext *Context;
1846 ALsource *Source;
1847 ALint count;
1849 Context = GetContextRef();
1850 if(!Context) return;
1852 WriteLock(&Context->PropLock);
1853 LockSourcesRead(Context);
1854 if((Source=LookupSource(Context, source)) == NULL)
1855 alSetError(Context, AL_INVALID_NAME);
1856 else if(!values)
1857 alSetError(Context, AL_INVALID_VALUE);
1858 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1859 alSetError(Context, AL_INVALID_ENUM);
1860 else
1862 ALfloat fvals[6];
1863 ALint i;
1865 for(i = 0;i < count;i++)
1866 fvals[i] = (ALfloat)values[i];
1867 SetSourcefv(Source, Context, param, fvals);
1869 UnlockSourcesRead(Context);
1870 WriteUnlock(&Context->PropLock);
1872 ALCcontext_DecRef(Context);
1876 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1878 ALCcontext *Context;
1879 ALsource *Source;
1881 Context = GetContextRef();
1882 if(!Context) return;
1884 WriteLock(&Context->PropLock);
1885 LockSourcesRead(Context);
1886 if((Source=LookupSource(Context, source)) == NULL)
1887 alSetError(Context, AL_INVALID_NAME);
1888 else if(!(IntValsByProp(param) == 1))
1889 alSetError(Context, AL_INVALID_ENUM);
1890 else
1891 SetSourceiv(Source, Context, param, &value);
1892 UnlockSourcesRead(Context);
1893 WriteUnlock(&Context->PropLock);
1895 ALCcontext_DecRef(Context);
1898 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1900 ALCcontext *Context;
1901 ALsource *Source;
1903 Context = GetContextRef();
1904 if(!Context) return;
1906 WriteLock(&Context->PropLock);
1907 LockSourcesRead(Context);
1908 if((Source=LookupSource(Context, source)) == NULL)
1909 alSetError(Context, AL_INVALID_NAME);
1910 else if(!(IntValsByProp(param) == 3))
1911 alSetError(Context, AL_INVALID_ENUM);
1912 else
1914 ALint ivals[3] = { value1, value2, value3 };
1915 SetSourceiv(Source, Context, param, ivals);
1917 UnlockSourcesRead(Context);
1918 WriteUnlock(&Context->PropLock);
1920 ALCcontext_DecRef(Context);
1923 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1925 ALCcontext *Context;
1926 ALsource *Source;
1928 Context = GetContextRef();
1929 if(!Context) return;
1931 WriteLock(&Context->PropLock);
1932 LockSourcesRead(Context);
1933 if((Source=LookupSource(Context, source)) == NULL)
1934 alSetError(Context, AL_INVALID_NAME);
1935 else if(!values)
1936 alSetError(Context, AL_INVALID_VALUE);
1937 else if(!(IntValsByProp(param) > 0))
1938 alSetError(Context, AL_INVALID_ENUM);
1939 else
1940 SetSourceiv(Source, Context, param, values);
1941 UnlockSourcesRead(Context);
1942 WriteUnlock(&Context->PropLock);
1944 ALCcontext_DecRef(Context);
1948 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1950 ALCcontext *Context;
1951 ALsource *Source;
1953 Context = GetContextRef();
1954 if(!Context) return;
1956 WriteLock(&Context->PropLock);
1957 LockSourcesRead(Context);
1958 if((Source=LookupSource(Context, source)) == NULL)
1959 alSetError(Context, AL_INVALID_NAME);
1960 else if(!(Int64ValsByProp(param) == 1))
1961 alSetError(Context, AL_INVALID_ENUM);
1962 else
1963 SetSourcei64v(Source, Context, param, &value);
1964 UnlockSourcesRead(Context);
1965 WriteUnlock(&Context->PropLock);
1967 ALCcontext_DecRef(Context);
1970 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1972 ALCcontext *Context;
1973 ALsource *Source;
1975 Context = GetContextRef();
1976 if(!Context) return;
1978 WriteLock(&Context->PropLock);
1979 LockSourcesRead(Context);
1980 if((Source=LookupSource(Context, source)) == NULL)
1981 alSetError(Context, AL_INVALID_NAME);
1982 else if(!(Int64ValsByProp(param) == 3))
1983 alSetError(Context, AL_INVALID_ENUM);
1984 else
1986 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1987 SetSourcei64v(Source, Context, param, i64vals);
1989 UnlockSourcesRead(Context);
1990 WriteUnlock(&Context->PropLock);
1992 ALCcontext_DecRef(Context);
1995 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1997 ALCcontext *Context;
1998 ALsource *Source;
2000 Context = GetContextRef();
2001 if(!Context) return;
2003 WriteLock(&Context->PropLock);
2004 LockSourcesRead(Context);
2005 if((Source=LookupSource(Context, source)) == NULL)
2006 alSetError(Context, AL_INVALID_NAME);
2007 else if(!values)
2008 alSetError(Context, AL_INVALID_VALUE);
2009 else if(!(Int64ValsByProp(param) > 0))
2010 alSetError(Context, AL_INVALID_ENUM);
2011 else
2012 SetSourcei64v(Source, Context, param, values);
2013 UnlockSourcesRead(Context);
2014 WriteUnlock(&Context->PropLock);
2016 ALCcontext_DecRef(Context);
2020 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
2022 ALCcontext *Context;
2023 ALsource *Source;
2025 Context = GetContextRef();
2026 if(!Context) return;
2028 ReadLock(&Context->PropLock);
2029 LockSourcesRead(Context);
2030 if((Source=LookupSource(Context, source)) == NULL)
2031 alSetError(Context, AL_INVALID_NAME);
2032 else if(!value)
2033 alSetError(Context, AL_INVALID_VALUE);
2034 else if(!(FloatValsByProp(param) == 1))
2035 alSetError(Context, AL_INVALID_ENUM);
2036 else
2038 ALdouble dval;
2039 if(GetSourcedv(Source, Context, param, &dval))
2040 *value = (ALfloat)dval;
2042 UnlockSourcesRead(Context);
2043 ReadUnlock(&Context->PropLock);
2045 ALCcontext_DecRef(Context);
2049 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
2051 ALCcontext *Context;
2052 ALsource *Source;
2054 Context = GetContextRef();
2055 if(!Context) return;
2057 ReadLock(&Context->PropLock);
2058 LockSourcesRead(Context);
2059 if((Source=LookupSource(Context, source)) == NULL)
2060 alSetError(Context, AL_INVALID_NAME);
2061 else if(!(value1 && value2 && value3))
2062 alSetError(Context, AL_INVALID_VALUE);
2063 else if(!(FloatValsByProp(param) == 3))
2064 alSetError(Context, AL_INVALID_ENUM);
2065 else
2067 ALdouble dvals[3];
2068 if(GetSourcedv(Source, Context, param, dvals))
2070 *value1 = (ALfloat)dvals[0];
2071 *value2 = (ALfloat)dvals[1];
2072 *value3 = (ALfloat)dvals[2];
2075 UnlockSourcesRead(Context);
2076 ReadUnlock(&Context->PropLock);
2078 ALCcontext_DecRef(Context);
2082 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
2084 ALCcontext *Context;
2085 ALsource *Source;
2086 ALint count;
2088 Context = GetContextRef();
2089 if(!Context) return;
2091 ReadLock(&Context->PropLock);
2092 LockSourcesRead(Context);
2093 if((Source=LookupSource(Context, source)) == NULL)
2094 alSetError(Context, AL_INVALID_NAME);
2095 else if(!values)
2096 alSetError(Context, AL_INVALID_VALUE);
2097 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
2098 alSetError(Context, AL_INVALID_ENUM);
2099 else
2101 ALdouble dvals[6];
2102 if(GetSourcedv(Source, Context, param, dvals))
2104 ALint i;
2105 for(i = 0;i < count;i++)
2106 values[i] = (ALfloat)dvals[i];
2109 UnlockSourcesRead(Context);
2110 ReadUnlock(&Context->PropLock);
2112 ALCcontext_DecRef(Context);
2116 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
2118 ALCcontext *Context;
2119 ALsource *Source;
2121 Context = GetContextRef();
2122 if(!Context) return;
2124 ReadLock(&Context->PropLock);
2125 LockSourcesRead(Context);
2126 if((Source=LookupSource(Context, source)) == NULL)
2127 alSetError(Context, AL_INVALID_NAME);
2128 else if(!value)
2129 alSetError(Context, AL_INVALID_VALUE);
2130 else if(!(DoubleValsByProp(param) == 1))
2131 alSetError(Context, AL_INVALID_ENUM);
2132 else
2133 GetSourcedv(Source, Context, param, value);
2134 UnlockSourcesRead(Context);
2135 ReadUnlock(&Context->PropLock);
2137 ALCcontext_DecRef(Context);
2140 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
2142 ALCcontext *Context;
2143 ALsource *Source;
2145 Context = GetContextRef();
2146 if(!Context) return;
2148 ReadLock(&Context->PropLock);
2149 LockSourcesRead(Context);
2150 if((Source=LookupSource(Context, source)) == NULL)
2151 alSetError(Context, AL_INVALID_NAME);
2152 else if(!(value1 && value2 && value3))
2153 alSetError(Context, AL_INVALID_VALUE);
2154 else if(!(DoubleValsByProp(param) == 3))
2155 alSetError(Context, AL_INVALID_ENUM);
2156 else
2158 ALdouble dvals[3];
2159 if(GetSourcedv(Source, Context, param, dvals))
2161 *value1 = dvals[0];
2162 *value2 = dvals[1];
2163 *value3 = dvals[2];
2166 UnlockSourcesRead(Context);
2167 ReadUnlock(&Context->PropLock);
2169 ALCcontext_DecRef(Context);
2172 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
2174 ALCcontext *Context;
2175 ALsource *Source;
2177 Context = GetContextRef();
2178 if(!Context) return;
2180 ReadLock(&Context->PropLock);
2181 LockSourcesRead(Context);
2182 if((Source=LookupSource(Context, source)) == NULL)
2183 alSetError(Context, AL_INVALID_NAME);
2184 else if(!values)
2185 alSetError(Context, AL_INVALID_VALUE);
2186 else if(!(DoubleValsByProp(param) > 0))
2187 alSetError(Context, AL_INVALID_ENUM);
2188 else
2189 GetSourcedv(Source, Context, param, values);
2190 UnlockSourcesRead(Context);
2191 ReadUnlock(&Context->PropLock);
2193 ALCcontext_DecRef(Context);
2197 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2199 ALCcontext *Context;
2200 ALsource *Source;
2202 Context = GetContextRef();
2203 if(!Context) return;
2205 ReadLock(&Context->PropLock);
2206 LockSourcesRead(Context);
2207 if((Source=LookupSource(Context, source)) == NULL)
2208 alSetError(Context, AL_INVALID_NAME);
2209 else if(!value)
2210 alSetError(Context, AL_INVALID_VALUE);
2211 else if(!(IntValsByProp(param) == 1))
2212 alSetError(Context, AL_INVALID_ENUM);
2213 else
2214 GetSourceiv(Source, Context, param, value);
2215 UnlockSourcesRead(Context);
2216 ReadUnlock(&Context->PropLock);
2218 ALCcontext_DecRef(Context);
2222 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2224 ALCcontext *Context;
2225 ALsource *Source;
2227 Context = GetContextRef();
2228 if(!Context) return;
2230 ReadLock(&Context->PropLock);
2231 LockSourcesRead(Context);
2232 if((Source=LookupSource(Context, source)) == NULL)
2233 alSetError(Context, AL_INVALID_NAME);
2234 else if(!(value1 && value2 && value3))
2235 alSetError(Context, AL_INVALID_VALUE);
2236 else if(!(IntValsByProp(param) == 3))
2237 alSetError(Context, AL_INVALID_ENUM);
2238 else
2240 ALint ivals[3];
2241 if(GetSourceiv(Source, Context, param, ivals))
2243 *value1 = ivals[0];
2244 *value2 = ivals[1];
2245 *value3 = ivals[2];
2248 UnlockSourcesRead(Context);
2249 ReadUnlock(&Context->PropLock);
2251 ALCcontext_DecRef(Context);
2255 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2257 ALCcontext *Context;
2258 ALsource *Source;
2260 Context = GetContextRef();
2261 if(!Context) return;
2263 ReadLock(&Context->PropLock);
2264 LockSourcesRead(Context);
2265 if((Source=LookupSource(Context, source)) == NULL)
2266 alSetError(Context, AL_INVALID_NAME);
2267 else if(!values)
2268 alSetError(Context, AL_INVALID_VALUE);
2269 else if(!(IntValsByProp(param) > 0))
2270 alSetError(Context, AL_INVALID_ENUM);
2271 else
2272 GetSourceiv(Source, Context, param, values);
2273 UnlockSourcesRead(Context);
2274 ReadUnlock(&Context->PropLock);
2276 ALCcontext_DecRef(Context);
2280 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2282 ALCcontext *Context;
2283 ALsource *Source;
2285 Context = GetContextRef();
2286 if(!Context) return;
2288 ReadLock(&Context->PropLock);
2289 LockSourcesRead(Context);
2290 if((Source=LookupSource(Context, source)) == NULL)
2291 alSetError(Context, AL_INVALID_NAME);
2292 else if(!value)
2293 alSetError(Context, AL_INVALID_VALUE);
2294 else if(!(Int64ValsByProp(param) == 1))
2295 alSetError(Context, AL_INVALID_ENUM);
2296 else
2297 GetSourcei64v(Source, Context, param, value);
2298 UnlockSourcesRead(Context);
2299 ReadUnlock(&Context->PropLock);
2301 ALCcontext_DecRef(Context);
2304 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
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(!(value1 && value2 && value3))
2317 alSetError(Context, AL_INVALID_VALUE);
2318 else if(!(Int64ValsByProp(param) == 3))
2319 alSetError(Context, AL_INVALID_ENUM);
2320 else
2322 ALint64 i64vals[3];
2323 if(GetSourcei64v(Source, Context, param, i64vals))
2325 *value1 = i64vals[0];
2326 *value2 = i64vals[1];
2327 *value3 = i64vals[2];
2330 UnlockSourcesRead(Context);
2331 ReadUnlock(&Context->PropLock);
2333 ALCcontext_DecRef(Context);
2336 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2338 ALCcontext *Context;
2339 ALsource *Source;
2341 Context = GetContextRef();
2342 if(!Context) return;
2344 ReadLock(&Context->PropLock);
2345 LockSourcesRead(Context);
2346 if((Source=LookupSource(Context, source)) == NULL)
2347 alSetError(Context, AL_INVALID_NAME);
2348 else if(!values)
2349 alSetError(Context, AL_INVALID_VALUE);
2350 else if(!(Int64ValsByProp(param) > 0))
2351 alSetError(Context, AL_INVALID_ENUM);
2352 else
2353 GetSourcei64v(Source, Context, param, values);
2354 UnlockSourcesRead(Context);
2355 ReadUnlock(&Context->PropLock);
2357 ALCcontext_DecRef(Context);
2361 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2363 alSourcePlayv(1, &source);
2365 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2367 ALCcontext *context;
2368 ALCdevice *device;
2369 ALsource *source;
2370 ALvoice *voice;
2371 ALsizei i, j;
2373 context = GetContextRef();
2374 if(!context) return;
2376 LockSourcesRead(context);
2377 if(!(n >= 0))
2378 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2379 for(i = 0;i < n;i++)
2381 if(!LookupSource(context, sources[i]))
2382 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2385 device = context->Device;
2386 ALCdevice_Lock(device);
2387 /* If the device is disconnected, go right to stopped. */
2388 if(!device->Connected)
2390 for(i = 0;i < n;i++)
2392 source = LookupSource(context, sources[i]);
2393 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2395 ALCdevice_Unlock(device);
2396 goto done;
2399 while(n > context->MaxVoices-context->VoiceCount)
2401 ALsizei newcount = context->MaxVoices << 1;
2402 if(context->MaxVoices >= newcount)
2404 ALCdevice_Unlock(device);
2405 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2407 AllocateVoices(context, newcount, device->NumAuxSends);
2410 for(i = 0;i < n;i++)
2412 ALbufferlistitem *BufferList;
2413 ALbuffer *buffer = NULL;
2415 source = LookupSource(context, sources[i]);
2416 WriteLock(&source->queue_lock);
2417 /* Check that there is a queue containing at least one valid, non zero
2418 * length Buffer.
2420 BufferList = source->queue;
2421 while(BufferList)
2423 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2424 break;
2425 BufferList = BufferList->next;
2428 /* If there's nothing to play, go right to stopped. */
2429 if(!BufferList)
2431 /* NOTE: A source without any playable buffers should not have an
2432 * ALvoice since it shouldn't be in a playing or paused state. So
2433 * there's no need to look up its voice and clear the source.
2435 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2436 source->OffsetType = AL_NONE;
2437 source->Offset = 0.0;
2438 goto finish_play;
2441 voice = GetSourceVoice(source, context);
2442 switch(GetSourceState(source, voice))
2444 case AL_PLAYING:
2445 assert(voice != NULL);
2446 /* A source that's already playing is restarted from the beginning. */
2447 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
2448 ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
2449 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release);
2450 goto finish_play;
2452 case AL_PAUSED:
2453 assert(voice != NULL);
2454 /* A source that's paused simply resumes. Make sure it uses the
2455 * volume last specified; there's no reason to fade from where
2456 * it stopped at.
2458 voice->Flags &= ~VOICE_IS_MOVING;
2459 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
2460 ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release);
2461 goto finish_play;
2463 default:
2464 break;
2467 /* Make sure this source isn't already active, and if not, look for an
2468 * unused voice to put it in.
2470 assert(voice == NULL);
2471 for(j = 0;j < context->VoiceCount;j++)
2473 if(ATOMIC_LOAD(&context->Voices[j]->Source, almemory_order_acquire) == NULL)
2475 voice = context->Voices[j];
2476 break;
2479 if(voice == NULL)
2480 voice = context->Voices[context->VoiceCount++];
2481 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2483 ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acquire);
2484 UpdateSourceProps(source, voice, device->NumAuxSends);
2486 /* A source that's not playing or paused has any offset applied when it
2487 * starts playing.
2489 if(source->Looping)
2490 ATOMIC_STORE(&voice->loop_buffer, source->queue, almemory_order_relaxed);
2491 else
2492 ATOMIC_STORE(&voice->loop_buffer, NULL, almemory_order_relaxed);
2493 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
2494 ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
2495 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed);
2496 if(source->OffsetType != AL_NONE)
2497 ApplyOffset(source, voice);
2499 voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2500 voice->SampleSize = BytesFromFmt(buffer->FmtType);
2502 /* Clear previous samples. */
2503 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
2505 /* Clear the stepping value so the mixer knows not to mix this until
2506 * the update gets applied.
2508 voice->Step = 0;
2510 voice->Flags = 0;
2511 for(j = 0;j < voice->NumChannels;j++)
2512 memset(&voice->Direct.Params[j].Hrtf.State, 0,
2513 sizeof(voice->Direct.Params[j].Hrtf.State));
2514 if(device->AvgSpeakerDist > 0.0f)
2516 ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC /
2517 (device->AvgSpeakerDist * device->Frequency);
2518 for(j = 0;j < voice->NumChannels;j++)
2520 NfcFilterCreate1(&voice->Direct.Params[j].NFCtrlFilter[0], 0.0f, w1);
2521 NfcFilterCreate2(&voice->Direct.Params[j].NFCtrlFilter[1], 0.0f, w1);
2522 NfcFilterCreate3(&voice->Direct.Params[j].NFCtrlFilter[2], 0.0f, w1);
2526 ATOMIC_STORE(&voice->Source, source, almemory_order_relaxed);
2527 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
2528 ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release);
2529 finish_play:
2530 WriteUnlock(&source->queue_lock);
2532 ALCdevice_Unlock(device);
2534 done:
2535 UnlockSourcesRead(context);
2536 ALCcontext_DecRef(context);
2539 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2541 alSourcePausev(1, &source);
2543 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2545 ALCcontext *context;
2546 ALCdevice *device;
2547 ALsource *source;
2548 ALvoice *voice;
2549 ALsizei i;
2551 context = GetContextRef();
2552 if(!context) return;
2554 LockSourcesRead(context);
2555 if(!(n >= 0))
2556 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2557 for(i = 0;i < n;i++)
2559 if(!LookupSource(context, sources[i]))
2560 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2563 device = context->Device;
2564 ALCdevice_Lock(device);
2565 for(i = 0;i < n;i++)
2567 source = LookupSource(context, sources[i]);
2568 WriteLock(&source->queue_lock);
2569 if((voice=GetSourceVoice(source, context)) != NULL)
2571 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2572 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2573 althrd_yield();
2575 if(GetSourceState(source, voice) == AL_PLAYING)
2576 ATOMIC_STORE(&source->state, AL_PAUSED, almemory_order_release);
2577 WriteUnlock(&source->queue_lock);
2579 ALCdevice_Unlock(device);
2581 done:
2582 UnlockSourcesRead(context);
2583 ALCcontext_DecRef(context);
2586 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2588 alSourceStopv(1, &source);
2590 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2592 ALCcontext *context;
2593 ALCdevice *device;
2594 ALsource *source;
2595 ALvoice *voice;
2596 ALsizei i;
2598 context = GetContextRef();
2599 if(!context) return;
2601 LockSourcesRead(context);
2602 if(!(n >= 0))
2603 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2604 for(i = 0;i < n;i++)
2606 if(!LookupSource(context, sources[i]))
2607 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2610 device = context->Device;
2611 ALCdevice_Lock(device);
2612 for(i = 0;i < n;i++)
2614 source = LookupSource(context, sources[i]);
2615 WriteLock(&source->queue_lock);
2616 if((voice=GetSourceVoice(source, context)) != NULL)
2618 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
2619 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2620 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2621 althrd_yield();
2623 if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL)
2624 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2625 source->OffsetType = AL_NONE;
2626 source->Offset = 0.0;
2627 WriteUnlock(&source->queue_lock);
2629 ALCdevice_Unlock(device);
2631 done:
2632 UnlockSourcesRead(context);
2633 ALCcontext_DecRef(context);
2636 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2638 alSourceRewindv(1, &source);
2640 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2642 ALCcontext *context;
2643 ALCdevice *device;
2644 ALsource *source;
2645 ALvoice *voice;
2646 ALsizei i;
2648 context = GetContextRef();
2649 if(!context) return;
2651 LockSourcesRead(context);
2652 if(!(n >= 0))
2653 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2654 for(i = 0;i < n;i++)
2656 if(!LookupSource(context, sources[i]))
2657 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2660 device = context->Device;
2661 ALCdevice_Lock(device);
2662 for(i = 0;i < n;i++)
2664 source = LookupSource(context, sources[i]);
2665 WriteLock(&source->queue_lock);
2666 if((voice=GetSourceVoice(source, context)) != NULL)
2668 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
2669 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2670 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2671 althrd_yield();
2673 if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL)
2674 ATOMIC_STORE(&source->state, AL_INITIAL, almemory_order_relaxed);
2675 source->OffsetType = AL_NONE;
2676 source->Offset = 0.0;
2677 WriteUnlock(&source->queue_lock);
2679 ALCdevice_Unlock(device);
2681 done:
2682 UnlockSourcesRead(context);
2683 ALCcontext_DecRef(context);
2687 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2689 ALCdevice *device;
2690 ALCcontext *context;
2691 ALsource *source;
2692 ALsizei i;
2693 ALbufferlistitem *BufferListStart;
2694 ALbufferlistitem *BufferList;
2695 ALbuffer *BufferFmt = NULL;
2697 if(nb == 0)
2698 return;
2700 context = GetContextRef();
2701 if(!context) return;
2703 device = context->Device;
2705 LockSourcesRead(context);
2706 if(!(nb >= 0))
2707 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2708 if((source=LookupSource(context, src)) == NULL)
2709 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2711 WriteLock(&source->queue_lock);
2712 if(source->SourceType == AL_STATIC)
2714 WriteUnlock(&source->queue_lock);
2715 /* Can't queue on a Static Source */
2716 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2719 /* Check for a valid Buffer, for its frequency and format */
2720 BufferList = source->queue;
2721 while(BufferList)
2723 if(BufferList->buffer)
2725 BufferFmt = BufferList->buffer;
2726 break;
2728 BufferList = BufferList->next;
2731 LockBuffersRead(device);
2732 BufferListStart = NULL;
2733 BufferList = NULL;
2734 for(i = 0;i < nb;i++)
2736 ALbuffer *buffer = NULL;
2737 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2739 WriteUnlock(&source->queue_lock);
2740 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2743 if(!BufferListStart)
2745 BufferListStart = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
2746 BufferList = BufferListStart;
2748 else
2750 BufferList->next = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
2751 BufferList = BufferList->next;
2753 BufferList->buffer = buffer;
2754 BufferList->next = NULL;
2755 if(!buffer) continue;
2757 /* Hold a read lock on each buffer being queued while checking all
2758 * provided buffers. This is done so other threads don't see an extra
2759 * reference on some buffers if this operation ends up failing. */
2760 ReadLock(&buffer->lock);
2761 IncrementRef(&buffer->ref);
2763 if(BufferFmt == NULL)
2764 BufferFmt = buffer;
2765 else if(BufferFmt->Frequency != buffer->Frequency ||
2766 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2767 BufferFmt->OriginalType != buffer->OriginalType)
2769 WriteUnlock(&source->queue_lock);
2770 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2772 buffer_error:
2773 /* A buffer failed (invalid ID or format), so unlock and release
2774 * each buffer we had. */
2775 while(BufferListStart)
2777 ALbufferlistitem *next = BufferListStart->next;
2778 if((buffer=BufferListStart->buffer) != NULL)
2780 DecrementRef(&buffer->ref);
2781 ReadUnlock(&buffer->lock);
2783 al_free(BufferListStart);
2784 BufferListStart = next;
2786 UnlockBuffersRead(device);
2787 goto done;
2790 /* All buffers good, unlock them now. */
2791 BufferList = BufferListStart;
2792 while(BufferList != NULL)
2794 ALbuffer *buffer = BufferList->buffer;
2795 if(buffer) ReadUnlock(&buffer->lock);
2796 BufferList = BufferList->next;
2798 UnlockBuffersRead(device);
2800 /* Source is now streaming */
2801 source->SourceType = AL_STREAMING;
2803 if(!(BufferList=source->queue))
2804 source->queue = BufferListStart;
2805 else
2807 while(BufferList->next != NULL)
2808 BufferList = BufferList->next;
2809 BufferList->next = BufferListStart;
2811 WriteUnlock(&source->queue_lock);
2813 done:
2814 UnlockSourcesRead(context);
2815 ALCcontext_DecRef(context);
2818 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2820 ALCcontext *context;
2821 ALsource *source;
2822 ALbufferlistitem *OldHead;
2823 ALbufferlistitem *OldTail;
2824 ALbufferlistitem *Current;
2825 ALvoice *voice;
2826 ALsizei i = 0;
2828 context = GetContextRef();
2829 if(!context) return;
2831 LockSourcesRead(context);
2832 if(!(nb >= 0))
2833 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2835 if((source=LookupSource(context, src)) == NULL)
2836 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2838 /* Nothing to unqueue. */
2839 if(nb == 0) goto done;
2841 WriteLock(&source->queue_lock);
2842 if(source->Looping || source->SourceType != AL_STREAMING)
2844 WriteUnlock(&source->queue_lock);
2845 /* Trying to unqueue buffers on a looping or non-streaming source. */
2846 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2849 /* Find the new buffer queue head */
2850 OldTail = source->queue;
2851 Current = NULL;
2852 if((voice=GetSourceVoice(source, context)) != NULL)
2853 Current = ATOMIC_LOAD_SEQ(&voice->current_buffer);
2854 else if(ATOMIC_LOAD_SEQ(&source->state) == AL_INITIAL)
2855 Current = OldTail;
2856 if(OldTail != Current)
2858 for(i = 1;i < nb;i++)
2860 ALbufferlistitem *next = OldTail->next;
2861 if(!next || next == Current) break;
2862 OldTail = next;
2865 if(i != nb)
2867 WriteUnlock(&source->queue_lock);
2868 /* Trying to unqueue pending buffers. */
2869 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2872 /* Swap it, and cut the new head from the old. */
2873 OldHead = source->queue;
2874 source->queue = OldTail->next;
2875 OldTail->next = NULL;
2876 WriteUnlock(&source->queue_lock);
2878 while(OldHead != NULL)
2880 ALbufferlistitem *next = OldHead->next;
2881 ALbuffer *buffer = OldHead->buffer;
2883 if(!buffer)
2884 *(buffers++) = 0;
2885 else
2887 *(buffers++) = buffer->id;
2888 DecrementRef(&buffer->ref);
2891 al_free(OldHead);
2892 OldHead = next;
2895 done:
2896 UnlockSourcesRead(context);
2897 ALCcontext_DecRef(context);
2901 static void InitSourceParams(ALsource *Source, ALsizei num_sends)
2903 ALsizei i;
2905 RWLockInit(&Source->queue_lock);
2907 Source->InnerAngle = 360.0f;
2908 Source->OuterAngle = 360.0f;
2909 Source->Pitch = 1.0f;
2910 Source->Position[0] = 0.0f;
2911 Source->Position[1] = 0.0f;
2912 Source->Position[2] = 0.0f;
2913 Source->Velocity[0] = 0.0f;
2914 Source->Velocity[1] = 0.0f;
2915 Source->Velocity[2] = 0.0f;
2916 Source->Direction[0] = 0.0f;
2917 Source->Direction[1] = 0.0f;
2918 Source->Direction[2] = 0.0f;
2919 Source->Orientation[0][0] = 0.0f;
2920 Source->Orientation[0][1] = 0.0f;
2921 Source->Orientation[0][2] = -1.0f;
2922 Source->Orientation[1][0] = 0.0f;
2923 Source->Orientation[1][1] = 1.0f;
2924 Source->Orientation[1][2] = 0.0f;
2925 Source->RefDistance = 1.0f;
2926 Source->MaxDistance = FLT_MAX;
2927 Source->RollOffFactor = 1.0f;
2928 Source->Gain = 1.0f;
2929 Source->MinGain = 0.0f;
2930 Source->MaxGain = 1.0f;
2931 Source->OuterGain = 0.0f;
2932 Source->OuterGainHF = 1.0f;
2934 Source->DryGainHFAuto = AL_TRUE;
2935 Source->WetGainAuto = AL_TRUE;
2936 Source->WetGainHFAuto = AL_TRUE;
2937 Source->AirAbsorptionFactor = 0.0f;
2938 Source->RoomRolloffFactor = 0.0f;
2939 Source->DopplerFactor = 1.0f;
2940 Source->HeadRelative = AL_FALSE;
2941 Source->Looping = AL_FALSE;
2942 Source->DistanceModel = DefaultDistanceModel;
2943 Source->DirectChannels = AL_FALSE;
2945 Source->StereoPan[0] = DEG2RAD( 30.0f);
2946 Source->StereoPan[1] = DEG2RAD(-30.0f);
2948 Source->Radius = 0.0f;
2950 Source->Direct.Gain = 1.0f;
2951 Source->Direct.GainHF = 1.0f;
2952 Source->Direct.HFReference = LOWPASSFREQREF;
2953 Source->Direct.GainLF = 1.0f;
2954 Source->Direct.LFReference = HIGHPASSFREQREF;
2955 Source->Send = al_calloc(16, num_sends*sizeof(Source->Send[0]));
2956 for(i = 0;i < num_sends;i++)
2958 Source->Send[i].Slot = NULL;
2959 Source->Send[i].Gain = 1.0f;
2960 Source->Send[i].GainHF = 1.0f;
2961 Source->Send[i].HFReference = LOWPASSFREQREF;
2962 Source->Send[i].GainLF = 1.0f;
2963 Source->Send[i].LFReference = HIGHPASSFREQREF;
2966 Source->Offset = 0.0;
2967 Source->OffsetType = AL_NONE;
2968 Source->SourceType = AL_UNDETERMINED;
2969 ATOMIC_INIT(&Source->state, AL_INITIAL);
2971 Source->queue = NULL;
2973 /* No way to do an 'init' here, so just test+set with relaxed ordering and
2974 * ignore the test.
2976 ATOMIC_FLAG_TEST_AND_SET(&Source->PropsClean, almemory_order_relaxed);
2979 static void DeinitSource(ALsource *source, ALsizei num_sends)
2981 ALbufferlistitem *BufferList;
2982 ALsizei i;
2984 BufferList = source->queue;
2985 while(BufferList != NULL)
2987 ALbufferlistitem *next = BufferList->next;
2988 if(BufferList->buffer != NULL)
2989 DecrementRef(&BufferList->buffer->ref);
2990 al_free(BufferList);
2991 BufferList = next;
2993 source->queue = NULL;
2995 if(source->Send)
2997 for(i = 0;i < num_sends;i++)
2999 if(source->Send[i].Slot)
3000 DecrementRef(&source->Send[i].Slot->ref);
3001 source->Send[i].Slot = NULL;
3003 al_free(source->Send);
3004 source->Send = NULL;
3008 static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends)
3010 struct ALvoiceProps *props;
3011 ALsizei i;
3013 /* Get an unused property container, or allocate a new one as needed. */
3014 props = ATOMIC_LOAD(&voice->FreeList, almemory_order_acquire);
3015 if(!props)
3016 props = al_calloc(16, FAM_SIZE(struct ALvoiceProps, Send, num_sends));
3017 else
3019 struct ALvoiceProps *next;
3020 do {
3021 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
3022 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&voice->FreeList, &props, next,
3023 almemory_order_acq_rel, almemory_order_acquire) == 0);
3026 /* Copy in current property values. */
3027 props->Pitch = source->Pitch;
3028 props->Gain = source->Gain;
3029 props->OuterGain = source->OuterGain;
3030 props->MinGain = source->MinGain;
3031 props->MaxGain = source->MaxGain;
3032 props->InnerAngle = source->InnerAngle;
3033 props->OuterAngle = source->OuterAngle;
3034 props->RefDistance = source->RefDistance;
3035 props->MaxDistance = source->MaxDistance;
3036 props->RollOffFactor = source->RollOffFactor;
3037 for(i = 0;i < 3;i++)
3038 props->Position[i] = source->Position[i];
3039 for(i = 0;i < 3;i++)
3040 props->Velocity[i] = source->Velocity[i];
3041 for(i = 0;i < 3;i++)
3042 props->Direction[i] = source->Direction[i];
3043 for(i = 0;i < 2;i++)
3045 ALsizei j;
3046 for(j = 0;j < 3;j++)
3047 props->Orientation[i][j] = source->Orientation[i][j];
3049 props->HeadRelative = source->HeadRelative;
3050 props->DistanceModel = source->DistanceModel;
3051 props->DirectChannels = source->DirectChannels;
3053 props->DryGainHFAuto = source->DryGainHFAuto;
3054 props->WetGainAuto = source->WetGainAuto;
3055 props->WetGainHFAuto = source->WetGainHFAuto;
3056 props->OuterGainHF = source->OuterGainHF;
3058 props->AirAbsorptionFactor = source->AirAbsorptionFactor;
3059 props->RoomRolloffFactor = source->RoomRolloffFactor;
3060 props->DopplerFactor = source->DopplerFactor;
3062 props->StereoPan[0] = source->StereoPan[0];
3063 props->StereoPan[1] = source->StereoPan[1];
3065 props->Radius = source->Radius;
3067 props->Direct.Gain = source->Direct.Gain;
3068 props->Direct.GainHF = source->Direct.GainHF;
3069 props->Direct.HFReference = source->Direct.HFReference;
3070 props->Direct.GainLF = source->Direct.GainLF;
3071 props->Direct.LFReference = source->Direct.LFReference;
3073 for(i = 0;i < num_sends;i++)
3075 props->Send[i].Slot = source->Send[i].Slot;
3076 props->Send[i].Gain = source->Send[i].Gain;
3077 props->Send[i].GainHF = source->Send[i].GainHF;
3078 props->Send[i].HFReference = source->Send[i].HFReference;
3079 props->Send[i].GainLF = source->Send[i].GainLF;
3080 props->Send[i].LFReference = source->Send[i].LFReference;
3083 /* Set the new container for updating internal parameters. */
3084 props = ATOMIC_EXCHANGE_PTR(&voice->Update, props, almemory_order_acq_rel);
3085 if(props)
3087 /* If there was an unused update container, put it back in the
3088 * freelist.
3090 ATOMIC_REPLACE_HEAD(struct ALvoiceProps*, &voice->FreeList, props);
3094 void UpdateAllSourceProps(ALCcontext *context)
3096 ALsizei num_sends = context->Device->NumAuxSends;
3097 ALsizei pos;
3099 for(pos = 0;pos < context->VoiceCount;pos++)
3101 ALvoice *voice = context->Voices[pos];
3102 ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire);
3103 if(source && !ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acq_rel))
3104 UpdateSourceProps(source, voice, num_sends);
3109 /* GetSourceSampleOffset
3111 * Gets the current read offset for the given Source, in 32.32 fixed-point
3112 * samples. The offset is relative to the start of the queue (not the start of
3113 * the current buffer).
3115 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3117 ALCdevice *device = context->Device;
3118 const ALbufferlistitem *Current;
3119 ALuint64 readPos;
3120 ALuint refcount;
3121 ALvoice *voice;
3123 ReadLock(&Source->queue_lock);
3124 do {
3125 Current = NULL;
3126 readPos = 0;
3127 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3128 althrd_yield();
3129 *clocktime = GetDeviceClockTime(device);
3131 voice = GetSourceVoice(Source, context);
3132 if(voice)
3134 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3136 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << 32;
3137 readPos |= (ALuint64)ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) <<
3138 (32-FRACTIONBITS);
3140 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3141 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3143 if(voice)
3145 const ALbufferlistitem *BufferList = Source->queue;
3146 while(BufferList && BufferList != Current)
3148 if(BufferList->buffer)
3149 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
3150 BufferList = BufferList->next;
3152 readPos = minu64(readPos, U64(0x7fffffffffffffff));
3155 ReadUnlock(&Source->queue_lock);
3156 return (ALint64)readPos;
3159 /* GetSourceSecOffset
3161 * Gets the current read offset for the given Source, in seconds. The offset is
3162 * relative to the start of the queue (not the start of the current buffer).
3164 static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3166 ALCdevice *device = context->Device;
3167 const ALbufferlistitem *Current;
3168 ALuint64 readPos;
3169 ALuint refcount;
3170 ALdouble offset;
3171 ALvoice *voice;
3173 ReadLock(&Source->queue_lock);
3174 do {
3175 Current = NULL;
3176 readPos = 0;
3177 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3178 althrd_yield();
3179 *clocktime = GetDeviceClockTime(device);
3181 voice = GetSourceVoice(Source, context);
3182 if(voice)
3184 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3186 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) <<
3187 FRACTIONBITS;
3188 readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3190 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3191 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3193 offset = 0.0;
3194 if(voice)
3196 const ALbufferlistitem *BufferList = Source->queue;
3197 const ALbuffer *BufferFmt = NULL;
3198 while(BufferList && BufferList != Current)
3200 const ALbuffer *buffer = BufferList->buffer;
3201 if(buffer != NULL)
3203 if(!BufferFmt) BufferFmt = buffer;
3204 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
3206 BufferList = BufferList->next;
3209 while(BufferList && !BufferFmt)
3211 BufferFmt = BufferList->buffer;
3212 BufferList = BufferList->next;
3214 assert(BufferFmt != NULL);
3216 offset = (ALdouble)readPos / (ALdouble)FRACTIONONE /
3217 (ALdouble)BufferFmt->Frequency;
3220 ReadUnlock(&Source->queue_lock);
3221 return offset;
3224 /* GetSourceOffset
3226 * Gets the current read offset for the given Source, in the appropriate format
3227 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3228 * queue (not the start of the current buffer).
3230 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context)
3232 ALCdevice *device = context->Device;
3233 const ALbufferlistitem *Current;
3234 ALuint readPos;
3235 ALsizei readPosFrac;
3236 ALuint refcount;
3237 ALdouble offset;
3238 ALvoice *voice;
3240 ReadLock(&Source->queue_lock);
3241 do {
3242 Current = NULL;
3243 readPos = readPosFrac = 0;
3244 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3245 althrd_yield();
3246 voice = GetSourceVoice(Source, context);
3247 if(voice)
3249 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3251 readPos = ATOMIC_LOAD(&voice->position, almemory_order_relaxed);
3252 readPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3254 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3255 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3257 offset = 0.0;
3258 if(voice)
3260 const ALbufferlistitem *BufferList = Source->queue;
3261 const ALbuffer *BufferFmt = NULL;
3262 ALboolean readFin = AL_FALSE;
3263 ALuint totalBufferLen = 0;
3265 while(BufferList != NULL)
3267 const ALbuffer *buffer;
3268 readFin = readFin || (BufferList == Current);
3269 if((buffer=BufferList->buffer) != NULL)
3271 if(!BufferFmt) BufferFmt = buffer;
3272 totalBufferLen += buffer->SampleLen;
3273 if(!readFin) readPos += buffer->SampleLen;
3275 BufferList = BufferList->next;
3277 assert(BufferFmt != NULL);
3279 if(Source->Looping)
3280 readPos %= totalBufferLen;
3281 else
3283 /* Wrap back to 0 */
3284 if(readPos >= totalBufferLen)
3285 readPos = readPosFrac = 0;
3288 offset = 0.0;
3289 switch(name)
3291 case AL_SEC_OFFSET:
3292 offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE) / BufferFmt->Frequency;
3293 break;
3295 case AL_SAMPLE_OFFSET:
3296 offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
3297 break;
3299 case AL_BYTE_OFFSET:
3300 if(BufferFmt->OriginalType == UserFmtIMA4)
3302 ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
3303 ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels);
3304 ALuint FrameBlockSize = BufferFmt->OriginalAlign;
3306 /* Round down to nearest ADPCM block */
3307 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3309 else if(BufferFmt->OriginalType == UserFmtMSADPCM)
3311 ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
3312 ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels);
3313 ALuint FrameBlockSize = BufferFmt->OriginalAlign;
3315 /* Round down to nearest ADPCM block */
3316 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3318 else
3320 ALuint FrameSize = FrameSizeFromUserFmt(BufferFmt->OriginalChannels,
3321 BufferFmt->OriginalType);
3322 offset = (ALdouble)(readPos * FrameSize);
3324 break;
3328 ReadUnlock(&Source->queue_lock);
3329 return offset;
3333 /* ApplyOffset
3335 * Apply the stored playback offset to the Source. This function will update
3336 * the number of buffers "played" given the stored offset.
3338 static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice)
3340 ALbufferlistitem *BufferList;
3341 const ALbuffer *Buffer;
3342 ALuint bufferLen, totalBufferLen;
3343 ALuint offset = 0;
3344 ALsizei frac = 0;
3346 /* Get sample frame offset */
3347 if(!GetSampleOffset(Source, &offset, &frac))
3348 return AL_FALSE;
3350 totalBufferLen = 0;
3351 BufferList = Source->queue;
3352 while(BufferList && totalBufferLen <= offset)
3354 Buffer = BufferList->buffer;
3355 bufferLen = Buffer ? Buffer->SampleLen : 0;
3357 if(bufferLen > offset-totalBufferLen)
3359 /* Offset is in this buffer */
3360 ATOMIC_STORE(&voice->position, offset - totalBufferLen, almemory_order_relaxed);
3361 ATOMIC_STORE(&voice->position_fraction, frac, almemory_order_relaxed);
3362 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_release);
3363 return AL_TRUE;
3366 totalBufferLen += bufferLen;
3368 BufferList = BufferList->next;
3371 /* Offset is out of range of the queue */
3372 return AL_FALSE;
3376 /* GetSampleOffset
3378 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3379 * or Second offset supplied by the application). This takes into account the
3380 * fact that the buffer format may have been modifed since.
3382 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac)
3384 const ALbuffer *BufferFmt = NULL;
3385 const ALbufferlistitem *BufferList;
3386 ALdouble dbloff, dblfrac;
3388 /* Find the first valid Buffer in the Queue */
3389 BufferList = Source->queue;
3390 while(BufferList)
3392 if((BufferFmt=BufferList->buffer) != NULL)
3393 break;
3394 BufferList = BufferList->next;
3396 if(!BufferFmt)
3398 Source->OffsetType = AL_NONE;
3399 Source->Offset = 0.0;
3400 return AL_FALSE;
3403 switch(Source->OffsetType)
3405 case AL_BYTE_OFFSET:
3406 /* Determine the ByteOffset (and ensure it is block aligned) */
3407 *offset = (ALuint)Source->Offset;
3408 if(BufferFmt->OriginalType == UserFmtIMA4)
3410 ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
3411 *offset /= align * ChannelsFromUserFmt(BufferFmt->OriginalChannels);
3412 *offset *= BufferFmt->OriginalAlign;
3414 else if(BufferFmt->OriginalType == UserFmtMSADPCM)
3416 ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
3417 *offset /= align * ChannelsFromUserFmt(BufferFmt->OriginalChannels);
3418 *offset *= BufferFmt->OriginalAlign;
3420 else
3421 *offset /= FrameSizeFromUserFmt(BufferFmt->OriginalChannels,
3422 BufferFmt->OriginalType);
3423 *frac = 0;
3424 break;
3426 case AL_SAMPLE_OFFSET:
3427 dblfrac = modf(Source->Offset, &dbloff);
3428 *offset = (ALuint)mind(dbloff, UINT_MAX);
3429 *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3430 break;
3432 case AL_SEC_OFFSET:
3433 dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff);
3434 *offset = (ALuint)mind(dbloff, UINT_MAX);
3435 *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3436 break;
3438 Source->OffsetType = AL_NONE;
3439 Source->Offset = 0.0;
3441 return AL_TRUE;
3445 /* ReleaseALSources
3447 * Destroys all sources in the source map.
3449 ALvoid ReleaseALSources(ALCcontext *Context)
3451 ALCdevice *device = Context->Device;
3452 ALsizei pos;
3453 for(pos = 0;pos < Context->SourceMap.size;pos++)
3455 ALsource *temp = Context->SourceMap.values[pos];
3456 Context->SourceMap.values[pos] = NULL;
3458 DeinitSource(temp, device->NumAuxSends);
3460 FreeThunkEntry(temp->id);
3461 memset(temp, 0, sizeof(*temp));
3462 al_free(temp);