Only send source updates for sources that have updated
[openal-soft.git] / OpenAL32 / alSource.c
blob9ef58115538f65ff5ab31871b6b3845c5c6a6048
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <math.h>
26 #include <float.h>
28 #include "AL/al.h"
29 #include "AL/alc.h"
30 #include "alMain.h"
31 #include "alError.h"
32 #include "alSource.h"
33 #include "alBuffer.h"
34 #include "alThunk.h"
35 #include "alAuxEffectSlot.h"
37 #include "backends/base.h"
39 #include "threads.h"
40 #include "almalloc.h"
43 extern inline void LockSourcesRead(ALCcontext *context);
44 extern inline void UnlockSourcesRead(ALCcontext *context);
45 extern inline void LockSourcesWrite(ALCcontext *context);
46 extern inline void UnlockSourcesWrite(ALCcontext *context);
47 extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
48 extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
50 static void InitSourceParams(ALsource *Source);
51 static void DeinitSource(ALsource *source);
52 static void UpdateSourceProps(ALsource *source, ALuint num_sends);
53 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime);
54 static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime);
55 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device);
56 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac);
58 typedef enum SourceProp {
59 srcPitch = AL_PITCH,
60 srcGain = AL_GAIN,
61 srcMinGain = AL_MIN_GAIN,
62 srcMaxGain = AL_MAX_GAIN,
63 srcMaxDistance = AL_MAX_DISTANCE,
64 srcRolloffFactor = AL_ROLLOFF_FACTOR,
65 srcDopplerFactor = AL_DOPPLER_FACTOR,
66 srcConeOuterGain = AL_CONE_OUTER_GAIN,
67 srcSecOffset = AL_SEC_OFFSET,
68 srcSampleOffset = AL_SAMPLE_OFFSET,
69 srcByteOffset = AL_BYTE_OFFSET,
70 srcConeInnerAngle = AL_CONE_INNER_ANGLE,
71 srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
72 srcRefDistance = AL_REFERENCE_DISTANCE,
74 srcPosition = AL_POSITION,
75 srcVelocity = AL_VELOCITY,
76 srcDirection = AL_DIRECTION,
78 srcSourceRelative = AL_SOURCE_RELATIVE,
79 srcLooping = AL_LOOPING,
80 srcBuffer = AL_BUFFER,
81 srcSourceState = AL_SOURCE_STATE,
82 srcBuffersQueued = AL_BUFFERS_QUEUED,
83 srcBuffersProcessed = AL_BUFFERS_PROCESSED,
84 srcSourceType = AL_SOURCE_TYPE,
86 /* ALC_EXT_EFX */
87 srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
88 srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
89 srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
90 srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
91 srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
92 srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
93 srcDirectFilter = AL_DIRECT_FILTER,
94 srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
96 /* AL_SOFT_direct_channels */
97 srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
99 /* AL_EXT_source_distance_model */
100 srcDistanceModel = AL_DISTANCE_MODEL,
102 srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
103 srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
104 srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
106 /* AL_SOFT_source_latency */
107 srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
108 srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
110 /* AL_EXT_STEREO_ANGLES */
111 srcAngles = AL_STEREO_ANGLES,
113 /* AL_EXT_SOURCE_RADIUS */
114 srcRadius = AL_SOURCE_RADIUS,
116 /* AL_EXT_BFORMAT */
117 srcOrientation = AL_ORIENTATION,
118 } SourceProp;
120 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
121 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
122 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
124 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
125 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
126 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
128 static inline ALvoice *GetSourceVoice(const ALsource *source, const ALCcontext *context)
130 ALvoice *voice = context->Voices;
131 ALvoice *voice_end = voice + context->VoiceCount;
132 while(voice != voice_end)
134 if(voice->Source == source)
135 return voice;
137 return NULL;
140 static inline bool SourceShouldUpdate(const ALsource *source, const ALCcontext *context)
142 return (source->state == AL_PLAYING || source->state == AL_PAUSED) &&
143 !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire);
146 static ALint FloatValsByProp(ALenum prop)
148 if(prop != (ALenum)((SourceProp)prop))
149 return 0;
150 switch((SourceProp)prop)
152 case AL_PITCH:
153 case AL_GAIN:
154 case AL_MIN_GAIN:
155 case AL_MAX_GAIN:
156 case AL_MAX_DISTANCE:
157 case AL_ROLLOFF_FACTOR:
158 case AL_DOPPLER_FACTOR:
159 case AL_CONE_OUTER_GAIN:
160 case AL_SEC_OFFSET:
161 case AL_SAMPLE_OFFSET:
162 case AL_BYTE_OFFSET:
163 case AL_CONE_INNER_ANGLE:
164 case AL_CONE_OUTER_ANGLE:
165 case AL_REFERENCE_DISTANCE:
166 case AL_CONE_OUTER_GAINHF:
167 case AL_AIR_ABSORPTION_FACTOR:
168 case AL_ROOM_ROLLOFF_FACTOR:
169 case AL_DIRECT_FILTER_GAINHF_AUTO:
170 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
171 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
172 case AL_DIRECT_CHANNELS_SOFT:
173 case AL_DISTANCE_MODEL:
174 case AL_SOURCE_RELATIVE:
175 case AL_LOOPING:
176 case AL_SOURCE_STATE:
177 case AL_BUFFERS_QUEUED:
178 case AL_BUFFERS_PROCESSED:
179 case AL_SOURCE_TYPE:
180 case AL_BYTE_LENGTH_SOFT:
181 case AL_SAMPLE_LENGTH_SOFT:
182 case AL_SEC_LENGTH_SOFT:
183 case AL_SOURCE_RADIUS:
184 return 1;
186 case AL_STEREO_ANGLES:
187 return 2;
189 case AL_POSITION:
190 case AL_VELOCITY:
191 case AL_DIRECTION:
192 return 3;
194 case AL_ORIENTATION:
195 return 6;
197 case AL_SEC_OFFSET_LATENCY_SOFT:
198 break; /* Double only */
200 case AL_BUFFER:
201 case AL_DIRECT_FILTER:
202 case AL_AUXILIARY_SEND_FILTER:
203 break; /* i/i64 only */
204 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
205 break; /* i64 only */
207 return 0;
209 static ALint DoubleValsByProp(ALenum prop)
211 if(prop != (ALenum)((SourceProp)prop))
212 return 0;
213 switch((SourceProp)prop)
215 case AL_PITCH:
216 case AL_GAIN:
217 case AL_MIN_GAIN:
218 case AL_MAX_GAIN:
219 case AL_MAX_DISTANCE:
220 case AL_ROLLOFF_FACTOR:
221 case AL_DOPPLER_FACTOR:
222 case AL_CONE_OUTER_GAIN:
223 case AL_SEC_OFFSET:
224 case AL_SAMPLE_OFFSET:
225 case AL_BYTE_OFFSET:
226 case AL_CONE_INNER_ANGLE:
227 case AL_CONE_OUTER_ANGLE:
228 case AL_REFERENCE_DISTANCE:
229 case AL_CONE_OUTER_GAINHF:
230 case AL_AIR_ABSORPTION_FACTOR:
231 case AL_ROOM_ROLLOFF_FACTOR:
232 case AL_DIRECT_FILTER_GAINHF_AUTO:
233 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
234 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
235 case AL_DIRECT_CHANNELS_SOFT:
236 case AL_DISTANCE_MODEL:
237 case AL_SOURCE_RELATIVE:
238 case AL_LOOPING:
239 case AL_SOURCE_STATE:
240 case AL_BUFFERS_QUEUED:
241 case AL_BUFFERS_PROCESSED:
242 case AL_SOURCE_TYPE:
243 case AL_BYTE_LENGTH_SOFT:
244 case AL_SAMPLE_LENGTH_SOFT:
245 case AL_SEC_LENGTH_SOFT:
246 case AL_SOURCE_RADIUS:
247 return 1;
249 case AL_SEC_OFFSET_LATENCY_SOFT:
250 case AL_STEREO_ANGLES:
251 return 2;
253 case AL_POSITION:
254 case AL_VELOCITY:
255 case AL_DIRECTION:
256 return 3;
258 case AL_ORIENTATION:
259 return 6;
261 case AL_BUFFER:
262 case AL_DIRECT_FILTER:
263 case AL_AUXILIARY_SEND_FILTER:
264 break; /* i/i64 only */
265 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
266 break; /* i64 only */
268 return 0;
271 static ALint IntValsByProp(ALenum prop)
273 if(prop != (ALenum)((SourceProp)prop))
274 return 0;
275 switch((SourceProp)prop)
277 case AL_PITCH:
278 case AL_GAIN:
279 case AL_MIN_GAIN:
280 case AL_MAX_GAIN:
281 case AL_MAX_DISTANCE:
282 case AL_ROLLOFF_FACTOR:
283 case AL_DOPPLER_FACTOR:
284 case AL_CONE_OUTER_GAIN:
285 case AL_SEC_OFFSET:
286 case AL_SAMPLE_OFFSET:
287 case AL_BYTE_OFFSET:
288 case AL_CONE_INNER_ANGLE:
289 case AL_CONE_OUTER_ANGLE:
290 case AL_REFERENCE_DISTANCE:
291 case AL_CONE_OUTER_GAINHF:
292 case AL_AIR_ABSORPTION_FACTOR:
293 case AL_ROOM_ROLLOFF_FACTOR:
294 case AL_DIRECT_FILTER_GAINHF_AUTO:
295 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
296 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
297 case AL_DIRECT_CHANNELS_SOFT:
298 case AL_DISTANCE_MODEL:
299 case AL_SOURCE_RELATIVE:
300 case AL_LOOPING:
301 case AL_BUFFER:
302 case AL_SOURCE_STATE:
303 case AL_BUFFERS_QUEUED:
304 case AL_BUFFERS_PROCESSED:
305 case AL_SOURCE_TYPE:
306 case AL_DIRECT_FILTER:
307 case AL_BYTE_LENGTH_SOFT:
308 case AL_SAMPLE_LENGTH_SOFT:
309 case AL_SEC_LENGTH_SOFT:
310 case AL_SOURCE_RADIUS:
311 return 1;
313 case AL_POSITION:
314 case AL_VELOCITY:
315 case AL_DIRECTION:
316 case AL_AUXILIARY_SEND_FILTER:
317 return 3;
319 case AL_ORIENTATION:
320 return 6;
322 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
323 break; /* i64 only */
324 case AL_SEC_OFFSET_LATENCY_SOFT:
325 break; /* Double only */
326 case AL_STEREO_ANGLES:
327 break; /* Float/double only */
329 return 0;
331 static ALint Int64ValsByProp(ALenum prop)
333 if(prop != (ALenum)((SourceProp)prop))
334 return 0;
335 switch((SourceProp)prop)
337 case AL_PITCH:
338 case AL_GAIN:
339 case AL_MIN_GAIN:
340 case AL_MAX_GAIN:
341 case AL_MAX_DISTANCE:
342 case AL_ROLLOFF_FACTOR:
343 case AL_DOPPLER_FACTOR:
344 case AL_CONE_OUTER_GAIN:
345 case AL_SEC_OFFSET:
346 case AL_SAMPLE_OFFSET:
347 case AL_BYTE_OFFSET:
348 case AL_CONE_INNER_ANGLE:
349 case AL_CONE_OUTER_ANGLE:
350 case AL_REFERENCE_DISTANCE:
351 case AL_CONE_OUTER_GAINHF:
352 case AL_AIR_ABSORPTION_FACTOR:
353 case AL_ROOM_ROLLOFF_FACTOR:
354 case AL_DIRECT_FILTER_GAINHF_AUTO:
355 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
356 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
357 case AL_DIRECT_CHANNELS_SOFT:
358 case AL_DISTANCE_MODEL:
359 case AL_SOURCE_RELATIVE:
360 case AL_LOOPING:
361 case AL_BUFFER:
362 case AL_SOURCE_STATE:
363 case AL_BUFFERS_QUEUED:
364 case AL_BUFFERS_PROCESSED:
365 case AL_SOURCE_TYPE:
366 case AL_DIRECT_FILTER:
367 case AL_BYTE_LENGTH_SOFT:
368 case AL_SAMPLE_LENGTH_SOFT:
369 case AL_SEC_LENGTH_SOFT:
370 case AL_SOURCE_RADIUS:
371 return 1;
373 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
374 return 2;
376 case AL_POSITION:
377 case AL_VELOCITY:
378 case AL_DIRECTION:
379 case AL_AUXILIARY_SEND_FILTER:
380 return 3;
382 case AL_ORIENTATION:
383 return 6;
385 case AL_SEC_OFFSET_LATENCY_SOFT:
386 break; /* Double only */
387 case AL_STEREO_ANGLES:
388 break; /* Float/double only */
390 return 0;
394 #define CHECKVAL(x) do { \
395 if(!(x)) \
396 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
397 } while(0)
399 #define DO_UPDATEPROPS() do { \
400 if(SourceShouldUpdate(Source, Context)) \
401 UpdateSourceProps(Source, device->NumAuxSends); \
402 else \
403 Source->NeedsUpdate = AL_TRUE; \
404 } while(0)
406 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
408 ALCdevice *device = Context->Device;
409 ALint ival;
411 switch(prop)
413 case AL_BYTE_LENGTH_SOFT:
414 case AL_SAMPLE_LENGTH_SOFT:
415 case AL_SEC_LENGTH_SOFT:
416 case AL_SEC_OFFSET_LATENCY_SOFT:
417 /* Query only */
418 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
420 case AL_PITCH:
421 CHECKVAL(*values >= 0.0f);
423 Source->Pitch = *values;
424 DO_UPDATEPROPS();
425 return AL_TRUE;
427 case AL_CONE_INNER_ANGLE:
428 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
430 Source->InnerAngle = *values;
431 DO_UPDATEPROPS();
432 return AL_TRUE;
434 case AL_CONE_OUTER_ANGLE:
435 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
437 Source->OuterAngle = *values;
438 DO_UPDATEPROPS();
439 return AL_TRUE;
441 case AL_GAIN:
442 CHECKVAL(*values >= 0.0f);
444 Source->Gain = *values;
445 DO_UPDATEPROPS();
446 return AL_TRUE;
448 case AL_MAX_DISTANCE:
449 CHECKVAL(*values >= 0.0f);
451 Source->MaxDistance = *values;
452 DO_UPDATEPROPS();
453 return AL_TRUE;
455 case AL_ROLLOFF_FACTOR:
456 CHECKVAL(*values >= 0.0f);
458 Source->RollOffFactor = *values;
459 DO_UPDATEPROPS();
460 return AL_TRUE;
462 case AL_REFERENCE_DISTANCE:
463 CHECKVAL(*values >= 0.0f);
465 Source->RefDistance = *values;
466 DO_UPDATEPROPS();
467 return AL_TRUE;
469 case AL_MIN_GAIN:
470 CHECKVAL(*values >= 0.0f);
472 Source->MinGain = *values;
473 DO_UPDATEPROPS();
474 return AL_TRUE;
476 case AL_MAX_GAIN:
477 CHECKVAL(*values >= 0.0f);
479 Source->MaxGain = *values;
480 DO_UPDATEPROPS();
481 return AL_TRUE;
483 case AL_CONE_OUTER_GAIN:
484 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
486 Source->OuterGain = *values;
487 DO_UPDATEPROPS();
488 return AL_TRUE;
490 case AL_CONE_OUTER_GAINHF:
491 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
493 Source->OuterGainHF = *values;
494 DO_UPDATEPROPS();
495 return AL_TRUE;
497 case AL_AIR_ABSORPTION_FACTOR:
498 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
500 Source->AirAbsorptionFactor = *values;
501 DO_UPDATEPROPS();
502 return AL_TRUE;
504 case AL_ROOM_ROLLOFF_FACTOR:
505 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
507 Source->RoomRolloffFactor = *values;
508 DO_UPDATEPROPS();
509 return AL_TRUE;
511 case AL_DOPPLER_FACTOR:
512 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
514 Source->DopplerFactor = *values;
515 DO_UPDATEPROPS();
516 return AL_TRUE;
518 case AL_SEC_OFFSET:
519 case AL_SAMPLE_OFFSET:
520 case AL_BYTE_OFFSET:
521 CHECKVAL(*values >= 0.0f);
523 Source->OffsetType = prop;
524 Source->Offset = *values;
526 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
527 !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire))
529 LockContext(Context);
530 WriteLock(&Source->queue_lock);
531 if(ApplyOffset(Source) == AL_FALSE)
533 WriteUnlock(&Source->queue_lock);
534 UnlockContext(Context);
535 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
537 WriteUnlock(&Source->queue_lock);
538 UnlockContext(Context);
540 return AL_TRUE;
542 case AL_SOURCE_RADIUS:
543 CHECKVAL(*values >= 0.0f && isfinite(*values));
545 Source->Radius = *values;
546 DO_UPDATEPROPS();
547 return AL_TRUE;
549 case AL_STEREO_ANGLES:
550 CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
552 Source->StereoPan[0] = values[0];
553 Source->StereoPan[1] = values[1];
554 DO_UPDATEPROPS();
555 return AL_TRUE;
558 case AL_POSITION:
559 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
561 Source->Position[0] = values[0];
562 Source->Position[1] = values[1];
563 Source->Position[2] = values[2];
564 DO_UPDATEPROPS();
565 return AL_TRUE;
567 case AL_VELOCITY:
568 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
570 Source->Velocity[0] = values[0];
571 Source->Velocity[1] = values[1];
572 Source->Velocity[2] = values[2];
573 DO_UPDATEPROPS();
574 return AL_TRUE;
576 case AL_DIRECTION:
577 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
579 Source->Direction[0] = values[0];
580 Source->Direction[1] = values[1];
581 Source->Direction[2] = values[2];
582 DO_UPDATEPROPS();
583 return AL_TRUE;
585 case AL_ORIENTATION:
586 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
587 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
589 Source->Orientation[0][0] = values[0];
590 Source->Orientation[0][1] = values[1];
591 Source->Orientation[0][2] = values[2];
592 Source->Orientation[1][0] = values[3];
593 Source->Orientation[1][1] = values[4];
594 Source->Orientation[1][2] = values[5];
595 DO_UPDATEPROPS();
596 return AL_TRUE;
599 case AL_SOURCE_RELATIVE:
600 case AL_LOOPING:
601 case AL_SOURCE_STATE:
602 case AL_SOURCE_TYPE:
603 case AL_DISTANCE_MODEL:
604 case AL_DIRECT_FILTER_GAINHF_AUTO:
605 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
606 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
607 case AL_DIRECT_CHANNELS_SOFT:
608 ival = (ALint)values[0];
609 return SetSourceiv(Source, Context, prop, &ival);
611 case AL_BUFFERS_QUEUED:
612 case AL_BUFFERS_PROCESSED:
613 ival = (ALint)((ALuint)values[0]);
614 return SetSourceiv(Source, Context, prop, &ival);
616 case AL_BUFFER:
617 case AL_DIRECT_FILTER:
618 case AL_AUXILIARY_SEND_FILTER:
619 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
620 break;
623 ERR("Unexpected property: 0x%04x\n", prop);
624 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
627 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
629 ALCdevice *device = Context->Device;
630 ALbuffer *buffer = NULL;
631 ALfilter *filter = NULL;
632 ALeffectslot *slot = NULL;
633 ALbufferlistitem *oldlist;
634 ALbufferlistitem *newlist;
635 ALfloat fvals[6];
637 switch(prop)
639 case AL_SOURCE_STATE:
640 case AL_SOURCE_TYPE:
641 case AL_BUFFERS_QUEUED:
642 case AL_BUFFERS_PROCESSED:
643 case AL_BYTE_LENGTH_SOFT:
644 case AL_SAMPLE_LENGTH_SOFT:
645 case AL_SEC_LENGTH_SOFT:
646 /* Query only */
647 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
649 case AL_SOURCE_RELATIVE:
650 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
652 Source->HeadRelative = (ALboolean)*values;
653 DO_UPDATEPROPS();
654 return AL_TRUE;
656 case AL_LOOPING:
657 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
659 WriteLock(&Source->queue_lock);
660 ATOMIC_STORE(&Source->looping, *values);
661 WriteUnlock(&Source->queue_lock);
662 return AL_TRUE;
664 case AL_BUFFER:
665 LockBuffersRead(device);
666 if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
668 UnlockBuffersRead(device);
669 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
672 WriteLock(&Source->queue_lock);
673 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
675 WriteUnlock(&Source->queue_lock);
676 UnlockBuffersRead(device);
677 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
680 if(buffer != NULL)
682 /* Add the selected buffer to a one-item queue */
683 newlist = malloc(sizeof(ALbufferlistitem));
684 newlist->buffer = buffer;
685 newlist->next = NULL;
686 IncrementRef(&buffer->ref);
688 /* Source is now Static */
689 Source->SourceType = AL_STATIC;
691 ReadLock(&buffer->lock);
692 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
693 Source->SampleSize = BytesFromFmt(buffer->FmtType);
694 ReadUnlock(&buffer->lock);
696 else
698 /* Source is now Undetermined */
699 Source->SourceType = AL_UNDETERMINED;
700 newlist = NULL;
702 oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist);
703 ATOMIC_STORE(&Source->current_buffer, newlist);
704 WriteUnlock(&Source->queue_lock);
705 UnlockBuffersRead(device);
707 /* Delete all elements in the previous queue */
708 while(oldlist != NULL)
710 ALbufferlistitem *temp = oldlist;
711 oldlist = temp->next;
713 if(temp->buffer)
714 DecrementRef(&temp->buffer->ref);
715 free(temp);
717 return AL_TRUE;
719 case AL_SEC_OFFSET:
720 case AL_SAMPLE_OFFSET:
721 case AL_BYTE_OFFSET:
722 CHECKVAL(*values >= 0);
724 Source->OffsetType = prop;
725 Source->Offset = *values;
727 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
728 !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire))
730 LockContext(Context);
731 WriteLock(&Source->queue_lock);
732 if(ApplyOffset(Source) == AL_FALSE)
734 WriteUnlock(&Source->queue_lock);
735 UnlockContext(Context);
736 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
738 WriteUnlock(&Source->queue_lock);
739 UnlockContext(Context);
741 return AL_TRUE;
743 case AL_DIRECT_FILTER:
744 LockFiltersRead(device);
745 if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
747 UnlockFiltersRead(device);
748 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
751 if(!filter)
753 Source->Direct.Gain = 1.0f;
754 Source->Direct.GainHF = 1.0f;
755 Source->Direct.HFReference = LOWPASSFREQREF;
756 Source->Direct.GainLF = 1.0f;
757 Source->Direct.LFReference = HIGHPASSFREQREF;
759 else
761 Source->Direct.Gain = filter->Gain;
762 Source->Direct.GainHF = filter->GainHF;
763 Source->Direct.HFReference = filter->HFReference;
764 Source->Direct.GainLF = filter->GainLF;
765 Source->Direct.LFReference = filter->LFReference;
767 UnlockFiltersRead(device);
768 DO_UPDATEPROPS();
769 return AL_TRUE;
771 case AL_DIRECT_FILTER_GAINHF_AUTO:
772 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
774 Source->DryGainHFAuto = *values;
775 DO_UPDATEPROPS();
776 return AL_TRUE;
778 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
779 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
781 Source->WetGainAuto = *values;
782 DO_UPDATEPROPS();
783 return AL_TRUE;
785 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
786 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
788 Source->WetGainHFAuto = *values;
789 DO_UPDATEPROPS();
790 return AL_TRUE;
792 case AL_DIRECT_CHANNELS_SOFT:
793 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
795 Source->DirectChannels = *values;
796 DO_UPDATEPROPS();
797 return AL_TRUE;
799 case AL_DISTANCE_MODEL:
800 CHECKVAL(*values == AL_NONE ||
801 *values == AL_INVERSE_DISTANCE ||
802 *values == AL_INVERSE_DISTANCE_CLAMPED ||
803 *values == AL_LINEAR_DISTANCE ||
804 *values == AL_LINEAR_DISTANCE_CLAMPED ||
805 *values == AL_EXPONENT_DISTANCE ||
806 *values == AL_EXPONENT_DISTANCE_CLAMPED);
808 Source->DistanceModel = *values;
809 if(Context->SourceDistanceModel)
810 DO_UPDATEPROPS();
811 return AL_TRUE;
814 case AL_AUXILIARY_SEND_FILTER:
815 LockEffectSlotsRead(Context);
816 LockFiltersRead(device);
817 if(!((ALuint)values[1] < device->NumAuxSends &&
818 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
819 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
821 UnlockFiltersRead(device);
822 UnlockEffectSlotsRead(Context);
823 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
826 if(!filter)
828 /* Disable filter */
829 Source->Send[values[1]].Gain = 1.0f;
830 Source->Send[values[1]].GainHF = 1.0f;
831 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
832 Source->Send[values[1]].GainLF = 1.0f;
833 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
835 else
837 Source->Send[values[1]].Gain = filter->Gain;
838 Source->Send[values[1]].GainHF = filter->GainHF;
839 Source->Send[values[1]].HFReference = filter->HFReference;
840 Source->Send[values[1]].GainLF = filter->GainLF;
841 Source->Send[values[1]].LFReference = filter->LFReference;
843 UnlockFiltersRead(device);
845 if(slot != Source->Send[values[1]].Slot &&
846 (Source->state == AL_PLAYING || Source->state == AL_PAUSED))
848 /* Add refcount on the new slot, and release the previous slot */
849 if(slot) IncrementRef(&slot->ref);
850 if(Source->Send[values[1]].Slot)
851 DecrementRef(&Source->Send[values[1]].Slot->ref);
852 Source->Send[values[1]].Slot = slot;
854 /* We must force an update if the auxiliary slot changed on a
855 * playing source, in case the slot is about to be deleted.
857 UpdateSourceProps(Source, device->NumAuxSends);
859 else
861 if(slot) IncrementRef(&slot->ref);
862 if(Source->Send[values[1]].Slot)
863 DecrementRef(&Source->Send[values[1]].Slot->ref);
864 Source->Send[values[1]].Slot = slot;
865 DO_UPDATEPROPS();
867 UnlockEffectSlotsRead(Context);
869 return AL_TRUE;
872 /* 1x float */
873 case AL_CONE_INNER_ANGLE:
874 case AL_CONE_OUTER_ANGLE:
875 case AL_PITCH:
876 case AL_GAIN:
877 case AL_MIN_GAIN:
878 case AL_MAX_GAIN:
879 case AL_REFERENCE_DISTANCE:
880 case AL_ROLLOFF_FACTOR:
881 case AL_CONE_OUTER_GAIN:
882 case AL_MAX_DISTANCE:
883 case AL_DOPPLER_FACTOR:
884 case AL_CONE_OUTER_GAINHF:
885 case AL_AIR_ABSORPTION_FACTOR:
886 case AL_ROOM_ROLLOFF_FACTOR:
887 case AL_SOURCE_RADIUS:
888 fvals[0] = (ALfloat)*values;
889 return SetSourcefv(Source, Context, (int)prop, fvals);
891 /* 3x float */
892 case AL_POSITION:
893 case AL_VELOCITY:
894 case AL_DIRECTION:
895 fvals[0] = (ALfloat)values[0];
896 fvals[1] = (ALfloat)values[1];
897 fvals[2] = (ALfloat)values[2];
898 return SetSourcefv(Source, Context, (int)prop, fvals);
900 /* 6x float */
901 case AL_ORIENTATION:
902 fvals[0] = (ALfloat)values[0];
903 fvals[1] = (ALfloat)values[1];
904 fvals[2] = (ALfloat)values[2];
905 fvals[3] = (ALfloat)values[3];
906 fvals[4] = (ALfloat)values[4];
907 fvals[5] = (ALfloat)values[5];
908 return SetSourcefv(Source, Context, (int)prop, fvals);
910 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
911 case AL_SEC_OFFSET_LATENCY_SOFT:
912 case AL_STEREO_ANGLES:
913 break;
916 ERR("Unexpected property: 0x%04x\n", prop);
917 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
920 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
922 ALfloat fvals[6];
923 ALint ivals[3];
925 switch(prop)
927 case AL_SOURCE_TYPE:
928 case AL_BUFFERS_QUEUED:
929 case AL_BUFFERS_PROCESSED:
930 case AL_SOURCE_STATE:
931 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
932 case AL_BYTE_LENGTH_SOFT:
933 case AL_SAMPLE_LENGTH_SOFT:
934 case AL_SEC_LENGTH_SOFT:
935 /* Query only */
936 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
939 /* 1x int */
940 case AL_SOURCE_RELATIVE:
941 case AL_LOOPING:
942 case AL_SEC_OFFSET:
943 case AL_SAMPLE_OFFSET:
944 case AL_BYTE_OFFSET:
945 case AL_DIRECT_FILTER_GAINHF_AUTO:
946 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
947 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
948 case AL_DIRECT_CHANNELS_SOFT:
949 case AL_DISTANCE_MODEL:
950 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
952 ivals[0] = (ALint)*values;
953 return SetSourceiv(Source, Context, (int)prop, ivals);
955 /* 1x uint */
956 case AL_BUFFER:
957 case AL_DIRECT_FILTER:
958 CHECKVAL(*values <= UINT_MAX && *values >= 0);
960 ivals[0] = (ALuint)*values;
961 return SetSourceiv(Source, Context, (int)prop, ivals);
963 /* 3x uint */
964 case AL_AUXILIARY_SEND_FILTER:
965 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
966 values[1] <= UINT_MAX && values[1] >= 0 &&
967 values[2] <= UINT_MAX && values[2] >= 0);
969 ivals[0] = (ALuint)values[0];
970 ivals[1] = (ALuint)values[1];
971 ivals[2] = (ALuint)values[2];
972 return SetSourceiv(Source, Context, (int)prop, ivals);
974 /* 1x float */
975 case AL_CONE_INNER_ANGLE:
976 case AL_CONE_OUTER_ANGLE:
977 case AL_PITCH:
978 case AL_GAIN:
979 case AL_MIN_GAIN:
980 case AL_MAX_GAIN:
981 case AL_REFERENCE_DISTANCE:
982 case AL_ROLLOFF_FACTOR:
983 case AL_CONE_OUTER_GAIN:
984 case AL_MAX_DISTANCE:
985 case AL_DOPPLER_FACTOR:
986 case AL_CONE_OUTER_GAINHF:
987 case AL_AIR_ABSORPTION_FACTOR:
988 case AL_ROOM_ROLLOFF_FACTOR:
989 case AL_SOURCE_RADIUS:
990 fvals[0] = (ALfloat)*values;
991 return SetSourcefv(Source, Context, (int)prop, fvals);
993 /* 3x float */
994 case AL_POSITION:
995 case AL_VELOCITY:
996 case AL_DIRECTION:
997 fvals[0] = (ALfloat)values[0];
998 fvals[1] = (ALfloat)values[1];
999 fvals[2] = (ALfloat)values[2];
1000 return SetSourcefv(Source, Context, (int)prop, fvals);
1002 /* 6x float */
1003 case AL_ORIENTATION:
1004 fvals[0] = (ALfloat)values[0];
1005 fvals[1] = (ALfloat)values[1];
1006 fvals[2] = (ALfloat)values[2];
1007 fvals[3] = (ALfloat)values[3];
1008 fvals[4] = (ALfloat)values[4];
1009 fvals[5] = (ALfloat)values[5];
1010 return SetSourcefv(Source, Context, (int)prop, fvals);
1012 case AL_SEC_OFFSET_LATENCY_SOFT:
1013 case AL_STEREO_ANGLES:
1014 break;
1017 ERR("Unexpected property: 0x%04x\n", prop);
1018 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1021 #undef CHECKVAL
1024 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
1026 ALCdevice *device = Context->Device;
1027 ALbufferlistitem *BufferList;
1028 ClockLatency clocktime;
1029 ALuint64 srcclock;
1030 ALint ivals[3];
1031 ALboolean err;
1033 switch(prop)
1035 case AL_GAIN:
1036 *values = Source->Gain;
1037 return AL_TRUE;
1039 case AL_PITCH:
1040 *values = Source->Pitch;
1041 return AL_TRUE;
1043 case AL_MAX_DISTANCE:
1044 *values = Source->MaxDistance;
1045 return AL_TRUE;
1047 case AL_ROLLOFF_FACTOR:
1048 *values = Source->RollOffFactor;
1049 return AL_TRUE;
1051 case AL_REFERENCE_DISTANCE:
1052 *values = Source->RefDistance;
1053 return AL_TRUE;
1055 case AL_CONE_INNER_ANGLE:
1056 *values = Source->InnerAngle;
1057 return AL_TRUE;
1059 case AL_CONE_OUTER_ANGLE:
1060 *values = Source->OuterAngle;
1061 return AL_TRUE;
1063 case AL_MIN_GAIN:
1064 *values = Source->MinGain;
1065 return AL_TRUE;
1067 case AL_MAX_GAIN:
1068 *values = Source->MaxGain;
1069 return AL_TRUE;
1071 case AL_CONE_OUTER_GAIN:
1072 *values = Source->OuterGain;
1073 return AL_TRUE;
1075 case AL_SEC_OFFSET:
1076 case AL_SAMPLE_OFFSET:
1077 case AL_BYTE_OFFSET:
1078 *values = GetSourceOffset(Source, prop, device);
1079 return AL_TRUE;
1081 case AL_CONE_OUTER_GAINHF:
1082 *values = Source->OuterGainHF;
1083 return AL_TRUE;
1085 case AL_AIR_ABSORPTION_FACTOR:
1086 *values = Source->AirAbsorptionFactor;
1087 return AL_TRUE;
1089 case AL_ROOM_ROLLOFF_FACTOR:
1090 *values = Source->RoomRolloffFactor;
1091 return AL_TRUE;
1093 case AL_DOPPLER_FACTOR:
1094 *values = Source->DopplerFactor;
1095 return AL_TRUE;
1097 case AL_SEC_LENGTH_SOFT:
1098 ReadLock(&Source->queue_lock);
1099 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1100 *values = 0;
1101 else
1103 ALint length = 0;
1104 ALsizei freq = 1;
1105 do {
1106 ALbuffer *buffer = BufferList->buffer;
1107 if(buffer && buffer->SampleLen > 0)
1109 freq = buffer->Frequency;
1110 length += buffer->SampleLen;
1112 } while((BufferList=BufferList->next) != NULL);
1113 *values = (ALdouble)length / (ALdouble)freq;
1115 ReadUnlock(&Source->queue_lock);
1116 return AL_TRUE;
1118 case AL_SOURCE_RADIUS:
1119 *values = Source->Radius;
1120 return AL_TRUE;
1122 case AL_STEREO_ANGLES:
1123 values[0] = Source->StereoPan[0];
1124 values[1] = Source->StereoPan[1];
1125 return AL_TRUE;
1127 case AL_SEC_OFFSET_LATENCY_SOFT:
1128 /* Get the source offset with the clock time first. Then get the
1129 * clock time with the device latency. Order is important.
1131 values[0] = GetSourceSecOffset(Source, device, &srcclock);
1132 clocktime = V0(device->Backend,getClockLatency)();
1133 if(srcclock == (ALuint64)clocktime.ClockTime)
1134 values[1] = (ALdouble)clocktime.Latency / 1000000000.0;
1135 else
1137 /* If the clock time incremented, reduce the latency by that
1138 * much since it's that much closer to the source offset it got
1139 * earlier.
1141 ALuint64 diff = clocktime.ClockTime - srcclock;
1142 values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) /
1143 1000000000.0;
1145 return AL_TRUE;
1147 case AL_POSITION:
1148 values[0] = Source->Position[0];
1149 values[1] = Source->Position[1];
1150 values[2] = Source->Position[2];
1151 return AL_TRUE;
1153 case AL_VELOCITY:
1154 values[0] = Source->Velocity[0];
1155 values[1] = Source->Velocity[1];
1156 values[2] = Source->Velocity[2];
1157 return AL_TRUE;
1159 case AL_DIRECTION:
1160 values[0] = Source->Direction[0];
1161 values[1] = Source->Direction[1];
1162 values[2] = Source->Direction[2];
1163 return AL_TRUE;
1165 case AL_ORIENTATION:
1166 values[0] = Source->Orientation[0][0];
1167 values[1] = Source->Orientation[0][1];
1168 values[2] = Source->Orientation[0][2];
1169 values[3] = Source->Orientation[1][0];
1170 values[4] = Source->Orientation[1][1];
1171 values[5] = Source->Orientation[1][2];
1172 return AL_TRUE;
1174 /* 1x int */
1175 case AL_SOURCE_RELATIVE:
1176 case AL_LOOPING:
1177 case AL_SOURCE_STATE:
1178 case AL_BUFFERS_QUEUED:
1179 case AL_BUFFERS_PROCESSED:
1180 case AL_SOURCE_TYPE:
1181 case AL_DIRECT_FILTER_GAINHF_AUTO:
1182 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1183 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1184 case AL_DIRECT_CHANNELS_SOFT:
1185 case AL_BYTE_LENGTH_SOFT:
1186 case AL_SAMPLE_LENGTH_SOFT:
1187 case AL_DISTANCE_MODEL:
1188 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1189 *values = (ALdouble)ivals[0];
1190 return err;
1192 case AL_BUFFER:
1193 case AL_DIRECT_FILTER:
1194 case AL_AUXILIARY_SEND_FILTER:
1195 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1196 break;
1199 ERR("Unexpected property: 0x%04x\n", prop);
1200 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1203 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1205 ALbufferlistitem *BufferList;
1206 ALdouble dvals[6];
1207 ALboolean err;
1209 switch(prop)
1211 case AL_SOURCE_RELATIVE:
1212 *values = Source->HeadRelative;
1213 return AL_TRUE;
1215 case AL_LOOPING:
1216 *values = ATOMIC_LOAD(&Source->looping);
1217 return AL_TRUE;
1219 case AL_BUFFER:
1220 ReadLock(&Source->queue_lock);
1221 BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) :
1222 ATOMIC_LOAD(&Source->current_buffer);
1223 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1224 ReadUnlock(&Source->queue_lock);
1225 return AL_TRUE;
1227 case AL_SOURCE_STATE:
1228 *values = Source->state;
1229 return AL_TRUE;
1231 case AL_BYTE_LENGTH_SOFT:
1232 ReadLock(&Source->queue_lock);
1233 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1234 *values = 0;
1235 else
1237 ALint length = 0;
1238 do {
1239 ALbuffer *buffer = BufferList->buffer;
1240 if(buffer && buffer->SampleLen > 0)
1242 ALuint byte_align, sample_align;
1243 if(buffer->OriginalType == UserFmtIMA4)
1245 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1246 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1247 sample_align = buffer->OriginalAlign;
1249 else if(buffer->OriginalType == UserFmtMSADPCM)
1251 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1252 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1253 sample_align = buffer->OriginalAlign;
1255 else
1257 ALsizei align = buffer->OriginalAlign;
1258 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1259 sample_align = buffer->OriginalAlign;
1262 length += buffer->SampleLen / sample_align * byte_align;
1264 } while((BufferList=BufferList->next) != NULL);
1265 *values = length;
1267 ReadUnlock(&Source->queue_lock);
1268 return AL_TRUE;
1270 case AL_SAMPLE_LENGTH_SOFT:
1271 ReadLock(&Source->queue_lock);
1272 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1273 *values = 0;
1274 else
1276 ALint length = 0;
1277 do {
1278 ALbuffer *buffer = BufferList->buffer;
1279 if(buffer) length += buffer->SampleLen;
1280 } while((BufferList=BufferList->next) != NULL);
1281 *values = length;
1283 ReadUnlock(&Source->queue_lock);
1284 return AL_TRUE;
1286 case AL_BUFFERS_QUEUED:
1287 ReadLock(&Source->queue_lock);
1288 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1289 *values = 0;
1290 else
1292 ALsizei count = 0;
1293 do {
1294 ++count;
1295 } while((BufferList=BufferList->next) != NULL);
1296 *values = count;
1298 ReadUnlock(&Source->queue_lock);
1299 return AL_TRUE;
1301 case AL_BUFFERS_PROCESSED:
1302 ReadLock(&Source->queue_lock);
1303 if(ATOMIC_LOAD(&Source->looping) || Source->SourceType != AL_STREAMING)
1305 /* Buffers on a looping source are in a perpetual state of
1306 * PENDING, so don't report any as PROCESSED */
1307 *values = 0;
1309 else
1311 const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue);
1312 const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer);
1313 ALsizei played = 0;
1314 while(BufferList && BufferList != Current)
1316 played++;
1317 BufferList = BufferList->next;
1319 *values = played;
1321 ReadUnlock(&Source->queue_lock);
1322 return AL_TRUE;
1324 case AL_SOURCE_TYPE:
1325 *values = Source->SourceType;
1326 return AL_TRUE;
1328 case AL_DIRECT_FILTER_GAINHF_AUTO:
1329 *values = Source->DryGainHFAuto;
1330 return AL_TRUE;
1332 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1333 *values = Source->WetGainAuto;
1334 return AL_TRUE;
1336 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1337 *values = Source->WetGainHFAuto;
1338 return AL_TRUE;
1340 case AL_DIRECT_CHANNELS_SOFT:
1341 *values = Source->DirectChannels;
1342 return AL_TRUE;
1344 case AL_DISTANCE_MODEL:
1345 *values = Source->DistanceModel;
1346 return AL_TRUE;
1348 /* 1x float/double */
1349 case AL_CONE_INNER_ANGLE:
1350 case AL_CONE_OUTER_ANGLE:
1351 case AL_PITCH:
1352 case AL_GAIN:
1353 case AL_MIN_GAIN:
1354 case AL_MAX_GAIN:
1355 case AL_REFERENCE_DISTANCE:
1356 case AL_ROLLOFF_FACTOR:
1357 case AL_CONE_OUTER_GAIN:
1358 case AL_MAX_DISTANCE:
1359 case AL_SEC_OFFSET:
1360 case AL_SAMPLE_OFFSET:
1361 case AL_BYTE_OFFSET:
1362 case AL_DOPPLER_FACTOR:
1363 case AL_AIR_ABSORPTION_FACTOR:
1364 case AL_ROOM_ROLLOFF_FACTOR:
1365 case AL_CONE_OUTER_GAINHF:
1366 case AL_SEC_LENGTH_SOFT:
1367 case AL_SOURCE_RADIUS:
1368 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1369 *values = (ALint)dvals[0];
1370 return err;
1372 /* 3x float/double */
1373 case AL_POSITION:
1374 case AL_VELOCITY:
1375 case AL_DIRECTION:
1376 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1378 values[0] = (ALint)dvals[0];
1379 values[1] = (ALint)dvals[1];
1380 values[2] = (ALint)dvals[2];
1382 return err;
1384 /* 6x float/double */
1385 case AL_ORIENTATION:
1386 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1388 values[0] = (ALint)dvals[0];
1389 values[1] = (ALint)dvals[1];
1390 values[2] = (ALint)dvals[2];
1391 values[3] = (ALint)dvals[3];
1392 values[4] = (ALint)dvals[4];
1393 values[5] = (ALint)dvals[5];
1395 return err;
1397 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1398 break; /* i64 only */
1399 case AL_SEC_OFFSET_LATENCY_SOFT:
1400 break; /* Double only */
1401 case AL_STEREO_ANGLES:
1402 break; /* Float/double only */
1404 case AL_DIRECT_FILTER:
1405 case AL_AUXILIARY_SEND_FILTER:
1406 break; /* ??? */
1409 ERR("Unexpected property: 0x%04x\n", prop);
1410 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1413 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1415 ALCdevice *device = Context->Device;
1416 ClockLatency clocktime;
1417 ALuint64 srcclock;
1418 ALdouble dvals[6];
1419 ALint ivals[3];
1420 ALboolean err;
1422 switch(prop)
1424 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1425 /* Get the source offset with the clock time first. Then get the
1426 * clock time with the device latency. Order is important.
1428 values[0] = GetSourceSampleOffset(Source, device, &srcclock);
1429 clocktime = V0(device->Backend,getClockLatency)();
1430 if(srcclock == (ALuint64)clocktime.ClockTime)
1431 values[1] = clocktime.Latency;
1432 else
1434 /* If the clock time incremented, reduce the latency by that
1435 * much since it's that much closer to the source offset it got
1436 * earlier.
1438 ALuint64 diff = clocktime.ClockTime - srcclock;
1439 values[1] = clocktime.Latency - minu64(clocktime.Latency, diff);
1441 return AL_TRUE;
1443 /* 1x float/double */
1444 case AL_CONE_INNER_ANGLE:
1445 case AL_CONE_OUTER_ANGLE:
1446 case AL_PITCH:
1447 case AL_GAIN:
1448 case AL_MIN_GAIN:
1449 case AL_MAX_GAIN:
1450 case AL_REFERENCE_DISTANCE:
1451 case AL_ROLLOFF_FACTOR:
1452 case AL_CONE_OUTER_GAIN:
1453 case AL_MAX_DISTANCE:
1454 case AL_SEC_OFFSET:
1455 case AL_SAMPLE_OFFSET:
1456 case AL_BYTE_OFFSET:
1457 case AL_DOPPLER_FACTOR:
1458 case AL_AIR_ABSORPTION_FACTOR:
1459 case AL_ROOM_ROLLOFF_FACTOR:
1460 case AL_CONE_OUTER_GAINHF:
1461 case AL_SEC_LENGTH_SOFT:
1462 case AL_SOURCE_RADIUS:
1463 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1464 *values = (ALint64)dvals[0];
1465 return err;
1467 /* 3x float/double */
1468 case AL_POSITION:
1469 case AL_VELOCITY:
1470 case AL_DIRECTION:
1471 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1473 values[0] = (ALint64)dvals[0];
1474 values[1] = (ALint64)dvals[1];
1475 values[2] = (ALint64)dvals[2];
1477 return err;
1479 /* 6x float/double */
1480 case AL_ORIENTATION:
1481 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1483 values[0] = (ALint64)dvals[0];
1484 values[1] = (ALint64)dvals[1];
1485 values[2] = (ALint64)dvals[2];
1486 values[3] = (ALint64)dvals[3];
1487 values[4] = (ALint64)dvals[4];
1488 values[5] = (ALint64)dvals[5];
1490 return err;
1492 /* 1x int */
1493 case AL_SOURCE_RELATIVE:
1494 case AL_LOOPING:
1495 case AL_SOURCE_STATE:
1496 case AL_BUFFERS_QUEUED:
1497 case AL_BUFFERS_PROCESSED:
1498 case AL_BYTE_LENGTH_SOFT:
1499 case AL_SAMPLE_LENGTH_SOFT:
1500 case AL_SOURCE_TYPE:
1501 case AL_DIRECT_FILTER_GAINHF_AUTO:
1502 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1503 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1504 case AL_DIRECT_CHANNELS_SOFT:
1505 case AL_DISTANCE_MODEL:
1506 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1507 *values = ivals[0];
1508 return err;
1510 /* 1x uint */
1511 case AL_BUFFER:
1512 case AL_DIRECT_FILTER:
1513 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1514 *values = (ALuint)ivals[0];
1515 return err;
1517 /* 3x uint */
1518 case AL_AUXILIARY_SEND_FILTER:
1519 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1521 values[0] = (ALuint)ivals[0];
1522 values[1] = (ALuint)ivals[1];
1523 values[2] = (ALuint)ivals[2];
1525 return err;
1527 case AL_SEC_OFFSET_LATENCY_SOFT:
1528 break; /* Double only */
1529 case AL_STEREO_ANGLES:
1530 break; /* Float/double only */
1533 ERR("Unexpected property: 0x%04x\n", prop);
1534 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1538 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1540 ALCcontext *context;
1541 ALsizei cur = 0;
1542 ALenum err;
1544 context = GetContextRef();
1545 if(!context) return;
1547 if(!(n >= 0))
1548 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1549 for(cur = 0;cur < n;cur++)
1551 ALsource *source = al_calloc(16, sizeof(ALsource));
1552 if(!source)
1554 alDeleteSources(cur, sources);
1555 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1557 InitSourceParams(source);
1559 err = NewThunkEntry(&source->id);
1560 if(err == AL_NO_ERROR)
1561 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1562 if(err != AL_NO_ERROR)
1564 FreeThunkEntry(source->id);
1565 memset(source, 0, sizeof(ALsource));
1566 al_free(source);
1568 alDeleteSources(cur, sources);
1569 SET_ERROR_AND_GOTO(context, err, done);
1572 sources[cur] = source->id;
1575 done:
1576 ALCcontext_DecRef(context);
1580 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1582 ALCcontext *context;
1583 ALsource *Source;
1584 ALsizei i;
1586 context = GetContextRef();
1587 if(!context) return;
1589 LockSourcesWrite(context);
1590 if(!(n >= 0))
1591 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1593 /* Check that all Sources are valid */
1594 for(i = 0;i < n;i++)
1596 if(LookupSource(context, sources[i]) == NULL)
1597 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1599 for(i = 0;i < n;i++)
1601 ALvoice *voice;
1603 if((Source=RemoveSource(context, sources[i])) == NULL)
1604 continue;
1605 FreeThunkEntry(Source->id);
1607 LockContext(context);
1608 voice = GetSourceVoice(Source, context);
1609 if(voice) voice->Source = NULL;
1610 UnlockContext(context);
1612 DeinitSource(Source);
1614 memset(Source, 0, sizeof(*Source));
1615 al_free(Source);
1618 done:
1619 UnlockSourcesWrite(context);
1620 ALCcontext_DecRef(context);
1624 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1626 ALCcontext *context;
1627 ALboolean ret;
1629 context = GetContextRef();
1630 if(!context) return AL_FALSE;
1632 LockSourcesRead(context);
1633 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1634 UnlockSourcesRead(context);
1636 ALCcontext_DecRef(context);
1638 return ret;
1642 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1644 ALCcontext *Context;
1645 ALsource *Source;
1647 Context = GetContextRef();
1648 if(!Context) return;
1650 WriteLock(&Context->PropLock);
1651 LockSourcesRead(Context);
1652 if((Source=LookupSource(Context, source)) == NULL)
1653 alSetError(Context, AL_INVALID_NAME);
1654 else if(!(FloatValsByProp(param) == 1))
1655 alSetError(Context, AL_INVALID_ENUM);
1656 else
1657 SetSourcefv(Source, Context, param, &value);
1658 UnlockSourcesRead(Context);
1659 WriteUnlock(&Context->PropLock);
1661 ALCcontext_DecRef(Context);
1664 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1666 ALCcontext *Context;
1667 ALsource *Source;
1669 Context = GetContextRef();
1670 if(!Context) return;
1672 WriteLock(&Context->PropLock);
1673 LockSourcesRead(Context);
1674 if((Source=LookupSource(Context, source)) == NULL)
1675 alSetError(Context, AL_INVALID_NAME);
1676 else if(!(FloatValsByProp(param) == 3))
1677 alSetError(Context, AL_INVALID_ENUM);
1678 else
1680 ALfloat fvals[3] = { value1, value2, value3 };
1681 SetSourcefv(Source, Context, param, fvals);
1683 UnlockSourcesRead(Context);
1684 WriteUnlock(&Context->PropLock);
1686 ALCcontext_DecRef(Context);
1689 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1691 ALCcontext *Context;
1692 ALsource *Source;
1694 Context = GetContextRef();
1695 if(!Context) return;
1697 WriteLock(&Context->PropLock);
1698 LockSourcesRead(Context);
1699 if((Source=LookupSource(Context, source)) == NULL)
1700 alSetError(Context, AL_INVALID_NAME);
1701 else if(!values)
1702 alSetError(Context, AL_INVALID_VALUE);
1703 else if(!(FloatValsByProp(param) > 0))
1704 alSetError(Context, AL_INVALID_ENUM);
1705 else
1706 SetSourcefv(Source, Context, param, values);
1707 UnlockSourcesRead(Context);
1708 WriteUnlock(&Context->PropLock);
1710 ALCcontext_DecRef(Context);
1714 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1716 ALCcontext *Context;
1717 ALsource *Source;
1719 Context = GetContextRef();
1720 if(!Context) return;
1722 WriteLock(&Context->PropLock);
1723 LockSourcesRead(Context);
1724 if((Source=LookupSource(Context, source)) == NULL)
1725 alSetError(Context, AL_INVALID_NAME);
1726 else if(!(DoubleValsByProp(param) == 1))
1727 alSetError(Context, AL_INVALID_ENUM);
1728 else
1730 ALfloat fval = (ALfloat)value;
1731 SetSourcefv(Source, Context, param, &fval);
1733 UnlockSourcesRead(Context);
1734 WriteUnlock(&Context->PropLock);
1736 ALCcontext_DecRef(Context);
1739 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1741 ALCcontext *Context;
1742 ALsource *Source;
1744 Context = GetContextRef();
1745 if(!Context) return;
1747 WriteLock(&Context->PropLock);
1748 LockSourcesRead(Context);
1749 if((Source=LookupSource(Context, source)) == NULL)
1750 alSetError(Context, AL_INVALID_NAME);
1751 else if(!(DoubleValsByProp(param) == 3))
1752 alSetError(Context, AL_INVALID_ENUM);
1753 else
1755 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1756 SetSourcefv(Source, Context, param, fvals);
1758 UnlockSourcesRead(Context);
1759 WriteUnlock(&Context->PropLock);
1761 ALCcontext_DecRef(Context);
1764 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1766 ALCcontext *Context;
1767 ALsource *Source;
1768 ALint count;
1770 Context = GetContextRef();
1771 if(!Context) return;
1773 WriteLock(&Context->PropLock);
1774 LockSourcesRead(Context);
1775 if((Source=LookupSource(Context, source)) == NULL)
1776 alSetError(Context, AL_INVALID_NAME);
1777 else if(!values)
1778 alSetError(Context, AL_INVALID_VALUE);
1779 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1780 alSetError(Context, AL_INVALID_ENUM);
1781 else
1783 ALfloat fvals[6];
1784 ALint i;
1786 for(i = 0;i < count;i++)
1787 fvals[i] = (ALfloat)values[i];
1788 SetSourcefv(Source, Context, param, fvals);
1790 UnlockSourcesRead(Context);
1791 WriteUnlock(&Context->PropLock);
1793 ALCcontext_DecRef(Context);
1797 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1799 ALCcontext *Context;
1800 ALsource *Source;
1802 Context = GetContextRef();
1803 if(!Context) return;
1805 WriteLock(&Context->PropLock);
1806 LockSourcesRead(Context);
1807 if((Source=LookupSource(Context, source)) == NULL)
1808 alSetError(Context, AL_INVALID_NAME);
1809 else if(!(IntValsByProp(param) == 1))
1810 alSetError(Context, AL_INVALID_ENUM);
1811 else
1812 SetSourceiv(Source, Context, param, &value);
1813 UnlockSourcesRead(Context);
1814 WriteUnlock(&Context->PropLock);
1816 ALCcontext_DecRef(Context);
1819 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1821 ALCcontext *Context;
1822 ALsource *Source;
1824 Context = GetContextRef();
1825 if(!Context) return;
1827 WriteLock(&Context->PropLock);
1828 LockSourcesRead(Context);
1829 if((Source=LookupSource(Context, source)) == NULL)
1830 alSetError(Context, AL_INVALID_NAME);
1831 else if(!(IntValsByProp(param) == 3))
1832 alSetError(Context, AL_INVALID_ENUM);
1833 else
1835 ALint ivals[3] = { value1, value2, value3 };
1836 SetSourceiv(Source, Context, param, ivals);
1838 UnlockSourcesRead(Context);
1839 WriteUnlock(&Context->PropLock);
1841 ALCcontext_DecRef(Context);
1844 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1846 ALCcontext *Context;
1847 ALsource *Source;
1849 Context = GetContextRef();
1850 if(!Context) return;
1852 WriteLock(&Context->PropLock);
1853 LockSourcesRead(Context);
1854 if((Source=LookupSource(Context, source)) == NULL)
1855 alSetError(Context, AL_INVALID_NAME);
1856 else if(!values)
1857 alSetError(Context, AL_INVALID_VALUE);
1858 else if(!(IntValsByProp(param) > 0))
1859 alSetError(Context, AL_INVALID_ENUM);
1860 else
1861 SetSourceiv(Source, Context, param, values);
1862 UnlockSourcesRead(Context);
1863 WriteUnlock(&Context->PropLock);
1865 ALCcontext_DecRef(Context);
1869 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1871 ALCcontext *Context;
1872 ALsource *Source;
1874 Context = GetContextRef();
1875 if(!Context) return;
1877 WriteLock(&Context->PropLock);
1878 LockSourcesRead(Context);
1879 if((Source=LookupSource(Context, source)) == NULL)
1880 alSetError(Context, AL_INVALID_NAME);
1881 else if(!(Int64ValsByProp(param) == 1))
1882 alSetError(Context, AL_INVALID_ENUM);
1883 else
1884 SetSourcei64v(Source, Context, param, &value);
1885 UnlockSourcesRead(Context);
1886 WriteUnlock(&Context->PropLock);
1888 ALCcontext_DecRef(Context);
1891 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1893 ALCcontext *Context;
1894 ALsource *Source;
1896 Context = GetContextRef();
1897 if(!Context) return;
1899 WriteLock(&Context->PropLock);
1900 LockSourcesRead(Context);
1901 if((Source=LookupSource(Context, source)) == NULL)
1902 alSetError(Context, AL_INVALID_NAME);
1903 else if(!(Int64ValsByProp(param) == 3))
1904 alSetError(Context, AL_INVALID_ENUM);
1905 else
1907 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1908 SetSourcei64v(Source, Context, param, i64vals);
1910 UnlockSourcesRead(Context);
1911 WriteUnlock(&Context->PropLock);
1913 ALCcontext_DecRef(Context);
1916 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1918 ALCcontext *Context;
1919 ALsource *Source;
1921 Context = GetContextRef();
1922 if(!Context) return;
1924 WriteLock(&Context->PropLock);
1925 LockSourcesRead(Context);
1926 if((Source=LookupSource(Context, source)) == NULL)
1927 alSetError(Context, AL_INVALID_NAME);
1928 else if(!values)
1929 alSetError(Context, AL_INVALID_VALUE);
1930 else if(!(Int64ValsByProp(param) > 0))
1931 alSetError(Context, AL_INVALID_ENUM);
1932 else
1933 SetSourcei64v(Source, Context, param, values);
1934 UnlockSourcesRead(Context);
1935 WriteUnlock(&Context->PropLock);
1937 ALCcontext_DecRef(Context);
1941 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1943 ALCcontext *Context;
1944 ALsource *Source;
1946 Context = GetContextRef();
1947 if(!Context) return;
1949 ReadLock(&Context->PropLock);
1950 LockSourcesRead(Context);
1951 if((Source=LookupSource(Context, source)) == NULL)
1952 alSetError(Context, AL_INVALID_NAME);
1953 else if(!value)
1954 alSetError(Context, AL_INVALID_VALUE);
1955 else if(!(FloatValsByProp(param) == 1))
1956 alSetError(Context, AL_INVALID_ENUM);
1957 else
1959 ALdouble dval;
1960 if(GetSourcedv(Source, Context, param, &dval))
1961 *value = (ALfloat)dval;
1963 UnlockSourcesRead(Context);
1964 ReadUnlock(&Context->PropLock);
1966 ALCcontext_DecRef(Context);
1970 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1972 ALCcontext *Context;
1973 ALsource *Source;
1975 Context = GetContextRef();
1976 if(!Context) return;
1978 ReadLock(&Context->PropLock);
1979 LockSourcesRead(Context);
1980 if((Source=LookupSource(Context, source)) == NULL)
1981 alSetError(Context, AL_INVALID_NAME);
1982 else if(!(value1 && value2 && value3))
1983 alSetError(Context, AL_INVALID_VALUE);
1984 else if(!(FloatValsByProp(param) == 3))
1985 alSetError(Context, AL_INVALID_ENUM);
1986 else
1988 ALdouble dvals[3];
1989 if(GetSourcedv(Source, Context, param, dvals))
1991 *value1 = (ALfloat)dvals[0];
1992 *value2 = (ALfloat)dvals[1];
1993 *value3 = (ALfloat)dvals[2];
1996 UnlockSourcesRead(Context);
1997 ReadUnlock(&Context->PropLock);
1999 ALCcontext_DecRef(Context);
2003 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
2005 ALCcontext *Context;
2006 ALsource *Source;
2007 ALint count;
2009 Context = GetContextRef();
2010 if(!Context) return;
2012 ReadLock(&Context->PropLock);
2013 LockSourcesRead(Context);
2014 if((Source=LookupSource(Context, source)) == NULL)
2015 alSetError(Context, AL_INVALID_NAME);
2016 else if(!values)
2017 alSetError(Context, AL_INVALID_VALUE);
2018 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
2019 alSetError(Context, AL_INVALID_ENUM);
2020 else
2022 ALdouble dvals[6];
2023 if(GetSourcedv(Source, Context, param, dvals))
2025 ALint i;
2026 for(i = 0;i < count;i++)
2027 values[i] = (ALfloat)dvals[i];
2030 UnlockSourcesRead(Context);
2031 ReadUnlock(&Context->PropLock);
2033 ALCcontext_DecRef(Context);
2037 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
2039 ALCcontext *Context;
2040 ALsource *Source;
2042 Context = GetContextRef();
2043 if(!Context) return;
2045 ReadLock(&Context->PropLock);
2046 LockSourcesRead(Context);
2047 if((Source=LookupSource(Context, source)) == NULL)
2048 alSetError(Context, AL_INVALID_NAME);
2049 else if(!value)
2050 alSetError(Context, AL_INVALID_VALUE);
2051 else if(!(DoubleValsByProp(param) == 1))
2052 alSetError(Context, AL_INVALID_ENUM);
2053 else
2054 GetSourcedv(Source, Context, param, value);
2055 UnlockSourcesRead(Context);
2056 ReadUnlock(&Context->PropLock);
2058 ALCcontext_DecRef(Context);
2061 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
2063 ALCcontext *Context;
2064 ALsource *Source;
2066 Context = GetContextRef();
2067 if(!Context) return;
2069 ReadLock(&Context->PropLock);
2070 LockSourcesRead(Context);
2071 if((Source=LookupSource(Context, source)) == NULL)
2072 alSetError(Context, AL_INVALID_NAME);
2073 else if(!(value1 && value2 && value3))
2074 alSetError(Context, AL_INVALID_VALUE);
2075 else if(!(DoubleValsByProp(param) == 3))
2076 alSetError(Context, AL_INVALID_ENUM);
2077 else
2079 ALdouble dvals[3];
2080 if(GetSourcedv(Source, Context, param, dvals))
2082 *value1 = dvals[0];
2083 *value2 = dvals[1];
2084 *value3 = dvals[2];
2087 UnlockSourcesRead(Context);
2088 ReadUnlock(&Context->PropLock);
2090 ALCcontext_DecRef(Context);
2093 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
2095 ALCcontext *Context;
2096 ALsource *Source;
2098 Context = GetContextRef();
2099 if(!Context) return;
2101 ReadLock(&Context->PropLock);
2102 LockSourcesRead(Context);
2103 if((Source=LookupSource(Context, source)) == NULL)
2104 alSetError(Context, AL_INVALID_NAME);
2105 else if(!values)
2106 alSetError(Context, AL_INVALID_VALUE);
2107 else if(!(DoubleValsByProp(param) > 0))
2108 alSetError(Context, AL_INVALID_ENUM);
2109 else
2110 GetSourcedv(Source, Context, param, values);
2111 UnlockSourcesRead(Context);
2112 ReadUnlock(&Context->PropLock);
2114 ALCcontext_DecRef(Context);
2118 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2120 ALCcontext *Context;
2121 ALsource *Source;
2123 Context = GetContextRef();
2124 if(!Context) return;
2126 ReadLock(&Context->PropLock);
2127 LockSourcesRead(Context);
2128 if((Source=LookupSource(Context, source)) == NULL)
2129 alSetError(Context, AL_INVALID_NAME);
2130 else if(!value)
2131 alSetError(Context, AL_INVALID_VALUE);
2132 else if(!(IntValsByProp(param) == 1))
2133 alSetError(Context, AL_INVALID_ENUM);
2134 else
2135 GetSourceiv(Source, Context, param, value);
2136 UnlockSourcesRead(Context);
2137 ReadUnlock(&Context->PropLock);
2139 ALCcontext_DecRef(Context);
2143 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2145 ALCcontext *Context;
2146 ALsource *Source;
2148 Context = GetContextRef();
2149 if(!Context) return;
2151 ReadLock(&Context->PropLock);
2152 LockSourcesRead(Context);
2153 if((Source=LookupSource(Context, source)) == NULL)
2154 alSetError(Context, AL_INVALID_NAME);
2155 else if(!(value1 && value2 && value3))
2156 alSetError(Context, AL_INVALID_VALUE);
2157 else if(!(IntValsByProp(param) == 3))
2158 alSetError(Context, AL_INVALID_ENUM);
2159 else
2161 ALint ivals[3];
2162 if(GetSourceiv(Source, Context, param, ivals))
2164 *value1 = ivals[0];
2165 *value2 = ivals[1];
2166 *value3 = ivals[2];
2169 UnlockSourcesRead(Context);
2170 ReadUnlock(&Context->PropLock);
2172 ALCcontext_DecRef(Context);
2176 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2178 ALCcontext *Context;
2179 ALsource *Source;
2181 Context = GetContextRef();
2182 if(!Context) return;
2184 ReadLock(&Context->PropLock);
2185 LockSourcesRead(Context);
2186 if((Source=LookupSource(Context, source)) == NULL)
2187 alSetError(Context, AL_INVALID_NAME);
2188 else if(!values)
2189 alSetError(Context, AL_INVALID_VALUE);
2190 else if(!(IntValsByProp(param) > 0))
2191 alSetError(Context, AL_INVALID_ENUM);
2192 else
2193 GetSourceiv(Source, Context, param, values);
2194 UnlockSourcesRead(Context);
2195 ReadUnlock(&Context->PropLock);
2197 ALCcontext_DecRef(Context);
2201 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2203 ALCcontext *Context;
2204 ALsource *Source;
2206 Context = GetContextRef();
2207 if(!Context) return;
2209 ReadLock(&Context->PropLock);
2210 LockSourcesRead(Context);
2211 if((Source=LookupSource(Context, source)) == NULL)
2212 alSetError(Context, AL_INVALID_NAME);
2213 else if(!value)
2214 alSetError(Context, AL_INVALID_VALUE);
2215 else if(!(Int64ValsByProp(param) == 1))
2216 alSetError(Context, AL_INVALID_ENUM);
2217 else
2218 GetSourcei64v(Source, Context, param, value);
2219 UnlockSourcesRead(Context);
2220 ReadUnlock(&Context->PropLock);
2222 ALCcontext_DecRef(Context);
2225 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2227 ALCcontext *Context;
2228 ALsource *Source;
2230 Context = GetContextRef();
2231 if(!Context) return;
2233 ReadLock(&Context->PropLock);
2234 LockSourcesRead(Context);
2235 if((Source=LookupSource(Context, source)) == NULL)
2236 alSetError(Context, AL_INVALID_NAME);
2237 else if(!(value1 && value2 && value3))
2238 alSetError(Context, AL_INVALID_VALUE);
2239 else if(!(Int64ValsByProp(param) == 3))
2240 alSetError(Context, AL_INVALID_ENUM);
2241 else
2243 ALint64 i64vals[3];
2244 if(GetSourcei64v(Source, Context, param, i64vals))
2246 *value1 = i64vals[0];
2247 *value2 = i64vals[1];
2248 *value3 = i64vals[2];
2251 UnlockSourcesRead(Context);
2252 ReadUnlock(&Context->PropLock);
2254 ALCcontext_DecRef(Context);
2257 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2259 ALCcontext *Context;
2260 ALsource *Source;
2262 Context = GetContextRef();
2263 if(!Context) return;
2265 ReadLock(&Context->PropLock);
2266 LockSourcesRead(Context);
2267 if((Source=LookupSource(Context, source)) == NULL)
2268 alSetError(Context, AL_INVALID_NAME);
2269 else if(!values)
2270 alSetError(Context, AL_INVALID_VALUE);
2271 else if(!(Int64ValsByProp(param) > 0))
2272 alSetError(Context, AL_INVALID_ENUM);
2273 else
2274 GetSourcei64v(Source, Context, param, values);
2275 UnlockSourcesRead(Context);
2276 ReadUnlock(&Context->PropLock);
2278 ALCcontext_DecRef(Context);
2282 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2284 alSourcePlayv(1, &source);
2286 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2288 ALCcontext *context;
2289 ALsource *source;
2290 ALsizei i;
2292 context = GetContextRef();
2293 if(!context) return;
2295 LockSourcesRead(context);
2296 if(!(n >= 0))
2297 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2298 for(i = 0;i < n;i++)
2300 if(!LookupSource(context, sources[i]))
2301 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2304 LockContext(context);
2305 while(n > context->MaxVoices-context->VoiceCount)
2307 ALvoice *temp = NULL;
2308 ALsizei newcount;
2310 newcount = context->MaxVoices << 1;
2311 if(newcount > 0)
2312 temp = al_malloc(16, newcount * sizeof(context->Voices[0]));
2313 if(!temp)
2315 UnlockContext(context);
2316 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2318 memcpy(temp, context->Voices, context->MaxVoices * sizeof(temp[0]));
2319 memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0]));
2321 al_free(context->Voices);
2322 context->Voices = temp;
2323 context->MaxVoices = newcount;
2326 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll)
2328 for(i = 0;i < n;i++)
2330 source = LookupSource(context, sources[i]);
2331 source->new_state = AL_PLAYING;
2334 else
2336 for(i = 0;i < n;i++)
2338 source = LookupSource(context, sources[i]);
2339 SetSourceState(source, context, AL_PLAYING);
2342 UnlockContext(context);
2344 done:
2345 UnlockSourcesRead(context);
2346 ALCcontext_DecRef(context);
2349 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2351 alSourcePausev(1, &source);
2353 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2355 ALCcontext *context;
2356 ALsource *source;
2357 ALsizei i;
2359 context = GetContextRef();
2360 if(!context) return;
2362 LockSourcesRead(context);
2363 if(!(n >= 0))
2364 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2365 for(i = 0;i < n;i++)
2367 if(!LookupSource(context, sources[i]))
2368 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2371 LockContext(context);
2372 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
2374 for(i = 0;i < n;i++)
2376 source = LookupSource(context, sources[i]);
2377 source->new_state = AL_PAUSED;
2380 else
2382 for(i = 0;i < n;i++)
2384 source = LookupSource(context, sources[i]);
2385 SetSourceState(source, context, AL_PAUSED);
2388 UnlockContext(context);
2390 done:
2391 UnlockSourcesRead(context);
2392 ALCcontext_DecRef(context);
2395 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2397 alSourceStopv(1, &source);
2399 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2401 ALCcontext *context;
2402 ALsource *source;
2403 ALsizei i;
2405 context = GetContextRef();
2406 if(!context) return;
2408 LockSourcesRead(context);
2409 if(!(n >= 0))
2410 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2411 for(i = 0;i < n;i++)
2413 if(!LookupSource(context, sources[i]))
2414 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2417 LockContext(context);
2418 for(i = 0;i < n;i++)
2420 source = LookupSource(context, sources[i]);
2421 source->new_state = AL_NONE;
2422 SetSourceState(source, context, AL_STOPPED);
2424 UnlockContext(context);
2426 done:
2427 UnlockSourcesRead(context);
2428 ALCcontext_DecRef(context);
2431 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2433 alSourceRewindv(1, &source);
2435 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2437 ALCcontext *context;
2438 ALsource *source;
2439 ALsizei i;
2441 context = GetContextRef();
2442 if(!context) return;
2444 LockSourcesRead(context);
2445 if(!(n >= 0))
2446 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2447 for(i = 0;i < n;i++)
2449 if(!LookupSource(context, sources[i]))
2450 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2453 LockContext(context);
2454 for(i = 0;i < n;i++)
2456 source = LookupSource(context, sources[i]);
2457 source->new_state = AL_NONE;
2458 SetSourceState(source, context, AL_INITIAL);
2460 UnlockContext(context);
2462 done:
2463 UnlockSourcesRead(context);
2464 ALCcontext_DecRef(context);
2468 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2470 ALCdevice *device;
2471 ALCcontext *context;
2472 ALsource *source;
2473 ALsizei i;
2474 ALbufferlistitem *BufferListStart;
2475 ALbufferlistitem *BufferList;
2476 ALbuffer *BufferFmt = NULL;
2478 if(nb == 0)
2479 return;
2481 context = GetContextRef();
2482 if(!context) return;
2484 device = context->Device;
2486 LockSourcesRead(context);
2487 if(!(nb >= 0))
2488 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2489 if((source=LookupSource(context, src)) == NULL)
2490 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2492 WriteLock(&source->queue_lock);
2493 if(source->SourceType == AL_STATIC)
2495 WriteUnlock(&source->queue_lock);
2496 /* Can't queue on a Static Source */
2497 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2500 /* Check for a valid Buffer, for its frequency and format */
2501 BufferList = ATOMIC_LOAD(&source->queue);
2502 while(BufferList)
2504 if(BufferList->buffer)
2506 BufferFmt = BufferList->buffer;
2507 break;
2509 BufferList = BufferList->next;
2512 LockBuffersRead(device);
2513 BufferListStart = NULL;
2514 BufferList = NULL;
2515 for(i = 0;i < nb;i++)
2517 ALbuffer *buffer = NULL;
2518 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2520 WriteUnlock(&source->queue_lock);
2521 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2524 if(!BufferListStart)
2526 BufferListStart = malloc(sizeof(ALbufferlistitem));
2527 BufferList = BufferListStart;
2529 else
2531 BufferList->next = malloc(sizeof(ALbufferlistitem));
2532 BufferList = BufferList->next;
2534 BufferList->buffer = buffer;
2535 BufferList->next = NULL;
2536 if(!buffer) continue;
2538 /* Hold a read lock on each buffer being queued while checking all
2539 * provided buffers. This is done so other threads don't see an extra
2540 * reference on some buffers if this operation ends up failing. */
2541 ReadLock(&buffer->lock);
2542 IncrementRef(&buffer->ref);
2544 if(BufferFmt == NULL)
2546 BufferFmt = buffer;
2548 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2549 source->SampleSize = BytesFromFmt(buffer->FmtType);
2551 else if(BufferFmt->Frequency != buffer->Frequency ||
2552 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2553 BufferFmt->OriginalType != buffer->OriginalType)
2555 WriteUnlock(&source->queue_lock);
2556 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2558 buffer_error:
2559 /* A buffer failed (invalid ID or format), so unlock and release
2560 * each buffer we had. */
2561 while(BufferListStart)
2563 ALbufferlistitem *next = BufferListStart->next;
2564 if((buffer=BufferListStart->buffer) != NULL)
2566 DecrementRef(&buffer->ref);
2567 ReadUnlock(&buffer->lock);
2569 free(BufferListStart);
2570 BufferListStart = next;
2572 UnlockBuffersRead(device);
2573 goto done;
2576 /* All buffers good, unlock them now. */
2577 BufferList = BufferListStart;
2578 while(BufferList != NULL)
2580 ALbuffer *buffer = BufferList->buffer;
2581 if(buffer) ReadUnlock(&buffer->lock);
2582 BufferList = BufferList->next;
2584 UnlockBuffersRead(device);
2586 /* Source is now streaming */
2587 source->SourceType = AL_STREAMING;
2589 BufferList = NULL;
2590 if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
2592 /* Queue head is not NULL, append to the end of the queue */
2593 while(BufferList->next != NULL)
2594 BufferList = BufferList->next;
2595 BufferList->next = BufferListStart;
2597 /* If the current buffer was at the end (NULL), put it at the start of the newly queued
2598 * buffers.
2600 BufferList = NULL;
2601 ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
2602 WriteUnlock(&source->queue_lock);
2604 done:
2605 UnlockSourcesRead(context);
2606 ALCcontext_DecRef(context);
2609 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2611 ALCcontext *context;
2612 ALsource *source;
2613 ALbufferlistitem *OldHead;
2614 ALbufferlistitem *OldTail;
2615 ALbufferlistitem *Current;
2616 ALsizei i = 0;
2618 if(nb == 0)
2619 return;
2621 context = GetContextRef();
2622 if(!context) return;
2624 LockSourcesRead(context);
2625 if(!(nb >= 0))
2626 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2628 if((source=LookupSource(context, src)) == NULL)
2629 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2631 WriteLock(&source->queue_lock);
2632 if(ATOMIC_LOAD(&source->looping) || source->SourceType != AL_STREAMING)
2634 WriteUnlock(&source->queue_lock);
2635 /* Trying to unqueue buffers on a looping or non-streaming source. */
2636 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2639 /* Find the new buffer queue head */
2640 OldTail = ATOMIC_LOAD(&source->queue);
2641 Current = ATOMIC_LOAD(&source->current_buffer);
2642 if(OldTail != Current)
2644 for(i = 1;i < nb;i++)
2646 ALbufferlistitem *next = OldTail->next;
2647 if(!next || next == Current) break;
2648 OldTail = next;
2651 if(i != nb)
2653 WriteUnlock(&source->queue_lock);
2654 /* Trying to unqueue pending buffers. */
2655 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2658 /* Swap it, and cut the new head from the old. */
2659 OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, OldTail->next);
2660 if(OldTail->next)
2662 ALCdevice *device = context->Device;
2663 uint count;
2665 /* Once the active mix (if any) is done, it's safe to cut the old tail
2666 * from the new head.
2668 if(((count=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
2670 while(count == ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))
2671 althrd_yield();
2673 ATOMIC_THREAD_FENCE(almemory_order_acq_rel);
2674 OldTail->next = NULL;
2676 WriteUnlock(&source->queue_lock);
2678 while(OldHead != NULL)
2680 ALbufferlistitem *next = OldHead->next;
2681 ALbuffer *buffer = OldHead->buffer;
2683 if(!buffer)
2684 *(buffers++) = 0;
2685 else
2687 *(buffers++) = buffer->id;
2688 DecrementRef(&buffer->ref);
2691 free(OldHead);
2692 OldHead = next;
2695 done:
2696 UnlockSourcesRead(context);
2697 ALCcontext_DecRef(context);
2701 static void InitSourceParams(ALsource *Source)
2703 ALuint i;
2705 RWLockInit(&Source->queue_lock);
2707 Source->InnerAngle = 360.0f;
2708 Source->OuterAngle = 360.0f;
2709 Source->Pitch = 1.0f;
2710 Source->Position[0] = 0.0f;
2711 Source->Position[1] = 0.0f;
2712 Source->Position[2] = 0.0f;
2713 Source->Velocity[0] = 0.0f;
2714 Source->Velocity[1] = 0.0f;
2715 Source->Velocity[2] = 0.0f;
2716 Source->Direction[0] = 0.0f;
2717 Source->Direction[1] = 0.0f;
2718 Source->Direction[2] = 0.0f;
2719 Source->Orientation[0][0] = 0.0f;
2720 Source->Orientation[0][1] = 0.0f;
2721 Source->Orientation[0][2] = -1.0f;
2722 Source->Orientation[1][0] = 0.0f;
2723 Source->Orientation[1][1] = 1.0f;
2724 Source->Orientation[1][2] = 0.0f;
2725 Source->RefDistance = 1.0f;
2726 Source->MaxDistance = FLT_MAX;
2727 Source->RollOffFactor = 1.0f;
2728 Source->Gain = 1.0f;
2729 Source->MinGain = 0.0f;
2730 Source->MaxGain = 1.0f;
2731 Source->OuterGain = 0.0f;
2732 Source->OuterGainHF = 1.0f;
2734 Source->DryGainHFAuto = AL_TRUE;
2735 Source->WetGainAuto = AL_TRUE;
2736 Source->WetGainHFAuto = AL_TRUE;
2737 Source->AirAbsorptionFactor = 0.0f;
2738 Source->RoomRolloffFactor = 0.0f;
2739 Source->DopplerFactor = 1.0f;
2740 Source->DirectChannels = AL_FALSE;
2742 Source->StereoPan[0] = DEG2RAD( 30.0f);
2743 Source->StereoPan[1] = DEG2RAD(-30.0f);
2745 Source->Radius = 0.0f;
2747 Source->DistanceModel = DefaultDistanceModel;
2749 Source->Direct.Gain = 1.0f;
2750 Source->Direct.GainHF = 1.0f;
2751 Source->Direct.HFReference = LOWPASSFREQREF;
2752 Source->Direct.GainLF = 1.0f;
2753 Source->Direct.LFReference = HIGHPASSFREQREF;
2754 for(i = 0;i < MAX_SENDS;i++)
2756 Source->Send[i].Gain = 1.0f;
2757 Source->Send[i].GainHF = 1.0f;
2758 Source->Send[i].HFReference = LOWPASSFREQREF;
2759 Source->Send[i].GainLF = 1.0f;
2760 Source->Send[i].LFReference = HIGHPASSFREQREF;
2763 Source->Offset = 0.0;
2764 Source->OffsetType = AL_NONE;
2765 Source->SourceType = AL_UNDETERMINED;
2766 Source->state = AL_INITIAL;
2767 Source->new_state = AL_NONE;
2769 ATOMIC_INIT(&Source->queue, NULL);
2770 ATOMIC_INIT(&Source->current_buffer, NULL);
2772 ATOMIC_INIT(&Source->position, 0);
2773 ATOMIC_INIT(&Source->position_fraction, 0);
2775 ATOMIC_INIT(&Source->looping, AL_FALSE);
2777 Source->NeedsUpdate = AL_TRUE;
2779 ATOMIC_INIT(&Source->Update, NULL);
2780 ATOMIC_INIT(&Source->FreeList, NULL);
2783 static void DeinitSource(ALsource *source)
2785 ALbufferlistitem *BufferList;
2786 struct ALsourceProps *props;
2787 size_t count = 0;
2788 size_t i;
2790 props = ATOMIC_LOAD(&source->Update);
2791 if(props) al_free(props);
2793 props = ATOMIC_LOAD(&source->FreeList, almemory_order_relaxed);
2794 while(props)
2796 struct ALsourceProps *next;
2797 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2798 al_free(props);
2799 props = next;
2800 ++count;
2802 /* This is excessively spammy if it traces every source destruction, so
2803 * just warn if it was unexpectedly large.
2805 if(count > 3)
2806 WARN("Freed "SZFMT" Source property objects\n", count);
2808 BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NULL);
2809 while(BufferList != NULL)
2811 ALbufferlistitem *next = BufferList->next;
2812 if(BufferList->buffer != NULL)
2813 DecrementRef(&BufferList->buffer->ref);
2814 free(BufferList);
2815 BufferList = next;
2818 for(i = 0;i < MAX_SENDS;++i)
2820 if(source->Send[i].Slot)
2821 DecrementRef(&source->Send[i].Slot->ref);
2822 source->Send[i].Slot = NULL;
2826 static void UpdateSourceProps(ALsource *source, ALuint num_sends)
2828 struct ALsourceProps *props;
2829 size_t i;
2831 /* Get an unused property container, or allocate a new one as needed. */
2832 props = ATOMIC_LOAD(&source->FreeList, almemory_order_acquire);
2833 if(!props)
2834 props = al_calloc(16, sizeof(*props));
2835 else
2837 struct ALsourceProps *next;
2838 do {
2839 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2840 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*,
2841 &source->FreeList, &props, next, almemory_order_acq_rel,
2842 almemory_order_acquire) == 0);
2845 /* Copy in current property values. */
2846 ATOMIC_STORE(&props->Pitch, source->Pitch, almemory_order_relaxed);
2847 ATOMIC_STORE(&props->Gain, source->Gain, almemory_order_relaxed);
2848 ATOMIC_STORE(&props->OuterGain, source->OuterGain, almemory_order_relaxed);
2849 ATOMIC_STORE(&props->MinGain, source->MinGain, almemory_order_relaxed);
2850 ATOMIC_STORE(&props->MaxGain, source->MaxGain, almemory_order_relaxed);
2851 ATOMIC_STORE(&props->InnerAngle, source->InnerAngle, almemory_order_relaxed);
2852 ATOMIC_STORE(&props->OuterAngle, source->OuterAngle, almemory_order_relaxed);
2853 ATOMIC_STORE(&props->RefDistance, source->RefDistance, almemory_order_relaxed);
2854 ATOMIC_STORE(&props->MaxDistance, source->MaxDistance, almemory_order_relaxed);
2855 ATOMIC_STORE(&props->RollOffFactor, source->RollOffFactor, almemory_order_relaxed);
2856 for(i = 0;i < 3;i++)
2857 ATOMIC_STORE(&props->Position[i], source->Position[i], almemory_order_relaxed);
2858 for(i = 0;i < 3;i++)
2859 ATOMIC_STORE(&props->Velocity[i], source->Velocity[i], almemory_order_relaxed);
2860 for(i = 0;i < 3;i++)
2861 ATOMIC_STORE(&props->Direction[i], source->Direction[i], almemory_order_relaxed);
2862 for(i = 0;i < 2;i++)
2864 size_t j;
2865 for(j = 0;j < 3;j++)
2866 ATOMIC_STORE(&props->Orientation[i][j], source->Orientation[i][j],
2867 almemory_order_relaxed);
2869 ATOMIC_STORE(&props->HeadRelative, source->HeadRelative, almemory_order_relaxed);
2870 ATOMIC_STORE(&props->DistanceModel, source->DistanceModel, almemory_order_relaxed);
2871 ATOMIC_STORE(&props->DirectChannels, source->DirectChannels, almemory_order_relaxed);
2873 ATOMIC_STORE(&props->DryGainHFAuto, source->DryGainHFAuto, almemory_order_relaxed);
2874 ATOMIC_STORE(&props->WetGainAuto, source->WetGainAuto, almemory_order_relaxed);
2875 ATOMIC_STORE(&props->WetGainHFAuto, source->WetGainHFAuto, almemory_order_relaxed);
2876 ATOMIC_STORE(&props->OuterGainHF, source->OuterGainHF, almemory_order_relaxed);
2878 ATOMIC_STORE(&props->AirAbsorptionFactor, source->AirAbsorptionFactor, almemory_order_relaxed);
2879 ATOMIC_STORE(&props->RoomRolloffFactor, source->RoomRolloffFactor, almemory_order_relaxed);
2880 ATOMIC_STORE(&props->DopplerFactor, source->DopplerFactor, almemory_order_relaxed);
2882 ATOMIC_STORE(&props->StereoPan[0], source->StereoPan[0], almemory_order_relaxed);
2883 ATOMIC_STORE(&props->StereoPan[1], source->StereoPan[1], almemory_order_relaxed);
2885 ATOMIC_STORE(&props->Radius, source->Radius, almemory_order_relaxed);
2887 ATOMIC_STORE(&props->Direct.Gain, source->Direct.Gain, almemory_order_relaxed);
2888 ATOMIC_STORE(&props->Direct.GainHF, source->Direct.GainHF, almemory_order_relaxed);
2889 ATOMIC_STORE(&props->Direct.HFReference, source->Direct.HFReference, almemory_order_relaxed);
2890 ATOMIC_STORE(&props->Direct.GainLF, source->Direct.GainLF, almemory_order_relaxed);
2891 ATOMIC_STORE(&props->Direct.LFReference, source->Direct.LFReference, almemory_order_relaxed);
2893 for(i = 0;i < num_sends;i++)
2895 ATOMIC_STORE(&props->Send[i].Slot, source->Send[i].Slot, almemory_order_relaxed);
2896 ATOMIC_STORE(&props->Send[i].Gain, source->Send[i].Gain, almemory_order_relaxed);
2897 ATOMIC_STORE(&props->Send[i].GainHF, source->Send[i].GainHF, almemory_order_relaxed);
2898 ATOMIC_STORE(&props->Send[i].HFReference, source->Send[i].HFReference,
2899 almemory_order_relaxed);
2900 ATOMIC_STORE(&props->Send[i].GainLF, source->Send[i].GainLF, almemory_order_relaxed);
2901 ATOMIC_STORE(&props->Send[i].LFReference, source->Send[i].LFReference,
2902 almemory_order_relaxed);
2905 /* Set the new container for updating internal parameters. */
2906 props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, props, almemory_order_acq_rel);
2907 if(props)
2909 /* If there was an unused update container, put it back in the
2910 * freelist.
2912 struct ALsourceProps *first = ATOMIC_LOAD(&source->FreeList);
2913 do {
2914 ATOMIC_STORE(&props->next, first, almemory_order_relaxed);
2915 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*,
2916 &source->FreeList, &first, props, almemory_order_acq_rel,
2917 almemory_order_acquire) == 0);
2921 void UpdateAllSourceProps(ALCcontext *context)
2923 ALuint num_sends = context->Device->NumAuxSends;
2924 ALsizei pos;
2926 for(pos = 0;pos < context->VoiceCount;pos++)
2928 ALvoice *voice = &context->Voices[pos];
2929 ALsource *source = voice->Source;
2930 if(source != NULL && (source->state == AL_PLAYING ||
2931 source->state == AL_PAUSED) &&
2932 source->NeedsUpdate)
2934 source->NeedsUpdate = AL_FALSE;
2935 UpdateSourceProps(source, num_sends);
2941 /* SetSourceState
2943 * Sets the source's new play state given its current state.
2945 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2947 WriteLock(&Source->queue_lock);
2948 if(state == AL_PLAYING)
2950 ALCdevice *device = Context->Device;
2951 ALbufferlistitem *BufferList;
2952 ALboolean discontinuity;
2953 ALvoice *voice = NULL;
2954 ALsizei i;
2956 /* Check that there is a queue containing at least one valid, non zero
2957 * length Buffer. */
2958 BufferList = ATOMIC_LOAD(&Source->queue);
2959 while(BufferList)
2961 ALbuffer *buffer;
2962 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2963 break;
2964 BufferList = BufferList->next;
2967 if(Source->state != AL_PAUSED)
2969 Source->state = AL_PLAYING;
2970 ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed);
2971 ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed);
2972 ATOMIC_STORE(&Source->position_fraction, 0, almemory_order_release);
2973 discontinuity = AL_TRUE;
2975 else
2977 Source->state = AL_PLAYING;
2978 discontinuity = AL_FALSE;
2981 // Check if an Offset has been set
2982 if(Source->OffsetType != AL_NONE)
2984 ApplyOffset(Source);
2985 /* discontinuity = AL_TRUE;??? */
2988 /* If there's nothing to play, or device is disconnected, go right to
2989 * stopped */
2990 if(!BufferList || !device->Connected)
2991 goto do_stop;
2993 /* Make sure this source isn't already active, and if not, look for an
2994 * unused voice to put it in.
2996 voice = GetSourceVoice(Source, Context);
2997 if(voice == NULL)
2999 for(i = 0;i < Context->VoiceCount;i++)
3001 if(Context->Voices[i].Source == NULL)
3003 voice = &Context->Voices[i];
3004 voice->Source = Source;
3005 break;
3008 if(voice == NULL)
3010 voice = &Context->Voices[Context->VoiceCount++];
3011 voice->Source = Source;
3013 discontinuity = AL_TRUE;
3016 if(discontinuity)
3018 /* Clear previous samples if playback is discontinuous. */
3019 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
3021 /* Clear the stepping value so the mixer knows not to mix this
3022 * until the update gets applied.
3024 voice->Step = 0;
3027 voice->Moving = AL_FALSE;
3028 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
3030 ALsizei j;
3031 for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
3032 voice->Chan[i].Direct.Hrtf.State.History[j] = 0.0f;
3033 for(j = 0;j < HRIR_LENGTH;j++)
3035 voice->Chan[i].Direct.Hrtf.State.Values[j][0] = 0.0f;
3036 voice->Chan[i].Direct.Hrtf.State.Values[j][1] = 0.0f;
3040 Source->NeedsUpdate = AL_FALSE;
3041 UpdateSourceProps(Source, device->NumAuxSends);
3043 else if(state == AL_PAUSED)
3045 if(Source->state == AL_PLAYING)
3046 Source->state = AL_PAUSED;
3048 else if(state == AL_STOPPED)
3050 do_stop:
3051 if(Source->state != AL_INITIAL)
3053 Source->state = AL_STOPPED;
3054 ATOMIC_STORE(&Source->current_buffer, NULL);
3056 Source->OffsetType = AL_NONE;
3057 Source->Offset = 0.0;
3059 else if(state == AL_INITIAL)
3061 if(Source->state != AL_INITIAL)
3063 Source->state = AL_INITIAL;
3064 ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue),
3065 almemory_order_relaxed);
3066 ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed);
3067 ATOMIC_STORE(&Source->position_fraction, 0);
3069 Source->OffsetType = AL_NONE;
3070 Source->Offset = 0.0;
3072 WriteUnlock(&Source->queue_lock);
3075 /* GetSourceSampleOffset
3077 * Gets the current read offset for the given Source, in 32.32 fixed-point
3078 * samples. The offset is relative to the start of the queue (not the start of
3079 * the current buffer).
3081 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime)
3083 const ALbufferlistitem *BufferList;
3084 const ALbufferlistitem *Current;
3085 ALuint64 readPos;
3086 ALuint refcount;
3088 ReadLock(&Source->queue_lock);
3089 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
3091 ReadUnlock(&Source->queue_lock);
3092 do {
3093 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3094 althrd_yield();
3095 *clocktime = GetDeviceClockTime(device);
3096 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3097 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3098 return 0;
3101 do {
3102 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3103 althrd_yield();
3104 *clocktime = GetDeviceClockTime(device);
3106 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3107 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3109 readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << 32;
3110 readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed) <<
3111 (32-FRACTIONBITS);
3112 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3113 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3114 while(BufferList && BufferList != Current)
3116 if(BufferList->buffer)
3117 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
3118 BufferList = BufferList->next;
3121 ReadUnlock(&Source->queue_lock);
3122 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
3125 /* GetSourceSecOffset
3127 * Gets the current read offset for the given Source, in seconds. The offset is
3128 * relative to the start of the queue (not the start of the current buffer).
3130 static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime)
3132 const ALbufferlistitem *BufferList;
3133 const ALbufferlistitem *Current;
3134 const ALbuffer *Buffer = NULL;
3135 ALuint64 readPos;
3136 ALuint refcount;
3138 ReadLock(&Source->queue_lock);
3139 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
3141 ReadUnlock(&Source->queue_lock);
3142 do {
3143 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3144 althrd_yield();
3145 *clocktime = GetDeviceClockTime(device);
3146 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3147 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3148 return 0.0;
3151 do {
3152 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3153 althrd_yield();
3154 *clocktime = GetDeviceClockTime(device);
3156 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3157 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3159 readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed)<<FRACTIONBITS;
3160 readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed);
3161 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3162 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3163 while(BufferList && BufferList != Current)
3165 const ALbuffer *buffer = BufferList->buffer;
3166 if(buffer != NULL)
3168 if(!Buffer) Buffer = buffer;
3169 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
3171 BufferList = BufferList->next;
3174 while(BufferList && !Buffer)
3176 Buffer = BufferList->buffer;
3177 BufferList = BufferList->next;
3179 assert(Buffer != NULL);
3181 ReadUnlock(&Source->queue_lock);
3182 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
3185 /* GetSourceOffset
3187 * Gets the current read offset for the given Source, in the appropriate format
3188 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3189 * queue (not the start of the current buffer).
3191 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device)
3193 const ALbufferlistitem *BufferList;
3194 const ALbufferlistitem *Current;
3195 const ALbuffer *Buffer = NULL;
3196 ALboolean readFin = AL_FALSE;
3197 ALuint readPos, readPosFrac;
3198 ALuint totalBufferLen;
3199 ALdouble offset = 0.0;
3200 ALboolean looping;
3201 ALuint refcount;
3203 ReadLock(&Source->queue_lock);
3204 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
3206 ReadUnlock(&Source->queue_lock);
3207 return 0.0;
3210 totalBufferLen = 0;
3211 do {
3212 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3213 althrd_yield();
3214 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3215 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3217 readPos = ATOMIC_LOAD(&Source->position, almemory_order_relaxed);
3218 readPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed);
3220 looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed);
3221 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3222 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3224 while(BufferList != NULL)
3226 const ALbuffer *buffer;
3227 readFin = readFin || (BufferList == Current);
3228 if((buffer=BufferList->buffer) != NULL)
3230 if(!Buffer) Buffer = buffer;
3231 totalBufferLen += buffer->SampleLen;
3232 if(!readFin) readPos += buffer->SampleLen;
3234 BufferList = BufferList->next;
3236 assert(Buffer != NULL);
3238 if(looping)
3239 readPos %= totalBufferLen;
3240 else
3242 /* Wrap back to 0 */
3243 if(readPos >= totalBufferLen)
3244 readPos = readPosFrac = 0;
3247 switch(name)
3249 case AL_SEC_OFFSET:
3250 offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
3251 break;
3253 case AL_SAMPLE_OFFSET:
3254 offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
3255 break;
3257 case AL_BYTE_OFFSET:
3258 if(Buffer->OriginalType == UserFmtIMA4)
3260 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3261 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3262 ALuint FrameBlockSize = Buffer->OriginalAlign;
3264 /* Round down to nearest ADPCM block */
3265 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3267 else if(Buffer->OriginalType == UserFmtMSADPCM)
3269 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3270 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3271 ALuint FrameBlockSize = Buffer->OriginalAlign;
3273 /* Round down to nearest ADPCM block */
3274 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3276 else
3278 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3279 offset = (ALdouble)(readPos * FrameSize);
3281 break;
3284 ReadUnlock(&Source->queue_lock);
3285 return offset;
3289 /* ApplyOffset
3291 * Apply the stored playback offset to the Source. This function will update
3292 * the number of buffers "played" given the stored offset.
3294 ALboolean ApplyOffset(ALsource *Source)
3296 ALbufferlistitem *BufferList;
3297 const ALbuffer *Buffer;
3298 ALuint bufferLen, totalBufferLen;
3299 ALuint offset=0, frac=0;
3301 /* Get sample frame offset */
3302 if(!GetSampleOffset(Source, &offset, &frac))
3303 return AL_FALSE;
3305 totalBufferLen = 0;
3306 BufferList = ATOMIC_LOAD(&Source->queue);
3307 while(BufferList && totalBufferLen <= offset)
3309 Buffer = BufferList->buffer;
3310 bufferLen = Buffer ? Buffer->SampleLen : 0;
3312 if(bufferLen > offset-totalBufferLen)
3314 /* Offset is in this buffer */
3315 ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed);
3317 ATOMIC_STORE(&Source->position, offset - totalBufferLen, almemory_order_relaxed);
3318 ATOMIC_STORE(&Source->position_fraction, frac, almemory_order_release);
3319 return AL_TRUE;
3322 totalBufferLen += bufferLen;
3324 BufferList = BufferList->next;
3327 /* Offset is out of range of the queue */
3328 return AL_FALSE;
3332 /* GetSampleOffset
3334 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3335 * or Second offset supplied by the application). This takes into account the
3336 * fact that the buffer format may have been modifed since.
3338 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
3340 const ALbuffer *Buffer = NULL;
3341 const ALbufferlistitem *BufferList;
3342 ALdouble dbloff, dblfrac;
3344 /* Find the first valid Buffer in the Queue */
3345 BufferList = ATOMIC_LOAD(&Source->queue);
3346 while(BufferList)
3348 if(BufferList->buffer)
3350 Buffer = BufferList->buffer;
3351 break;
3353 BufferList = BufferList->next;
3355 if(!Buffer)
3357 Source->OffsetType = AL_NONE;
3358 Source->Offset = 0.0;
3359 return AL_FALSE;
3362 switch(Source->OffsetType)
3364 case AL_BYTE_OFFSET:
3365 /* Determine the ByteOffset (and ensure it is block aligned) */
3366 *offset = (ALuint)Source->Offset;
3367 if(Buffer->OriginalType == UserFmtIMA4)
3369 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3370 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3371 *offset *= Buffer->OriginalAlign;
3373 else if(Buffer->OriginalType == UserFmtMSADPCM)
3375 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3376 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3377 *offset *= Buffer->OriginalAlign;
3379 else
3380 *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3381 *frac = 0;
3382 break;
3384 case AL_SAMPLE_OFFSET:
3385 dblfrac = modf(Source->Offset, &dbloff);
3386 *offset = (ALuint)mind(dbloff, UINT_MAX);
3387 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3388 break;
3390 case AL_SEC_OFFSET:
3391 dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
3392 *offset = (ALuint)mind(dbloff, UINT_MAX);
3393 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3394 break;
3396 Source->OffsetType = AL_NONE;
3397 Source->Offset = 0.0;
3399 return AL_TRUE;
3403 /* ReleaseALSources
3405 * Destroys all sources in the source map.
3407 ALvoid ReleaseALSources(ALCcontext *Context)
3409 ALsizei pos;
3410 for(pos = 0;pos < Context->SourceMap.size;pos++)
3412 ALsource *temp = Context->SourceMap.values[pos];
3413 Context->SourceMap.values[pos] = NULL;
3415 DeinitSource(temp);
3417 FreeThunkEntry(temp->id);
3418 memset(temp, 0, sizeof(*temp));
3419 al_free(temp);