Store an index to a given source's voice
[openal-soft.git] / OpenAL32 / alSource.c
bloba7e5fc17f8715d68b0b6477c6671192344cb7e39
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 static ALsource *AllocSource(ALCcontext *context);
44 static void FreeSource(ALCcontext *context, ALsource *source);
45 static void InitSourceParams(ALsource *Source, ALsizei num_sends);
46 static void DeinitSource(ALsource *source, ALsizei num_sends);
47 static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends, ALCcontext *context);
48 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime);
49 static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime);
50 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context);
51 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac);
52 static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice);
54 static inline void LockSourceList(ALCcontext *context)
55 { almtx_lock(&context->SourceLock); }
56 static inline void UnlockSourceList(ALCcontext *context)
57 { almtx_unlock(&context->SourceLock); }
59 static inline ALsource *LookupSource(ALCcontext *context, ALuint id)
61 SourceSubList *sublist;
62 ALuint lidx = (id-1) >> 6;
63 ALsizei slidx = (id-1) & 0x3f;
65 if(UNLIKELY(lidx >= VECTOR_SIZE(context->SourceList)))
66 return NULL;
67 sublist = &VECTOR_ELEM(context->SourceList, lidx);
68 if(UNLIKELY(sublist->FreeMask & (U64(1)<<slidx)))
69 return NULL;
70 return sublist->Sources + slidx;
73 static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id)
75 BufferSubList *sublist;
76 ALuint lidx = (id-1) >> 6;
77 ALsizei slidx = (id-1) & 0x3f;
79 if(UNLIKELY(lidx >= VECTOR_SIZE(device->BufferList)))
80 return NULL;
81 sublist = &VECTOR_ELEM(device->BufferList, lidx);
82 if(UNLIKELY(sublist->FreeMask & (U64(1)<<slidx)))
83 return NULL;
84 return sublist->Buffers + slidx;
87 static inline ALfilter *LookupFilter(ALCdevice *device, ALuint id)
89 FilterSubList *sublist;
90 ALuint lidx = (id-1) >> 6;
91 ALsizei slidx = (id-1) & 0x3f;
93 if(UNLIKELY(lidx >= VECTOR_SIZE(device->FilterList)))
94 return NULL;
95 sublist = &VECTOR_ELEM(device->FilterList, lidx);
96 if(UNLIKELY(sublist->FreeMask & (U64(1)<<slidx)))
97 return NULL;
98 return sublist->Filters + slidx;
101 static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id)
103 id--;
104 if(UNLIKELY(id >= VECTOR_SIZE(context->EffectSlotList)))
105 return NULL;
106 return VECTOR_ELEM(context->EffectSlotList, id);
110 typedef enum SourceProp {
111 srcPitch = AL_PITCH,
112 srcGain = AL_GAIN,
113 srcMinGain = AL_MIN_GAIN,
114 srcMaxGain = AL_MAX_GAIN,
115 srcMaxDistance = AL_MAX_DISTANCE,
116 srcRolloffFactor = AL_ROLLOFF_FACTOR,
117 srcDopplerFactor = AL_DOPPLER_FACTOR,
118 srcConeOuterGain = AL_CONE_OUTER_GAIN,
119 srcSecOffset = AL_SEC_OFFSET,
120 srcSampleOffset = AL_SAMPLE_OFFSET,
121 srcByteOffset = AL_BYTE_OFFSET,
122 srcConeInnerAngle = AL_CONE_INNER_ANGLE,
123 srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
124 srcRefDistance = AL_REFERENCE_DISTANCE,
126 srcPosition = AL_POSITION,
127 srcVelocity = AL_VELOCITY,
128 srcDirection = AL_DIRECTION,
130 srcSourceRelative = AL_SOURCE_RELATIVE,
131 srcLooping = AL_LOOPING,
132 srcBuffer = AL_BUFFER,
133 srcSourceState = AL_SOURCE_STATE,
134 srcBuffersQueued = AL_BUFFERS_QUEUED,
135 srcBuffersProcessed = AL_BUFFERS_PROCESSED,
136 srcSourceType = AL_SOURCE_TYPE,
138 /* ALC_EXT_EFX */
139 srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
140 srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
141 srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
142 srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
143 srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
144 srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
145 srcDirectFilter = AL_DIRECT_FILTER,
146 srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
148 /* AL_SOFT_direct_channels */
149 srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
151 /* AL_EXT_source_distance_model */
152 srcDistanceModel = AL_DISTANCE_MODEL,
154 srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
155 srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
156 srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
158 /* AL_SOFT_source_latency */
159 srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
160 srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
162 /* AL_EXT_STEREO_ANGLES */
163 srcAngles = AL_STEREO_ANGLES,
165 /* AL_EXT_SOURCE_RADIUS */
166 srcRadius = AL_SOURCE_RADIUS,
168 /* AL_EXT_BFORMAT */
169 srcOrientation = AL_ORIENTATION,
171 /* AL_SOFT_source_resampler */
172 srcResampler = AL_SOURCE_RESAMPLER_SOFT,
174 /* AL_SOFT_source_spatialize */
175 srcSpatialize = AL_SOURCE_SPATIALIZE_SOFT,
177 /* ALC_SOFT_device_clock */
178 srcSampleOffsetClockSOFT = AL_SAMPLE_OFFSET_CLOCK_SOFT,
179 srcSecOffsetClockSOFT = AL_SEC_OFFSET_CLOCK_SOFT,
180 } SourceProp;
182 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
183 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
184 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
186 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
187 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
188 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
190 static inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context)
192 ALint idx = source->VoiceIdx;
193 if(idx >= 0 && idx < context->VoiceCount)
195 ALvoice *voice = context->Voices[idx];
196 if(ATOMIC_LOAD(&voice->Source, almemory_order_acquire) == source)
197 return voice;
199 source->VoiceIdx = -1;
200 return NULL;
204 * Returns if the last known state for the source was playing or paused. Does
205 * not sync with the mixer voice.
207 static inline bool IsPlayingOrPaused(ALsource *source)
209 ALenum state = ATOMIC_LOAD(&source->state, almemory_order_acquire);
210 return state == AL_PLAYING || state == AL_PAUSED;
214 * Returns an updated source state using the matching voice's status (or lack
215 * thereof).
217 static inline ALenum GetSourceState(ALsource *source, ALvoice *voice)
219 if(!voice)
221 ALenum state = AL_PLAYING;
222 if(ATOMIC_COMPARE_EXCHANGE_STRONG(&source->state, &state, AL_STOPPED,
223 almemory_order_acq_rel, almemory_order_acquire))
224 return AL_STOPPED;
225 return state;
227 return ATOMIC_LOAD(&source->state, almemory_order_acquire);
231 * Returns if the source should specify an update, given the context's
232 * deferring state and the source's last known state.
234 static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context)
236 return !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) &&
237 IsPlayingOrPaused(source);
240 static ALint FloatValsByProp(ALenum prop)
242 if(prop != (ALenum)((SourceProp)prop))
243 return 0;
244 switch((SourceProp)prop)
246 case AL_PITCH:
247 case AL_GAIN:
248 case AL_MIN_GAIN:
249 case AL_MAX_GAIN:
250 case AL_MAX_DISTANCE:
251 case AL_ROLLOFF_FACTOR:
252 case AL_DOPPLER_FACTOR:
253 case AL_CONE_OUTER_GAIN:
254 case AL_SEC_OFFSET:
255 case AL_SAMPLE_OFFSET:
256 case AL_BYTE_OFFSET:
257 case AL_CONE_INNER_ANGLE:
258 case AL_CONE_OUTER_ANGLE:
259 case AL_REFERENCE_DISTANCE:
260 case AL_CONE_OUTER_GAINHF:
261 case AL_AIR_ABSORPTION_FACTOR:
262 case AL_ROOM_ROLLOFF_FACTOR:
263 case AL_DIRECT_FILTER_GAINHF_AUTO:
264 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
265 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
266 case AL_DIRECT_CHANNELS_SOFT:
267 case AL_DISTANCE_MODEL:
268 case AL_SOURCE_RELATIVE:
269 case AL_LOOPING:
270 case AL_SOURCE_STATE:
271 case AL_BUFFERS_QUEUED:
272 case AL_BUFFERS_PROCESSED:
273 case AL_SOURCE_TYPE:
274 case AL_BYTE_LENGTH_SOFT:
275 case AL_SAMPLE_LENGTH_SOFT:
276 case AL_SEC_LENGTH_SOFT:
277 case AL_SOURCE_RADIUS:
278 case AL_SOURCE_RESAMPLER_SOFT:
279 case AL_SOURCE_SPATIALIZE_SOFT:
280 return 1;
282 case AL_STEREO_ANGLES:
283 return 2;
285 case AL_POSITION:
286 case AL_VELOCITY:
287 case AL_DIRECTION:
288 return 3;
290 case AL_ORIENTATION:
291 return 6;
293 case AL_SEC_OFFSET_LATENCY_SOFT:
294 case AL_SEC_OFFSET_CLOCK_SOFT:
295 break; /* Double only */
297 case AL_BUFFER:
298 case AL_DIRECT_FILTER:
299 case AL_AUXILIARY_SEND_FILTER:
300 break; /* i/i64 only */
301 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
302 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
303 break; /* i64 only */
305 return 0;
307 static ALint DoubleValsByProp(ALenum prop)
309 if(prop != (ALenum)((SourceProp)prop))
310 return 0;
311 switch((SourceProp)prop)
313 case AL_PITCH:
314 case AL_GAIN:
315 case AL_MIN_GAIN:
316 case AL_MAX_GAIN:
317 case AL_MAX_DISTANCE:
318 case AL_ROLLOFF_FACTOR:
319 case AL_DOPPLER_FACTOR:
320 case AL_CONE_OUTER_GAIN:
321 case AL_SEC_OFFSET:
322 case AL_SAMPLE_OFFSET:
323 case AL_BYTE_OFFSET:
324 case AL_CONE_INNER_ANGLE:
325 case AL_CONE_OUTER_ANGLE:
326 case AL_REFERENCE_DISTANCE:
327 case AL_CONE_OUTER_GAINHF:
328 case AL_AIR_ABSORPTION_FACTOR:
329 case AL_ROOM_ROLLOFF_FACTOR:
330 case AL_DIRECT_FILTER_GAINHF_AUTO:
331 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
332 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
333 case AL_DIRECT_CHANNELS_SOFT:
334 case AL_DISTANCE_MODEL:
335 case AL_SOURCE_RELATIVE:
336 case AL_LOOPING:
337 case AL_SOURCE_STATE:
338 case AL_BUFFERS_QUEUED:
339 case AL_BUFFERS_PROCESSED:
340 case AL_SOURCE_TYPE:
341 case AL_BYTE_LENGTH_SOFT:
342 case AL_SAMPLE_LENGTH_SOFT:
343 case AL_SEC_LENGTH_SOFT:
344 case AL_SOURCE_RADIUS:
345 case AL_SOURCE_RESAMPLER_SOFT:
346 case AL_SOURCE_SPATIALIZE_SOFT:
347 return 1;
349 case AL_SEC_OFFSET_LATENCY_SOFT:
350 case AL_SEC_OFFSET_CLOCK_SOFT:
351 case AL_STEREO_ANGLES:
352 return 2;
354 case AL_POSITION:
355 case AL_VELOCITY:
356 case AL_DIRECTION:
357 return 3;
359 case AL_ORIENTATION:
360 return 6;
362 case AL_BUFFER:
363 case AL_DIRECT_FILTER:
364 case AL_AUXILIARY_SEND_FILTER:
365 break; /* i/i64 only */
366 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
367 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
368 break; /* i64 only */
370 return 0;
373 static ALint IntValsByProp(ALenum prop)
375 if(prop != (ALenum)((SourceProp)prop))
376 return 0;
377 switch((SourceProp)prop)
379 case AL_PITCH:
380 case AL_GAIN:
381 case AL_MIN_GAIN:
382 case AL_MAX_GAIN:
383 case AL_MAX_DISTANCE:
384 case AL_ROLLOFF_FACTOR:
385 case AL_DOPPLER_FACTOR:
386 case AL_CONE_OUTER_GAIN:
387 case AL_SEC_OFFSET:
388 case AL_SAMPLE_OFFSET:
389 case AL_BYTE_OFFSET:
390 case AL_CONE_INNER_ANGLE:
391 case AL_CONE_OUTER_ANGLE:
392 case AL_REFERENCE_DISTANCE:
393 case AL_CONE_OUTER_GAINHF:
394 case AL_AIR_ABSORPTION_FACTOR:
395 case AL_ROOM_ROLLOFF_FACTOR:
396 case AL_DIRECT_FILTER_GAINHF_AUTO:
397 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
398 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
399 case AL_DIRECT_CHANNELS_SOFT:
400 case AL_DISTANCE_MODEL:
401 case AL_SOURCE_RELATIVE:
402 case AL_LOOPING:
403 case AL_BUFFER:
404 case AL_SOURCE_STATE:
405 case AL_BUFFERS_QUEUED:
406 case AL_BUFFERS_PROCESSED:
407 case AL_SOURCE_TYPE:
408 case AL_DIRECT_FILTER:
409 case AL_BYTE_LENGTH_SOFT:
410 case AL_SAMPLE_LENGTH_SOFT:
411 case AL_SEC_LENGTH_SOFT:
412 case AL_SOURCE_RADIUS:
413 case AL_SOURCE_RESAMPLER_SOFT:
414 case AL_SOURCE_SPATIALIZE_SOFT:
415 return 1;
417 case AL_POSITION:
418 case AL_VELOCITY:
419 case AL_DIRECTION:
420 case AL_AUXILIARY_SEND_FILTER:
421 return 3;
423 case AL_ORIENTATION:
424 return 6;
426 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
427 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
428 break; /* i64 only */
429 case AL_SEC_OFFSET_LATENCY_SOFT:
430 case AL_SEC_OFFSET_CLOCK_SOFT:
431 break; /* Double only */
432 case AL_STEREO_ANGLES:
433 break; /* Float/double only */
435 return 0;
437 static ALint Int64ValsByProp(ALenum prop)
439 if(prop != (ALenum)((SourceProp)prop))
440 return 0;
441 switch((SourceProp)prop)
443 case AL_PITCH:
444 case AL_GAIN:
445 case AL_MIN_GAIN:
446 case AL_MAX_GAIN:
447 case AL_MAX_DISTANCE:
448 case AL_ROLLOFF_FACTOR:
449 case AL_DOPPLER_FACTOR:
450 case AL_CONE_OUTER_GAIN:
451 case AL_SEC_OFFSET:
452 case AL_SAMPLE_OFFSET:
453 case AL_BYTE_OFFSET:
454 case AL_CONE_INNER_ANGLE:
455 case AL_CONE_OUTER_ANGLE:
456 case AL_REFERENCE_DISTANCE:
457 case AL_CONE_OUTER_GAINHF:
458 case AL_AIR_ABSORPTION_FACTOR:
459 case AL_ROOM_ROLLOFF_FACTOR:
460 case AL_DIRECT_FILTER_GAINHF_AUTO:
461 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
462 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
463 case AL_DIRECT_CHANNELS_SOFT:
464 case AL_DISTANCE_MODEL:
465 case AL_SOURCE_RELATIVE:
466 case AL_LOOPING:
467 case AL_BUFFER:
468 case AL_SOURCE_STATE:
469 case AL_BUFFERS_QUEUED:
470 case AL_BUFFERS_PROCESSED:
471 case AL_SOURCE_TYPE:
472 case AL_DIRECT_FILTER:
473 case AL_BYTE_LENGTH_SOFT:
474 case AL_SAMPLE_LENGTH_SOFT:
475 case AL_SEC_LENGTH_SOFT:
476 case AL_SOURCE_RADIUS:
477 case AL_SOURCE_RESAMPLER_SOFT:
478 case AL_SOURCE_SPATIALIZE_SOFT:
479 return 1;
481 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
482 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
483 return 2;
485 case AL_POSITION:
486 case AL_VELOCITY:
487 case AL_DIRECTION:
488 case AL_AUXILIARY_SEND_FILTER:
489 return 3;
491 case AL_ORIENTATION:
492 return 6;
494 case AL_SEC_OFFSET_LATENCY_SOFT:
495 case AL_SEC_OFFSET_CLOCK_SOFT:
496 break; /* Double only */
497 case AL_STEREO_ANGLES:
498 break; /* Float/double only */
500 return 0;
504 #define CHECKVAL(x) do { \
505 if(!(x)) \
507 alSetError(Context, AL_INVALID_VALUE, "Value out of range"); \
508 return AL_FALSE; \
510 } while(0)
512 #define DO_UPDATEPROPS() do { \
513 ALvoice *voice; \
514 if(SourceShouldUpdate(Source, Context) && \
515 (voice=GetSourceVoice(Source, Context)) != NULL) \
516 UpdateSourceProps(Source, voice, device->NumAuxSends, Context); \
517 else \
518 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \
519 } while(0)
521 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
523 ALCdevice *device = Context->Device;
524 ALint ival;
526 switch(prop)
528 case AL_BYTE_LENGTH_SOFT:
529 case AL_SAMPLE_LENGTH_SOFT:
530 case AL_SEC_LENGTH_SOFT:
531 case AL_SEC_OFFSET_LATENCY_SOFT:
532 case AL_SEC_OFFSET_CLOCK_SOFT:
533 /* Query only */
534 SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
535 "Setting read-only source property 0x%04x", prop);
537 case AL_PITCH:
538 CHECKVAL(*values >= 0.0f);
540 Source->Pitch = *values;
541 DO_UPDATEPROPS();
542 return AL_TRUE;
544 case AL_CONE_INNER_ANGLE:
545 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
547 Source->InnerAngle = *values;
548 DO_UPDATEPROPS();
549 return AL_TRUE;
551 case AL_CONE_OUTER_ANGLE:
552 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
554 Source->OuterAngle = *values;
555 DO_UPDATEPROPS();
556 return AL_TRUE;
558 case AL_GAIN:
559 CHECKVAL(*values >= 0.0f);
561 Source->Gain = *values;
562 DO_UPDATEPROPS();
563 return AL_TRUE;
565 case AL_MAX_DISTANCE:
566 CHECKVAL(*values >= 0.0f);
568 Source->MaxDistance = *values;
569 DO_UPDATEPROPS();
570 return AL_TRUE;
572 case AL_ROLLOFF_FACTOR:
573 CHECKVAL(*values >= 0.0f);
575 Source->RolloffFactor = *values;
576 DO_UPDATEPROPS();
577 return AL_TRUE;
579 case AL_REFERENCE_DISTANCE:
580 CHECKVAL(*values >= 0.0f);
582 Source->RefDistance = *values;
583 DO_UPDATEPROPS();
584 return AL_TRUE;
586 case AL_MIN_GAIN:
587 CHECKVAL(*values >= 0.0f);
589 Source->MinGain = *values;
590 DO_UPDATEPROPS();
591 return AL_TRUE;
593 case AL_MAX_GAIN:
594 CHECKVAL(*values >= 0.0f);
596 Source->MaxGain = *values;
597 DO_UPDATEPROPS();
598 return AL_TRUE;
600 case AL_CONE_OUTER_GAIN:
601 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
603 Source->OuterGain = *values;
604 DO_UPDATEPROPS();
605 return AL_TRUE;
607 case AL_CONE_OUTER_GAINHF:
608 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
610 Source->OuterGainHF = *values;
611 DO_UPDATEPROPS();
612 return AL_TRUE;
614 case AL_AIR_ABSORPTION_FACTOR:
615 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
617 Source->AirAbsorptionFactor = *values;
618 DO_UPDATEPROPS();
619 return AL_TRUE;
621 case AL_ROOM_ROLLOFF_FACTOR:
622 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
624 Source->RoomRolloffFactor = *values;
625 DO_UPDATEPROPS();
626 return AL_TRUE;
628 case AL_DOPPLER_FACTOR:
629 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
631 Source->DopplerFactor = *values;
632 DO_UPDATEPROPS();
633 return AL_TRUE;
635 case AL_SEC_OFFSET:
636 case AL_SAMPLE_OFFSET:
637 case AL_BYTE_OFFSET:
638 CHECKVAL(*values >= 0.0f);
640 Source->OffsetType = prop;
641 Source->Offset = *values;
643 if(IsPlayingOrPaused(Source))
645 ALvoice *voice;
647 ALCdevice_Lock(Context->Device);
648 /* Double-check that the source is still playing while we have
649 * the lock.
651 voice = GetSourceVoice(Source, Context);
652 if(voice)
654 WriteLock(&Source->queue_lock);
655 if(ApplyOffset(Source, voice) == AL_FALSE)
657 WriteUnlock(&Source->queue_lock);
658 ALCdevice_Unlock(Context->Device);
659 SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid offset");
661 WriteUnlock(&Source->queue_lock);
663 ALCdevice_Unlock(Context->Device);
665 return AL_TRUE;
667 case AL_SOURCE_RADIUS:
668 CHECKVAL(*values >= 0.0f && isfinite(*values));
670 Source->Radius = *values;
671 DO_UPDATEPROPS();
672 return AL_TRUE;
674 case AL_STEREO_ANGLES:
675 CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
677 Source->StereoPan[0] = values[0];
678 Source->StereoPan[1] = values[1];
679 DO_UPDATEPROPS();
680 return AL_TRUE;
683 case AL_POSITION:
684 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
686 Source->Position[0] = values[0];
687 Source->Position[1] = values[1];
688 Source->Position[2] = values[2];
689 DO_UPDATEPROPS();
690 return AL_TRUE;
692 case AL_VELOCITY:
693 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
695 Source->Velocity[0] = values[0];
696 Source->Velocity[1] = values[1];
697 Source->Velocity[2] = values[2];
698 DO_UPDATEPROPS();
699 return AL_TRUE;
701 case AL_DIRECTION:
702 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
704 Source->Direction[0] = values[0];
705 Source->Direction[1] = values[1];
706 Source->Direction[2] = values[2];
707 DO_UPDATEPROPS();
708 return AL_TRUE;
710 case AL_ORIENTATION:
711 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
712 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
714 Source->Orientation[0][0] = values[0];
715 Source->Orientation[0][1] = values[1];
716 Source->Orientation[0][2] = values[2];
717 Source->Orientation[1][0] = values[3];
718 Source->Orientation[1][1] = values[4];
719 Source->Orientation[1][2] = values[5];
720 DO_UPDATEPROPS();
721 return AL_TRUE;
724 case AL_SOURCE_RELATIVE:
725 case AL_LOOPING:
726 case AL_SOURCE_STATE:
727 case AL_SOURCE_TYPE:
728 case AL_DISTANCE_MODEL:
729 case AL_DIRECT_FILTER_GAINHF_AUTO:
730 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
731 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
732 case AL_DIRECT_CHANNELS_SOFT:
733 case AL_SOURCE_RESAMPLER_SOFT:
734 case AL_SOURCE_SPATIALIZE_SOFT:
735 ival = (ALint)values[0];
736 return SetSourceiv(Source, Context, prop, &ival);
738 case AL_BUFFERS_QUEUED:
739 case AL_BUFFERS_PROCESSED:
740 ival = (ALint)((ALuint)values[0]);
741 return SetSourceiv(Source, Context, prop, &ival);
743 case AL_BUFFER:
744 case AL_DIRECT_FILTER:
745 case AL_AUXILIARY_SEND_FILTER:
746 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
747 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
748 break;
751 ERR("Unexpected property: 0x%04x\n", prop);
752 SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source float property 0x%04x", prop);
755 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
757 ALCdevice *device = Context->Device;
758 ALbuffer *buffer = NULL;
759 ALfilter *filter = NULL;
760 ALeffectslot *slot = NULL;
761 ALbufferlistitem *oldlist;
762 ALfloat fvals[6];
764 switch(prop)
766 case AL_SOURCE_STATE:
767 case AL_SOURCE_TYPE:
768 case AL_BUFFERS_QUEUED:
769 case AL_BUFFERS_PROCESSED:
770 case AL_BYTE_LENGTH_SOFT:
771 case AL_SAMPLE_LENGTH_SOFT:
772 case AL_SEC_LENGTH_SOFT:
773 /* Query only */
774 SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
775 "Setting read-only source property 0x%04x", prop);
777 case AL_SOURCE_RELATIVE:
778 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
780 Source->HeadRelative = (ALboolean)*values;
781 DO_UPDATEPROPS();
782 return AL_TRUE;
784 case AL_LOOPING:
785 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
787 WriteLock(&Source->queue_lock);
788 Source->Looping = (ALboolean)*values;
789 if(IsPlayingOrPaused(Source))
791 ALvoice *voice = GetSourceVoice(Source, Context);
792 if(voice)
794 if(Source->Looping)
795 ATOMIC_STORE(&voice->loop_buffer, Source->queue, almemory_order_release);
796 else
797 ATOMIC_STORE(&voice->loop_buffer, NULL, almemory_order_release);
799 /* If the source is playing, wait for the current mix to finish
800 * to ensure it isn't currently looping back or reaching the
801 * end.
803 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
804 althrd_yield();
807 WriteUnlock(&Source->queue_lock);
808 return AL_TRUE;
810 case AL_BUFFER:
811 LockBufferList(device);
812 if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
814 UnlockBufferList(device);
815 SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid buffer ID %u",
816 *values);
819 WriteLock(&Source->queue_lock);
820 if(buffer && buffer->MappedAccess != 0 &&
821 !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
823 WriteUnlock(&Source->queue_lock);
824 UnlockBufferList(device);
825 SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
826 "Setting non-persistently mapped buffer %u", buffer->id);
828 else
830 ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context));
831 if(state == AL_PLAYING || state == AL_PAUSED)
833 WriteUnlock(&Source->queue_lock);
834 UnlockBufferList(device);
835 SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
836 "Setting buffer on playing or paused source %u", Source->id);
840 oldlist = Source->queue;
841 if(buffer != NULL)
843 /* Add the selected buffer to a one-item queue */
844 ALbufferlistitem *newlist = al_calloc(DEF_ALIGN,
845 FAM_SIZE(ALbufferlistitem, buffers, 1));
846 ATOMIC_INIT(&newlist->next, NULL);
847 newlist->num_buffers = 1;
848 newlist->buffers[0] = buffer;
849 IncrementRef(&buffer->ref);
851 /* Source is now Static */
852 Source->SourceType = AL_STATIC;
853 Source->queue = newlist;
855 else
857 /* Source is now Undetermined */
858 Source->SourceType = AL_UNDETERMINED;
859 Source->queue = NULL;
861 WriteUnlock(&Source->queue_lock);
862 UnlockBufferList(device);
864 /* Delete all elements in the previous queue */
865 while(oldlist != NULL)
867 ALsizei i;
868 ALbufferlistitem *temp = oldlist;
869 oldlist = ATOMIC_LOAD(&temp->next, almemory_order_relaxed);
871 for(i = 0;i < temp->num_buffers;i++)
873 if(temp->buffers[i])
874 DecrementRef(&temp->buffers[i]->ref);
876 al_free(temp);
878 return AL_TRUE;
880 case AL_SEC_OFFSET:
881 case AL_SAMPLE_OFFSET:
882 case AL_BYTE_OFFSET:
883 CHECKVAL(*values >= 0);
885 Source->OffsetType = prop;
886 Source->Offset = *values;
888 if(IsPlayingOrPaused(Source))
890 ALvoice *voice;
892 ALCdevice_Lock(Context->Device);
893 voice = GetSourceVoice(Source, Context);
894 if(voice)
896 WriteLock(&Source->queue_lock);
897 if(ApplyOffset(Source, voice) == AL_FALSE)
899 WriteUnlock(&Source->queue_lock);
900 ALCdevice_Unlock(Context->Device);
901 SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE,
902 "Invalid source offset");
904 WriteUnlock(&Source->queue_lock);
906 ALCdevice_Unlock(Context->Device);
908 return AL_TRUE;
910 case AL_DIRECT_FILTER:
911 LockFilterList(device);
912 if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
914 UnlockFilterList(device);
915 SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u",
916 *values);
919 if(!filter)
921 Source->Direct.Gain = 1.0f;
922 Source->Direct.GainHF = 1.0f;
923 Source->Direct.HFReference = LOWPASSFREQREF;
924 Source->Direct.GainLF = 1.0f;
925 Source->Direct.LFReference = HIGHPASSFREQREF;
927 else
929 Source->Direct.Gain = filter->Gain;
930 Source->Direct.GainHF = filter->GainHF;
931 Source->Direct.HFReference = filter->HFReference;
932 Source->Direct.GainLF = filter->GainLF;
933 Source->Direct.LFReference = filter->LFReference;
935 UnlockFilterList(device);
936 DO_UPDATEPROPS();
937 return AL_TRUE;
939 case AL_DIRECT_FILTER_GAINHF_AUTO:
940 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
942 Source->DryGainHFAuto = *values;
943 DO_UPDATEPROPS();
944 return AL_TRUE;
946 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
947 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
949 Source->WetGainAuto = *values;
950 DO_UPDATEPROPS();
951 return AL_TRUE;
953 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
954 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
956 Source->WetGainHFAuto = *values;
957 DO_UPDATEPROPS();
958 return AL_TRUE;
960 case AL_DIRECT_CHANNELS_SOFT:
961 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
963 Source->DirectChannels = *values;
964 DO_UPDATEPROPS();
965 return AL_TRUE;
967 case AL_DISTANCE_MODEL:
968 CHECKVAL(*values == AL_NONE ||
969 *values == AL_INVERSE_DISTANCE ||
970 *values == AL_INVERSE_DISTANCE_CLAMPED ||
971 *values == AL_LINEAR_DISTANCE ||
972 *values == AL_LINEAR_DISTANCE_CLAMPED ||
973 *values == AL_EXPONENT_DISTANCE ||
974 *values == AL_EXPONENT_DISTANCE_CLAMPED);
976 Source->DistanceModel = *values;
977 if(Context->SourceDistanceModel)
978 DO_UPDATEPROPS();
979 return AL_TRUE;
981 case AL_SOURCE_RESAMPLER_SOFT:
982 CHECKVAL(*values >= 0 && *values <= ResamplerMax);
984 Source->Resampler = *values;
985 DO_UPDATEPROPS();
986 return AL_TRUE;
988 case AL_SOURCE_SPATIALIZE_SOFT:
989 CHECKVAL(*values >= AL_FALSE && *values <= AL_AUTO_SOFT);
991 Source->Spatialize = *values;
992 DO_UPDATEPROPS();
993 return AL_TRUE;
996 case AL_AUXILIARY_SEND_FILTER:
997 LockEffectSlotList(Context);
998 if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL))
1000 UnlockEffectSlotList(Context);
1001 SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u",
1002 values[0]);
1004 if(!((ALuint)values[1] < (ALuint)device->NumAuxSends))
1006 UnlockEffectSlotList(Context);
1007 SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]);
1009 LockFilterList(device);
1010 if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL))
1012 UnlockFilterList(device);
1013 UnlockEffectSlotList(Context);
1014 SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u",
1015 values[2]);
1018 if(!filter)
1020 /* Disable filter */
1021 Source->Send[values[1]].Gain = 1.0f;
1022 Source->Send[values[1]].GainHF = 1.0f;
1023 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
1024 Source->Send[values[1]].GainLF = 1.0f;
1025 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
1027 else
1029 Source->Send[values[1]].Gain = filter->Gain;
1030 Source->Send[values[1]].GainHF = filter->GainHF;
1031 Source->Send[values[1]].HFReference = filter->HFReference;
1032 Source->Send[values[1]].GainLF = filter->GainLF;
1033 Source->Send[values[1]].LFReference = filter->LFReference;
1035 UnlockFilterList(device);
1037 if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source))
1039 ALvoice *voice;
1040 /* Add refcount on the new slot, and release the previous slot */
1041 if(slot) IncrementRef(&slot->ref);
1042 if(Source->Send[values[1]].Slot)
1043 DecrementRef(&Source->Send[values[1]].Slot->ref);
1044 Source->Send[values[1]].Slot = slot;
1046 /* We must force an update if the auxiliary slot changed on an
1047 * active source, in case the slot is about to be deleted.
1049 if((voice=GetSourceVoice(Source, Context)) != NULL)
1050 UpdateSourceProps(Source, voice, device->NumAuxSends, Context);
1051 else
1052 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release);
1054 else
1056 if(slot) IncrementRef(&slot->ref);
1057 if(Source->Send[values[1]].Slot)
1058 DecrementRef(&Source->Send[values[1]].Slot->ref);
1059 Source->Send[values[1]].Slot = slot;
1060 DO_UPDATEPROPS();
1062 UnlockEffectSlotList(Context);
1064 return AL_TRUE;
1067 /* 1x float */
1068 case AL_CONE_INNER_ANGLE:
1069 case AL_CONE_OUTER_ANGLE:
1070 case AL_PITCH:
1071 case AL_GAIN:
1072 case AL_MIN_GAIN:
1073 case AL_MAX_GAIN:
1074 case AL_REFERENCE_DISTANCE:
1075 case AL_ROLLOFF_FACTOR:
1076 case AL_CONE_OUTER_GAIN:
1077 case AL_MAX_DISTANCE:
1078 case AL_DOPPLER_FACTOR:
1079 case AL_CONE_OUTER_GAINHF:
1080 case AL_AIR_ABSORPTION_FACTOR:
1081 case AL_ROOM_ROLLOFF_FACTOR:
1082 case AL_SOURCE_RADIUS:
1083 fvals[0] = (ALfloat)*values;
1084 return SetSourcefv(Source, Context, (int)prop, fvals);
1086 /* 3x float */
1087 case AL_POSITION:
1088 case AL_VELOCITY:
1089 case AL_DIRECTION:
1090 fvals[0] = (ALfloat)values[0];
1091 fvals[1] = (ALfloat)values[1];
1092 fvals[2] = (ALfloat)values[2];
1093 return SetSourcefv(Source, Context, (int)prop, fvals);
1095 /* 6x float */
1096 case AL_ORIENTATION:
1097 fvals[0] = (ALfloat)values[0];
1098 fvals[1] = (ALfloat)values[1];
1099 fvals[2] = (ALfloat)values[2];
1100 fvals[3] = (ALfloat)values[3];
1101 fvals[4] = (ALfloat)values[4];
1102 fvals[5] = (ALfloat)values[5];
1103 return SetSourcefv(Source, Context, (int)prop, fvals);
1105 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1106 case AL_SEC_OFFSET_LATENCY_SOFT:
1107 case AL_SEC_OFFSET_CLOCK_SOFT:
1108 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
1109 case AL_STEREO_ANGLES:
1110 break;
1113 ERR("Unexpected property: 0x%04x\n", prop);
1114 SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x",
1115 prop);
1118 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
1120 ALfloat fvals[6];
1121 ALint ivals[3];
1123 switch(prop)
1125 case AL_SOURCE_TYPE:
1126 case AL_BUFFERS_QUEUED:
1127 case AL_BUFFERS_PROCESSED:
1128 case AL_SOURCE_STATE:
1129 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1130 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
1131 case AL_BYTE_LENGTH_SOFT:
1132 case AL_SAMPLE_LENGTH_SOFT:
1133 case AL_SEC_LENGTH_SOFT:
1134 /* Query only */
1135 SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
1136 "Setting read-only source property 0x%04x", prop);
1138 /* 1x int */
1139 case AL_SOURCE_RELATIVE:
1140 case AL_LOOPING:
1141 case AL_SEC_OFFSET:
1142 case AL_SAMPLE_OFFSET:
1143 case AL_BYTE_OFFSET:
1144 case AL_DIRECT_FILTER_GAINHF_AUTO:
1145 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1146 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1147 case AL_DIRECT_CHANNELS_SOFT:
1148 case AL_DISTANCE_MODEL:
1149 case AL_SOURCE_RESAMPLER_SOFT:
1150 case AL_SOURCE_SPATIALIZE_SOFT:
1151 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
1153 ivals[0] = (ALint)*values;
1154 return SetSourceiv(Source, Context, (int)prop, ivals);
1156 /* 1x uint */
1157 case AL_BUFFER:
1158 case AL_DIRECT_FILTER:
1159 CHECKVAL(*values <= UINT_MAX && *values >= 0);
1161 ivals[0] = (ALuint)*values;
1162 return SetSourceiv(Source, Context, (int)prop, ivals);
1164 /* 3x uint */
1165 case AL_AUXILIARY_SEND_FILTER:
1166 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
1167 values[1] <= UINT_MAX && values[1] >= 0 &&
1168 values[2] <= UINT_MAX && values[2] >= 0);
1170 ivals[0] = (ALuint)values[0];
1171 ivals[1] = (ALuint)values[1];
1172 ivals[2] = (ALuint)values[2];
1173 return SetSourceiv(Source, Context, (int)prop, ivals);
1175 /* 1x float */
1176 case AL_CONE_INNER_ANGLE:
1177 case AL_CONE_OUTER_ANGLE:
1178 case AL_PITCH:
1179 case AL_GAIN:
1180 case AL_MIN_GAIN:
1181 case AL_MAX_GAIN:
1182 case AL_REFERENCE_DISTANCE:
1183 case AL_ROLLOFF_FACTOR:
1184 case AL_CONE_OUTER_GAIN:
1185 case AL_MAX_DISTANCE:
1186 case AL_DOPPLER_FACTOR:
1187 case AL_CONE_OUTER_GAINHF:
1188 case AL_AIR_ABSORPTION_FACTOR:
1189 case AL_ROOM_ROLLOFF_FACTOR:
1190 case AL_SOURCE_RADIUS:
1191 fvals[0] = (ALfloat)*values;
1192 return SetSourcefv(Source, Context, (int)prop, fvals);
1194 /* 3x float */
1195 case AL_POSITION:
1196 case AL_VELOCITY:
1197 case AL_DIRECTION:
1198 fvals[0] = (ALfloat)values[0];
1199 fvals[1] = (ALfloat)values[1];
1200 fvals[2] = (ALfloat)values[2];
1201 return SetSourcefv(Source, Context, (int)prop, fvals);
1203 /* 6x float */
1204 case AL_ORIENTATION:
1205 fvals[0] = (ALfloat)values[0];
1206 fvals[1] = (ALfloat)values[1];
1207 fvals[2] = (ALfloat)values[2];
1208 fvals[3] = (ALfloat)values[3];
1209 fvals[4] = (ALfloat)values[4];
1210 fvals[5] = (ALfloat)values[5];
1211 return SetSourcefv(Source, Context, (int)prop, fvals);
1213 case AL_SEC_OFFSET_LATENCY_SOFT:
1214 case AL_SEC_OFFSET_CLOCK_SOFT:
1215 case AL_STEREO_ANGLES:
1216 break;
1219 ERR("Unexpected property: 0x%04x\n", prop);
1220 SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x",
1221 prop);
1224 #undef CHECKVAL
1227 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
1229 ALCdevice *device = Context->Device;
1230 ALbufferlistitem *BufferList;
1231 ClockLatency clocktime;
1232 ALuint64 srcclock;
1233 ALint ivals[3];
1234 ALboolean err;
1236 switch(prop)
1238 case AL_GAIN:
1239 *values = Source->Gain;
1240 return AL_TRUE;
1242 case AL_PITCH:
1243 *values = Source->Pitch;
1244 return AL_TRUE;
1246 case AL_MAX_DISTANCE:
1247 *values = Source->MaxDistance;
1248 return AL_TRUE;
1250 case AL_ROLLOFF_FACTOR:
1251 *values = Source->RolloffFactor;
1252 return AL_TRUE;
1254 case AL_REFERENCE_DISTANCE:
1255 *values = Source->RefDistance;
1256 return AL_TRUE;
1258 case AL_CONE_INNER_ANGLE:
1259 *values = Source->InnerAngle;
1260 return AL_TRUE;
1262 case AL_CONE_OUTER_ANGLE:
1263 *values = Source->OuterAngle;
1264 return AL_TRUE;
1266 case AL_MIN_GAIN:
1267 *values = Source->MinGain;
1268 return AL_TRUE;
1270 case AL_MAX_GAIN:
1271 *values = Source->MaxGain;
1272 return AL_TRUE;
1274 case AL_CONE_OUTER_GAIN:
1275 *values = Source->OuterGain;
1276 return AL_TRUE;
1278 case AL_SEC_OFFSET:
1279 case AL_SAMPLE_OFFSET:
1280 case AL_BYTE_OFFSET:
1281 *values = GetSourceOffset(Source, prop, Context);
1282 return AL_TRUE;
1284 case AL_CONE_OUTER_GAINHF:
1285 *values = Source->OuterGainHF;
1286 return AL_TRUE;
1288 case AL_AIR_ABSORPTION_FACTOR:
1289 *values = Source->AirAbsorptionFactor;
1290 return AL_TRUE;
1292 case AL_ROOM_ROLLOFF_FACTOR:
1293 *values = Source->RoomRolloffFactor;
1294 return AL_TRUE;
1296 case AL_DOPPLER_FACTOR:
1297 *values = Source->DopplerFactor;
1298 return AL_TRUE;
1300 case AL_SEC_LENGTH_SOFT:
1301 ReadLock(&Source->queue_lock);
1302 if(!(BufferList=Source->queue))
1303 *values = 0;
1304 else
1306 ALint length = 0;
1307 ALsizei freq = 1;
1308 do {
1309 ALsizei max_len = 0;
1310 ALsizei i;
1311 for(i = 0;i < BufferList->num_buffers;i++)
1313 ALbuffer *buffer = BufferList->buffers[i];
1314 if(buffer && buffer->SampleLen > 0)
1316 freq = buffer->Frequency;
1317 max_len = maxi(max_len, buffer->SampleLen);
1320 length += max_len;
1321 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
1322 } while(BufferList != NULL);
1323 *values = (ALdouble)length / (ALdouble)freq;
1325 ReadUnlock(&Source->queue_lock);
1326 return AL_TRUE;
1328 case AL_SOURCE_RADIUS:
1329 *values = Source->Radius;
1330 return AL_TRUE;
1332 case AL_STEREO_ANGLES:
1333 values[0] = Source->StereoPan[0];
1334 values[1] = Source->StereoPan[1];
1335 return AL_TRUE;
1337 case AL_SEC_OFFSET_LATENCY_SOFT:
1338 /* Get the source offset with the clock time first. Then get the
1339 * clock time with the device latency. Order is important.
1341 values[0] = GetSourceSecOffset(Source, Context, &srcclock);
1342 clocktime = V0(device->Backend,getClockLatency)();
1343 if(srcclock == (ALuint64)clocktime.ClockTime)
1344 values[1] = (ALdouble)clocktime.Latency / 1000000000.0;
1345 else
1347 /* If the clock time incremented, reduce the latency by that
1348 * much since it's that much closer to the source offset it got
1349 * earlier.
1351 ALuint64 diff = clocktime.ClockTime - srcclock;
1352 values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) /
1353 1000000000.0;
1355 return AL_TRUE;
1357 case AL_SEC_OFFSET_CLOCK_SOFT:
1358 values[0] = GetSourceSecOffset(Source, Context, &srcclock);
1359 values[1] = srcclock / 1000000000.0;
1360 return AL_TRUE;
1362 case AL_POSITION:
1363 values[0] = Source->Position[0];
1364 values[1] = Source->Position[1];
1365 values[2] = Source->Position[2];
1366 return AL_TRUE;
1368 case AL_VELOCITY:
1369 values[0] = Source->Velocity[0];
1370 values[1] = Source->Velocity[1];
1371 values[2] = Source->Velocity[2];
1372 return AL_TRUE;
1374 case AL_DIRECTION:
1375 values[0] = Source->Direction[0];
1376 values[1] = Source->Direction[1];
1377 values[2] = Source->Direction[2];
1378 return AL_TRUE;
1380 case AL_ORIENTATION:
1381 values[0] = Source->Orientation[0][0];
1382 values[1] = Source->Orientation[0][1];
1383 values[2] = Source->Orientation[0][2];
1384 values[3] = Source->Orientation[1][0];
1385 values[4] = Source->Orientation[1][1];
1386 values[5] = Source->Orientation[1][2];
1387 return AL_TRUE;
1389 /* 1x int */
1390 case AL_SOURCE_RELATIVE:
1391 case AL_LOOPING:
1392 case AL_SOURCE_STATE:
1393 case AL_BUFFERS_QUEUED:
1394 case AL_BUFFERS_PROCESSED:
1395 case AL_SOURCE_TYPE:
1396 case AL_DIRECT_FILTER_GAINHF_AUTO:
1397 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1398 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1399 case AL_DIRECT_CHANNELS_SOFT:
1400 case AL_BYTE_LENGTH_SOFT:
1401 case AL_SAMPLE_LENGTH_SOFT:
1402 case AL_DISTANCE_MODEL:
1403 case AL_SOURCE_RESAMPLER_SOFT:
1404 case AL_SOURCE_SPATIALIZE_SOFT:
1405 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1406 *values = (ALdouble)ivals[0];
1407 return err;
1409 case AL_BUFFER:
1410 case AL_DIRECT_FILTER:
1411 case AL_AUXILIARY_SEND_FILTER:
1412 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1413 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
1414 break;
1417 ERR("Unexpected property: 0x%04x\n", prop);
1418 SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source double property 0x%04x",
1419 prop);
1422 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1424 ALbufferlistitem *BufferList;
1425 ALdouble dvals[6];
1426 ALboolean err;
1428 switch(prop)
1430 case AL_SOURCE_RELATIVE:
1431 *values = Source->HeadRelative;
1432 return AL_TRUE;
1434 case AL_LOOPING:
1435 *values = Source->Looping;
1436 return AL_TRUE;
1438 case AL_BUFFER:
1439 ReadLock(&Source->queue_lock);
1440 BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : NULL;
1441 *values = (BufferList && BufferList->num_buffers >= 1 && BufferList->buffers[0]) ?
1442 BufferList->buffers[0]->id : 0;
1443 ReadUnlock(&Source->queue_lock);
1444 return AL_TRUE;
1446 case AL_SOURCE_STATE:
1447 *values = GetSourceState(Source, GetSourceVoice(Source, Context));
1448 return AL_TRUE;
1450 case AL_BYTE_LENGTH_SOFT:
1451 ReadLock(&Source->queue_lock);
1452 if(!(BufferList=Source->queue))
1453 *values = 0;
1454 else
1456 ALint length = 0;
1457 do {
1458 ALsizei max_len = 0;
1459 ALsizei i;
1460 for(i = 0;i < BufferList->num_buffers;i++)
1462 ALbuffer *buffer = BufferList->buffers[i];
1463 if(buffer && buffer->SampleLen > 0)
1465 ALuint byte_align, sample_align;
1466 if(buffer->OriginalType == UserFmtIMA4)
1468 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1469 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1470 sample_align = buffer->OriginalAlign;
1472 else if(buffer->OriginalType == UserFmtMSADPCM)
1474 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1475 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1476 sample_align = buffer->OriginalAlign;
1478 else
1480 ALsizei align = buffer->OriginalAlign;
1481 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1482 sample_align = buffer->OriginalAlign;
1485 max_len = maxi(max_len, buffer->SampleLen / sample_align * byte_align);
1488 length += max_len;
1490 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
1491 } while(BufferList != NULL);
1492 *values = length;
1494 ReadUnlock(&Source->queue_lock);
1495 return AL_TRUE;
1497 case AL_SAMPLE_LENGTH_SOFT:
1498 ReadLock(&Source->queue_lock);
1499 if(!(BufferList=Source->queue))
1500 *values = 0;
1501 else
1503 ALint length = 0;
1504 do {
1505 ALsizei max_len = 0;
1506 ALsizei i;
1507 for(i = 0;i < BufferList->num_buffers;i++)
1509 ALbuffer *buffer = BufferList->buffers[i];
1510 if(buffer) max_len = maxi(max_len, buffer->SampleLen);
1512 length += max_len;
1513 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
1514 } while(BufferList != NULL);
1515 *values = length;
1517 ReadUnlock(&Source->queue_lock);
1518 return AL_TRUE;
1520 case AL_BUFFERS_QUEUED:
1521 ReadLock(&Source->queue_lock);
1522 if(!(BufferList=Source->queue))
1523 *values = 0;
1524 else
1526 ALsizei count = 0;
1527 do {
1528 ++count;
1529 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
1530 } while(BufferList != NULL);
1531 *values = count;
1533 ReadUnlock(&Source->queue_lock);
1534 return AL_TRUE;
1536 case AL_BUFFERS_PROCESSED:
1537 ReadLock(&Source->queue_lock);
1538 if(Source->Looping || Source->SourceType != AL_STREAMING)
1540 /* Buffers on a looping source are in a perpetual state of
1541 * PENDING, so don't report any as PROCESSED */
1542 *values = 0;
1544 else
1546 const ALbufferlistitem *BufferList = Source->queue;
1547 const ALbufferlistitem *Current = NULL;
1548 ALsizei played = 0;
1549 ALvoice *voice;
1551 if((voice=GetSourceVoice(Source, Context)) != NULL)
1552 Current = ATOMIC_LOAD_SEQ(&voice->current_buffer);
1553 else if(ATOMIC_LOAD_SEQ(&Source->state) == AL_INITIAL)
1554 Current = BufferList;
1556 while(BufferList && BufferList != Current)
1558 played++;
1559 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
1560 almemory_order_relaxed);
1562 *values = played;
1564 ReadUnlock(&Source->queue_lock);
1565 return AL_TRUE;
1567 case AL_SOURCE_TYPE:
1568 *values = Source->SourceType;
1569 return AL_TRUE;
1571 case AL_DIRECT_FILTER_GAINHF_AUTO:
1572 *values = Source->DryGainHFAuto;
1573 return AL_TRUE;
1575 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1576 *values = Source->WetGainAuto;
1577 return AL_TRUE;
1579 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1580 *values = Source->WetGainHFAuto;
1581 return AL_TRUE;
1583 case AL_DIRECT_CHANNELS_SOFT:
1584 *values = Source->DirectChannels;
1585 return AL_TRUE;
1587 case AL_DISTANCE_MODEL:
1588 *values = Source->DistanceModel;
1589 return AL_TRUE;
1591 case AL_SOURCE_RESAMPLER_SOFT:
1592 *values = Source->Resampler;
1593 return AL_TRUE;
1595 case AL_SOURCE_SPATIALIZE_SOFT:
1596 *values = Source->Spatialize;
1597 return AL_TRUE;
1599 /* 1x float/double */
1600 case AL_CONE_INNER_ANGLE:
1601 case AL_CONE_OUTER_ANGLE:
1602 case AL_PITCH:
1603 case AL_GAIN:
1604 case AL_MIN_GAIN:
1605 case AL_MAX_GAIN:
1606 case AL_REFERENCE_DISTANCE:
1607 case AL_ROLLOFF_FACTOR:
1608 case AL_CONE_OUTER_GAIN:
1609 case AL_MAX_DISTANCE:
1610 case AL_SEC_OFFSET:
1611 case AL_SAMPLE_OFFSET:
1612 case AL_BYTE_OFFSET:
1613 case AL_DOPPLER_FACTOR:
1614 case AL_AIR_ABSORPTION_FACTOR:
1615 case AL_ROOM_ROLLOFF_FACTOR:
1616 case AL_CONE_OUTER_GAINHF:
1617 case AL_SEC_LENGTH_SOFT:
1618 case AL_SOURCE_RADIUS:
1619 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1620 *values = (ALint)dvals[0];
1621 return err;
1623 /* 3x float/double */
1624 case AL_POSITION:
1625 case AL_VELOCITY:
1626 case AL_DIRECTION:
1627 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1629 values[0] = (ALint)dvals[0];
1630 values[1] = (ALint)dvals[1];
1631 values[2] = (ALint)dvals[2];
1633 return err;
1635 /* 6x float/double */
1636 case AL_ORIENTATION:
1637 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1639 values[0] = (ALint)dvals[0];
1640 values[1] = (ALint)dvals[1];
1641 values[2] = (ALint)dvals[2];
1642 values[3] = (ALint)dvals[3];
1643 values[4] = (ALint)dvals[4];
1644 values[5] = (ALint)dvals[5];
1646 return err;
1648 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1649 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
1650 break; /* i64 only */
1651 case AL_SEC_OFFSET_LATENCY_SOFT:
1652 case AL_SEC_OFFSET_CLOCK_SOFT:
1653 break; /* Double only */
1654 case AL_STEREO_ANGLES:
1655 break; /* Float/double only */
1657 case AL_DIRECT_FILTER:
1658 case AL_AUXILIARY_SEND_FILTER:
1659 break; /* ??? */
1662 ERR("Unexpected property: 0x%04x\n", prop);
1663 SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x",
1664 prop);
1667 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1669 ALCdevice *device = Context->Device;
1670 ClockLatency clocktime;
1671 ALuint64 srcclock;
1672 ALdouble dvals[6];
1673 ALint ivals[3];
1674 ALboolean err;
1676 switch(prop)
1678 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1679 /* Get the source offset with the clock time first. Then get the
1680 * clock time with the device latency. Order is important.
1682 values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
1683 clocktime = V0(device->Backend,getClockLatency)();
1684 if(srcclock == (ALuint64)clocktime.ClockTime)
1685 values[1] = clocktime.Latency;
1686 else
1688 /* If the clock time incremented, reduce the latency by that
1689 * much since it's that much closer to the source offset it got
1690 * earlier.
1692 ALuint64 diff = clocktime.ClockTime - srcclock;
1693 values[1] = clocktime.Latency - minu64(clocktime.Latency, diff);
1695 return AL_TRUE;
1697 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
1698 values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
1699 values[1] = srcclock;
1700 return AL_TRUE;
1702 /* 1x float/double */
1703 case AL_CONE_INNER_ANGLE:
1704 case AL_CONE_OUTER_ANGLE:
1705 case AL_PITCH:
1706 case AL_GAIN:
1707 case AL_MIN_GAIN:
1708 case AL_MAX_GAIN:
1709 case AL_REFERENCE_DISTANCE:
1710 case AL_ROLLOFF_FACTOR:
1711 case AL_CONE_OUTER_GAIN:
1712 case AL_MAX_DISTANCE:
1713 case AL_SEC_OFFSET:
1714 case AL_SAMPLE_OFFSET:
1715 case AL_BYTE_OFFSET:
1716 case AL_DOPPLER_FACTOR:
1717 case AL_AIR_ABSORPTION_FACTOR:
1718 case AL_ROOM_ROLLOFF_FACTOR:
1719 case AL_CONE_OUTER_GAINHF:
1720 case AL_SEC_LENGTH_SOFT:
1721 case AL_SOURCE_RADIUS:
1722 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1723 *values = (ALint64)dvals[0];
1724 return err;
1726 /* 3x float/double */
1727 case AL_POSITION:
1728 case AL_VELOCITY:
1729 case AL_DIRECTION:
1730 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1732 values[0] = (ALint64)dvals[0];
1733 values[1] = (ALint64)dvals[1];
1734 values[2] = (ALint64)dvals[2];
1736 return err;
1738 /* 6x float/double */
1739 case AL_ORIENTATION:
1740 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1742 values[0] = (ALint64)dvals[0];
1743 values[1] = (ALint64)dvals[1];
1744 values[2] = (ALint64)dvals[2];
1745 values[3] = (ALint64)dvals[3];
1746 values[4] = (ALint64)dvals[4];
1747 values[5] = (ALint64)dvals[5];
1749 return err;
1751 /* 1x int */
1752 case AL_SOURCE_RELATIVE:
1753 case AL_LOOPING:
1754 case AL_SOURCE_STATE:
1755 case AL_BUFFERS_QUEUED:
1756 case AL_BUFFERS_PROCESSED:
1757 case AL_BYTE_LENGTH_SOFT:
1758 case AL_SAMPLE_LENGTH_SOFT:
1759 case AL_SOURCE_TYPE:
1760 case AL_DIRECT_FILTER_GAINHF_AUTO:
1761 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1762 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1763 case AL_DIRECT_CHANNELS_SOFT:
1764 case AL_DISTANCE_MODEL:
1765 case AL_SOURCE_RESAMPLER_SOFT:
1766 case AL_SOURCE_SPATIALIZE_SOFT:
1767 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1768 *values = ivals[0];
1769 return err;
1771 /* 1x uint */
1772 case AL_BUFFER:
1773 case AL_DIRECT_FILTER:
1774 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1775 *values = (ALuint)ivals[0];
1776 return err;
1778 /* 3x uint */
1779 case AL_AUXILIARY_SEND_FILTER:
1780 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1782 values[0] = (ALuint)ivals[0];
1783 values[1] = (ALuint)ivals[1];
1784 values[2] = (ALuint)ivals[2];
1786 return err;
1788 case AL_SEC_OFFSET_LATENCY_SOFT:
1789 case AL_SEC_OFFSET_CLOCK_SOFT:
1790 break; /* Double only */
1791 case AL_STEREO_ANGLES:
1792 break; /* Float/double only */
1795 ERR("Unexpected property: 0x%04x\n", prop);
1796 SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x",
1797 prop);
1801 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1803 ALCcontext *context;
1804 ALsizei cur = 0;
1806 context = GetContextRef();
1807 if(!context) return;
1809 if(!(n >= 0))
1810 alSetError(context, AL_INVALID_VALUE, "Generating %d sources", n);
1811 else for(cur = 0;cur < n;cur++)
1813 ALsource *source = AllocSource(context);
1814 if(!source)
1816 alDeleteSources(cur, sources);
1817 break;
1819 sources[cur] = source->id;
1822 ALCcontext_DecRef(context);
1826 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1828 ALCcontext *context;
1829 ALsource *Source;
1830 ALsizei i;
1832 context = GetContextRef();
1833 if(!context) return;
1835 LockSourceList(context);
1836 if(!(n >= 0))
1837 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d sources", n);
1839 /* Check that all Sources are valid */
1840 for(i = 0;i < n;i++)
1842 if(LookupSource(context, sources[i]) == NULL)
1843 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]);
1845 for(i = 0;i < n;i++)
1847 if((Source=LookupSource(context, sources[i])) != NULL)
1848 FreeSource(context, Source);
1851 done:
1852 UnlockSourceList(context);
1853 ALCcontext_DecRef(context);
1857 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1859 ALCcontext *context;
1860 ALboolean ret;
1862 context = GetContextRef();
1863 if(!context) return AL_FALSE;
1865 LockSourceList(context);
1866 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1867 UnlockSourceList(context);
1869 ALCcontext_DecRef(context);
1871 return ret;
1875 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1877 ALCcontext *Context;
1878 ALsource *Source;
1880 Context = GetContextRef();
1881 if(!Context) return;
1883 WriteLock(&Context->PropLock);
1884 LockSourceList(Context);
1885 if((Source=LookupSource(Context, source)) == NULL)
1886 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
1887 else if(!(FloatValsByProp(param) == 1))
1888 alSetError(Context, AL_INVALID_ENUM, "Invalid float property 0x%04x", param);
1889 else
1890 SetSourcefv(Source, Context, param, &value);
1891 UnlockSourceList(Context);
1892 WriteUnlock(&Context->PropLock);
1894 ALCcontext_DecRef(Context);
1897 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1899 ALCcontext *Context;
1900 ALsource *Source;
1902 Context = GetContextRef();
1903 if(!Context) return;
1905 WriteLock(&Context->PropLock);
1906 LockSourceList(Context);
1907 if((Source=LookupSource(Context, source)) == NULL)
1908 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
1909 else if(!(FloatValsByProp(param) == 3))
1910 alSetError(Context, AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param);
1911 else
1913 ALfloat fvals[3] = { value1, value2, value3 };
1914 SetSourcefv(Source, Context, param, fvals);
1916 UnlockSourceList(Context);
1917 WriteUnlock(&Context->PropLock);
1919 ALCcontext_DecRef(Context);
1922 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1924 ALCcontext *Context;
1925 ALsource *Source;
1927 Context = GetContextRef();
1928 if(!Context) return;
1930 WriteLock(&Context->PropLock);
1931 LockSourceList(Context);
1932 if((Source=LookupSource(Context, source)) == NULL)
1933 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
1934 else if(!values)
1935 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
1936 else if(!(FloatValsByProp(param) > 0))
1937 alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param);
1938 else
1939 SetSourcefv(Source, Context, param, values);
1940 UnlockSourceList(Context);
1941 WriteUnlock(&Context->PropLock);
1943 ALCcontext_DecRef(Context);
1947 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1949 ALCcontext *Context;
1950 ALsource *Source;
1952 Context = GetContextRef();
1953 if(!Context) return;
1955 WriteLock(&Context->PropLock);
1956 LockSourceList(Context);
1957 if((Source=LookupSource(Context, source)) == NULL)
1958 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
1959 else if(!(DoubleValsByProp(param) == 1))
1960 alSetError(Context, AL_INVALID_ENUM, "Invalid double property 0x%04x", param);
1961 else
1963 ALfloat fval = (ALfloat)value;
1964 SetSourcefv(Source, Context, param, &fval);
1966 UnlockSourceList(Context);
1967 WriteUnlock(&Context->PropLock);
1969 ALCcontext_DecRef(Context);
1972 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1974 ALCcontext *Context;
1975 ALsource *Source;
1977 Context = GetContextRef();
1978 if(!Context) return;
1980 WriteLock(&Context->PropLock);
1981 LockSourceList(Context);
1982 if((Source=LookupSource(Context, source)) == NULL)
1983 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
1984 else if(!(DoubleValsByProp(param) == 3))
1985 alSetError(Context, AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param);
1986 else
1988 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1989 SetSourcefv(Source, Context, param, fvals);
1991 UnlockSourceList(Context);
1992 WriteUnlock(&Context->PropLock);
1994 ALCcontext_DecRef(Context);
1997 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1999 ALCcontext *Context;
2000 ALsource *Source;
2001 ALint count;
2003 Context = GetContextRef();
2004 if(!Context) return;
2006 WriteLock(&Context->PropLock);
2007 LockSourceList(Context);
2008 if((Source=LookupSource(Context, source)) == NULL)
2009 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2010 else if(!values)
2011 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2012 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
2013 alSetError(Context, AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param);
2014 else
2016 ALfloat fvals[6];
2017 ALint i;
2019 for(i = 0;i < count;i++)
2020 fvals[i] = (ALfloat)values[i];
2021 SetSourcefv(Source, Context, param, fvals);
2023 UnlockSourceList(Context);
2024 WriteUnlock(&Context->PropLock);
2026 ALCcontext_DecRef(Context);
2030 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
2032 ALCcontext *Context;
2033 ALsource *Source;
2035 Context = GetContextRef();
2036 if(!Context) return;
2038 WriteLock(&Context->PropLock);
2039 LockSourceList(Context);
2040 if((Source=LookupSource(Context, source)) == NULL)
2041 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2042 else if(!(IntValsByProp(param) == 1))
2043 alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param);
2044 else
2045 SetSourceiv(Source, Context, param, &value);
2046 UnlockSourceList(Context);
2047 WriteUnlock(&Context->PropLock);
2049 ALCcontext_DecRef(Context);
2052 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
2054 ALCcontext *Context;
2055 ALsource *Source;
2057 Context = GetContextRef();
2058 if(!Context) return;
2060 WriteLock(&Context->PropLock);
2061 LockSourceList(Context);
2062 if((Source=LookupSource(Context, source)) == NULL)
2063 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2064 else if(!(IntValsByProp(param) == 3))
2065 alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param);
2066 else
2068 ALint ivals[3] = { value1, value2, value3 };
2069 SetSourceiv(Source, Context, param, ivals);
2071 UnlockSourceList(Context);
2072 WriteUnlock(&Context->PropLock);
2074 ALCcontext_DecRef(Context);
2077 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
2079 ALCcontext *Context;
2080 ALsource *Source;
2082 Context = GetContextRef();
2083 if(!Context) return;
2085 WriteLock(&Context->PropLock);
2086 LockSourceList(Context);
2087 if((Source=LookupSource(Context, source)) == NULL)
2088 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2089 else if(!values)
2090 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2091 else if(!(IntValsByProp(param) > 0))
2092 alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param);
2093 else
2094 SetSourceiv(Source, Context, param, values);
2095 UnlockSourceList(Context);
2096 WriteUnlock(&Context->PropLock);
2098 ALCcontext_DecRef(Context);
2102 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
2104 ALCcontext *Context;
2105 ALsource *Source;
2107 Context = GetContextRef();
2108 if(!Context) return;
2110 WriteLock(&Context->PropLock);
2111 LockSourceList(Context);
2112 if((Source=LookupSource(Context, source)) == NULL)
2113 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2114 else if(!(Int64ValsByProp(param) == 1))
2115 alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param);
2116 else
2117 SetSourcei64v(Source, Context, param, &value);
2118 UnlockSourceList(Context);
2119 WriteUnlock(&Context->PropLock);
2121 ALCcontext_DecRef(Context);
2124 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
2126 ALCcontext *Context;
2127 ALsource *Source;
2129 Context = GetContextRef();
2130 if(!Context) return;
2132 WriteLock(&Context->PropLock);
2133 LockSourceList(Context);
2134 if((Source=LookupSource(Context, source)) == NULL)
2135 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2136 else if(!(Int64ValsByProp(param) == 3))
2137 alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param);
2138 else
2140 ALint64SOFT i64vals[3] = { value1, value2, value3 };
2141 SetSourcei64v(Source, Context, param, i64vals);
2143 UnlockSourceList(Context);
2144 WriteUnlock(&Context->PropLock);
2146 ALCcontext_DecRef(Context);
2149 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
2151 ALCcontext *Context;
2152 ALsource *Source;
2154 Context = GetContextRef();
2155 if(!Context) return;
2157 WriteLock(&Context->PropLock);
2158 LockSourceList(Context);
2159 if((Source=LookupSource(Context, source)) == NULL)
2160 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2161 else if(!values)
2162 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2163 else if(!(Int64ValsByProp(param) > 0))
2164 alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param);
2165 else
2166 SetSourcei64v(Source, Context, param, values);
2167 UnlockSourceList(Context);
2168 WriteUnlock(&Context->PropLock);
2170 ALCcontext_DecRef(Context);
2174 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
2176 ALCcontext *Context;
2177 ALsource *Source;
2179 Context = GetContextRef();
2180 if(!Context) return;
2182 ReadLock(&Context->PropLock);
2183 LockSourceList(Context);
2184 if((Source=LookupSource(Context, source)) == NULL)
2185 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2186 else if(!value)
2187 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2188 else if(!(FloatValsByProp(param) == 1))
2189 alSetError(Context, AL_INVALID_ENUM, "Invalid float property 0x%04x", param);
2190 else
2192 ALdouble dval;
2193 if(GetSourcedv(Source, Context, param, &dval))
2194 *value = (ALfloat)dval;
2196 UnlockSourceList(Context);
2197 ReadUnlock(&Context->PropLock);
2199 ALCcontext_DecRef(Context);
2203 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
2205 ALCcontext *Context;
2206 ALsource *Source;
2208 Context = GetContextRef();
2209 if(!Context) return;
2211 ReadLock(&Context->PropLock);
2212 LockSourceList(Context);
2213 if((Source=LookupSource(Context, source)) == NULL)
2214 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2215 else if(!(value1 && value2 && value3))
2216 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2217 else if(!(FloatValsByProp(param) == 3))
2218 alSetError(Context, AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param);
2219 else
2221 ALdouble dvals[3];
2222 if(GetSourcedv(Source, Context, param, dvals))
2224 *value1 = (ALfloat)dvals[0];
2225 *value2 = (ALfloat)dvals[1];
2226 *value3 = (ALfloat)dvals[2];
2229 UnlockSourceList(Context);
2230 ReadUnlock(&Context->PropLock);
2232 ALCcontext_DecRef(Context);
2236 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
2238 ALCcontext *Context;
2239 ALsource *Source;
2240 ALint count;
2242 Context = GetContextRef();
2243 if(!Context) return;
2245 ReadLock(&Context->PropLock);
2246 LockSourceList(Context);
2247 if((Source=LookupSource(Context, source)) == NULL)
2248 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2249 else if(!values)
2250 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2251 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
2252 alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param);
2253 else
2255 ALdouble dvals[6];
2256 if(GetSourcedv(Source, Context, param, dvals))
2258 ALint i;
2259 for(i = 0;i < count;i++)
2260 values[i] = (ALfloat)dvals[i];
2263 UnlockSourceList(Context);
2264 ReadUnlock(&Context->PropLock);
2266 ALCcontext_DecRef(Context);
2270 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
2272 ALCcontext *Context;
2273 ALsource *Source;
2275 Context = GetContextRef();
2276 if(!Context) return;
2278 ReadLock(&Context->PropLock);
2279 LockSourceList(Context);
2280 if((Source=LookupSource(Context, source)) == NULL)
2281 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2282 else if(!value)
2283 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2284 else if(!(DoubleValsByProp(param) == 1))
2285 alSetError(Context, AL_INVALID_ENUM, "Invalid double property 0x%04x", param);
2286 else
2287 GetSourcedv(Source, Context, param, value);
2288 UnlockSourceList(Context);
2289 ReadUnlock(&Context->PropLock);
2291 ALCcontext_DecRef(Context);
2294 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
2296 ALCcontext *Context;
2297 ALsource *Source;
2299 Context = GetContextRef();
2300 if(!Context) return;
2302 ReadLock(&Context->PropLock);
2303 LockSourceList(Context);
2304 if((Source=LookupSource(Context, source)) == NULL)
2305 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2306 else if(!(value1 && value2 && value3))
2307 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2308 else if(!(DoubleValsByProp(param) == 3))
2309 alSetError(Context, AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param);
2310 else
2312 ALdouble dvals[3];
2313 if(GetSourcedv(Source, Context, param, dvals))
2315 *value1 = dvals[0];
2316 *value2 = dvals[1];
2317 *value3 = dvals[2];
2320 UnlockSourceList(Context);
2321 ReadUnlock(&Context->PropLock);
2323 ALCcontext_DecRef(Context);
2326 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
2328 ALCcontext *Context;
2329 ALsource *Source;
2331 Context = GetContextRef();
2332 if(!Context) return;
2334 ReadLock(&Context->PropLock);
2335 LockSourceList(Context);
2336 if((Source=LookupSource(Context, source)) == NULL)
2337 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2338 else if(!values)
2339 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2340 else if(!(DoubleValsByProp(param) > 0))
2341 alSetError(Context, AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param);
2342 else
2343 GetSourcedv(Source, Context, param, values);
2344 UnlockSourceList(Context);
2345 ReadUnlock(&Context->PropLock);
2347 ALCcontext_DecRef(Context);
2351 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2353 ALCcontext *Context;
2354 ALsource *Source;
2356 Context = GetContextRef();
2357 if(!Context) return;
2359 ReadLock(&Context->PropLock);
2360 LockSourceList(Context);
2361 if((Source=LookupSource(Context, source)) == NULL)
2362 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2363 else if(!value)
2364 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2365 else if(!(IntValsByProp(param) == 1))
2366 alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param);
2367 else
2368 GetSourceiv(Source, Context, param, value);
2369 UnlockSourceList(Context);
2370 ReadUnlock(&Context->PropLock);
2372 ALCcontext_DecRef(Context);
2376 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2378 ALCcontext *Context;
2379 ALsource *Source;
2381 Context = GetContextRef();
2382 if(!Context) return;
2384 ReadLock(&Context->PropLock);
2385 LockSourceList(Context);
2386 if((Source=LookupSource(Context, source)) == NULL)
2387 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2388 else if(!(value1 && value2 && value3))
2389 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2390 else if(!(IntValsByProp(param) == 3))
2391 alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param);
2392 else
2394 ALint ivals[3];
2395 if(GetSourceiv(Source, Context, param, ivals))
2397 *value1 = ivals[0];
2398 *value2 = ivals[1];
2399 *value3 = ivals[2];
2402 UnlockSourceList(Context);
2403 ReadUnlock(&Context->PropLock);
2405 ALCcontext_DecRef(Context);
2409 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2411 ALCcontext *Context;
2412 ALsource *Source;
2414 Context = GetContextRef();
2415 if(!Context) return;
2417 ReadLock(&Context->PropLock);
2418 LockSourceList(Context);
2419 if((Source=LookupSource(Context, source)) == NULL)
2420 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2421 else if(!values)
2422 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2423 else if(!(IntValsByProp(param) > 0))
2424 alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param);
2425 else
2426 GetSourceiv(Source, Context, param, values);
2427 UnlockSourceList(Context);
2428 ReadUnlock(&Context->PropLock);
2430 ALCcontext_DecRef(Context);
2434 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2436 ALCcontext *Context;
2437 ALsource *Source;
2439 Context = GetContextRef();
2440 if(!Context) return;
2442 ReadLock(&Context->PropLock);
2443 LockSourceList(Context);
2444 if((Source=LookupSource(Context, source)) == NULL)
2445 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2446 else if(!value)
2447 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2448 else if(!(Int64ValsByProp(param) == 1))
2449 alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param);
2450 else
2451 GetSourcei64v(Source, Context, param, value);
2452 UnlockSourceList(Context);
2453 ReadUnlock(&Context->PropLock);
2455 ALCcontext_DecRef(Context);
2458 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2460 ALCcontext *Context;
2461 ALsource *Source;
2463 Context = GetContextRef();
2464 if(!Context) return;
2466 ReadLock(&Context->PropLock);
2467 LockSourceList(Context);
2468 if((Source=LookupSource(Context, source)) == NULL)
2469 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2470 else if(!(value1 && value2 && value3))
2471 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2472 else if(!(Int64ValsByProp(param) == 3))
2473 alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param);
2474 else
2476 ALint64 i64vals[3];
2477 if(GetSourcei64v(Source, Context, param, i64vals))
2479 *value1 = i64vals[0];
2480 *value2 = i64vals[1];
2481 *value3 = i64vals[2];
2484 UnlockSourceList(Context);
2485 ReadUnlock(&Context->PropLock);
2487 ALCcontext_DecRef(Context);
2490 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2492 ALCcontext *Context;
2493 ALsource *Source;
2495 Context = GetContextRef();
2496 if(!Context) return;
2498 ReadLock(&Context->PropLock);
2499 LockSourceList(Context);
2500 if((Source=LookupSource(Context, source)) == NULL)
2501 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source);
2502 else if(!values)
2503 alSetError(Context, AL_INVALID_VALUE, "NULL pointer");
2504 else if(!(Int64ValsByProp(param) > 0))
2505 alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param);
2506 else
2507 GetSourcei64v(Source, Context, param, values);
2508 UnlockSourceList(Context);
2509 ReadUnlock(&Context->PropLock);
2511 ALCcontext_DecRef(Context);
2515 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2517 alSourcePlayv(1, &source);
2519 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2521 ALCcontext *context;
2522 ALCdevice *device;
2523 ALsource *source;
2524 ALvoice *voice;
2525 ALsizei i, j;
2527 context = GetContextRef();
2528 if(!context) return;
2530 LockSourceList(context);
2531 if(!(n >= 0))
2532 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Playing %d sources", n);
2533 for(i = 0;i < n;i++)
2535 if(!LookupSource(context, sources[i]))
2536 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]);
2539 device = context->Device;
2540 ALCdevice_Lock(device);
2541 /* If the device is disconnected, go right to stopped. */
2542 if(!device->Connected)
2544 for(i = 0;i < n;i++)
2546 source = LookupSource(context, sources[i]);
2547 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2549 ALCdevice_Unlock(device);
2550 goto done;
2553 while(n > context->MaxVoices-context->VoiceCount)
2555 ALsizei newcount = context->MaxVoices << 1;
2556 if(context->MaxVoices >= newcount)
2558 ALCdevice_Unlock(device);
2559 SETERR_GOTO(context, AL_OUT_OF_MEMORY, done,
2560 "Overflow increasing voice count %d -> %d", context->MaxVoices, newcount);
2562 AllocateVoices(context, newcount, device->NumAuxSends);
2565 for(i = 0;i < n;i++)
2567 ALbufferlistitem *BufferList;
2568 ALbuffer *buffer = NULL;
2569 bool start_fading = false;
2570 ALint vidx = -1;
2571 ALsizei s;
2573 source = LookupSource(context, sources[i]);
2574 WriteLock(&source->queue_lock);
2575 /* Check that there is a queue containing at least one valid, non zero
2576 * length Buffer.
2578 BufferList = source->queue;
2579 while(BufferList)
2581 ALsizei b;
2582 for(b = 0;b < BufferList->num_buffers;b++)
2584 buffer = BufferList->buffers[b];
2585 if(buffer && buffer->SampleLen > 0) break;
2587 if(buffer && buffer->SampleLen > 0) break;
2588 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
2591 /* If there's nothing to play, go right to stopped. */
2592 if(!BufferList)
2594 /* NOTE: A source without any playable buffers should not have an
2595 * ALvoice since it shouldn't be in a playing or paused state. So
2596 * there's no need to look up its voice and clear the source.
2598 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2599 source->OffsetType = AL_NONE;
2600 source->Offset = 0.0;
2601 goto finish_play;
2604 voice = GetSourceVoice(source, context);
2605 switch(GetSourceState(source, voice))
2607 case AL_PLAYING:
2608 assert(voice != NULL);
2609 /* A source that's already playing is restarted from the beginning. */
2610 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
2611 ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
2612 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release);
2613 goto finish_play;
2615 case AL_PAUSED:
2616 assert(voice != NULL);
2617 /* A source that's paused simply resumes. */
2618 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
2619 ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release);
2620 goto finish_play;
2622 default:
2623 break;
2626 /* Make sure this source isn't already active, and if not, look for an
2627 * unused voice to put it in.
2629 assert(voice == NULL);
2630 for(j = 0;j < context->VoiceCount;j++)
2632 if(ATOMIC_LOAD(&context->Voices[j]->Source, almemory_order_acquire) == NULL)
2634 vidx = j;
2635 break;
2638 if(vidx == -1)
2639 vidx = context->VoiceCount++;
2640 voice = context->Voices[vidx];
2641 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2643 ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acquire);
2644 UpdateSourceProps(source, voice, device->NumAuxSends, context);
2646 /* A source that's not playing or paused has any offset applied when it
2647 * starts playing.
2649 if(source->Looping)
2650 ATOMIC_STORE(&voice->loop_buffer, source->queue, almemory_order_relaxed);
2651 else
2652 ATOMIC_STORE(&voice->loop_buffer, NULL, almemory_order_relaxed);
2653 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
2654 ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
2655 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed);
2656 if(source->OffsetType != AL_NONE)
2658 ApplyOffset(source, voice);
2659 start_fading = ATOMIC_LOAD(&voice->position, almemory_order_relaxed) != 0 ||
2660 ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) != 0 ||
2661 ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed) != BufferList;
2664 voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2665 voice->SampleSize = BytesFromFmt(buffer->FmtType);
2667 /* Clear previous samples. */
2668 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
2670 /* Clear the stepping value so the mixer knows not to mix this until
2671 * the update gets applied.
2673 voice->Step = 0;
2675 voice->Flags = start_fading ? VOICE_IS_FADING : 0;
2676 if(source->SourceType == AL_STATIC) voice->Flags |= VOICE_IS_STATIC;
2677 memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*voice->NumChannels);
2678 for(s = 0;s < device->NumAuxSends;s++)
2679 memset(voice->Send[s].Params, 0, sizeof(voice->Send[s].Params[0])*voice->NumChannels);
2680 if(device->AvgSpeakerDist > 0.0f)
2682 ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC /
2683 (device->AvgSpeakerDist * device->Frequency);
2684 for(j = 0;j < voice->NumChannels;j++)
2686 NfcFilterCreate1(&voice->Direct.Params[j].NFCtrlFilter[0], 0.0f, w1);
2687 NfcFilterCreate2(&voice->Direct.Params[j].NFCtrlFilter[1], 0.0f, w1);
2688 NfcFilterCreate3(&voice->Direct.Params[j].NFCtrlFilter[2], 0.0f, w1);
2692 ATOMIC_STORE(&voice->Source, source, almemory_order_relaxed);
2693 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
2694 ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release);
2695 source->VoiceIdx = vidx;
2696 finish_play:
2697 WriteUnlock(&source->queue_lock);
2699 ALCdevice_Unlock(device);
2701 done:
2702 UnlockSourceList(context);
2703 ALCcontext_DecRef(context);
2706 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2708 alSourcePausev(1, &source);
2710 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2712 ALCcontext *context;
2713 ALCdevice *device;
2714 ALsource *source;
2715 ALvoice *voice;
2716 ALsizei i;
2718 context = GetContextRef();
2719 if(!context) return;
2721 LockSourceList(context);
2722 if(!(n >= 0))
2723 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Pausing %d sources", n);
2724 for(i = 0;i < n;i++)
2726 if(!LookupSource(context, sources[i]))
2727 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]);
2730 device = context->Device;
2731 ALCdevice_Lock(device);
2732 for(i = 0;i < n;i++)
2734 source = LookupSource(context, sources[i]);
2735 WriteLock(&source->queue_lock);
2736 if((voice=GetSourceVoice(source, context)) != NULL)
2738 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2739 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2740 althrd_yield();
2742 if(GetSourceState(source, voice) == AL_PLAYING)
2743 ATOMIC_STORE(&source->state, AL_PAUSED, almemory_order_release);
2744 WriteUnlock(&source->queue_lock);
2746 ALCdevice_Unlock(device);
2748 done:
2749 UnlockSourceList(context);
2750 ALCcontext_DecRef(context);
2753 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2755 alSourceStopv(1, &source);
2757 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2759 ALCcontext *context;
2760 ALCdevice *device;
2761 ALsource *source;
2762 ALvoice *voice;
2763 ALsizei i;
2765 context = GetContextRef();
2766 if(!context) return;
2768 LockSourceList(context);
2769 if(!(n >= 0))
2770 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Stopping %d sources", n);
2771 for(i = 0;i < n;i++)
2773 if(!LookupSource(context, sources[i]))
2774 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]);
2777 device = context->Device;
2778 ALCdevice_Lock(device);
2779 for(i = 0;i < n;i++)
2781 source = LookupSource(context, sources[i]);
2782 WriteLock(&source->queue_lock);
2783 if((voice=GetSourceVoice(source, context)) != NULL)
2785 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
2786 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2787 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2788 althrd_yield();
2790 if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL)
2791 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2792 source->OffsetType = AL_NONE;
2793 source->Offset = 0.0;
2794 WriteUnlock(&source->queue_lock);
2796 ALCdevice_Unlock(device);
2798 done:
2799 UnlockSourceList(context);
2800 ALCcontext_DecRef(context);
2803 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2805 alSourceRewindv(1, &source);
2807 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2809 ALCcontext *context;
2810 ALCdevice *device;
2811 ALsource *source;
2812 ALvoice *voice;
2813 ALsizei i;
2815 context = GetContextRef();
2816 if(!context) return;
2818 LockSourceList(context);
2819 if(!(n >= 0))
2820 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Rewinding %d sources", n);
2821 for(i = 0;i < n;i++)
2823 if(!LookupSource(context, sources[i]))
2824 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]);
2827 device = context->Device;
2828 ALCdevice_Lock(device);
2829 for(i = 0;i < n;i++)
2831 source = LookupSource(context, sources[i]);
2832 WriteLock(&source->queue_lock);
2833 if((voice=GetSourceVoice(source, context)) != NULL)
2835 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
2836 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2837 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2838 althrd_yield();
2840 if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL)
2841 ATOMIC_STORE(&source->state, AL_INITIAL, almemory_order_relaxed);
2842 source->OffsetType = AL_NONE;
2843 source->Offset = 0.0;
2844 WriteUnlock(&source->queue_lock);
2846 ALCdevice_Unlock(device);
2848 done:
2849 UnlockSourceList(context);
2850 ALCcontext_DecRef(context);
2854 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2856 ALCdevice *device;
2857 ALCcontext *context;
2858 ALsource *source;
2859 ALsizei i;
2860 ALbufferlistitem *BufferListStart;
2861 ALbufferlistitem *BufferList;
2862 ALbuffer *BufferFmt = NULL;
2864 if(nb == 0)
2865 return;
2867 context = GetContextRef();
2868 if(!context) return;
2870 device = context->Device;
2872 LockSourceList(context);
2873 if(!(nb >= 0))
2874 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Queueing %d buffers", nb);
2875 if((source=LookupSource(context, src)) == NULL)
2876 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src);
2878 WriteLock(&source->queue_lock);
2879 if(source->SourceType == AL_STATIC)
2881 WriteUnlock(&source->queue_lock);
2882 /* Can't queue on a Static Source */
2883 SETERR_GOTO(context, AL_INVALID_OPERATION, done, "Queueing onto static source %u", src);
2886 /* Check for a valid Buffer, for its frequency and format */
2887 BufferList = source->queue;
2888 while(BufferList)
2890 for(i = 0;i < BufferList->num_buffers;i++)
2892 if((BufferFmt=BufferList->buffers[i]) != NULL)
2893 break;
2895 if(BufferFmt) break;
2896 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
2899 LockBufferList(device);
2900 BufferListStart = NULL;
2901 BufferList = NULL;
2902 for(i = 0;i < nb;i++)
2904 ALbuffer *buffer = NULL;
2905 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2907 WriteUnlock(&source->queue_lock);
2908 SETERR_GOTO(context, AL_INVALID_NAME, buffer_error, "Queueing invalid buffer ID %u",
2909 buffers[i]);
2912 if(!BufferListStart)
2914 BufferListStart = al_calloc(DEF_ALIGN,
2915 FAM_SIZE(ALbufferlistitem, buffers, 1));
2916 BufferList = BufferListStart;
2918 else
2920 ALbufferlistitem *item = al_calloc(DEF_ALIGN,
2921 FAM_SIZE(ALbufferlistitem, buffers, 1));
2922 ATOMIC_STORE(&BufferList->next, item, almemory_order_relaxed);
2923 BufferList = item;
2925 ATOMIC_INIT(&BufferList->next, NULL);
2926 BufferList->num_buffers = 1;
2927 BufferList->buffers[0] = buffer;
2928 if(!buffer) continue;
2930 /* Hold a read lock on each buffer being queued while checking all
2931 * provided buffers. This is done so other threads don't see an extra
2932 * reference on some buffers if this operation ends up failing. */
2933 ReadLock(&buffer->lock);
2934 IncrementRef(&buffer->ref);
2936 if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
2938 WriteUnlock(&source->queue_lock);
2939 SETERR_GOTO(context, AL_INVALID_OPERATION, buffer_error,
2940 "Queueing non-persistently mapped buffer %u", buffer->id);
2943 if(BufferFmt == NULL)
2944 BufferFmt = buffer;
2945 else if(BufferFmt->Frequency != buffer->Frequency ||
2946 BufferFmt->FmtChannels != buffer->FmtChannels ||
2947 BufferFmt->OriginalType != buffer->OriginalType)
2949 WriteUnlock(&source->queue_lock);
2950 alSetError(context, AL_INVALID_OPERATION, "Queueing buffer with mismatched format");
2952 buffer_error:
2953 /* A buffer failed (invalid ID or format), so unlock and release
2954 * each buffer we had. */
2955 while(BufferListStart)
2957 ALbufferlistitem *next = ATOMIC_LOAD(&BufferListStart->next,
2958 almemory_order_relaxed);
2959 for(i = 0;i < BufferListStart->num_buffers;i++)
2961 if((buffer=BufferListStart->buffers[i]) != NULL)
2963 DecrementRef(&buffer->ref);
2964 ReadUnlock(&buffer->lock);
2967 al_free(BufferListStart);
2968 BufferListStart = next;
2970 UnlockBufferList(device);
2971 goto done;
2974 /* All buffers good, unlock them now. */
2975 BufferList = BufferListStart;
2976 while(BufferList != NULL)
2978 for(i = 0;i < BufferList->num_buffers;i++)
2980 ALbuffer *buffer = BufferList->buffers[i];
2981 if(buffer) ReadUnlock(&buffer->lock);
2983 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
2985 UnlockBufferList(device);
2987 /* Source is now streaming */
2988 source->SourceType = AL_STREAMING;
2990 if(!(BufferList=source->queue))
2991 source->queue = BufferListStart;
2992 else
2994 ALbufferlistitem *next;
2995 while((next=ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed)) != NULL)
2996 BufferList = next;
2997 ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release);
2999 WriteUnlock(&source->queue_lock);
3001 done:
3002 UnlockSourceList(context);
3003 ALCcontext_DecRef(context);
3006 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
3008 ALCcontext *context;
3009 ALsource *source;
3010 ALbufferlistitem *OldHead;
3011 ALbufferlistitem *OldTail;
3012 ALbufferlistitem *Current;
3013 ALvoice *voice;
3014 ALsizei i = 0;
3016 context = GetContextRef();
3017 if(!context) return;
3019 LockSourceList(context);
3020 if(!(nb >= 0))
3021 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing %d buffers", nb);
3022 if((source=LookupSource(context, src)) == NULL)
3023 SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src);
3025 /* Nothing to unqueue. */
3026 if(nb == 0) goto done;
3028 WriteLock(&source->queue_lock);
3029 if(source->Looping)
3031 WriteUnlock(&source->queue_lock);
3032 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing from looping source %u", src);
3034 if(source->SourceType != AL_STREAMING)
3036 WriteUnlock(&source->queue_lock);
3037 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing from a non-streaming source %u",
3038 src);
3041 /* Find the new buffer queue head */
3042 OldTail = source->queue;
3043 Current = NULL;
3044 if((voice=GetSourceVoice(source, context)) != NULL)
3045 Current = ATOMIC_LOAD_SEQ(&voice->current_buffer);
3046 else if(ATOMIC_LOAD_SEQ(&source->state) == AL_INITIAL)
3047 Current = OldTail;
3048 if(OldTail != Current && OldTail->num_buffers == 1)
3050 for(i = 1;i < nb;i++)
3052 ALbufferlistitem *next = ATOMIC_LOAD(&OldTail->next, almemory_order_relaxed);
3053 if(!next || next == Current || next->num_buffers != 1) break;
3054 OldTail = next;
3057 if(i != nb)
3059 WriteUnlock(&source->queue_lock);
3060 SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing pending buffers");
3063 /* Swap it, and cut the new head from the old. */
3064 OldHead = source->queue;
3065 source->queue = ATOMIC_EXCHANGE_PTR(&OldTail->next, NULL, almemory_order_acq_rel);
3066 WriteUnlock(&source->queue_lock);
3068 while(OldHead != NULL)
3070 ALbufferlistitem *next = ATOMIC_LOAD(&OldHead->next, almemory_order_relaxed);
3071 ALbuffer *buffer = OldHead->buffers[0];
3073 if(!buffer)
3074 *(buffers++) = 0;
3075 else
3077 *(buffers++) = buffer->id;
3078 DecrementRef(&buffer->ref);
3081 al_free(OldHead);
3082 OldHead = next;
3085 done:
3086 UnlockSourceList(context);
3087 ALCcontext_DecRef(context);
3091 static void InitSourceParams(ALsource *Source, ALsizei num_sends)
3093 ALsizei i;
3095 RWLockInit(&Source->queue_lock);
3097 Source->InnerAngle = 360.0f;
3098 Source->OuterAngle = 360.0f;
3099 Source->Pitch = 1.0f;
3100 Source->Position[0] = 0.0f;
3101 Source->Position[1] = 0.0f;
3102 Source->Position[2] = 0.0f;
3103 Source->Velocity[0] = 0.0f;
3104 Source->Velocity[1] = 0.0f;
3105 Source->Velocity[2] = 0.0f;
3106 Source->Direction[0] = 0.0f;
3107 Source->Direction[1] = 0.0f;
3108 Source->Direction[2] = 0.0f;
3109 Source->Orientation[0][0] = 0.0f;
3110 Source->Orientation[0][1] = 0.0f;
3111 Source->Orientation[0][2] = -1.0f;
3112 Source->Orientation[1][0] = 0.0f;
3113 Source->Orientation[1][1] = 1.0f;
3114 Source->Orientation[1][2] = 0.0f;
3115 Source->RefDistance = 1.0f;
3116 Source->MaxDistance = FLT_MAX;
3117 Source->RolloffFactor = 1.0f;
3118 Source->Gain = 1.0f;
3119 Source->MinGain = 0.0f;
3120 Source->MaxGain = 1.0f;
3121 Source->OuterGain = 0.0f;
3122 Source->OuterGainHF = 1.0f;
3124 Source->DryGainHFAuto = AL_TRUE;
3125 Source->WetGainAuto = AL_TRUE;
3126 Source->WetGainHFAuto = AL_TRUE;
3127 Source->AirAbsorptionFactor = 0.0f;
3128 Source->RoomRolloffFactor = 0.0f;
3129 Source->DopplerFactor = 1.0f;
3130 Source->HeadRelative = AL_FALSE;
3131 Source->Looping = AL_FALSE;
3132 Source->DistanceModel = DefaultDistanceModel;
3133 Source->Resampler = ResamplerDefault;
3134 Source->DirectChannels = AL_FALSE;
3135 Source->Spatialize = SpatializeAuto;
3137 Source->StereoPan[0] = DEG2RAD( 30.0f);
3138 Source->StereoPan[1] = DEG2RAD(-30.0f);
3140 Source->Radius = 0.0f;
3142 Source->Direct.Gain = 1.0f;
3143 Source->Direct.GainHF = 1.0f;
3144 Source->Direct.HFReference = LOWPASSFREQREF;
3145 Source->Direct.GainLF = 1.0f;
3146 Source->Direct.LFReference = HIGHPASSFREQREF;
3147 Source->Send = al_calloc(16, num_sends*sizeof(Source->Send[0]));
3148 for(i = 0;i < num_sends;i++)
3150 Source->Send[i].Slot = NULL;
3151 Source->Send[i].Gain = 1.0f;
3152 Source->Send[i].GainHF = 1.0f;
3153 Source->Send[i].HFReference = LOWPASSFREQREF;
3154 Source->Send[i].GainLF = 1.0f;
3155 Source->Send[i].LFReference = HIGHPASSFREQREF;
3158 Source->Offset = 0.0;
3159 Source->OffsetType = AL_NONE;
3160 Source->SourceType = AL_UNDETERMINED;
3161 ATOMIC_INIT(&Source->state, AL_INITIAL);
3163 Source->queue = NULL;
3165 /* No way to do an 'init' here, so just test+set with relaxed ordering and
3166 * ignore the test.
3168 ATOMIC_FLAG_TEST_AND_SET(&Source->PropsClean, almemory_order_relaxed);
3170 Source->VoiceIdx = -1;
3173 static void DeinitSource(ALsource *source, ALsizei num_sends)
3175 ALbufferlistitem *BufferList;
3176 ALsizei i;
3178 BufferList = source->queue;
3179 while(BufferList != NULL)
3181 ALbufferlistitem *next = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
3182 for(i = 0;i < BufferList->num_buffers;i++)
3184 if(BufferList->buffers[i] != NULL)
3185 DecrementRef(&BufferList->buffers[i]->ref);
3187 al_free(BufferList);
3188 BufferList = next;
3190 source->queue = NULL;
3192 if(source->Send)
3194 for(i = 0;i < num_sends;i++)
3196 if(source->Send[i].Slot)
3197 DecrementRef(&source->Send[i].Slot->ref);
3198 source->Send[i].Slot = NULL;
3200 al_free(source->Send);
3201 source->Send = NULL;
3205 static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends, ALCcontext *context)
3207 struct ALvoiceProps *props;
3208 ALsizei i;
3210 /* Get an unused property container, or allocate a new one as needed. */
3211 props = ATOMIC_LOAD(&context->FreeVoiceProps, almemory_order_acquire);
3212 if(!props)
3213 props = al_calloc(16, FAM_SIZE(struct ALvoiceProps, Send, num_sends));
3214 else
3216 struct ALvoiceProps *next;
3217 do {
3218 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
3219 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeVoiceProps, &props, next,
3220 almemory_order_acq_rel, almemory_order_acquire) == 0);
3223 /* Copy in current property values. */
3224 props->Pitch = source->Pitch;
3225 props->Gain = source->Gain;
3226 props->OuterGain = source->OuterGain;
3227 props->MinGain = source->MinGain;
3228 props->MaxGain = source->MaxGain;
3229 props->InnerAngle = source->InnerAngle;
3230 props->OuterAngle = source->OuterAngle;
3231 props->RefDistance = source->RefDistance;
3232 props->MaxDistance = source->MaxDistance;
3233 props->RolloffFactor = source->RolloffFactor;
3234 for(i = 0;i < 3;i++)
3235 props->Position[i] = source->Position[i];
3236 for(i = 0;i < 3;i++)
3237 props->Velocity[i] = source->Velocity[i];
3238 for(i = 0;i < 3;i++)
3239 props->Direction[i] = source->Direction[i];
3240 for(i = 0;i < 2;i++)
3242 ALsizei j;
3243 for(j = 0;j < 3;j++)
3244 props->Orientation[i][j] = source->Orientation[i][j];
3246 props->HeadRelative = source->HeadRelative;
3247 props->DistanceModel = source->DistanceModel;
3248 props->Resampler = source->Resampler;
3249 props->DirectChannels = source->DirectChannels;
3250 props->SpatializeMode = source->Spatialize;
3252 props->DryGainHFAuto = source->DryGainHFAuto;
3253 props->WetGainAuto = source->WetGainAuto;
3254 props->WetGainHFAuto = source->WetGainHFAuto;
3255 props->OuterGainHF = source->OuterGainHF;
3257 props->AirAbsorptionFactor = source->AirAbsorptionFactor;
3258 props->RoomRolloffFactor = source->RoomRolloffFactor;
3259 props->DopplerFactor = source->DopplerFactor;
3261 props->StereoPan[0] = source->StereoPan[0];
3262 props->StereoPan[1] = source->StereoPan[1];
3264 props->Radius = source->Radius;
3266 props->Direct.Gain = source->Direct.Gain;
3267 props->Direct.GainHF = source->Direct.GainHF;
3268 props->Direct.HFReference = source->Direct.HFReference;
3269 props->Direct.GainLF = source->Direct.GainLF;
3270 props->Direct.LFReference = source->Direct.LFReference;
3272 for(i = 0;i < num_sends;i++)
3274 props->Send[i].Slot = source->Send[i].Slot;
3275 props->Send[i].Gain = source->Send[i].Gain;
3276 props->Send[i].GainHF = source->Send[i].GainHF;
3277 props->Send[i].HFReference = source->Send[i].HFReference;
3278 props->Send[i].GainLF = source->Send[i].GainLF;
3279 props->Send[i].LFReference = source->Send[i].LFReference;
3282 /* Set the new container for updating internal parameters. */
3283 props = ATOMIC_EXCHANGE_PTR(&voice->Update, props, almemory_order_acq_rel);
3284 if(props)
3286 /* If there was an unused update container, put it back in the
3287 * freelist.
3289 ATOMIC_REPLACE_HEAD(struct ALvoiceProps*, &context->FreeVoiceProps, props);
3293 void UpdateAllSourceProps(ALCcontext *context)
3295 ALsizei num_sends = context->Device->NumAuxSends;
3296 ALsizei pos;
3298 for(pos = 0;pos < context->VoiceCount;pos++)
3300 ALvoice *voice = context->Voices[pos];
3301 ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire);
3302 if(source && !ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acq_rel))
3303 UpdateSourceProps(source, voice, num_sends, context);
3308 /* GetSourceSampleOffset
3310 * Gets the current read offset for the given Source, in 32.32 fixed-point
3311 * samples. The offset is relative to the start of the queue (not the start of
3312 * the current buffer).
3314 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3316 ALCdevice *device = context->Device;
3317 const ALbufferlistitem *Current;
3318 ALuint64 readPos;
3319 ALuint refcount;
3320 ALvoice *voice;
3322 ReadLock(&Source->queue_lock);
3323 do {
3324 Current = NULL;
3325 readPos = 0;
3326 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3327 althrd_yield();
3328 *clocktime = GetDeviceClockTime(device);
3330 voice = GetSourceVoice(Source, context);
3331 if(voice)
3333 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3335 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << 32;
3336 readPos |= (ALuint64)ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) <<
3337 (32-FRACTIONBITS);
3339 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3340 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3342 if(voice)
3344 const ALbufferlistitem *BufferList = Source->queue;
3345 while(BufferList && BufferList != Current)
3347 ALsizei max_len = 0;
3348 ALsizei i;
3350 for(i = 0;i < BufferList->num_buffers;i++)
3352 ALbuffer *buffer = BufferList->buffers[i];
3353 if(buffer) max_len = maxi(max_len, buffer->SampleLen);
3355 readPos += (ALuint64)max_len << 32;
3356 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3357 almemory_order_relaxed);
3359 readPos = minu64(readPos, U64(0x7fffffffffffffff));
3362 ReadUnlock(&Source->queue_lock);
3363 return (ALint64)readPos;
3366 /* GetSourceSecOffset
3368 * Gets the current read offset for the given Source, in seconds. The offset is
3369 * relative to the start of the queue (not the start of the current buffer).
3371 static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3373 ALCdevice *device = context->Device;
3374 const ALbufferlistitem *Current;
3375 ALuint64 readPos;
3376 ALuint refcount;
3377 ALdouble offset;
3378 ALvoice *voice;
3380 ReadLock(&Source->queue_lock);
3381 do {
3382 Current = NULL;
3383 readPos = 0;
3384 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3385 althrd_yield();
3386 *clocktime = GetDeviceClockTime(device);
3388 voice = GetSourceVoice(Source, context);
3389 if(voice)
3391 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3393 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) <<
3394 FRACTIONBITS;
3395 readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3397 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3398 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3400 offset = 0.0;
3401 if(voice)
3403 const ALbufferlistitem *BufferList = Source->queue;
3404 const ALbuffer *BufferFmt = NULL;
3405 while(BufferList && BufferList != Current)
3407 ALsizei max_len = 0;
3408 ALsizei i;
3410 for(i = 0;i < BufferList->num_buffers;i++)
3412 ALbuffer *buffer = BufferList->buffers[i];
3413 if(buffer)
3415 if(!BufferFmt) BufferFmt = buffer;
3416 max_len = maxi(max_len, buffer->SampleLen);
3419 readPos += (ALuint64)max_len << FRACTIONBITS;
3420 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3421 almemory_order_relaxed);
3424 while(BufferList && !BufferFmt)
3426 ALsizei i;
3427 for(i = 0;i < BufferList->num_buffers && !BufferFmt;i++)
3428 BufferFmt = BufferList->buffers[i];
3429 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3430 almemory_order_relaxed);
3432 assert(BufferFmt != NULL);
3434 offset = (ALdouble)readPos / (ALdouble)FRACTIONONE /
3435 (ALdouble)BufferFmt->Frequency;
3438 ReadUnlock(&Source->queue_lock);
3439 return offset;
3442 /* GetSourceOffset
3444 * Gets the current read offset for the given Source, in the appropriate format
3445 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3446 * queue (not the start of the current buffer).
3448 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context)
3450 ALCdevice *device = context->Device;
3451 const ALbufferlistitem *Current;
3452 ALuint readPos;
3453 ALsizei readPosFrac;
3454 ALuint refcount;
3455 ALdouble offset;
3456 ALvoice *voice;
3458 ReadLock(&Source->queue_lock);
3459 do {
3460 Current = NULL;
3461 readPos = readPosFrac = 0;
3462 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3463 althrd_yield();
3464 voice = GetSourceVoice(Source, context);
3465 if(voice)
3467 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3469 readPos = ATOMIC_LOAD(&voice->position, almemory_order_relaxed);
3470 readPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3472 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3473 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3475 offset = 0.0;
3476 if(voice)
3478 const ALbufferlistitem *BufferList = Source->queue;
3479 const ALbuffer *BufferFmt = NULL;
3480 ALboolean readFin = AL_FALSE;
3481 ALuint totalBufferLen = 0;
3483 while(BufferList != NULL)
3485 ALsizei max_len = 0;
3486 ALsizei i;
3488 readFin = readFin || (BufferList == Current);
3489 for(i = 0;i < BufferList->num_buffers;i++)
3491 ALbuffer *buffer = BufferList->buffers[i];
3492 if(buffer)
3494 if(!BufferFmt) BufferFmt = buffer;
3495 max_len = maxi(max_len, buffer->SampleLen);
3498 totalBufferLen += max_len;
3499 if(!readFin) readPos += max_len;
3501 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3502 almemory_order_relaxed);
3504 assert(BufferFmt != NULL);
3506 if(Source->Looping)
3507 readPos %= totalBufferLen;
3508 else
3510 /* Wrap back to 0 */
3511 if(readPos >= totalBufferLen)
3512 readPos = readPosFrac = 0;
3515 offset = 0.0;
3516 switch(name)
3518 case AL_SEC_OFFSET:
3519 offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE) / BufferFmt->Frequency;
3520 break;
3522 case AL_SAMPLE_OFFSET:
3523 offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
3524 break;
3526 case AL_BYTE_OFFSET:
3527 if(BufferFmt->OriginalType == UserFmtIMA4)
3529 ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
3530 ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels);
3531 ALuint FrameBlockSize = BufferFmt->OriginalAlign;
3533 /* Round down to nearest ADPCM block */
3534 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3536 else if(BufferFmt->OriginalType == UserFmtMSADPCM)
3538 ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
3539 ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels);
3540 ALuint FrameBlockSize = BufferFmt->OriginalAlign;
3542 /* Round down to nearest ADPCM block */
3543 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3545 else
3547 ALuint FrameSize = FrameSizeFromFmt(BufferFmt->FmtChannels,
3548 BufferFmt->FmtType);
3549 offset = (ALdouble)(readPos * FrameSize);
3551 break;
3555 ReadUnlock(&Source->queue_lock);
3556 return offset;
3560 /* ApplyOffset
3562 * Apply the stored playback offset to the Source. This function will update
3563 * the number of buffers "played" given the stored offset.
3565 static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice)
3567 ALbufferlistitem *BufferList;
3568 ALuint bufferLen, totalBufferLen;
3569 ALuint offset = 0;
3570 ALsizei frac = 0;
3572 /* Get sample frame offset */
3573 if(!GetSampleOffset(Source, &offset, &frac))
3574 return AL_FALSE;
3576 totalBufferLen = 0;
3577 BufferList = Source->queue;
3578 while(BufferList && totalBufferLen <= offset)
3580 ALsizei max_len = 0;
3581 ALsizei i;
3583 for(i = 0;i < BufferList->num_buffers;i++)
3585 ALbuffer *buffer = BufferList->buffers[i];
3586 if(buffer) max_len = maxi(max_len, buffer->SampleLen);
3588 bufferLen = max_len;
3590 if(bufferLen > offset-totalBufferLen)
3592 /* Offset is in this buffer */
3593 ATOMIC_STORE(&voice->position, offset - totalBufferLen, almemory_order_relaxed);
3594 ATOMIC_STORE(&voice->position_fraction, frac, almemory_order_relaxed);
3595 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_release);
3596 return AL_TRUE;
3599 totalBufferLen += bufferLen;
3601 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
3604 /* Offset is out of range of the queue */
3605 return AL_FALSE;
3609 /* GetSampleOffset
3611 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3612 * or Second offset supplied by the application). This takes into account the
3613 * fact that the buffer format may have been modifed since.
3615 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac)
3617 const ALbuffer *BufferFmt = NULL;
3618 const ALbufferlistitem *BufferList;
3619 ALdouble dbloff, dblfrac;
3621 /* Find the first valid Buffer in the Queue */
3622 BufferList = Source->queue;
3623 while(BufferList)
3625 ALsizei i;
3626 for(i = 0;i < BufferList->num_buffers && !BufferFmt;i++)
3627 BufferFmt = BufferList->buffers[i];
3628 if(BufferFmt) break;
3629 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3630 almemory_order_relaxed);
3632 if(!BufferFmt)
3634 Source->OffsetType = AL_NONE;
3635 Source->Offset = 0.0;
3636 return AL_FALSE;
3639 switch(Source->OffsetType)
3641 case AL_BYTE_OFFSET:
3642 /* Determine the ByteOffset (and ensure it is block aligned) */
3643 *offset = (ALuint)Source->Offset;
3644 if(BufferFmt->OriginalType == UserFmtIMA4)
3646 ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
3647 *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels);
3648 *offset *= BufferFmt->OriginalAlign;
3650 else if(BufferFmt->OriginalType == UserFmtMSADPCM)
3652 ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
3653 *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels);
3654 *offset *= BufferFmt->OriginalAlign;
3656 else
3657 *offset /= FrameSizeFromFmt(BufferFmt->FmtChannels, BufferFmt->FmtType);
3658 *frac = 0;
3659 break;
3661 case AL_SAMPLE_OFFSET:
3662 dblfrac = modf(Source->Offset, &dbloff);
3663 *offset = (ALuint)mind(dbloff, UINT_MAX);
3664 *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3665 break;
3667 case AL_SEC_OFFSET:
3668 dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff);
3669 *offset = (ALuint)mind(dbloff, UINT_MAX);
3670 *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3671 break;
3673 Source->OffsetType = AL_NONE;
3674 Source->Offset = 0.0;
3676 return AL_TRUE;
3680 static ALsource *AllocSource(ALCcontext *context)
3682 ALCdevice *device = context->Device;
3683 SourceSubList *sublist, *subend;
3684 ALsource *source = NULL;
3685 ALsizei lidx = 0;
3686 ALsizei slidx;
3688 almtx_lock(&context->SourceLock);
3689 if(context->NumSources >= device->SourcesMax)
3691 almtx_unlock(&context->SourceLock);
3692 alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax);
3693 return NULL;
3695 sublist = VECTOR_BEGIN(context->SourceList);
3696 subend = VECTOR_END(context->SourceList);
3697 for(;sublist != subend;++sublist)
3699 if(sublist->FreeMask)
3701 slidx = CTZ64(sublist->FreeMask);
3702 source = sublist->Sources + slidx;
3703 break;
3705 ++lidx;
3707 if(UNLIKELY(!source))
3709 const SourceSubList empty_sublist = { 0, NULL };
3710 /* Don't allocate so many list entries that the 32-bit ID could
3711 * overflow...
3713 if(UNLIKELY(VECTOR_SIZE(context->SourceList) >= 1<<25))
3715 almtx_unlock(&device->BufferLock);
3716 alSetError(context, AL_OUT_OF_MEMORY, "Too many sources allocated");
3717 return NULL;
3719 lidx = (ALsizei)VECTOR_SIZE(context->SourceList);
3720 VECTOR_PUSH_BACK(context->SourceList, empty_sublist);
3721 sublist = &VECTOR_BACK(context->SourceList);
3722 sublist->FreeMask = ~U64(0);
3723 sublist->Sources = al_calloc(16, sizeof(ALsource)*64);
3724 if(UNLIKELY(!sublist->Sources))
3726 VECTOR_POP_BACK(context->SourceList);
3727 almtx_unlock(&context->SourceLock);
3728 alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate source batch");
3729 return NULL;
3732 slidx = 0;
3733 source = sublist->Sources + slidx;
3736 memset(source, 0, sizeof(*source));
3737 InitSourceParams(source, device->NumAuxSends);
3739 /* Add 1 to avoid source ID 0. */
3740 source->id = ((lidx<<6) | slidx) + 1;
3742 context->NumSources++;
3743 sublist->FreeMask &= ~(U64(1)<<slidx);
3744 almtx_unlock(&context->SourceLock);
3746 return source;
3749 static void FreeSource(ALCcontext *context, ALsource *source)
3751 ALCdevice *device = context->Device;
3752 ALuint id = source->id - 1;
3753 ALsizei lidx = id >> 6;
3754 ALsizei slidx = id & 0x3f;
3755 ALvoice *voice;
3757 ALCdevice_Lock(device);
3758 if((voice=GetSourceVoice(source, context)) != NULL)
3760 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
3761 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
3763 ALCdevice_Unlock(device);
3765 DeinitSource(source, device->NumAuxSends);
3766 memset(source, 0, sizeof(*source));
3768 VECTOR_ELEM(context->SourceList, lidx).FreeMask |= U64(1) << slidx;
3769 context->NumSources--;
3772 /* ReleaseALSources
3774 * Destroys all sources in the source map.
3776 ALvoid ReleaseALSources(ALCcontext *context)
3778 ALCdevice *device = context->Device;
3779 SourceSubList *sublist = VECTOR_BEGIN(context->SourceList);
3780 SourceSubList *subend = VECTOR_END(context->SourceList);
3781 size_t leftover = 0;
3782 for(;sublist != subend;++sublist)
3784 ALuint64 usemask = ~sublist->FreeMask;
3785 while(usemask)
3787 ALsizei idx = CTZ64(usemask);
3788 ALsource *source = sublist->Sources + idx;
3790 DeinitSource(source, device->NumAuxSends);
3791 memset(source, 0, sizeof(*source));
3792 ++leftover;
3794 usemask &= ~(U64(1) << idx);
3796 sublist->FreeMask = ~usemask;
3798 if(leftover > 0)
3799 WARN("(%p) Deleted "SZFMT" Source%s\n", device, leftover, (leftover==1)?"":"s");