Ignore the listening angle for the wet path sound cones
[openal-soft.git] / OpenAL32 / alSource.c
blob090b46598900f41542f5f916d828a33f99d6eaee
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <math.h>
26 #include <float.h>
28 #include "AL/al.h"
29 #include "AL/alc.h"
30 #include "alMain.h"
31 #include "alError.h"
32 #include "alSource.h"
33 #include "alBuffer.h"
34 #include "alThunk.h"
35 #include "alAuxEffectSlot.h"
37 #include "backends/base.h"
39 #include "threads.h"
40 #include "almalloc.h"
43 extern inline void LockSourcesRead(ALCcontext *context);
44 extern inline void UnlockSourcesRead(ALCcontext *context);
45 extern inline void LockSourcesWrite(ALCcontext *context);
46 extern inline void UnlockSourcesWrite(ALCcontext *context);
47 extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
48 extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
50 static ALvoid InitSourceParams(ALsource *Source);
51 static ALvoid DeinitSource(ALsource *source);
52 static ALint64 GetSourceSampleOffset(ALsource *Source);
53 static ALdouble GetSourceSecOffset(ALsource *Source);
54 static ALdouble GetSourceOffset(ALsource *Source, ALenum name);
55 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac);
57 typedef enum SourceProp {
58 srcPitch = AL_PITCH,
59 srcGain = AL_GAIN,
60 srcMinGain = AL_MIN_GAIN,
61 srcMaxGain = AL_MAX_GAIN,
62 srcMaxDistance = AL_MAX_DISTANCE,
63 srcRolloffFactor = AL_ROLLOFF_FACTOR,
64 srcDopplerFactor = AL_DOPPLER_FACTOR,
65 srcConeOuterGain = AL_CONE_OUTER_GAIN,
66 srcSecOffset = AL_SEC_OFFSET,
67 srcSampleOffset = AL_SAMPLE_OFFSET,
68 srcByteOffset = AL_BYTE_OFFSET,
69 srcConeInnerAngle = AL_CONE_INNER_ANGLE,
70 srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
71 srcRefDistance = AL_REFERENCE_DISTANCE,
73 srcPosition = AL_POSITION,
74 srcVelocity = AL_VELOCITY,
75 srcDirection = AL_DIRECTION,
77 srcSourceRelative = AL_SOURCE_RELATIVE,
78 srcLooping = AL_LOOPING,
79 srcBuffer = AL_BUFFER,
80 srcSourceState = AL_SOURCE_STATE,
81 srcBuffersQueued = AL_BUFFERS_QUEUED,
82 srcBuffersProcessed = AL_BUFFERS_PROCESSED,
83 srcSourceType = AL_SOURCE_TYPE,
85 /* ALC_EXT_EFX */
86 srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
87 srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
88 srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
89 srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
90 srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
91 srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
92 srcDirectFilter = AL_DIRECT_FILTER,
93 srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
95 /* AL_SOFT_direct_channels */
96 srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
98 /* AL_EXT_source_distance_model */
99 srcDistanceModel = AL_DISTANCE_MODEL,
101 srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
102 srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
103 srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
105 /* AL_SOFT_source_latency */
106 srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
107 srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
109 /* AL_EXT_STEREO_ANGLES */
110 srcAngles = AL_STEREO_ANGLES,
112 /* AL_EXT_SOURCE_RADIUS */
113 srcRadius = AL_SOURCE_RADIUS,
115 /* AL_EXT_BFORMAT */
116 srcOrientation = AL_ORIENTATION,
117 } SourceProp;
119 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
120 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
121 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
123 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
124 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
125 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
127 static inline bool SourceShouldUpdate(const ALsource *source, const ALCcontext *context)
129 return (source->state == AL_PLAYING || source->state == AL_PAUSED) &&
130 !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire);
133 static ALint FloatValsByProp(ALenum prop)
135 if(prop != (ALenum)((SourceProp)prop))
136 return 0;
137 switch((SourceProp)prop)
139 case AL_PITCH:
140 case AL_GAIN:
141 case AL_MIN_GAIN:
142 case AL_MAX_GAIN:
143 case AL_MAX_DISTANCE:
144 case AL_ROLLOFF_FACTOR:
145 case AL_DOPPLER_FACTOR:
146 case AL_CONE_OUTER_GAIN:
147 case AL_SEC_OFFSET:
148 case AL_SAMPLE_OFFSET:
149 case AL_BYTE_OFFSET:
150 case AL_CONE_INNER_ANGLE:
151 case AL_CONE_OUTER_ANGLE:
152 case AL_REFERENCE_DISTANCE:
153 case AL_CONE_OUTER_GAINHF:
154 case AL_AIR_ABSORPTION_FACTOR:
155 case AL_ROOM_ROLLOFF_FACTOR:
156 case AL_DIRECT_FILTER_GAINHF_AUTO:
157 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
158 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
159 case AL_DIRECT_CHANNELS_SOFT:
160 case AL_DISTANCE_MODEL:
161 case AL_SOURCE_RELATIVE:
162 case AL_LOOPING:
163 case AL_SOURCE_STATE:
164 case AL_BUFFERS_QUEUED:
165 case AL_BUFFERS_PROCESSED:
166 case AL_SOURCE_TYPE:
167 case AL_BYTE_LENGTH_SOFT:
168 case AL_SAMPLE_LENGTH_SOFT:
169 case AL_SEC_LENGTH_SOFT:
170 case AL_SOURCE_RADIUS:
171 return 1;
173 case AL_STEREO_ANGLES:
174 return 2;
176 case AL_POSITION:
177 case AL_VELOCITY:
178 case AL_DIRECTION:
179 return 3;
181 case AL_ORIENTATION:
182 return 6;
184 case AL_SEC_OFFSET_LATENCY_SOFT:
185 break; /* Double only */
187 case AL_BUFFER:
188 case AL_DIRECT_FILTER:
189 case AL_AUXILIARY_SEND_FILTER:
190 break; /* i/i64 only */
191 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
192 break; /* i64 only */
194 return 0;
196 static ALint DoubleValsByProp(ALenum prop)
198 if(prop != (ALenum)((SourceProp)prop))
199 return 0;
200 switch((SourceProp)prop)
202 case AL_PITCH:
203 case AL_GAIN:
204 case AL_MIN_GAIN:
205 case AL_MAX_GAIN:
206 case AL_MAX_DISTANCE:
207 case AL_ROLLOFF_FACTOR:
208 case AL_DOPPLER_FACTOR:
209 case AL_CONE_OUTER_GAIN:
210 case AL_SEC_OFFSET:
211 case AL_SAMPLE_OFFSET:
212 case AL_BYTE_OFFSET:
213 case AL_CONE_INNER_ANGLE:
214 case AL_CONE_OUTER_ANGLE:
215 case AL_REFERENCE_DISTANCE:
216 case AL_CONE_OUTER_GAINHF:
217 case AL_AIR_ABSORPTION_FACTOR:
218 case AL_ROOM_ROLLOFF_FACTOR:
219 case AL_DIRECT_FILTER_GAINHF_AUTO:
220 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
221 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
222 case AL_DIRECT_CHANNELS_SOFT:
223 case AL_DISTANCE_MODEL:
224 case AL_SOURCE_RELATIVE:
225 case AL_LOOPING:
226 case AL_SOURCE_STATE:
227 case AL_BUFFERS_QUEUED:
228 case AL_BUFFERS_PROCESSED:
229 case AL_SOURCE_TYPE:
230 case AL_BYTE_LENGTH_SOFT:
231 case AL_SAMPLE_LENGTH_SOFT:
232 case AL_SEC_LENGTH_SOFT:
233 case AL_SOURCE_RADIUS:
234 return 1;
236 case AL_SEC_OFFSET_LATENCY_SOFT:
237 case AL_STEREO_ANGLES:
238 return 2;
240 case AL_POSITION:
241 case AL_VELOCITY:
242 case AL_DIRECTION:
243 return 3;
245 case AL_ORIENTATION:
246 return 6;
248 case AL_BUFFER:
249 case AL_DIRECT_FILTER:
250 case AL_AUXILIARY_SEND_FILTER:
251 break; /* i/i64 only */
252 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
253 break; /* i64 only */
255 return 0;
258 static ALint IntValsByProp(ALenum prop)
260 if(prop != (ALenum)((SourceProp)prop))
261 return 0;
262 switch((SourceProp)prop)
264 case AL_PITCH:
265 case AL_GAIN:
266 case AL_MIN_GAIN:
267 case AL_MAX_GAIN:
268 case AL_MAX_DISTANCE:
269 case AL_ROLLOFF_FACTOR:
270 case AL_DOPPLER_FACTOR:
271 case AL_CONE_OUTER_GAIN:
272 case AL_SEC_OFFSET:
273 case AL_SAMPLE_OFFSET:
274 case AL_BYTE_OFFSET:
275 case AL_CONE_INNER_ANGLE:
276 case AL_CONE_OUTER_ANGLE:
277 case AL_REFERENCE_DISTANCE:
278 case AL_CONE_OUTER_GAINHF:
279 case AL_AIR_ABSORPTION_FACTOR:
280 case AL_ROOM_ROLLOFF_FACTOR:
281 case AL_DIRECT_FILTER_GAINHF_AUTO:
282 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
283 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
284 case AL_DIRECT_CHANNELS_SOFT:
285 case AL_DISTANCE_MODEL:
286 case AL_SOURCE_RELATIVE:
287 case AL_LOOPING:
288 case AL_BUFFER:
289 case AL_SOURCE_STATE:
290 case AL_BUFFERS_QUEUED:
291 case AL_BUFFERS_PROCESSED:
292 case AL_SOURCE_TYPE:
293 case AL_DIRECT_FILTER:
294 case AL_BYTE_LENGTH_SOFT:
295 case AL_SAMPLE_LENGTH_SOFT:
296 case AL_SEC_LENGTH_SOFT:
297 case AL_SOURCE_RADIUS:
298 return 1;
300 case AL_POSITION:
301 case AL_VELOCITY:
302 case AL_DIRECTION:
303 case AL_AUXILIARY_SEND_FILTER:
304 return 3;
306 case AL_ORIENTATION:
307 return 6;
309 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
310 break; /* i64 only */
311 case AL_SEC_OFFSET_LATENCY_SOFT:
312 break; /* Double only */
313 case AL_STEREO_ANGLES:
314 break; /* Float/double only */
316 return 0;
318 static ALint Int64ValsByProp(ALenum prop)
320 if(prop != (ALenum)((SourceProp)prop))
321 return 0;
322 switch((SourceProp)prop)
324 case AL_PITCH:
325 case AL_GAIN:
326 case AL_MIN_GAIN:
327 case AL_MAX_GAIN:
328 case AL_MAX_DISTANCE:
329 case AL_ROLLOFF_FACTOR:
330 case AL_DOPPLER_FACTOR:
331 case AL_CONE_OUTER_GAIN:
332 case AL_SEC_OFFSET:
333 case AL_SAMPLE_OFFSET:
334 case AL_BYTE_OFFSET:
335 case AL_CONE_INNER_ANGLE:
336 case AL_CONE_OUTER_ANGLE:
337 case AL_REFERENCE_DISTANCE:
338 case AL_CONE_OUTER_GAINHF:
339 case AL_AIR_ABSORPTION_FACTOR:
340 case AL_ROOM_ROLLOFF_FACTOR:
341 case AL_DIRECT_FILTER_GAINHF_AUTO:
342 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
343 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
344 case AL_DIRECT_CHANNELS_SOFT:
345 case AL_DISTANCE_MODEL:
346 case AL_SOURCE_RELATIVE:
347 case AL_LOOPING:
348 case AL_BUFFER:
349 case AL_SOURCE_STATE:
350 case AL_BUFFERS_QUEUED:
351 case AL_BUFFERS_PROCESSED:
352 case AL_SOURCE_TYPE:
353 case AL_DIRECT_FILTER:
354 case AL_BYTE_LENGTH_SOFT:
355 case AL_SAMPLE_LENGTH_SOFT:
356 case AL_SEC_LENGTH_SOFT:
357 case AL_SOURCE_RADIUS:
358 return 1;
360 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
361 return 2;
363 case AL_POSITION:
364 case AL_VELOCITY:
365 case AL_DIRECTION:
366 case AL_AUXILIARY_SEND_FILTER:
367 return 3;
369 case AL_ORIENTATION:
370 return 6;
372 case AL_SEC_OFFSET_LATENCY_SOFT:
373 break; /* Double only */
374 case AL_STEREO_ANGLES:
375 break; /* Float/double only */
377 return 0;
381 #define CHECKVAL(x) do { \
382 if(!(x)) \
383 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
384 } while(0)
386 #define DO_UPDATEPROPS() do { \
387 if(SourceShouldUpdate(Source, Context)) \
388 UpdateSourceProps(Source, device->NumAuxSends); \
389 } while(0)
391 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
393 ALCdevice *device = Context->Device;
394 ALint ival;
396 switch(prop)
398 case AL_BYTE_LENGTH_SOFT:
399 case AL_SAMPLE_LENGTH_SOFT:
400 case AL_SEC_LENGTH_SOFT:
401 case AL_SEC_OFFSET_LATENCY_SOFT:
402 /* Query only */
403 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
405 case AL_PITCH:
406 CHECKVAL(*values >= 0.0f);
408 Source->Pitch = *values;
409 DO_UPDATEPROPS();
410 return AL_TRUE;
412 case AL_CONE_INNER_ANGLE:
413 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
415 Source->InnerAngle = *values;
416 DO_UPDATEPROPS();
417 return AL_TRUE;
419 case AL_CONE_OUTER_ANGLE:
420 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
422 Source->OuterAngle = *values;
423 DO_UPDATEPROPS();
424 return AL_TRUE;
426 case AL_GAIN:
427 CHECKVAL(*values >= 0.0f);
429 Source->Gain = *values;
430 DO_UPDATEPROPS();
431 return AL_TRUE;
433 case AL_MAX_DISTANCE:
434 CHECKVAL(*values >= 0.0f);
436 Source->MaxDistance = *values;
437 DO_UPDATEPROPS();
438 return AL_TRUE;
440 case AL_ROLLOFF_FACTOR:
441 CHECKVAL(*values >= 0.0f);
443 Source->RollOffFactor = *values;
444 DO_UPDATEPROPS();
445 return AL_TRUE;
447 case AL_REFERENCE_DISTANCE:
448 CHECKVAL(*values >= 0.0f);
450 Source->RefDistance = *values;
451 DO_UPDATEPROPS();
452 return AL_TRUE;
454 case AL_MIN_GAIN:
455 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
457 Source->MinGain = *values;
458 DO_UPDATEPROPS();
459 return AL_TRUE;
461 case AL_MAX_GAIN:
462 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
464 Source->MaxGain = *values;
465 DO_UPDATEPROPS();
466 return AL_TRUE;
468 case AL_CONE_OUTER_GAIN:
469 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
471 Source->OuterGain = *values;
472 DO_UPDATEPROPS();
473 return AL_TRUE;
475 case AL_CONE_OUTER_GAINHF:
476 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
478 Source->OuterGainHF = *values;
479 DO_UPDATEPROPS();
480 return AL_TRUE;
482 case AL_AIR_ABSORPTION_FACTOR:
483 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
485 Source->AirAbsorptionFactor = *values;
486 DO_UPDATEPROPS();
487 return AL_TRUE;
489 case AL_ROOM_ROLLOFF_FACTOR:
490 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
492 Source->RoomRolloffFactor = *values;
493 DO_UPDATEPROPS();
494 return AL_TRUE;
496 case AL_DOPPLER_FACTOR:
497 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
499 Source->DopplerFactor = *values;
500 DO_UPDATEPROPS();
501 return AL_TRUE;
503 case AL_SEC_OFFSET:
504 case AL_SAMPLE_OFFSET:
505 case AL_BYTE_OFFSET:
506 CHECKVAL(*values >= 0.0f);
508 Source->OffsetType = prop;
509 Source->Offset = *values;
511 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
512 !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire))
514 LockContext(Context);
515 WriteLock(&Source->queue_lock);
516 if(ApplyOffset(Source) == AL_FALSE)
518 WriteUnlock(&Source->queue_lock);
519 UnlockContext(Context);
520 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
522 WriteUnlock(&Source->queue_lock);
523 UnlockContext(Context);
525 return AL_TRUE;
527 case AL_SOURCE_RADIUS:
528 CHECKVAL(*values >= 0.0f && isfinite(*values));
530 Source->Radius = *values;
531 DO_UPDATEPROPS();
532 return AL_TRUE;
534 case AL_STEREO_ANGLES:
535 CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
537 Source->StereoPan[0] = values[0];
538 Source->StereoPan[1] = values[1];
539 DO_UPDATEPROPS();
540 return AL_TRUE;
543 case AL_POSITION:
544 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
546 Source->Position[0] = values[0];
547 Source->Position[1] = values[1];
548 Source->Position[2] = values[2];
549 DO_UPDATEPROPS();
550 return AL_TRUE;
552 case AL_VELOCITY:
553 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
555 Source->Velocity[0] = values[0];
556 Source->Velocity[1] = values[1];
557 Source->Velocity[2] = values[2];
558 DO_UPDATEPROPS();
559 return AL_TRUE;
561 case AL_DIRECTION:
562 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
564 Source->Direction[0] = values[0];
565 Source->Direction[1] = values[1];
566 Source->Direction[2] = values[2];
567 DO_UPDATEPROPS();
568 return AL_TRUE;
570 case AL_ORIENTATION:
571 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
572 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
574 Source->Orientation[0][0] = values[0];
575 Source->Orientation[0][1] = values[1];
576 Source->Orientation[0][2] = values[2];
577 Source->Orientation[1][0] = values[3];
578 Source->Orientation[1][1] = values[4];
579 Source->Orientation[1][2] = values[5];
580 DO_UPDATEPROPS();
581 return AL_TRUE;
584 case AL_SOURCE_RELATIVE:
585 case AL_LOOPING:
586 case AL_SOURCE_STATE:
587 case AL_SOURCE_TYPE:
588 case AL_DISTANCE_MODEL:
589 case AL_DIRECT_FILTER_GAINHF_AUTO:
590 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
591 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
592 case AL_DIRECT_CHANNELS_SOFT:
593 ival = (ALint)values[0];
594 return SetSourceiv(Source, Context, prop, &ival);
596 case AL_BUFFERS_QUEUED:
597 case AL_BUFFERS_PROCESSED:
598 ival = (ALint)((ALuint)values[0]);
599 return SetSourceiv(Source, Context, prop, &ival);
601 case AL_BUFFER:
602 case AL_DIRECT_FILTER:
603 case AL_AUXILIARY_SEND_FILTER:
604 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
605 break;
608 ERR("Unexpected property: 0x%04x\n", prop);
609 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
612 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
614 ALCdevice *device = Context->Device;
615 ALbuffer *buffer = NULL;
616 ALfilter *filter = NULL;
617 ALeffectslot *slot = NULL;
618 ALbufferlistitem *oldlist;
619 ALbufferlistitem *newlist;
620 ALfloat fvals[6];
622 switch(prop)
624 case AL_SOURCE_STATE:
625 case AL_SOURCE_TYPE:
626 case AL_BUFFERS_QUEUED:
627 case AL_BUFFERS_PROCESSED:
628 case AL_BYTE_LENGTH_SOFT:
629 case AL_SAMPLE_LENGTH_SOFT:
630 case AL_SEC_LENGTH_SOFT:
631 /* Query only */
632 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
634 case AL_SOURCE_RELATIVE:
635 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
637 Source->HeadRelative = (ALboolean)*values;
638 DO_UPDATEPROPS();
639 return AL_TRUE;
641 case AL_LOOPING:
642 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
644 Source->Looping = (ALboolean)*values;
645 DO_UPDATEPROPS();
646 return AL_TRUE;
648 case AL_BUFFER:
649 LockBuffersRead(device);
650 if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
652 UnlockBuffersRead(device);
653 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
656 WriteLock(&Source->queue_lock);
657 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
659 WriteUnlock(&Source->queue_lock);
660 UnlockBuffersRead(device);
661 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
664 if(buffer != NULL)
666 /* Add the selected buffer to a one-item queue */
667 newlist = malloc(sizeof(ALbufferlistitem));
668 newlist->buffer = buffer;
669 newlist->next = NULL;
670 IncrementRef(&buffer->ref);
672 /* Source is now Static */
673 Source->SourceType = AL_STATIC;
675 ReadLock(&buffer->lock);
676 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
677 Source->SampleSize = BytesFromFmt(buffer->FmtType);
678 ReadUnlock(&buffer->lock);
680 else
682 /* Source is now Undetermined */
683 Source->SourceType = AL_UNDETERMINED;
684 newlist = NULL;
686 oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist);
687 ATOMIC_STORE(&Source->current_buffer, newlist);
688 WriteUnlock(&Source->queue_lock);
689 UnlockBuffersRead(device);
691 /* Delete all elements in the previous queue */
692 while(oldlist != NULL)
694 ALbufferlistitem *temp = oldlist;
695 oldlist = temp->next;
697 if(temp->buffer)
698 DecrementRef(&temp->buffer->ref);
699 free(temp);
701 return AL_TRUE;
703 case AL_SEC_OFFSET:
704 case AL_SAMPLE_OFFSET:
705 case AL_BYTE_OFFSET:
706 CHECKVAL(*values >= 0);
708 Source->OffsetType = prop;
709 Source->Offset = *values;
711 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
712 !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire))
714 LockContext(Context);
715 WriteLock(&Source->queue_lock);
716 if(ApplyOffset(Source) == AL_FALSE)
718 WriteUnlock(&Source->queue_lock);
719 UnlockContext(Context);
720 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
722 WriteUnlock(&Source->queue_lock);
723 UnlockContext(Context);
725 return AL_TRUE;
727 case AL_DIRECT_FILTER:
728 LockFiltersRead(device);
729 if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
731 UnlockFiltersRead(device);
732 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
735 if(!filter)
737 Source->Direct.Gain = 1.0f;
738 Source->Direct.GainHF = 1.0f;
739 Source->Direct.HFReference = LOWPASSFREQREF;
740 Source->Direct.GainLF = 1.0f;
741 Source->Direct.LFReference = HIGHPASSFREQREF;
743 else
745 Source->Direct.Gain = filter->Gain;
746 Source->Direct.GainHF = filter->GainHF;
747 Source->Direct.HFReference = filter->HFReference;
748 Source->Direct.GainLF = filter->GainLF;
749 Source->Direct.LFReference = filter->LFReference;
751 UnlockFiltersRead(device);
752 DO_UPDATEPROPS();
753 return AL_TRUE;
755 case AL_DIRECT_FILTER_GAINHF_AUTO:
756 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
758 Source->DryGainHFAuto = *values;
759 DO_UPDATEPROPS();
760 return AL_TRUE;
762 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
763 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
765 Source->WetGainAuto = *values;
766 DO_UPDATEPROPS();
767 return AL_TRUE;
769 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
770 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
772 Source->WetGainHFAuto = *values;
773 DO_UPDATEPROPS();
774 return AL_TRUE;
776 case AL_DIRECT_CHANNELS_SOFT:
777 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
779 Source->DirectChannels = *values;
780 DO_UPDATEPROPS();
781 return AL_TRUE;
783 case AL_DISTANCE_MODEL:
784 CHECKVAL(*values == AL_NONE ||
785 *values == AL_INVERSE_DISTANCE ||
786 *values == AL_INVERSE_DISTANCE_CLAMPED ||
787 *values == AL_LINEAR_DISTANCE ||
788 *values == AL_LINEAR_DISTANCE_CLAMPED ||
789 *values == AL_EXPONENT_DISTANCE ||
790 *values == AL_EXPONENT_DISTANCE_CLAMPED);
792 Source->DistanceModel = *values;
793 if(Context->SourceDistanceModel)
794 DO_UPDATEPROPS();
795 return AL_TRUE;
798 case AL_AUXILIARY_SEND_FILTER:
799 LockFiltersRead(device);
800 if(!((ALuint)values[1] < device->NumAuxSends &&
801 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
802 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
804 UnlockFiltersRead(device);
805 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
808 if(!filter)
810 /* Disable filter */
811 Source->Send[values[1]].Gain = 1.0f;
812 Source->Send[values[1]].GainHF = 1.0f;
813 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
814 Source->Send[values[1]].GainLF = 1.0f;
815 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
817 else
819 Source->Send[values[1]].Gain = filter->Gain;
820 Source->Send[values[1]].GainHF = filter->GainHF;
821 Source->Send[values[1]].HFReference = filter->HFReference;
822 Source->Send[values[1]].GainLF = filter->GainLF;
823 Source->Send[values[1]].LFReference = filter->LFReference;
825 UnlockFiltersRead(device);
827 if(slot != Source->Send[values[1]].Slot &&
828 (Source->state == AL_PLAYING || Source->state == AL_PAUSED))
830 /* Add refcount on the new slot, and release the previous slot */
831 if(slot) IncrementRef(&slot->ref);
832 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
833 if(slot) DecrementRef(&slot->ref);
834 /* We must force an update if the auxiliary slot changed on a
835 * playing source, in case the slot is about to be deleted.
837 UpdateSourceProps(Source, device->NumAuxSends);
839 else
841 if(slot) IncrementRef(&slot->ref);
842 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
843 if(slot) DecrementRef(&slot->ref);
844 DO_UPDATEPROPS();
847 return AL_TRUE;
850 /* 1x float */
851 case AL_CONE_INNER_ANGLE:
852 case AL_CONE_OUTER_ANGLE:
853 case AL_PITCH:
854 case AL_GAIN:
855 case AL_MIN_GAIN:
856 case AL_MAX_GAIN:
857 case AL_REFERENCE_DISTANCE:
858 case AL_ROLLOFF_FACTOR:
859 case AL_CONE_OUTER_GAIN:
860 case AL_MAX_DISTANCE:
861 case AL_DOPPLER_FACTOR:
862 case AL_CONE_OUTER_GAINHF:
863 case AL_AIR_ABSORPTION_FACTOR:
864 case AL_ROOM_ROLLOFF_FACTOR:
865 case AL_SOURCE_RADIUS:
866 fvals[0] = (ALfloat)*values;
867 return SetSourcefv(Source, Context, (int)prop, fvals);
869 /* 3x float */
870 case AL_POSITION:
871 case AL_VELOCITY:
872 case AL_DIRECTION:
873 fvals[0] = (ALfloat)values[0];
874 fvals[1] = (ALfloat)values[1];
875 fvals[2] = (ALfloat)values[2];
876 return SetSourcefv(Source, Context, (int)prop, fvals);
878 /* 6x float */
879 case AL_ORIENTATION:
880 fvals[0] = (ALfloat)values[0];
881 fvals[1] = (ALfloat)values[1];
882 fvals[2] = (ALfloat)values[2];
883 fvals[3] = (ALfloat)values[3];
884 fvals[4] = (ALfloat)values[4];
885 fvals[5] = (ALfloat)values[5];
886 return SetSourcefv(Source, Context, (int)prop, fvals);
888 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
889 case AL_SEC_OFFSET_LATENCY_SOFT:
890 case AL_STEREO_ANGLES:
891 break;
894 ERR("Unexpected property: 0x%04x\n", prop);
895 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
898 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
900 ALfloat fvals[6];
901 ALint ivals[3];
903 switch(prop)
905 case AL_SOURCE_TYPE:
906 case AL_BUFFERS_QUEUED:
907 case AL_BUFFERS_PROCESSED:
908 case AL_SOURCE_STATE:
909 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
910 case AL_BYTE_LENGTH_SOFT:
911 case AL_SAMPLE_LENGTH_SOFT:
912 case AL_SEC_LENGTH_SOFT:
913 /* Query only */
914 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
917 /* 1x int */
918 case AL_SOURCE_RELATIVE:
919 case AL_LOOPING:
920 case AL_SEC_OFFSET:
921 case AL_SAMPLE_OFFSET:
922 case AL_BYTE_OFFSET:
923 case AL_DIRECT_FILTER_GAINHF_AUTO:
924 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
925 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
926 case AL_DIRECT_CHANNELS_SOFT:
927 case AL_DISTANCE_MODEL:
928 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
930 ivals[0] = (ALint)*values;
931 return SetSourceiv(Source, Context, (int)prop, ivals);
933 /* 1x uint */
934 case AL_BUFFER:
935 case AL_DIRECT_FILTER:
936 CHECKVAL(*values <= UINT_MAX && *values >= 0);
938 ivals[0] = (ALuint)*values;
939 return SetSourceiv(Source, Context, (int)prop, ivals);
941 /* 3x uint */
942 case AL_AUXILIARY_SEND_FILTER:
943 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
944 values[1] <= UINT_MAX && values[1] >= 0 &&
945 values[2] <= UINT_MAX && values[2] >= 0);
947 ivals[0] = (ALuint)values[0];
948 ivals[1] = (ALuint)values[1];
949 ivals[2] = (ALuint)values[2];
950 return SetSourceiv(Source, Context, (int)prop, ivals);
952 /* 1x float */
953 case AL_CONE_INNER_ANGLE:
954 case AL_CONE_OUTER_ANGLE:
955 case AL_PITCH:
956 case AL_GAIN:
957 case AL_MIN_GAIN:
958 case AL_MAX_GAIN:
959 case AL_REFERENCE_DISTANCE:
960 case AL_ROLLOFF_FACTOR:
961 case AL_CONE_OUTER_GAIN:
962 case AL_MAX_DISTANCE:
963 case AL_DOPPLER_FACTOR:
964 case AL_CONE_OUTER_GAINHF:
965 case AL_AIR_ABSORPTION_FACTOR:
966 case AL_ROOM_ROLLOFF_FACTOR:
967 case AL_SOURCE_RADIUS:
968 fvals[0] = (ALfloat)*values;
969 return SetSourcefv(Source, Context, (int)prop, fvals);
971 /* 3x float */
972 case AL_POSITION:
973 case AL_VELOCITY:
974 case AL_DIRECTION:
975 fvals[0] = (ALfloat)values[0];
976 fvals[1] = (ALfloat)values[1];
977 fvals[2] = (ALfloat)values[2];
978 return SetSourcefv(Source, Context, (int)prop, fvals);
980 /* 6x float */
981 case AL_ORIENTATION:
982 fvals[0] = (ALfloat)values[0];
983 fvals[1] = (ALfloat)values[1];
984 fvals[2] = (ALfloat)values[2];
985 fvals[3] = (ALfloat)values[3];
986 fvals[4] = (ALfloat)values[4];
987 fvals[5] = (ALfloat)values[5];
988 return SetSourcefv(Source, Context, (int)prop, fvals);
990 case AL_SEC_OFFSET_LATENCY_SOFT:
991 case AL_STEREO_ANGLES:
992 break;
995 ERR("Unexpected property: 0x%04x\n", prop);
996 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
999 #undef CHECKVAL
1002 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
1004 ALCdevice *device = Context->Device;
1005 ALbufferlistitem *BufferList;
1006 ALint ivals[3];
1007 ALboolean err;
1009 switch(prop)
1011 case AL_GAIN:
1012 *values = Source->Gain;
1013 return AL_TRUE;
1015 case AL_PITCH:
1016 *values = Source->Pitch;
1017 return AL_TRUE;
1019 case AL_MAX_DISTANCE:
1020 *values = Source->MaxDistance;
1021 return AL_TRUE;
1023 case AL_ROLLOFF_FACTOR:
1024 *values = Source->RollOffFactor;
1025 return AL_TRUE;
1027 case AL_REFERENCE_DISTANCE:
1028 *values = Source->RefDistance;
1029 return AL_TRUE;
1031 case AL_CONE_INNER_ANGLE:
1032 *values = Source->InnerAngle;
1033 return AL_TRUE;
1035 case AL_CONE_OUTER_ANGLE:
1036 *values = Source->OuterAngle;
1037 return AL_TRUE;
1039 case AL_MIN_GAIN:
1040 *values = Source->MinGain;
1041 return AL_TRUE;
1043 case AL_MAX_GAIN:
1044 *values = Source->MaxGain;
1045 return AL_TRUE;
1047 case AL_CONE_OUTER_GAIN:
1048 *values = Source->OuterGain;
1049 return AL_TRUE;
1051 case AL_SEC_OFFSET:
1052 case AL_SAMPLE_OFFSET:
1053 case AL_BYTE_OFFSET:
1054 LockContext(Context);
1055 *values = GetSourceOffset(Source, prop);
1056 UnlockContext(Context);
1057 return AL_TRUE;
1059 case AL_CONE_OUTER_GAINHF:
1060 *values = Source->OuterGainHF;
1061 return AL_TRUE;
1063 case AL_AIR_ABSORPTION_FACTOR:
1064 *values = Source->AirAbsorptionFactor;
1065 return AL_TRUE;
1067 case AL_ROOM_ROLLOFF_FACTOR:
1068 *values = Source->RoomRolloffFactor;
1069 return AL_TRUE;
1071 case AL_DOPPLER_FACTOR:
1072 *values = Source->DopplerFactor;
1073 return AL_TRUE;
1075 case AL_SEC_LENGTH_SOFT:
1076 ReadLock(&Source->queue_lock);
1077 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1078 *values = 0;
1079 else
1081 ALint length = 0;
1082 ALsizei freq = 1;
1083 do {
1084 ALbuffer *buffer = BufferList->buffer;
1085 if(buffer && buffer->SampleLen > 0)
1087 freq = buffer->Frequency;
1088 length += buffer->SampleLen;
1090 } while((BufferList=BufferList->next) != NULL);
1091 *values = (ALdouble)length / (ALdouble)freq;
1093 ReadUnlock(&Source->queue_lock);
1094 return AL_TRUE;
1096 case AL_SOURCE_RADIUS:
1097 *values = Source->Radius;
1098 return AL_TRUE;
1100 case AL_STEREO_ANGLES:
1101 values[0] = Source->StereoPan[0];
1102 values[1] = Source->StereoPan[1];
1103 return AL_TRUE;
1105 case AL_SEC_OFFSET_LATENCY_SOFT:
1106 LockContext(Context);
1107 values[0] = GetSourceSecOffset(Source);
1108 values[1] = (ALdouble)(V0(device->Backend,getLatency)()) /
1109 1000000000.0;
1110 UnlockContext(Context);
1111 return AL_TRUE;
1113 case AL_POSITION:
1114 values[0] = Source->Position[0];
1115 values[1] = Source->Position[1];
1116 values[2] = Source->Position[2];
1117 return AL_TRUE;
1119 case AL_VELOCITY:
1120 values[0] = Source->Velocity[0];
1121 values[1] = Source->Velocity[1];
1122 values[2] = Source->Velocity[2];
1123 return AL_TRUE;
1125 case AL_DIRECTION:
1126 values[0] = Source->Direction[0];
1127 values[1] = Source->Direction[1];
1128 values[2] = Source->Direction[2];
1129 return AL_TRUE;
1131 case AL_ORIENTATION:
1132 values[0] = Source->Orientation[0][0];
1133 values[1] = Source->Orientation[0][1];
1134 values[2] = Source->Orientation[0][2];
1135 values[3] = Source->Orientation[1][0];
1136 values[4] = Source->Orientation[1][1];
1137 values[5] = Source->Orientation[1][2];
1138 return AL_TRUE;
1140 /* 1x int */
1141 case AL_SOURCE_RELATIVE:
1142 case AL_LOOPING:
1143 case AL_SOURCE_STATE:
1144 case AL_BUFFERS_QUEUED:
1145 case AL_BUFFERS_PROCESSED:
1146 case AL_SOURCE_TYPE:
1147 case AL_DIRECT_FILTER_GAINHF_AUTO:
1148 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1149 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1150 case AL_DIRECT_CHANNELS_SOFT:
1151 case AL_BYTE_LENGTH_SOFT:
1152 case AL_SAMPLE_LENGTH_SOFT:
1153 case AL_DISTANCE_MODEL:
1154 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1155 *values = (ALdouble)ivals[0];
1156 return err;
1158 case AL_BUFFER:
1159 case AL_DIRECT_FILTER:
1160 case AL_AUXILIARY_SEND_FILTER:
1161 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1162 break;
1165 ERR("Unexpected property: 0x%04x\n", prop);
1166 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1169 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1171 ALbufferlistitem *BufferList;
1172 ALdouble dvals[6];
1173 ALboolean err;
1175 switch(prop)
1177 case AL_SOURCE_RELATIVE:
1178 *values = Source->HeadRelative;
1179 return AL_TRUE;
1181 case AL_LOOPING:
1182 *values = Source->Looping;
1183 return AL_TRUE;
1185 case AL_BUFFER:
1186 ReadLock(&Source->queue_lock);
1187 BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) :
1188 ATOMIC_LOAD(&Source->current_buffer);
1189 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1190 ReadUnlock(&Source->queue_lock);
1191 return AL_TRUE;
1193 case AL_SOURCE_STATE:
1194 *values = Source->state;
1195 return AL_TRUE;
1197 case AL_BYTE_LENGTH_SOFT:
1198 ReadLock(&Source->queue_lock);
1199 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1200 *values = 0;
1201 else
1203 ALint length = 0;
1204 do {
1205 ALbuffer *buffer = BufferList->buffer;
1206 if(buffer && buffer->SampleLen > 0)
1208 ALuint byte_align, sample_align;
1209 if(buffer->OriginalType == UserFmtIMA4)
1211 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1212 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1213 sample_align = buffer->OriginalAlign;
1215 else if(buffer->OriginalType == UserFmtMSADPCM)
1217 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1218 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1219 sample_align = buffer->OriginalAlign;
1221 else
1223 ALsizei align = buffer->OriginalAlign;
1224 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1225 sample_align = buffer->OriginalAlign;
1228 length += buffer->SampleLen / sample_align * byte_align;
1230 } while((BufferList=BufferList->next) != NULL);
1231 *values = length;
1233 ReadUnlock(&Source->queue_lock);
1234 return AL_TRUE;
1236 case AL_SAMPLE_LENGTH_SOFT:
1237 ReadLock(&Source->queue_lock);
1238 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1239 *values = 0;
1240 else
1242 ALint length = 0;
1243 do {
1244 ALbuffer *buffer = BufferList->buffer;
1245 if(buffer) length += buffer->SampleLen;
1246 } while((BufferList=BufferList->next) != NULL);
1247 *values = length;
1249 ReadUnlock(&Source->queue_lock);
1250 return AL_TRUE;
1252 case AL_BUFFERS_QUEUED:
1253 ReadLock(&Source->queue_lock);
1254 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1255 *values = 0;
1256 else
1258 ALsizei count = 0;
1259 do {
1260 ++count;
1261 } while((BufferList=BufferList->next) != NULL);
1262 *values = count;
1264 ReadUnlock(&Source->queue_lock);
1265 return AL_TRUE;
1267 case AL_BUFFERS_PROCESSED:
1268 ReadLock(&Source->queue_lock);
1269 if(Source->Looping || Source->SourceType != AL_STREAMING)
1271 /* Buffers on a looping source are in a perpetual state of
1272 * PENDING, so don't report any as PROCESSED */
1273 *values = 0;
1275 else
1277 const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue);
1278 const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer);
1279 ALsizei played = 0;
1280 while(BufferList && BufferList != Current)
1282 played++;
1283 BufferList = BufferList->next;
1285 *values = played;
1287 ReadUnlock(&Source->queue_lock);
1288 return AL_TRUE;
1290 case AL_SOURCE_TYPE:
1291 *values = Source->SourceType;
1292 return AL_TRUE;
1294 case AL_DIRECT_FILTER_GAINHF_AUTO:
1295 *values = Source->DryGainHFAuto;
1296 return AL_TRUE;
1298 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1299 *values = Source->WetGainAuto;
1300 return AL_TRUE;
1302 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1303 *values = Source->WetGainHFAuto;
1304 return AL_TRUE;
1306 case AL_DIRECT_CHANNELS_SOFT:
1307 *values = Source->DirectChannels;
1308 return AL_TRUE;
1310 case AL_DISTANCE_MODEL:
1311 *values = Source->DistanceModel;
1312 return AL_TRUE;
1314 /* 1x float/double */
1315 case AL_CONE_INNER_ANGLE:
1316 case AL_CONE_OUTER_ANGLE:
1317 case AL_PITCH:
1318 case AL_GAIN:
1319 case AL_MIN_GAIN:
1320 case AL_MAX_GAIN:
1321 case AL_REFERENCE_DISTANCE:
1322 case AL_ROLLOFF_FACTOR:
1323 case AL_CONE_OUTER_GAIN:
1324 case AL_MAX_DISTANCE:
1325 case AL_SEC_OFFSET:
1326 case AL_SAMPLE_OFFSET:
1327 case AL_BYTE_OFFSET:
1328 case AL_DOPPLER_FACTOR:
1329 case AL_AIR_ABSORPTION_FACTOR:
1330 case AL_ROOM_ROLLOFF_FACTOR:
1331 case AL_CONE_OUTER_GAINHF:
1332 case AL_SEC_LENGTH_SOFT:
1333 case AL_SOURCE_RADIUS:
1334 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1335 *values = (ALint)dvals[0];
1336 return err;
1338 /* 3x float/double */
1339 case AL_POSITION:
1340 case AL_VELOCITY:
1341 case AL_DIRECTION:
1342 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1344 values[0] = (ALint)dvals[0];
1345 values[1] = (ALint)dvals[1];
1346 values[2] = (ALint)dvals[2];
1348 return err;
1350 /* 6x float/double */
1351 case AL_ORIENTATION:
1352 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1354 values[0] = (ALint)dvals[0];
1355 values[1] = (ALint)dvals[1];
1356 values[2] = (ALint)dvals[2];
1357 values[3] = (ALint)dvals[3];
1358 values[4] = (ALint)dvals[4];
1359 values[5] = (ALint)dvals[5];
1361 return err;
1363 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1364 break; /* i64 only */
1365 case AL_SEC_OFFSET_LATENCY_SOFT:
1366 break; /* Double only */
1367 case AL_STEREO_ANGLES:
1368 break; /* Float/double only */
1370 case AL_DIRECT_FILTER:
1371 case AL_AUXILIARY_SEND_FILTER:
1372 break; /* ??? */
1375 ERR("Unexpected property: 0x%04x\n", prop);
1376 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1379 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1381 ALCdevice *device = Context->Device;
1382 ALdouble dvals[6];
1383 ALint ivals[3];
1384 ALboolean err;
1386 switch(prop)
1388 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1389 LockContext(Context);
1390 values[0] = GetSourceSampleOffset(Source);
1391 values[1] = V0(device->Backend,getLatency)();
1392 UnlockContext(Context);
1393 return AL_TRUE;
1395 /* 1x float/double */
1396 case AL_CONE_INNER_ANGLE:
1397 case AL_CONE_OUTER_ANGLE:
1398 case AL_PITCH:
1399 case AL_GAIN:
1400 case AL_MIN_GAIN:
1401 case AL_MAX_GAIN:
1402 case AL_REFERENCE_DISTANCE:
1403 case AL_ROLLOFF_FACTOR:
1404 case AL_CONE_OUTER_GAIN:
1405 case AL_MAX_DISTANCE:
1406 case AL_SEC_OFFSET:
1407 case AL_SAMPLE_OFFSET:
1408 case AL_BYTE_OFFSET:
1409 case AL_DOPPLER_FACTOR:
1410 case AL_AIR_ABSORPTION_FACTOR:
1411 case AL_ROOM_ROLLOFF_FACTOR:
1412 case AL_CONE_OUTER_GAINHF:
1413 case AL_SEC_LENGTH_SOFT:
1414 case AL_SOURCE_RADIUS:
1415 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1416 *values = (ALint64)dvals[0];
1417 return err;
1419 /* 3x float/double */
1420 case AL_POSITION:
1421 case AL_VELOCITY:
1422 case AL_DIRECTION:
1423 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1425 values[0] = (ALint64)dvals[0];
1426 values[1] = (ALint64)dvals[1];
1427 values[2] = (ALint64)dvals[2];
1429 return err;
1431 /* 6x float/double */
1432 case AL_ORIENTATION:
1433 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1435 values[0] = (ALint64)dvals[0];
1436 values[1] = (ALint64)dvals[1];
1437 values[2] = (ALint64)dvals[2];
1438 values[3] = (ALint64)dvals[3];
1439 values[4] = (ALint64)dvals[4];
1440 values[5] = (ALint64)dvals[5];
1442 return err;
1444 /* 1x int */
1445 case AL_SOURCE_RELATIVE:
1446 case AL_LOOPING:
1447 case AL_SOURCE_STATE:
1448 case AL_BUFFERS_QUEUED:
1449 case AL_BUFFERS_PROCESSED:
1450 case AL_BYTE_LENGTH_SOFT:
1451 case AL_SAMPLE_LENGTH_SOFT:
1452 case AL_SOURCE_TYPE:
1453 case AL_DIRECT_FILTER_GAINHF_AUTO:
1454 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1455 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1456 case AL_DIRECT_CHANNELS_SOFT:
1457 case AL_DISTANCE_MODEL:
1458 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1459 *values = ivals[0];
1460 return err;
1462 /* 1x uint */
1463 case AL_BUFFER:
1464 case AL_DIRECT_FILTER:
1465 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1466 *values = (ALuint)ivals[0];
1467 return err;
1469 /* 3x uint */
1470 case AL_AUXILIARY_SEND_FILTER:
1471 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1473 values[0] = (ALuint)ivals[0];
1474 values[1] = (ALuint)ivals[1];
1475 values[2] = (ALuint)ivals[2];
1477 return err;
1479 case AL_SEC_OFFSET_LATENCY_SOFT:
1480 break; /* Double only */
1481 case AL_STEREO_ANGLES:
1482 break; /* Float/double only */
1485 ERR("Unexpected property: 0x%04x\n", prop);
1486 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1490 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1492 ALCcontext *context;
1493 ALsizei cur = 0;
1494 ALenum err;
1496 context = GetContextRef();
1497 if(!context) return;
1499 if(!(n >= 0))
1500 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1501 for(cur = 0;cur < n;cur++)
1503 ALsource *source = al_calloc(16, sizeof(ALsource));
1504 if(!source)
1506 alDeleteSources(cur, sources);
1507 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1509 InitSourceParams(source);
1511 err = NewThunkEntry(&source->id);
1512 if(err == AL_NO_ERROR)
1513 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1514 if(err != AL_NO_ERROR)
1516 FreeThunkEntry(source->id);
1517 memset(source, 0, sizeof(ALsource));
1518 al_free(source);
1520 alDeleteSources(cur, sources);
1521 SET_ERROR_AND_GOTO(context, err, done);
1524 sources[cur] = source->id;
1527 done:
1528 ALCcontext_DecRef(context);
1532 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1534 ALCcontext *context;
1535 ALsource *Source;
1536 ALsizei i;
1538 context = GetContextRef();
1539 if(!context) return;
1541 LockSourcesWrite(context);
1542 if(!(n >= 0))
1543 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1545 /* Check that all Sources are valid */
1546 for(i = 0;i < n;i++)
1548 if(LookupSource(context, sources[i]) == NULL)
1549 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1551 for(i = 0;i < n;i++)
1553 ALvoice *voice, *voice_end;
1555 if((Source=RemoveSource(context, sources[i])) == NULL)
1556 continue;
1557 FreeThunkEntry(Source->id);
1559 LockContext(context);
1560 voice = context->Voices;
1561 voice_end = voice + context->VoiceCount;
1562 while(voice != voice_end)
1564 ALsource *old = Source;
1565 if(COMPARE_EXCHANGE(&voice->Source, &old, NULL))
1566 break;
1567 voice++;
1569 UnlockContext(context);
1571 DeinitSource(Source);
1573 memset(Source, 0, sizeof(*Source));
1574 al_free(Source);
1577 done:
1578 UnlockSourcesWrite(context);
1579 ALCcontext_DecRef(context);
1583 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1585 ALCcontext *context;
1586 ALboolean ret;
1588 context = GetContextRef();
1589 if(!context) return AL_FALSE;
1591 LockSourcesRead(context);
1592 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1593 UnlockSourcesRead(context);
1595 ALCcontext_DecRef(context);
1597 return ret;
1601 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1603 ALCcontext *Context;
1604 ALsource *Source;
1606 Context = GetContextRef();
1607 if(!Context) return;
1609 WriteLock(&Context->PropLock);
1610 LockSourcesRead(Context);
1611 if((Source=LookupSource(Context, source)) == NULL)
1612 alSetError(Context, AL_INVALID_NAME);
1613 else if(!(FloatValsByProp(param) == 1))
1614 alSetError(Context, AL_INVALID_ENUM);
1615 else
1616 SetSourcefv(Source, Context, param, &value);
1617 UnlockSourcesRead(Context);
1618 WriteUnlock(&Context->PropLock);
1620 ALCcontext_DecRef(Context);
1623 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1625 ALCcontext *Context;
1626 ALsource *Source;
1628 Context = GetContextRef();
1629 if(!Context) return;
1631 WriteLock(&Context->PropLock);
1632 LockSourcesRead(Context);
1633 if((Source=LookupSource(Context, source)) == NULL)
1634 alSetError(Context, AL_INVALID_NAME);
1635 else if(!(FloatValsByProp(param) == 3))
1636 alSetError(Context, AL_INVALID_ENUM);
1637 else
1639 ALfloat fvals[3] = { value1, value2, value3 };
1640 SetSourcefv(Source, Context, param, fvals);
1642 UnlockSourcesRead(Context);
1643 WriteUnlock(&Context->PropLock);
1645 ALCcontext_DecRef(Context);
1648 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1650 ALCcontext *Context;
1651 ALsource *Source;
1653 Context = GetContextRef();
1654 if(!Context) return;
1656 WriteLock(&Context->PropLock);
1657 LockSourcesRead(Context);
1658 if((Source=LookupSource(Context, source)) == NULL)
1659 alSetError(Context, AL_INVALID_NAME);
1660 else if(!values)
1661 alSetError(Context, AL_INVALID_VALUE);
1662 else if(!(FloatValsByProp(param) > 0))
1663 alSetError(Context, AL_INVALID_ENUM);
1664 else
1665 SetSourcefv(Source, Context, param, values);
1666 UnlockSourcesRead(Context);
1667 WriteUnlock(&Context->PropLock);
1669 ALCcontext_DecRef(Context);
1673 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1675 ALCcontext *Context;
1676 ALsource *Source;
1678 Context = GetContextRef();
1679 if(!Context) return;
1681 WriteLock(&Context->PropLock);
1682 LockSourcesRead(Context);
1683 if((Source=LookupSource(Context, source)) == NULL)
1684 alSetError(Context, AL_INVALID_NAME);
1685 else if(!(DoubleValsByProp(param) == 1))
1686 alSetError(Context, AL_INVALID_ENUM);
1687 else
1689 ALfloat fval = (ALfloat)value;
1690 SetSourcefv(Source, Context, param, &fval);
1692 UnlockSourcesRead(Context);
1693 WriteUnlock(&Context->PropLock);
1695 ALCcontext_DecRef(Context);
1698 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1700 ALCcontext *Context;
1701 ALsource *Source;
1703 Context = GetContextRef();
1704 if(!Context) return;
1706 WriteLock(&Context->PropLock);
1707 LockSourcesRead(Context);
1708 if((Source=LookupSource(Context, source)) == NULL)
1709 alSetError(Context, AL_INVALID_NAME);
1710 else if(!(DoubleValsByProp(param) == 3))
1711 alSetError(Context, AL_INVALID_ENUM);
1712 else
1714 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1715 SetSourcefv(Source, Context, param, fvals);
1717 UnlockSourcesRead(Context);
1718 WriteUnlock(&Context->PropLock);
1720 ALCcontext_DecRef(Context);
1723 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1725 ALCcontext *Context;
1726 ALsource *Source;
1727 ALint count;
1729 Context = GetContextRef();
1730 if(!Context) return;
1732 WriteLock(&Context->PropLock);
1733 LockSourcesRead(Context);
1734 if((Source=LookupSource(Context, source)) == NULL)
1735 alSetError(Context, AL_INVALID_NAME);
1736 else if(!values)
1737 alSetError(Context, AL_INVALID_VALUE);
1738 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1739 alSetError(Context, AL_INVALID_ENUM);
1740 else
1742 ALfloat fvals[6];
1743 ALint i;
1745 for(i = 0;i < count;i++)
1746 fvals[i] = (ALfloat)values[i];
1747 SetSourcefv(Source, Context, param, fvals);
1749 UnlockSourcesRead(Context);
1750 WriteUnlock(&Context->PropLock);
1752 ALCcontext_DecRef(Context);
1756 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1758 ALCcontext *Context;
1759 ALsource *Source;
1761 Context = GetContextRef();
1762 if(!Context) return;
1764 WriteLock(&Context->PropLock);
1765 LockSourcesRead(Context);
1766 if((Source=LookupSource(Context, source)) == NULL)
1767 alSetError(Context, AL_INVALID_NAME);
1768 else if(!(IntValsByProp(param) == 1))
1769 alSetError(Context, AL_INVALID_ENUM);
1770 else
1771 SetSourceiv(Source, Context, param, &value);
1772 UnlockSourcesRead(Context);
1773 WriteUnlock(&Context->PropLock);
1775 ALCcontext_DecRef(Context);
1778 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1780 ALCcontext *Context;
1781 ALsource *Source;
1783 Context = GetContextRef();
1784 if(!Context) return;
1786 WriteLock(&Context->PropLock);
1787 LockSourcesRead(Context);
1788 if((Source=LookupSource(Context, source)) == NULL)
1789 alSetError(Context, AL_INVALID_NAME);
1790 else if(!(IntValsByProp(param) == 3))
1791 alSetError(Context, AL_INVALID_ENUM);
1792 else
1794 ALint ivals[3] = { value1, value2, value3 };
1795 SetSourceiv(Source, Context, param, ivals);
1797 UnlockSourcesRead(Context);
1798 WriteUnlock(&Context->PropLock);
1800 ALCcontext_DecRef(Context);
1803 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1805 ALCcontext *Context;
1806 ALsource *Source;
1808 Context = GetContextRef();
1809 if(!Context) return;
1811 WriteLock(&Context->PropLock);
1812 LockSourcesRead(Context);
1813 if((Source=LookupSource(Context, source)) == NULL)
1814 alSetError(Context, AL_INVALID_NAME);
1815 else if(!values)
1816 alSetError(Context, AL_INVALID_VALUE);
1817 else if(!(IntValsByProp(param) > 0))
1818 alSetError(Context, AL_INVALID_ENUM);
1819 else
1820 SetSourceiv(Source, Context, param, values);
1821 UnlockSourcesRead(Context);
1822 WriteUnlock(&Context->PropLock);
1824 ALCcontext_DecRef(Context);
1828 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1830 ALCcontext *Context;
1831 ALsource *Source;
1833 Context = GetContextRef();
1834 if(!Context) return;
1836 WriteLock(&Context->PropLock);
1837 LockSourcesRead(Context);
1838 if((Source=LookupSource(Context, source)) == NULL)
1839 alSetError(Context, AL_INVALID_NAME);
1840 else if(!(Int64ValsByProp(param) == 1))
1841 alSetError(Context, AL_INVALID_ENUM);
1842 else
1843 SetSourcei64v(Source, Context, param, &value);
1844 UnlockSourcesRead(Context);
1845 WriteUnlock(&Context->PropLock);
1847 ALCcontext_DecRef(Context);
1850 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1852 ALCcontext *Context;
1853 ALsource *Source;
1855 Context = GetContextRef();
1856 if(!Context) return;
1858 WriteLock(&Context->PropLock);
1859 LockSourcesRead(Context);
1860 if((Source=LookupSource(Context, source)) == NULL)
1861 alSetError(Context, AL_INVALID_NAME);
1862 else if(!(Int64ValsByProp(param) == 3))
1863 alSetError(Context, AL_INVALID_ENUM);
1864 else
1866 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1867 SetSourcei64v(Source, Context, param, i64vals);
1869 UnlockSourcesRead(Context);
1870 WriteUnlock(&Context->PropLock);
1872 ALCcontext_DecRef(Context);
1875 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1877 ALCcontext *Context;
1878 ALsource *Source;
1880 Context = GetContextRef();
1881 if(!Context) return;
1883 WriteLock(&Context->PropLock);
1884 LockSourcesRead(Context);
1885 if((Source=LookupSource(Context, source)) == NULL)
1886 alSetError(Context, AL_INVALID_NAME);
1887 else if(!values)
1888 alSetError(Context, AL_INVALID_VALUE);
1889 else if(!(Int64ValsByProp(param) > 0))
1890 alSetError(Context, AL_INVALID_ENUM);
1891 else
1892 SetSourcei64v(Source, Context, param, values);
1893 UnlockSourcesRead(Context);
1894 WriteUnlock(&Context->PropLock);
1896 ALCcontext_DecRef(Context);
1900 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1902 ALCcontext *Context;
1903 ALsource *Source;
1905 Context = GetContextRef();
1906 if(!Context) return;
1908 ReadLock(&Context->PropLock);
1909 LockSourcesRead(Context);
1910 if((Source=LookupSource(Context, source)) == NULL)
1911 alSetError(Context, AL_INVALID_NAME);
1912 else if(!value)
1913 alSetError(Context, AL_INVALID_VALUE);
1914 else if(!(FloatValsByProp(param) == 1))
1915 alSetError(Context, AL_INVALID_ENUM);
1916 else
1918 ALdouble dval;
1919 if(GetSourcedv(Source, Context, param, &dval))
1920 *value = (ALfloat)dval;
1922 UnlockSourcesRead(Context);
1923 ReadUnlock(&Context->PropLock);
1925 ALCcontext_DecRef(Context);
1929 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1931 ALCcontext *Context;
1932 ALsource *Source;
1934 Context = GetContextRef();
1935 if(!Context) return;
1937 ReadLock(&Context->PropLock);
1938 LockSourcesRead(Context);
1939 if((Source=LookupSource(Context, source)) == NULL)
1940 alSetError(Context, AL_INVALID_NAME);
1941 else if(!(value1 && value2 && value3))
1942 alSetError(Context, AL_INVALID_VALUE);
1943 else if(!(FloatValsByProp(param) == 3))
1944 alSetError(Context, AL_INVALID_ENUM);
1945 else
1947 ALdouble dvals[3];
1948 if(GetSourcedv(Source, Context, param, dvals))
1950 *value1 = (ALfloat)dvals[0];
1951 *value2 = (ALfloat)dvals[1];
1952 *value3 = (ALfloat)dvals[2];
1955 UnlockSourcesRead(Context);
1956 ReadUnlock(&Context->PropLock);
1958 ALCcontext_DecRef(Context);
1962 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1964 ALCcontext *Context;
1965 ALsource *Source;
1966 ALint count;
1968 Context = GetContextRef();
1969 if(!Context) return;
1971 ReadLock(&Context->PropLock);
1972 LockSourcesRead(Context);
1973 if((Source=LookupSource(Context, source)) == NULL)
1974 alSetError(Context, AL_INVALID_NAME);
1975 else if(!values)
1976 alSetError(Context, AL_INVALID_VALUE);
1977 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
1978 alSetError(Context, AL_INVALID_ENUM);
1979 else
1981 ALdouble dvals[6];
1982 if(GetSourcedv(Source, Context, param, dvals))
1984 ALint i;
1985 for(i = 0;i < count;i++)
1986 values[i] = (ALfloat)dvals[i];
1989 UnlockSourcesRead(Context);
1990 ReadUnlock(&Context->PropLock);
1992 ALCcontext_DecRef(Context);
1996 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1998 ALCcontext *Context;
1999 ALsource *Source;
2001 Context = GetContextRef();
2002 if(!Context) return;
2004 ReadLock(&Context->PropLock);
2005 LockSourcesRead(Context);
2006 if((Source=LookupSource(Context, source)) == NULL)
2007 alSetError(Context, AL_INVALID_NAME);
2008 else if(!value)
2009 alSetError(Context, AL_INVALID_VALUE);
2010 else if(!(DoubleValsByProp(param) == 1))
2011 alSetError(Context, AL_INVALID_ENUM);
2012 else
2013 GetSourcedv(Source, Context, param, value);
2014 UnlockSourcesRead(Context);
2015 ReadUnlock(&Context->PropLock);
2017 ALCcontext_DecRef(Context);
2020 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
2022 ALCcontext *Context;
2023 ALsource *Source;
2025 Context = GetContextRef();
2026 if(!Context) return;
2028 ReadLock(&Context->PropLock);
2029 LockSourcesRead(Context);
2030 if((Source=LookupSource(Context, source)) == NULL)
2031 alSetError(Context, AL_INVALID_NAME);
2032 else if(!(value1 && value2 && value3))
2033 alSetError(Context, AL_INVALID_VALUE);
2034 else if(!(DoubleValsByProp(param) == 3))
2035 alSetError(Context, AL_INVALID_ENUM);
2036 else
2038 ALdouble dvals[3];
2039 if(GetSourcedv(Source, Context, param, dvals))
2041 *value1 = dvals[0];
2042 *value2 = dvals[1];
2043 *value3 = dvals[2];
2046 UnlockSourcesRead(Context);
2047 ReadUnlock(&Context->PropLock);
2049 ALCcontext_DecRef(Context);
2052 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
2054 ALCcontext *Context;
2055 ALsource *Source;
2057 Context = GetContextRef();
2058 if(!Context) return;
2060 ReadLock(&Context->PropLock);
2061 LockSourcesRead(Context);
2062 if((Source=LookupSource(Context, source)) == NULL)
2063 alSetError(Context, AL_INVALID_NAME);
2064 else if(!values)
2065 alSetError(Context, AL_INVALID_VALUE);
2066 else if(!(DoubleValsByProp(param) > 0))
2067 alSetError(Context, AL_INVALID_ENUM);
2068 else
2069 GetSourcedv(Source, Context, param, values);
2070 UnlockSourcesRead(Context);
2071 ReadUnlock(&Context->PropLock);
2073 ALCcontext_DecRef(Context);
2077 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2079 ALCcontext *Context;
2080 ALsource *Source;
2082 Context = GetContextRef();
2083 if(!Context) return;
2085 ReadLock(&Context->PropLock);
2086 LockSourcesRead(Context);
2087 if((Source=LookupSource(Context, source)) == NULL)
2088 alSetError(Context, AL_INVALID_NAME);
2089 else if(!value)
2090 alSetError(Context, AL_INVALID_VALUE);
2091 else if(!(IntValsByProp(param) == 1))
2092 alSetError(Context, AL_INVALID_ENUM);
2093 else
2094 GetSourceiv(Source, Context, param, value);
2095 UnlockSourcesRead(Context);
2096 ReadUnlock(&Context->PropLock);
2098 ALCcontext_DecRef(Context);
2102 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2104 ALCcontext *Context;
2105 ALsource *Source;
2107 Context = GetContextRef();
2108 if(!Context) return;
2110 ReadLock(&Context->PropLock);
2111 LockSourcesRead(Context);
2112 if((Source=LookupSource(Context, source)) == NULL)
2113 alSetError(Context, AL_INVALID_NAME);
2114 else if(!(value1 && value2 && value3))
2115 alSetError(Context, AL_INVALID_VALUE);
2116 else if(!(IntValsByProp(param) == 3))
2117 alSetError(Context, AL_INVALID_ENUM);
2118 else
2120 ALint ivals[3];
2121 if(GetSourceiv(Source, Context, param, ivals))
2123 *value1 = ivals[0];
2124 *value2 = ivals[1];
2125 *value3 = ivals[2];
2128 UnlockSourcesRead(Context);
2129 ReadUnlock(&Context->PropLock);
2131 ALCcontext_DecRef(Context);
2135 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2137 ALCcontext *Context;
2138 ALsource *Source;
2140 Context = GetContextRef();
2141 if(!Context) return;
2143 ReadLock(&Context->PropLock);
2144 LockSourcesRead(Context);
2145 if((Source=LookupSource(Context, source)) == NULL)
2146 alSetError(Context, AL_INVALID_NAME);
2147 else if(!values)
2148 alSetError(Context, AL_INVALID_VALUE);
2149 else if(!(IntValsByProp(param) > 0))
2150 alSetError(Context, AL_INVALID_ENUM);
2151 else
2152 GetSourceiv(Source, Context, param, values);
2153 UnlockSourcesRead(Context);
2154 ReadUnlock(&Context->PropLock);
2156 ALCcontext_DecRef(Context);
2160 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2162 ALCcontext *Context;
2163 ALsource *Source;
2165 Context = GetContextRef();
2166 if(!Context) return;
2168 ReadLock(&Context->PropLock);
2169 LockSourcesRead(Context);
2170 if((Source=LookupSource(Context, source)) == NULL)
2171 alSetError(Context, AL_INVALID_NAME);
2172 else if(!value)
2173 alSetError(Context, AL_INVALID_VALUE);
2174 else if(!(Int64ValsByProp(param) == 1))
2175 alSetError(Context, AL_INVALID_ENUM);
2176 else
2177 GetSourcei64v(Source, Context, param, value);
2178 UnlockSourcesRead(Context);
2179 ReadUnlock(&Context->PropLock);
2181 ALCcontext_DecRef(Context);
2184 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2186 ALCcontext *Context;
2187 ALsource *Source;
2189 Context = GetContextRef();
2190 if(!Context) return;
2192 ReadLock(&Context->PropLock);
2193 LockSourcesRead(Context);
2194 if((Source=LookupSource(Context, source)) == NULL)
2195 alSetError(Context, AL_INVALID_NAME);
2196 else if(!(value1 && value2 && value3))
2197 alSetError(Context, AL_INVALID_VALUE);
2198 else if(!(Int64ValsByProp(param) == 3))
2199 alSetError(Context, AL_INVALID_ENUM);
2200 else
2202 ALint64 i64vals[3];
2203 if(GetSourcei64v(Source, Context, param, i64vals))
2205 *value1 = i64vals[0];
2206 *value2 = i64vals[1];
2207 *value3 = i64vals[2];
2210 UnlockSourcesRead(Context);
2211 ReadUnlock(&Context->PropLock);
2213 ALCcontext_DecRef(Context);
2216 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2218 ALCcontext *Context;
2219 ALsource *Source;
2221 Context = GetContextRef();
2222 if(!Context) return;
2224 ReadLock(&Context->PropLock);
2225 LockSourcesRead(Context);
2226 if((Source=LookupSource(Context, source)) == NULL)
2227 alSetError(Context, AL_INVALID_NAME);
2228 else if(!values)
2229 alSetError(Context, AL_INVALID_VALUE);
2230 else if(!(Int64ValsByProp(param) > 0))
2231 alSetError(Context, AL_INVALID_ENUM);
2232 else
2233 GetSourcei64v(Source, Context, param, values);
2234 UnlockSourcesRead(Context);
2235 ReadUnlock(&Context->PropLock);
2237 ALCcontext_DecRef(Context);
2241 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2243 alSourcePlayv(1, &source);
2245 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2247 ALCcontext *context;
2248 ALsource *source;
2249 ALsizei i;
2251 context = GetContextRef();
2252 if(!context) return;
2254 LockSourcesRead(context);
2255 if(!(n >= 0))
2256 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2257 for(i = 0;i < n;i++)
2259 if(!LookupSource(context, sources[i]))
2260 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2263 LockContext(context);
2264 while(n > context->MaxVoices-context->VoiceCount)
2266 ALvoice *temp = NULL;
2267 ALsizei newcount;
2269 newcount = context->MaxVoices << 1;
2270 if(newcount > 0)
2271 temp = realloc(context->Voices, newcount * sizeof(context->Voices[0]));
2272 if(!temp)
2274 UnlockContext(context);
2275 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2277 memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0]));
2279 context->Voices = temp;
2280 context->MaxVoices = newcount;
2283 for(i = 0;i < n;i++)
2285 source = LookupSource(context, sources[i]);
2286 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
2287 source->new_state = AL_PLAYING;
2288 else
2289 SetSourceState(source, context, AL_PLAYING);
2291 UnlockContext(context);
2293 done:
2294 UnlockSourcesRead(context);
2295 ALCcontext_DecRef(context);
2298 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2300 alSourcePausev(1, &source);
2302 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2304 ALCcontext *context;
2305 ALsource *source;
2306 ALsizei i;
2308 context = GetContextRef();
2309 if(!context) return;
2311 LockSourcesRead(context);
2312 if(!(n >= 0))
2313 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2314 for(i = 0;i < n;i++)
2316 if(!LookupSource(context, sources[i]))
2317 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2320 LockContext(context);
2321 for(i = 0;i < n;i++)
2323 source = LookupSource(context, sources[i]);
2324 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
2325 source->new_state = AL_PAUSED;
2326 else
2327 SetSourceState(source, context, AL_PAUSED);
2329 UnlockContext(context);
2331 done:
2332 UnlockSourcesRead(context);
2333 ALCcontext_DecRef(context);
2336 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2338 alSourceStopv(1, &source);
2340 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2342 ALCcontext *context;
2343 ALsource *source;
2344 ALsizei i;
2346 context = GetContextRef();
2347 if(!context) return;
2349 LockSourcesRead(context);
2350 if(!(n >= 0))
2351 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2352 for(i = 0;i < n;i++)
2354 if(!LookupSource(context, sources[i]))
2355 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2358 LockContext(context);
2359 for(i = 0;i < n;i++)
2361 source = LookupSource(context, sources[i]);
2362 source->new_state = AL_NONE;
2363 SetSourceState(source, context, AL_STOPPED);
2365 UnlockContext(context);
2367 done:
2368 UnlockSourcesRead(context);
2369 ALCcontext_DecRef(context);
2372 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2374 alSourceRewindv(1, &source);
2376 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2378 ALCcontext *context;
2379 ALsource *source;
2380 ALsizei i;
2382 context = GetContextRef();
2383 if(!context) return;
2385 LockSourcesRead(context);
2386 if(!(n >= 0))
2387 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2388 for(i = 0;i < n;i++)
2390 if(!LookupSource(context, sources[i]))
2391 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2394 LockContext(context);
2395 for(i = 0;i < n;i++)
2397 source = LookupSource(context, sources[i]);
2398 source->new_state = AL_NONE;
2399 SetSourceState(source, context, AL_INITIAL);
2401 UnlockContext(context);
2403 done:
2404 UnlockSourcesRead(context);
2405 ALCcontext_DecRef(context);
2409 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2411 ALCdevice *device;
2412 ALCcontext *context;
2413 ALsource *source;
2414 ALsizei i;
2415 ALbufferlistitem *BufferListStart;
2416 ALbufferlistitem *BufferList;
2417 ALbuffer *BufferFmt = NULL;
2419 if(nb == 0)
2420 return;
2422 context = GetContextRef();
2423 if(!context) return;
2425 device = context->Device;
2427 LockSourcesRead(context);
2428 if(!(nb >= 0))
2429 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2430 if((source=LookupSource(context, src)) == NULL)
2431 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2433 WriteLock(&source->queue_lock);
2434 if(source->SourceType == AL_STATIC)
2436 WriteUnlock(&source->queue_lock);
2437 /* Can't queue on a Static Source */
2438 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2441 /* Check for a valid Buffer, for its frequency and format */
2442 BufferList = ATOMIC_LOAD(&source->queue);
2443 while(BufferList)
2445 if(BufferList->buffer)
2447 BufferFmt = BufferList->buffer;
2448 break;
2450 BufferList = BufferList->next;
2453 LockBuffersRead(device);
2454 BufferListStart = NULL;
2455 BufferList = NULL;
2456 for(i = 0;i < nb;i++)
2458 ALbuffer *buffer = NULL;
2459 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2461 WriteUnlock(&source->queue_lock);
2462 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2465 if(!BufferListStart)
2467 BufferListStart = malloc(sizeof(ALbufferlistitem));
2468 BufferList = BufferListStart;
2470 else
2472 BufferList->next = malloc(sizeof(ALbufferlistitem));
2473 BufferList = BufferList->next;
2475 BufferList->buffer = buffer;
2476 BufferList->next = NULL;
2477 if(!buffer) continue;
2479 /* Hold a read lock on each buffer being queued while checking all
2480 * provided buffers. This is done so other threads don't see an extra
2481 * reference on some buffers if this operation ends up failing. */
2482 ReadLock(&buffer->lock);
2483 IncrementRef(&buffer->ref);
2485 if(BufferFmt == NULL)
2487 BufferFmt = buffer;
2489 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2490 source->SampleSize = BytesFromFmt(buffer->FmtType);
2492 else if(BufferFmt->Frequency != buffer->Frequency ||
2493 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2494 BufferFmt->OriginalType != buffer->OriginalType)
2496 WriteUnlock(&source->queue_lock);
2497 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2499 buffer_error:
2500 /* A buffer failed (invalid ID or format), so unlock and release
2501 * each buffer we had. */
2502 while(BufferListStart)
2504 ALbufferlistitem *next = BufferListStart->next;
2505 if((buffer=BufferListStart->buffer) != NULL)
2507 DecrementRef(&buffer->ref);
2508 ReadUnlock(&buffer->lock);
2510 free(BufferListStart);
2511 BufferListStart = next;
2513 UnlockBuffersRead(device);
2514 goto done;
2517 /* All buffers good, unlock them now. */
2518 BufferList = BufferListStart;
2519 while(BufferList != NULL)
2521 ALbuffer *buffer = BufferList->buffer;
2522 if(buffer) ReadUnlock(&buffer->lock);
2523 BufferList = BufferList->next;
2525 UnlockBuffersRead(device);
2527 /* Source is now streaming */
2528 source->SourceType = AL_STREAMING;
2530 BufferList = NULL;
2531 if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
2533 /* Queue head is not NULL, append to the end of the queue */
2534 while(BufferList->next != NULL)
2535 BufferList = BufferList->next;
2536 BufferList->next = BufferListStart;
2538 /* If the current buffer was at the end (NULL), put it at the start of the newly queued
2539 * buffers.
2541 BufferList = NULL;
2542 ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
2543 WriteUnlock(&source->queue_lock);
2545 done:
2546 UnlockSourcesRead(context);
2547 ALCcontext_DecRef(context);
2550 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2552 ALCcontext *context;
2553 ALsource *source;
2554 ALbufferlistitem *OldHead;
2555 ALbufferlistitem *OldTail;
2556 ALbufferlistitem *Current;
2557 ALsizei i = 0;
2559 if(nb == 0)
2560 return;
2562 context = GetContextRef();
2563 if(!context) return;
2565 LockSourcesRead(context);
2566 if(!(nb >= 0))
2567 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2569 if((source=LookupSource(context, src)) == NULL)
2570 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2572 WriteLock(&source->queue_lock);
2573 /* Find the new buffer queue head */
2574 OldTail = ATOMIC_LOAD(&source->queue);
2575 Current = ATOMIC_LOAD(&source->current_buffer);
2576 if(OldTail != Current)
2578 for(i = 1;i < nb;i++)
2580 ALbufferlistitem *next = OldTail->next;
2581 if(!next || next == Current) break;
2582 OldTail = next;
2585 if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
2587 WriteUnlock(&source->queue_lock);
2588 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2589 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2592 /* Swap it, and cut the new head from the old. */
2593 OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, OldTail->next);
2594 if(OldTail->next)
2596 ALCdevice *device = context->Device;
2597 uint count;
2599 /* Once the active mix (if any) is done, it's safe to cut the old tail
2600 * from the new head.
2602 if(((count=ReadRef(&device->MixCount))&1) != 0)
2604 while(count == ReadRef(&device->MixCount))
2605 althrd_yield();
2607 OldTail->next = NULL;
2609 WriteUnlock(&source->queue_lock);
2611 while(OldHead != NULL)
2613 ALbufferlistitem *next = OldHead->next;
2614 ALbuffer *buffer = OldHead->buffer;
2616 if(!buffer)
2617 *(buffers++) = 0;
2618 else
2620 *(buffers++) = buffer->id;
2621 DecrementRef(&buffer->ref);
2624 free(OldHead);
2625 OldHead = next;
2628 done:
2629 UnlockSourcesRead(context);
2630 ALCcontext_DecRef(context);
2634 static ALvoid InitSourceParams(ALsource *Source)
2636 ALuint i;
2638 RWLockInit(&Source->queue_lock);
2640 Source->InnerAngle = 360.0f;
2641 Source->OuterAngle = 360.0f;
2642 Source->Pitch = 1.0f;
2643 Source->Position[0] = 0.0f;
2644 Source->Position[1] = 0.0f;
2645 Source->Position[2] = 0.0f;
2646 Source->Velocity[0] = 0.0f;
2647 Source->Velocity[1] = 0.0f;
2648 Source->Velocity[2] = 0.0f;
2649 Source->Direction[0] = 0.0f;
2650 Source->Direction[1] = 0.0f;
2651 Source->Direction[2] = 0.0f;
2652 Source->Orientation[0][0] = 0.0f;
2653 Source->Orientation[0][1] = 0.0f;
2654 Source->Orientation[0][2] = -1.0f;
2655 Source->Orientation[1][0] = 0.0f;
2656 Source->Orientation[1][1] = 1.0f;
2657 Source->Orientation[1][2] = 0.0f;
2658 Source->RefDistance = 1.0f;
2659 Source->MaxDistance = FLT_MAX;
2660 Source->RollOffFactor = 1.0f;
2661 Source->Looping = AL_FALSE;
2662 Source->Gain = 1.0f;
2663 Source->MinGain = 0.0f;
2664 Source->MaxGain = 1.0f;
2665 Source->OuterGain = 0.0f;
2666 Source->OuterGainHF = 1.0f;
2668 Source->DryGainHFAuto = AL_TRUE;
2669 Source->WetGainAuto = AL_TRUE;
2670 Source->WetGainHFAuto = AL_TRUE;
2671 Source->AirAbsorptionFactor = 0.0f;
2672 Source->RoomRolloffFactor = 0.0f;
2673 Source->DopplerFactor = 1.0f;
2674 Source->DirectChannels = AL_FALSE;
2676 Source->StereoPan[0] = DEG2RAD( 30.0f);
2677 Source->StereoPan[1] = DEG2RAD(-30.0f);
2679 Source->Radius = 0.0f;
2681 Source->DistanceModel = DefaultDistanceModel;
2683 Source->Direct.Gain = 1.0f;
2684 Source->Direct.GainHF = 1.0f;
2685 Source->Direct.HFReference = LOWPASSFREQREF;
2686 Source->Direct.GainLF = 1.0f;
2687 Source->Direct.LFReference = HIGHPASSFREQREF;
2688 for(i = 0;i < MAX_SENDS;i++)
2690 Source->Send[i].Gain = 1.0f;
2691 Source->Send[i].GainHF = 1.0f;
2692 Source->Send[i].HFReference = LOWPASSFREQREF;
2693 Source->Send[i].GainLF = 1.0f;
2694 Source->Send[i].LFReference = HIGHPASSFREQREF;
2697 Source->state = AL_INITIAL;
2698 Source->new_state = AL_NONE;
2699 Source->SourceType = AL_UNDETERMINED;
2700 Source->OffsetType = AL_NONE;
2701 Source->Offset = 0.0;
2703 ATOMIC_INIT(&Source->queue, NULL);
2704 ATOMIC_INIT(&Source->current_buffer, NULL);
2706 ATOMIC_INIT(&Source->Update, NULL);
2707 ATOMIC_INIT(&Source->FreeList, NULL);
2710 static ALvoid DeinitSource(ALsource *source)
2712 ALbufferlistitem *BufferList;
2713 struct ALsourceProps *props;
2714 size_t count = 0;
2715 size_t i;
2717 props = ATOMIC_LOAD(&source->Update);
2718 if(props) al_free(props);
2720 props = ATOMIC_LOAD(&source->FreeList, almemory_order_relaxed);
2721 while(props)
2723 struct ALsourceProps *next;
2724 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2725 al_free(props);
2726 props = next;
2727 ++count;
2729 /* This is excessively spammy if it traces every source destruction, so
2730 * just warn if it was unexpectedly large.
2732 if(count > 3)
2733 WARN("Freed "SZFMT" Source property objects\n", count);
2735 BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NULL);
2736 while(BufferList != NULL)
2738 ALbufferlistitem *next = BufferList->next;
2739 if(BufferList->buffer != NULL)
2740 DecrementRef(&BufferList->buffer->ref);
2741 free(BufferList);
2742 BufferList = next;
2745 for(i = 0;i < MAX_SENDS;++i)
2747 if(source->Send[i].Slot)
2748 DecrementRef(&source->Send[i].Slot->ref);
2749 source->Send[i].Slot = NULL;
2753 void UpdateSourceProps(ALsource *source, ALuint num_sends)
2755 struct ALsourceProps *props;
2756 size_t i;
2758 /* Get an unused property container, or allocate a new one as needed. */
2759 props = ATOMIC_LOAD(&source->FreeList, almemory_order_acquire);
2760 if(!props)
2761 props = al_calloc(16, sizeof(*props));
2762 else
2764 struct ALsourceProps *next;
2765 do {
2766 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2767 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*,
2768 &source->FreeList, &props, next, almemory_order_seq_cst,
2769 almemory_order_consume) == 0);
2772 /* Copy in current property values. */
2773 ATOMIC_STORE(&props->Pitch, source->Pitch, almemory_order_relaxed);
2774 ATOMIC_STORE(&props->Gain, source->Gain, almemory_order_relaxed);
2775 ATOMIC_STORE(&props->OuterGain, source->OuterGain, almemory_order_relaxed);
2776 ATOMIC_STORE(&props->MinGain, source->MinGain, almemory_order_relaxed);
2777 ATOMIC_STORE(&props->MaxGain, source->MaxGain, almemory_order_relaxed);
2778 ATOMIC_STORE(&props->InnerAngle, source->InnerAngle, almemory_order_relaxed);
2779 ATOMIC_STORE(&props->OuterAngle, source->OuterAngle, almemory_order_relaxed);
2780 ATOMIC_STORE(&props->RefDistance, source->RefDistance, almemory_order_relaxed);
2781 ATOMIC_STORE(&props->MaxDistance, source->MaxDistance, almemory_order_relaxed);
2782 ATOMIC_STORE(&props->RollOffFactor, source->RollOffFactor, almemory_order_relaxed);
2783 for(i = 0;i < 3;i++)
2784 ATOMIC_STORE(&props->Position[i], source->Position[i], almemory_order_relaxed);
2785 for(i = 0;i < 3;i++)
2786 ATOMIC_STORE(&props->Velocity[i], source->Velocity[i], almemory_order_relaxed);
2787 for(i = 0;i < 3;i++)
2788 ATOMIC_STORE(&props->Direction[i], source->Direction[i], almemory_order_relaxed);
2789 for(i = 0;i < 2;i++)
2791 size_t j;
2792 for(j = 0;j < 3;j++)
2793 ATOMIC_STORE(&props->Orientation[i][j], source->Orientation[i][j],
2794 almemory_order_relaxed);
2796 ATOMIC_STORE(&props->HeadRelative, source->HeadRelative, almemory_order_relaxed);
2797 ATOMIC_STORE(&props->Looping, source->Looping, almemory_order_relaxed);
2798 ATOMIC_STORE(&props->DistanceModel, source->DistanceModel, almemory_order_relaxed);
2799 ATOMIC_STORE(&props->DirectChannels, source->DirectChannels, almemory_order_relaxed);
2801 ATOMIC_STORE(&props->DryGainHFAuto, source->DryGainHFAuto, almemory_order_relaxed);
2802 ATOMIC_STORE(&props->WetGainAuto, source->WetGainAuto, almemory_order_relaxed);
2803 ATOMIC_STORE(&props->WetGainHFAuto, source->WetGainHFAuto, almemory_order_relaxed);
2804 ATOMIC_STORE(&props->OuterGainHF, source->OuterGainHF, almemory_order_relaxed);
2806 ATOMIC_STORE(&props->AirAbsorptionFactor, source->AirAbsorptionFactor, almemory_order_relaxed);
2807 ATOMIC_STORE(&props->RoomRolloffFactor, source->RoomRolloffFactor, almemory_order_relaxed);
2808 ATOMIC_STORE(&props->DopplerFactor, source->DopplerFactor, almemory_order_relaxed);
2810 ATOMIC_STORE(&props->StereoPan[0], source->StereoPan[0], almemory_order_relaxed);
2811 ATOMIC_STORE(&props->StereoPan[1], source->StereoPan[1], almemory_order_relaxed);
2813 ATOMIC_STORE(&props->Radius, source->Radius, almemory_order_relaxed);
2815 ATOMIC_STORE(&props->Direct.Gain, source->Direct.Gain, almemory_order_relaxed);
2816 ATOMIC_STORE(&props->Direct.GainHF, source->Direct.GainHF, almemory_order_relaxed);
2817 ATOMIC_STORE(&props->Direct.HFReference, source->Direct.HFReference, almemory_order_relaxed);
2818 ATOMIC_STORE(&props->Direct.GainLF, source->Direct.GainLF, almemory_order_relaxed);
2819 ATOMIC_STORE(&props->Direct.LFReference, source->Direct.LFReference, almemory_order_relaxed);
2821 for(i = 0;i < num_sends;i++)
2823 ATOMIC_STORE(&props->Send[i].Slot, source->Send[i].Slot, almemory_order_relaxed);
2824 ATOMIC_STORE(&props->Send[i].Gain, source->Send[i].Gain, almemory_order_relaxed);
2825 ATOMIC_STORE(&props->Send[i].GainHF, source->Send[i].GainHF, almemory_order_relaxed);
2826 ATOMIC_STORE(&props->Send[i].HFReference, source->Send[i].HFReference,
2827 almemory_order_relaxed);
2828 ATOMIC_STORE(&props->Send[i].GainLF, source->Send[i].GainLF, almemory_order_relaxed);
2829 ATOMIC_STORE(&props->Send[i].LFReference, source->Send[i].LFReference,
2830 almemory_order_relaxed);
2833 /* Set the new container for updating internal parameters. */
2834 props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, props, almemory_order_acq_rel);
2835 if(props)
2837 /* If there was an unused update container, put it back in the
2838 * freelist.
2840 struct ALsourceProps *first = ATOMIC_LOAD(&source->FreeList);
2841 do {
2842 ATOMIC_STORE(&props->next, first, almemory_order_relaxed);
2843 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*,
2844 &source->FreeList, &first, props) == 0);
2848 void UpdateAllSourceProps(ALCcontext *context)
2850 ALuint num_sends = context->Device->NumAuxSends;
2851 uint updates;
2852 ALsizei pos;
2854 /* Tell the mixer to stop applying updates, then wait for any active
2855 * updating to finish, before providing source updates.
2857 ATOMIC_STORE(&context->HoldUpdates, AL_TRUE);
2858 while(((updates=ReadRef(&context->UpdateCount))&1) != 0)
2859 althrd_yield();
2860 for(pos = 0;pos < context->VoiceCount;pos++)
2862 ALvoice *voice = &context->Voices[pos];
2863 ALsource *source = voice->Source;
2864 if(source != NULL && (source->state == AL_PLAYING ||
2865 source->state == AL_PAUSED))
2866 UpdateSourceProps(source, num_sends);
2868 /* Now with all updates declared, let the mixer continue applying them so
2869 * they all happen at once.
2871 ATOMIC_STORE(&context->HoldUpdates, AL_FALSE);
2875 /* SetSourceState
2877 * Sets the source's new play state given its current state.
2879 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2881 WriteLock(&Source->queue_lock);
2882 if(state == AL_PLAYING)
2884 ALCdevice *device = Context->Device;
2885 ALbufferlistitem *BufferList;
2886 ALboolean discontinuity;
2887 ALvoice *voice = NULL;
2888 ALsizei i;
2890 /* Check that there is a queue containing at least one valid, non zero
2891 * length Buffer. */
2892 BufferList = ATOMIC_LOAD(&Source->queue);
2893 while(BufferList)
2895 ALbuffer *buffer;
2896 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2897 break;
2898 BufferList = BufferList->next;
2901 if(Source->state != AL_PAUSED)
2903 Source->state = AL_PLAYING;
2904 Source->position = 0;
2905 Source->position_fraction = 0;
2906 ATOMIC_STORE(&Source->current_buffer, BufferList);
2907 discontinuity = AL_TRUE;
2909 else
2911 Source->state = AL_PLAYING;
2912 discontinuity = AL_FALSE;
2915 // Check if an Offset has been set
2916 if(Source->OffsetType != AL_NONE)
2918 ApplyOffset(Source);
2919 /* discontinuity = AL_TRUE;??? */
2922 /* If there's nothing to play, or device is disconnected, go right to
2923 * stopped */
2924 if(!BufferList || !device->Connected)
2925 goto do_stop;
2927 /* Make sure this source isn't already active, while looking for an
2928 * unused active source slot to put it in. */
2929 for(i = 0;i < Context->VoiceCount;i++)
2931 ALsource *old = Source;
2932 if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL))
2934 if(voice == NULL)
2936 voice = &Context->Voices[i];
2937 voice->Source = Source;
2939 break;
2941 old = NULL;
2942 if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source))
2943 voice = &Context->Voices[i];
2945 if(voice == NULL)
2947 voice = &Context->Voices[Context->VoiceCount++];
2948 voice->Source = Source;
2951 /* Clear previous samples if playback is discontinuous. */
2952 if(discontinuity)
2953 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
2955 voice->Moving = AL_FALSE;
2956 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
2958 ALsizei j;
2959 for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
2960 voice->Direct.Hrtf[i].State.History[j] = 0.0f;
2961 for(j = 0;j < HRIR_LENGTH;j++)
2963 voice->Direct.Hrtf[i].State.Values[j][0] = 0.0f;
2964 voice->Direct.Hrtf[i].State.Values[j][1] = 0.0f;
2968 UpdateSourceProps(Source, device->NumAuxSends);
2970 else if(state == AL_PAUSED)
2972 if(Source->state == AL_PLAYING)
2973 Source->state = AL_PAUSED;
2975 else if(state == AL_STOPPED)
2977 do_stop:
2978 if(Source->state != AL_INITIAL)
2980 Source->state = AL_STOPPED;
2981 ATOMIC_STORE(&Source->current_buffer, NULL);
2983 Source->OffsetType = AL_NONE;
2984 Source->Offset = 0.0;
2986 else if(state == AL_INITIAL)
2988 if(Source->state != AL_INITIAL)
2990 Source->state = AL_INITIAL;
2991 Source->position = 0;
2992 Source->position_fraction = 0;
2993 ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue));
2995 Source->OffsetType = AL_NONE;
2996 Source->Offset = 0.0;
2998 WriteUnlock(&Source->queue_lock);
3001 /* GetSourceSampleOffset
3003 * Gets the current read offset for the given Source, in 32.32 fixed-point
3004 * samples. The offset is relative to the start of the queue (not the start of
3005 * the current buffer).
3007 ALint64 GetSourceSampleOffset(ALsource *Source)
3009 const ALbufferlistitem *BufferList;
3010 const ALbufferlistitem *Current;
3011 ALuint64 readPos;
3013 ReadLock(&Source->queue_lock);
3014 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
3016 ReadUnlock(&Source->queue_lock);
3017 return 0;
3020 /* NOTE: This is the offset into the *current* buffer, so add the length of
3021 * any played buffers */
3022 readPos = (ALuint64)Source->position << 32;
3023 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
3024 BufferList = ATOMIC_LOAD(&Source->queue);
3025 Current = ATOMIC_LOAD(&Source->current_buffer);
3026 while(BufferList && BufferList != Current)
3028 if(BufferList->buffer)
3029 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
3030 BufferList = BufferList->next;
3033 ReadUnlock(&Source->queue_lock);
3034 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
3037 /* GetSourceSecOffset
3039 * Gets the current read offset for the given Source, in seconds. The offset is
3040 * relative to the start of the queue (not the start of the current buffer).
3042 static ALdouble GetSourceSecOffset(ALsource *Source)
3044 const ALbufferlistitem *BufferList;
3045 const ALbufferlistitem *Current;
3046 const ALbuffer *Buffer = NULL;
3047 ALuint64 readPos;
3049 ReadLock(&Source->queue_lock);
3050 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
3052 ReadUnlock(&Source->queue_lock);
3053 return 0.0;
3056 /* NOTE: This is the offset into the *current* buffer, so add the length of
3057 * any played buffers */
3058 readPos = (ALuint64)Source->position << FRACTIONBITS;
3059 readPos |= (ALuint64)Source->position_fraction;
3060 BufferList = ATOMIC_LOAD(&Source->queue);
3061 Current = ATOMIC_LOAD(&Source->current_buffer);
3062 while(BufferList && BufferList != Current)
3064 const ALbuffer *buffer = BufferList->buffer;
3065 if(buffer != NULL)
3067 if(!Buffer) Buffer = buffer;
3068 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
3070 BufferList = BufferList->next;
3073 while(BufferList && !Buffer)
3075 Buffer = BufferList->buffer;
3076 BufferList = BufferList->next;
3078 assert(Buffer != NULL);
3080 ReadUnlock(&Source->queue_lock);
3081 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
3084 /* GetSourceOffset
3086 * Gets the current read offset for the given Source, in the appropriate format
3087 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3088 * queue (not the start of the current buffer).
3090 static ALdouble GetSourceOffset(ALsource *Source, ALenum name)
3092 const ALbufferlistitem *BufferList;
3093 const ALbufferlistitem *Current;
3094 const ALbuffer *Buffer = NULL;
3095 ALboolean readFin = AL_FALSE;
3096 ALuint readPos, readPosFrac;
3097 ALuint totalBufferLen;
3098 ALdouble offset = 0.0;
3100 ReadLock(&Source->queue_lock);
3101 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
3103 ReadUnlock(&Source->queue_lock);
3104 return 0.0;
3107 /* NOTE: This is the offset into the *current* buffer, so add the length of
3108 * any played buffers */
3109 totalBufferLen = 0;
3110 readPos = Source->position;
3111 readPosFrac = Source->position_fraction;
3112 BufferList = ATOMIC_LOAD(&Source->queue);
3113 Current = ATOMIC_LOAD(&Source->current_buffer);
3114 while(BufferList != NULL)
3116 const ALbuffer *buffer;
3117 readFin = readFin || (BufferList == Current);
3118 if((buffer=BufferList->buffer) != NULL)
3120 if(!Buffer) Buffer = buffer;
3121 totalBufferLen += buffer->SampleLen;
3122 if(!readFin) readPos += buffer->SampleLen;
3124 BufferList = BufferList->next;
3126 assert(Buffer != NULL);
3128 if(Source->Looping)
3129 readPos %= totalBufferLen;
3130 else
3132 /* Wrap back to 0 */
3133 if(readPos >= totalBufferLen)
3134 readPos = readPosFrac = 0;
3137 switch(name)
3139 case AL_SEC_OFFSET:
3140 offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
3141 break;
3143 case AL_SAMPLE_OFFSET:
3144 offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
3145 break;
3147 case AL_BYTE_OFFSET:
3148 if(Buffer->OriginalType == UserFmtIMA4)
3150 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3151 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3152 ALuint FrameBlockSize = Buffer->OriginalAlign;
3154 /* Round down to nearest ADPCM block */
3155 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3157 else if(Buffer->OriginalType == UserFmtMSADPCM)
3159 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3160 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3161 ALuint FrameBlockSize = Buffer->OriginalAlign;
3163 /* Round down to nearest ADPCM block */
3164 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3166 else
3168 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3169 offset = (ALdouble)(readPos * FrameSize);
3171 break;
3174 ReadUnlock(&Source->queue_lock);
3175 return offset;
3179 /* ApplyOffset
3181 * Apply the stored playback offset to the Source. This function will update
3182 * the number of buffers "played" given the stored offset.
3184 ALboolean ApplyOffset(ALsource *Source)
3186 ALbufferlistitem *BufferList;
3187 const ALbuffer *Buffer;
3188 ALuint bufferLen, totalBufferLen;
3189 ALuint offset=0, frac=0;
3191 /* Get sample frame offset */
3192 if(!GetSampleOffset(Source, &offset, &frac))
3193 return AL_FALSE;
3195 totalBufferLen = 0;
3196 BufferList = ATOMIC_LOAD(&Source->queue);
3197 while(BufferList && totalBufferLen <= offset)
3199 Buffer = BufferList->buffer;
3200 bufferLen = Buffer ? Buffer->SampleLen : 0;
3202 if(bufferLen > offset-totalBufferLen)
3204 /* Offset is in this buffer */
3205 ATOMIC_STORE(&Source->current_buffer, BufferList);
3207 Source->position = offset - totalBufferLen;
3208 Source->position_fraction = frac;
3209 return AL_TRUE;
3212 totalBufferLen += bufferLen;
3214 BufferList = BufferList->next;
3217 /* Offset is out of range of the queue */
3218 return AL_FALSE;
3222 /* GetSampleOffset
3224 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3225 * or Second offset supplied by the application). This takes into account the
3226 * fact that the buffer format may have been modifed since.
3228 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
3230 const ALbuffer *Buffer = NULL;
3231 const ALbufferlistitem *BufferList;
3232 ALdouble dbloff, dblfrac;
3234 /* Find the first valid Buffer in the Queue */
3235 BufferList = ATOMIC_LOAD(&Source->queue);
3236 while(BufferList)
3238 if(BufferList->buffer)
3240 Buffer = BufferList->buffer;
3241 break;
3243 BufferList = BufferList->next;
3245 if(!Buffer)
3247 Source->OffsetType = AL_NONE;
3248 Source->Offset = 0.0;
3249 return AL_FALSE;
3252 switch(Source->OffsetType)
3254 case AL_BYTE_OFFSET:
3255 /* Determine the ByteOffset (and ensure it is block aligned) */
3256 *offset = (ALuint)Source->Offset;
3257 if(Buffer->OriginalType == UserFmtIMA4)
3259 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3260 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3261 *offset *= Buffer->OriginalAlign;
3263 else if(Buffer->OriginalType == UserFmtMSADPCM)
3265 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3266 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3267 *offset *= Buffer->OriginalAlign;
3269 else
3270 *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3271 *frac = 0;
3272 break;
3274 case AL_SAMPLE_OFFSET:
3275 dblfrac = modf(Source->Offset, &dbloff);
3276 *offset = (ALuint)mind(dbloff, UINT_MAX);
3277 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3278 break;
3280 case AL_SEC_OFFSET:
3281 dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
3282 *offset = (ALuint)mind(dbloff, UINT_MAX);
3283 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3284 break;
3286 Source->OffsetType = AL_NONE;
3287 Source->Offset = 0.0;
3289 return AL_TRUE;
3293 /* ReleaseALSources
3295 * Destroys all sources in the source map.
3297 ALvoid ReleaseALSources(ALCcontext *Context)
3299 ALsizei pos;
3300 for(pos = 0;pos < Context->SourceMap.size;pos++)
3302 ALsource *temp = Context->SourceMap.array[pos].value;
3303 Context->SourceMap.array[pos].value = NULL;
3305 DeinitSource(temp);
3307 FreeThunkEntry(temp->id);
3308 memset(temp, 0, sizeof(*temp));
3309 al_free(temp);