Make the voices' Send[] array dynamically sized
[openal-soft.git] / OpenAL32 / alSource.c
blobc541884b9aa2fdd8a304ff1f908d3f641a509833
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);
49 extern inline ALboolean IsPlayingOrPaused(const ALsource *source);
51 static void InitSourceParams(ALsource *Source);
52 static void DeinitSource(ALsource *source);
53 static void UpdateSourceProps(ALsource *source, ALuint num_sends);
54 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime);
55 static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime);
56 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device);
57 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac);
59 typedef enum SourceProp {
60 srcPitch = AL_PITCH,
61 srcGain = AL_GAIN,
62 srcMinGain = AL_MIN_GAIN,
63 srcMaxGain = AL_MAX_GAIN,
64 srcMaxDistance = AL_MAX_DISTANCE,
65 srcRolloffFactor = AL_ROLLOFF_FACTOR,
66 srcDopplerFactor = AL_DOPPLER_FACTOR,
67 srcConeOuterGain = AL_CONE_OUTER_GAIN,
68 srcSecOffset = AL_SEC_OFFSET,
69 srcSampleOffset = AL_SAMPLE_OFFSET,
70 srcByteOffset = AL_BYTE_OFFSET,
71 srcConeInnerAngle = AL_CONE_INNER_ANGLE,
72 srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
73 srcRefDistance = AL_REFERENCE_DISTANCE,
75 srcPosition = AL_POSITION,
76 srcVelocity = AL_VELOCITY,
77 srcDirection = AL_DIRECTION,
79 srcSourceRelative = AL_SOURCE_RELATIVE,
80 srcLooping = AL_LOOPING,
81 srcBuffer = AL_BUFFER,
82 srcSourceState = AL_SOURCE_STATE,
83 srcBuffersQueued = AL_BUFFERS_QUEUED,
84 srcBuffersProcessed = AL_BUFFERS_PROCESSED,
85 srcSourceType = AL_SOURCE_TYPE,
87 /* ALC_EXT_EFX */
88 srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
89 srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
90 srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
91 srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
92 srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
93 srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
94 srcDirectFilter = AL_DIRECT_FILTER,
95 srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
97 /* AL_SOFT_direct_channels */
98 srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
100 /* AL_EXT_source_distance_model */
101 srcDistanceModel = AL_DISTANCE_MODEL,
103 srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
104 srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
105 srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
107 /* AL_SOFT_source_latency */
108 srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
109 srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
111 /* AL_EXT_STEREO_ANGLES */
112 srcAngles = AL_STEREO_ANGLES,
114 /* AL_EXT_SOURCE_RADIUS */
115 srcRadius = AL_SOURCE_RADIUS,
117 /* AL_EXT_BFORMAT */
118 srcOrientation = AL_ORIENTATION,
119 } SourceProp;
121 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
122 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
123 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
125 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
126 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
127 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
129 static inline ALvoice *GetSourceVoice(const ALsource *source, const ALCcontext *context)
131 ALvoice **voice = context->Voices;
132 ALvoice **voice_end = voice + context->VoiceCount;
133 while(voice != voice_end)
135 if((*voice)->Source == source)
136 return *voice;
137 ++voice;
139 return NULL;
142 static inline bool SourceShouldUpdate(const ALsource *source, const ALCcontext *context)
144 return IsPlayingOrPaused(source) &&
145 !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire);
148 static ALint FloatValsByProp(ALenum prop)
150 if(prop != (ALenum)((SourceProp)prop))
151 return 0;
152 switch((SourceProp)prop)
154 case AL_PITCH:
155 case AL_GAIN:
156 case AL_MIN_GAIN:
157 case AL_MAX_GAIN:
158 case AL_MAX_DISTANCE:
159 case AL_ROLLOFF_FACTOR:
160 case AL_DOPPLER_FACTOR:
161 case AL_CONE_OUTER_GAIN:
162 case AL_SEC_OFFSET:
163 case AL_SAMPLE_OFFSET:
164 case AL_BYTE_OFFSET:
165 case AL_CONE_INNER_ANGLE:
166 case AL_CONE_OUTER_ANGLE:
167 case AL_REFERENCE_DISTANCE:
168 case AL_CONE_OUTER_GAINHF:
169 case AL_AIR_ABSORPTION_FACTOR:
170 case AL_ROOM_ROLLOFF_FACTOR:
171 case AL_DIRECT_FILTER_GAINHF_AUTO:
172 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
173 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
174 case AL_DIRECT_CHANNELS_SOFT:
175 case AL_DISTANCE_MODEL:
176 case AL_SOURCE_RELATIVE:
177 case AL_LOOPING:
178 case AL_SOURCE_STATE:
179 case AL_BUFFERS_QUEUED:
180 case AL_BUFFERS_PROCESSED:
181 case AL_SOURCE_TYPE:
182 case AL_BYTE_LENGTH_SOFT:
183 case AL_SAMPLE_LENGTH_SOFT:
184 case AL_SEC_LENGTH_SOFT:
185 case AL_SOURCE_RADIUS:
186 return 1;
188 case AL_STEREO_ANGLES:
189 return 2;
191 case AL_POSITION:
192 case AL_VELOCITY:
193 case AL_DIRECTION:
194 return 3;
196 case AL_ORIENTATION:
197 return 6;
199 case AL_SEC_OFFSET_LATENCY_SOFT:
200 break; /* Double only */
202 case AL_BUFFER:
203 case AL_DIRECT_FILTER:
204 case AL_AUXILIARY_SEND_FILTER:
205 break; /* i/i64 only */
206 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
207 break; /* i64 only */
209 return 0;
211 static ALint DoubleValsByProp(ALenum prop)
213 if(prop != (ALenum)((SourceProp)prop))
214 return 0;
215 switch((SourceProp)prop)
217 case AL_PITCH:
218 case AL_GAIN:
219 case AL_MIN_GAIN:
220 case AL_MAX_GAIN:
221 case AL_MAX_DISTANCE:
222 case AL_ROLLOFF_FACTOR:
223 case AL_DOPPLER_FACTOR:
224 case AL_CONE_OUTER_GAIN:
225 case AL_SEC_OFFSET:
226 case AL_SAMPLE_OFFSET:
227 case AL_BYTE_OFFSET:
228 case AL_CONE_INNER_ANGLE:
229 case AL_CONE_OUTER_ANGLE:
230 case AL_REFERENCE_DISTANCE:
231 case AL_CONE_OUTER_GAINHF:
232 case AL_AIR_ABSORPTION_FACTOR:
233 case AL_ROOM_ROLLOFF_FACTOR:
234 case AL_DIRECT_FILTER_GAINHF_AUTO:
235 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
236 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
237 case AL_DIRECT_CHANNELS_SOFT:
238 case AL_DISTANCE_MODEL:
239 case AL_SOURCE_RELATIVE:
240 case AL_LOOPING:
241 case AL_SOURCE_STATE:
242 case AL_BUFFERS_QUEUED:
243 case AL_BUFFERS_PROCESSED:
244 case AL_SOURCE_TYPE:
245 case AL_BYTE_LENGTH_SOFT:
246 case AL_SAMPLE_LENGTH_SOFT:
247 case AL_SEC_LENGTH_SOFT:
248 case AL_SOURCE_RADIUS:
249 return 1;
251 case AL_SEC_OFFSET_LATENCY_SOFT:
252 case AL_STEREO_ANGLES:
253 return 2;
255 case AL_POSITION:
256 case AL_VELOCITY:
257 case AL_DIRECTION:
258 return 3;
260 case AL_ORIENTATION:
261 return 6;
263 case AL_BUFFER:
264 case AL_DIRECT_FILTER:
265 case AL_AUXILIARY_SEND_FILTER:
266 break; /* i/i64 only */
267 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
268 break; /* i64 only */
270 return 0;
273 static ALint IntValsByProp(ALenum prop)
275 if(prop != (ALenum)((SourceProp)prop))
276 return 0;
277 switch((SourceProp)prop)
279 case AL_PITCH:
280 case AL_GAIN:
281 case AL_MIN_GAIN:
282 case AL_MAX_GAIN:
283 case AL_MAX_DISTANCE:
284 case AL_ROLLOFF_FACTOR:
285 case AL_DOPPLER_FACTOR:
286 case AL_CONE_OUTER_GAIN:
287 case AL_SEC_OFFSET:
288 case AL_SAMPLE_OFFSET:
289 case AL_BYTE_OFFSET:
290 case AL_CONE_INNER_ANGLE:
291 case AL_CONE_OUTER_ANGLE:
292 case AL_REFERENCE_DISTANCE:
293 case AL_CONE_OUTER_GAINHF:
294 case AL_AIR_ABSORPTION_FACTOR:
295 case AL_ROOM_ROLLOFF_FACTOR:
296 case AL_DIRECT_FILTER_GAINHF_AUTO:
297 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
298 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
299 case AL_DIRECT_CHANNELS_SOFT:
300 case AL_DISTANCE_MODEL:
301 case AL_SOURCE_RELATIVE:
302 case AL_LOOPING:
303 case AL_BUFFER:
304 case AL_SOURCE_STATE:
305 case AL_BUFFERS_QUEUED:
306 case AL_BUFFERS_PROCESSED:
307 case AL_SOURCE_TYPE:
308 case AL_DIRECT_FILTER:
309 case AL_BYTE_LENGTH_SOFT:
310 case AL_SAMPLE_LENGTH_SOFT:
311 case AL_SEC_LENGTH_SOFT:
312 case AL_SOURCE_RADIUS:
313 return 1;
315 case AL_POSITION:
316 case AL_VELOCITY:
317 case AL_DIRECTION:
318 case AL_AUXILIARY_SEND_FILTER:
319 return 3;
321 case AL_ORIENTATION:
322 return 6;
324 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
325 break; /* i64 only */
326 case AL_SEC_OFFSET_LATENCY_SOFT:
327 break; /* Double only */
328 case AL_STEREO_ANGLES:
329 break; /* Float/double only */
331 return 0;
333 static ALint Int64ValsByProp(ALenum prop)
335 if(prop != (ALenum)((SourceProp)prop))
336 return 0;
337 switch((SourceProp)prop)
339 case AL_PITCH:
340 case AL_GAIN:
341 case AL_MIN_GAIN:
342 case AL_MAX_GAIN:
343 case AL_MAX_DISTANCE:
344 case AL_ROLLOFF_FACTOR:
345 case AL_DOPPLER_FACTOR:
346 case AL_CONE_OUTER_GAIN:
347 case AL_SEC_OFFSET:
348 case AL_SAMPLE_OFFSET:
349 case AL_BYTE_OFFSET:
350 case AL_CONE_INNER_ANGLE:
351 case AL_CONE_OUTER_ANGLE:
352 case AL_REFERENCE_DISTANCE:
353 case AL_CONE_OUTER_GAINHF:
354 case AL_AIR_ABSORPTION_FACTOR:
355 case AL_ROOM_ROLLOFF_FACTOR:
356 case AL_DIRECT_FILTER_GAINHF_AUTO:
357 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
358 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
359 case AL_DIRECT_CHANNELS_SOFT:
360 case AL_DISTANCE_MODEL:
361 case AL_SOURCE_RELATIVE:
362 case AL_LOOPING:
363 case AL_BUFFER:
364 case AL_SOURCE_STATE:
365 case AL_BUFFERS_QUEUED:
366 case AL_BUFFERS_PROCESSED:
367 case AL_SOURCE_TYPE:
368 case AL_DIRECT_FILTER:
369 case AL_BYTE_LENGTH_SOFT:
370 case AL_SAMPLE_LENGTH_SOFT:
371 case AL_SEC_LENGTH_SOFT:
372 case AL_SOURCE_RADIUS:
373 return 1;
375 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
376 return 2;
378 case AL_POSITION:
379 case AL_VELOCITY:
380 case AL_DIRECTION:
381 case AL_AUXILIARY_SEND_FILTER:
382 return 3;
384 case AL_ORIENTATION:
385 return 6;
387 case AL_SEC_OFFSET_LATENCY_SOFT:
388 break; /* Double only */
389 case AL_STEREO_ANGLES:
390 break; /* Float/double only */
392 return 0;
396 #define CHECKVAL(x) do { \
397 if(!(x)) \
398 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
399 } while(0)
401 #define DO_UPDATEPROPS() do { \
402 if(SourceShouldUpdate(Source, Context)) \
403 UpdateSourceProps(Source, device->NumAuxSends); \
404 else \
405 Source->NeedsUpdate = AL_TRUE; \
406 } while(0)
408 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
410 ALCdevice *device = Context->Device;
411 ALint ival;
413 switch(prop)
415 case AL_BYTE_LENGTH_SOFT:
416 case AL_SAMPLE_LENGTH_SOFT:
417 case AL_SEC_LENGTH_SOFT:
418 case AL_SEC_OFFSET_LATENCY_SOFT:
419 /* Query only */
420 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
422 case AL_PITCH:
423 CHECKVAL(*values >= 0.0f);
425 Source->Pitch = *values;
426 DO_UPDATEPROPS();
427 return AL_TRUE;
429 case AL_CONE_INNER_ANGLE:
430 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
432 Source->InnerAngle = *values;
433 DO_UPDATEPROPS();
434 return AL_TRUE;
436 case AL_CONE_OUTER_ANGLE:
437 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
439 Source->OuterAngle = *values;
440 DO_UPDATEPROPS();
441 return AL_TRUE;
443 case AL_GAIN:
444 CHECKVAL(*values >= 0.0f);
446 Source->Gain = *values;
447 DO_UPDATEPROPS();
448 return AL_TRUE;
450 case AL_MAX_DISTANCE:
451 CHECKVAL(*values >= 0.0f);
453 Source->MaxDistance = *values;
454 DO_UPDATEPROPS();
455 return AL_TRUE;
457 case AL_ROLLOFF_FACTOR:
458 CHECKVAL(*values >= 0.0f);
460 Source->RollOffFactor = *values;
461 DO_UPDATEPROPS();
462 return AL_TRUE;
464 case AL_REFERENCE_DISTANCE:
465 CHECKVAL(*values >= 0.0f);
467 Source->RefDistance = *values;
468 DO_UPDATEPROPS();
469 return AL_TRUE;
471 case AL_MIN_GAIN:
472 CHECKVAL(*values >= 0.0f);
474 Source->MinGain = *values;
475 DO_UPDATEPROPS();
476 return AL_TRUE;
478 case AL_MAX_GAIN:
479 CHECKVAL(*values >= 0.0f);
481 Source->MaxGain = *values;
482 DO_UPDATEPROPS();
483 return AL_TRUE;
485 case AL_CONE_OUTER_GAIN:
486 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
488 Source->OuterGain = *values;
489 DO_UPDATEPROPS();
490 return AL_TRUE;
492 case AL_CONE_OUTER_GAINHF:
493 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
495 Source->OuterGainHF = *values;
496 DO_UPDATEPROPS();
497 return AL_TRUE;
499 case AL_AIR_ABSORPTION_FACTOR:
500 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
502 Source->AirAbsorptionFactor = *values;
503 DO_UPDATEPROPS();
504 return AL_TRUE;
506 case AL_ROOM_ROLLOFF_FACTOR:
507 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
509 Source->RoomRolloffFactor = *values;
510 DO_UPDATEPROPS();
511 return AL_TRUE;
513 case AL_DOPPLER_FACTOR:
514 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
516 Source->DopplerFactor = *values;
517 DO_UPDATEPROPS();
518 return AL_TRUE;
520 case AL_SEC_OFFSET:
521 case AL_SAMPLE_OFFSET:
522 case AL_BYTE_OFFSET:
523 CHECKVAL(*values >= 0.0f);
525 Source->OffsetType = prop;
526 Source->Offset = *values;
528 if(IsPlayingOrPaused(Source) &&
529 !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire))
531 ALCdevice_Lock(Context->Device);
532 WriteLock(&Source->queue_lock);
533 if(ApplyOffset(Source) == AL_FALSE)
535 WriteUnlock(&Source->queue_lock);
536 ALCdevice_Unlock(Context->Device);
537 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
539 WriteUnlock(&Source->queue_lock);
540 ALCdevice_Unlock(Context->Device);
542 return AL_TRUE;
544 case AL_SOURCE_RADIUS:
545 CHECKVAL(*values >= 0.0f && isfinite(*values));
547 Source->Radius = *values;
548 DO_UPDATEPROPS();
549 return AL_TRUE;
551 case AL_STEREO_ANGLES:
552 CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
554 Source->StereoPan[0] = values[0];
555 Source->StereoPan[1] = values[1];
556 DO_UPDATEPROPS();
557 return AL_TRUE;
560 case AL_POSITION:
561 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
563 Source->Position[0] = values[0];
564 Source->Position[1] = values[1];
565 Source->Position[2] = values[2];
566 DO_UPDATEPROPS();
567 return AL_TRUE;
569 case AL_VELOCITY:
570 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
572 Source->Velocity[0] = values[0];
573 Source->Velocity[1] = values[1];
574 Source->Velocity[2] = values[2];
575 DO_UPDATEPROPS();
576 return AL_TRUE;
578 case AL_DIRECTION:
579 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
581 Source->Direction[0] = values[0];
582 Source->Direction[1] = values[1];
583 Source->Direction[2] = values[2];
584 DO_UPDATEPROPS();
585 return AL_TRUE;
587 case AL_ORIENTATION:
588 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
589 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
591 Source->Orientation[0][0] = values[0];
592 Source->Orientation[0][1] = values[1];
593 Source->Orientation[0][2] = values[2];
594 Source->Orientation[1][0] = values[3];
595 Source->Orientation[1][1] = values[4];
596 Source->Orientation[1][2] = values[5];
597 DO_UPDATEPROPS();
598 return AL_TRUE;
601 case AL_SOURCE_RELATIVE:
602 case AL_LOOPING:
603 case AL_SOURCE_STATE:
604 case AL_SOURCE_TYPE:
605 case AL_DISTANCE_MODEL:
606 case AL_DIRECT_FILTER_GAINHF_AUTO:
607 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
608 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
609 case AL_DIRECT_CHANNELS_SOFT:
610 ival = (ALint)values[0];
611 return SetSourceiv(Source, Context, prop, &ival);
613 case AL_BUFFERS_QUEUED:
614 case AL_BUFFERS_PROCESSED:
615 ival = (ALint)((ALuint)values[0]);
616 return SetSourceiv(Source, Context, prop, &ival);
618 case AL_BUFFER:
619 case AL_DIRECT_FILTER:
620 case AL_AUXILIARY_SEND_FILTER:
621 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
622 break;
625 ERR("Unexpected property: 0x%04x\n", prop);
626 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
629 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
631 ALCdevice *device = Context->Device;
632 ALbuffer *buffer = NULL;
633 ALfilter *filter = NULL;
634 ALeffectslot *slot = NULL;
635 ALbufferlistitem *oldlist;
636 ALbufferlistitem *newlist;
637 ALfloat fvals[6];
639 switch(prop)
641 case AL_SOURCE_STATE:
642 case AL_SOURCE_TYPE:
643 case AL_BUFFERS_QUEUED:
644 case AL_BUFFERS_PROCESSED:
645 case AL_BYTE_LENGTH_SOFT:
646 case AL_SAMPLE_LENGTH_SOFT:
647 case AL_SEC_LENGTH_SOFT:
648 /* Query only */
649 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
651 case AL_SOURCE_RELATIVE:
652 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
654 Source->HeadRelative = (ALboolean)*values;
655 DO_UPDATEPROPS();
656 return AL_TRUE;
658 case AL_LOOPING:
659 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
661 WriteLock(&Source->queue_lock);
662 ATOMIC_STORE_SEQ(&Source->looping, *values);
663 WriteUnlock(&Source->queue_lock);
664 return AL_TRUE;
666 case AL_BUFFER:
667 LockBuffersRead(device);
668 if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
670 UnlockBuffersRead(device);
671 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
674 WriteLock(&Source->queue_lock);
675 if(IsPlayingOrPaused(Source))
677 WriteUnlock(&Source->queue_lock);
678 UnlockBuffersRead(device);
679 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
682 if(buffer != NULL)
684 /* Add the selected buffer to a one-item queue */
685 newlist = malloc(sizeof(ALbufferlistitem));
686 newlist->buffer = buffer;
687 newlist->next = NULL;
688 IncrementRef(&buffer->ref);
690 /* Source is now Static */
691 Source->SourceType = AL_STATIC;
693 ReadLock(&buffer->lock);
694 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
695 Source->SampleSize = BytesFromFmt(buffer->FmtType);
696 ReadUnlock(&buffer->lock);
698 else
700 /* Source is now Undetermined */
701 Source->SourceType = AL_UNDETERMINED;
702 newlist = NULL;
704 oldlist = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &Source->queue, newlist);
705 ATOMIC_STORE_SEQ(&Source->current_buffer, newlist);
706 WriteUnlock(&Source->queue_lock);
707 UnlockBuffersRead(device);
709 /* Delete all elements in the previous queue */
710 while(oldlist != NULL)
712 ALbufferlistitem *temp = oldlist;
713 oldlist = temp->next;
715 if(temp->buffer)
716 DecrementRef(&temp->buffer->ref);
717 free(temp);
719 return AL_TRUE;
721 case AL_SEC_OFFSET:
722 case AL_SAMPLE_OFFSET:
723 case AL_BYTE_OFFSET:
724 CHECKVAL(*values >= 0);
726 Source->OffsetType = prop;
727 Source->Offset = *values;
729 if(IsPlayingOrPaused(Source) &&
730 !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire))
732 ALCdevice_Lock(Context->Device);
733 WriteLock(&Source->queue_lock);
734 if(ApplyOffset(Source) == AL_FALSE)
736 WriteUnlock(&Source->queue_lock);
737 ALCdevice_Unlock(Context->Device);
738 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
740 WriteUnlock(&Source->queue_lock);
741 ALCdevice_Unlock(Context->Device);
743 return AL_TRUE;
745 case AL_DIRECT_FILTER:
746 LockFiltersRead(device);
747 if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
749 UnlockFiltersRead(device);
750 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
753 if(!filter)
755 Source->Direct.Gain = 1.0f;
756 Source->Direct.GainHF = 1.0f;
757 Source->Direct.HFReference = LOWPASSFREQREF;
758 Source->Direct.GainLF = 1.0f;
759 Source->Direct.LFReference = HIGHPASSFREQREF;
761 else
763 Source->Direct.Gain = filter->Gain;
764 Source->Direct.GainHF = filter->GainHF;
765 Source->Direct.HFReference = filter->HFReference;
766 Source->Direct.GainLF = filter->GainLF;
767 Source->Direct.LFReference = filter->LFReference;
769 UnlockFiltersRead(device);
770 DO_UPDATEPROPS();
771 return AL_TRUE;
773 case AL_DIRECT_FILTER_GAINHF_AUTO:
774 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
776 Source->DryGainHFAuto = *values;
777 DO_UPDATEPROPS();
778 return AL_TRUE;
780 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
781 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
783 Source->WetGainAuto = *values;
784 DO_UPDATEPROPS();
785 return AL_TRUE;
787 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
788 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
790 Source->WetGainHFAuto = *values;
791 DO_UPDATEPROPS();
792 return AL_TRUE;
794 case AL_DIRECT_CHANNELS_SOFT:
795 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
797 Source->DirectChannels = *values;
798 DO_UPDATEPROPS();
799 return AL_TRUE;
801 case AL_DISTANCE_MODEL:
802 CHECKVAL(*values == AL_NONE ||
803 *values == AL_INVERSE_DISTANCE ||
804 *values == AL_INVERSE_DISTANCE_CLAMPED ||
805 *values == AL_LINEAR_DISTANCE ||
806 *values == AL_LINEAR_DISTANCE_CLAMPED ||
807 *values == AL_EXPONENT_DISTANCE ||
808 *values == AL_EXPONENT_DISTANCE_CLAMPED);
810 Source->DistanceModel = *values;
811 if(Context->SourceDistanceModel)
812 DO_UPDATEPROPS();
813 return AL_TRUE;
816 case AL_AUXILIARY_SEND_FILTER:
817 LockEffectSlotsRead(Context);
818 LockFiltersRead(device);
819 if(!((ALuint)values[1] < device->NumAuxSends &&
820 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
821 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
823 UnlockFiltersRead(device);
824 UnlockEffectSlotsRead(Context);
825 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
828 if(!filter)
830 /* Disable filter */
831 Source->Send[values[1]].Gain = 1.0f;
832 Source->Send[values[1]].GainHF = 1.0f;
833 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
834 Source->Send[values[1]].GainLF = 1.0f;
835 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
837 else
839 Source->Send[values[1]].Gain = filter->Gain;
840 Source->Send[values[1]].GainHF = filter->GainHF;
841 Source->Send[values[1]].HFReference = filter->HFReference;
842 Source->Send[values[1]].GainLF = filter->GainLF;
843 Source->Send[values[1]].LFReference = filter->LFReference;
845 UnlockFiltersRead(device);
847 if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source))
849 /* Add refcount on the new slot, and release the previous slot */
850 if(slot) IncrementRef(&slot->ref);
851 if(Source->Send[values[1]].Slot)
852 DecrementRef(&Source->Send[values[1]].Slot->ref);
853 Source->Send[values[1]].Slot = slot;
855 /* We must force an update if the auxiliary slot changed on a
856 * playing source, in case the slot is about to be deleted.
858 UpdateSourceProps(Source, device->NumAuxSends);
860 else
862 if(slot) IncrementRef(&slot->ref);
863 if(Source->Send[values[1]].Slot)
864 DecrementRef(&Source->Send[values[1]].Slot->ref);
865 Source->Send[values[1]].Slot = slot;
866 DO_UPDATEPROPS();
868 UnlockEffectSlotsRead(Context);
870 return AL_TRUE;
873 /* 1x float */
874 case AL_CONE_INNER_ANGLE:
875 case AL_CONE_OUTER_ANGLE:
876 case AL_PITCH:
877 case AL_GAIN:
878 case AL_MIN_GAIN:
879 case AL_MAX_GAIN:
880 case AL_REFERENCE_DISTANCE:
881 case AL_ROLLOFF_FACTOR:
882 case AL_CONE_OUTER_GAIN:
883 case AL_MAX_DISTANCE:
884 case AL_DOPPLER_FACTOR:
885 case AL_CONE_OUTER_GAINHF:
886 case AL_AIR_ABSORPTION_FACTOR:
887 case AL_ROOM_ROLLOFF_FACTOR:
888 case AL_SOURCE_RADIUS:
889 fvals[0] = (ALfloat)*values;
890 return SetSourcefv(Source, Context, (int)prop, fvals);
892 /* 3x float */
893 case AL_POSITION:
894 case AL_VELOCITY:
895 case AL_DIRECTION:
896 fvals[0] = (ALfloat)values[0];
897 fvals[1] = (ALfloat)values[1];
898 fvals[2] = (ALfloat)values[2];
899 return SetSourcefv(Source, Context, (int)prop, fvals);
901 /* 6x float */
902 case AL_ORIENTATION:
903 fvals[0] = (ALfloat)values[0];
904 fvals[1] = (ALfloat)values[1];
905 fvals[2] = (ALfloat)values[2];
906 fvals[3] = (ALfloat)values[3];
907 fvals[4] = (ALfloat)values[4];
908 fvals[5] = (ALfloat)values[5];
909 return SetSourcefv(Source, Context, (int)prop, fvals);
911 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
912 case AL_SEC_OFFSET_LATENCY_SOFT:
913 case AL_STEREO_ANGLES:
914 break;
917 ERR("Unexpected property: 0x%04x\n", prop);
918 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
921 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
923 ALfloat fvals[6];
924 ALint ivals[3];
926 switch(prop)
928 case AL_SOURCE_TYPE:
929 case AL_BUFFERS_QUEUED:
930 case AL_BUFFERS_PROCESSED:
931 case AL_SOURCE_STATE:
932 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
933 case AL_BYTE_LENGTH_SOFT:
934 case AL_SAMPLE_LENGTH_SOFT:
935 case AL_SEC_LENGTH_SOFT:
936 /* Query only */
937 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
940 /* 1x int */
941 case AL_SOURCE_RELATIVE:
942 case AL_LOOPING:
943 case AL_SEC_OFFSET:
944 case AL_SAMPLE_OFFSET:
945 case AL_BYTE_OFFSET:
946 case AL_DIRECT_FILTER_GAINHF_AUTO:
947 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
948 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
949 case AL_DIRECT_CHANNELS_SOFT:
950 case AL_DISTANCE_MODEL:
951 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
953 ivals[0] = (ALint)*values;
954 return SetSourceiv(Source, Context, (int)prop, ivals);
956 /* 1x uint */
957 case AL_BUFFER:
958 case AL_DIRECT_FILTER:
959 CHECKVAL(*values <= UINT_MAX && *values >= 0);
961 ivals[0] = (ALuint)*values;
962 return SetSourceiv(Source, Context, (int)prop, ivals);
964 /* 3x uint */
965 case AL_AUXILIARY_SEND_FILTER:
966 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
967 values[1] <= UINT_MAX && values[1] >= 0 &&
968 values[2] <= UINT_MAX && values[2] >= 0);
970 ivals[0] = (ALuint)values[0];
971 ivals[1] = (ALuint)values[1];
972 ivals[2] = (ALuint)values[2];
973 return SetSourceiv(Source, Context, (int)prop, ivals);
975 /* 1x float */
976 case AL_CONE_INNER_ANGLE:
977 case AL_CONE_OUTER_ANGLE:
978 case AL_PITCH:
979 case AL_GAIN:
980 case AL_MIN_GAIN:
981 case AL_MAX_GAIN:
982 case AL_REFERENCE_DISTANCE:
983 case AL_ROLLOFF_FACTOR:
984 case AL_CONE_OUTER_GAIN:
985 case AL_MAX_DISTANCE:
986 case AL_DOPPLER_FACTOR:
987 case AL_CONE_OUTER_GAINHF:
988 case AL_AIR_ABSORPTION_FACTOR:
989 case AL_ROOM_ROLLOFF_FACTOR:
990 case AL_SOURCE_RADIUS:
991 fvals[0] = (ALfloat)*values;
992 return SetSourcefv(Source, Context, (int)prop, fvals);
994 /* 3x float */
995 case AL_POSITION:
996 case AL_VELOCITY:
997 case AL_DIRECTION:
998 fvals[0] = (ALfloat)values[0];
999 fvals[1] = (ALfloat)values[1];
1000 fvals[2] = (ALfloat)values[2];
1001 return SetSourcefv(Source, Context, (int)prop, fvals);
1003 /* 6x float */
1004 case AL_ORIENTATION:
1005 fvals[0] = (ALfloat)values[0];
1006 fvals[1] = (ALfloat)values[1];
1007 fvals[2] = (ALfloat)values[2];
1008 fvals[3] = (ALfloat)values[3];
1009 fvals[4] = (ALfloat)values[4];
1010 fvals[5] = (ALfloat)values[5];
1011 return SetSourcefv(Source, Context, (int)prop, fvals);
1013 case AL_SEC_OFFSET_LATENCY_SOFT:
1014 case AL_STEREO_ANGLES:
1015 break;
1018 ERR("Unexpected property: 0x%04x\n", prop);
1019 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1022 #undef CHECKVAL
1025 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
1027 ALCdevice *device = Context->Device;
1028 ALbufferlistitem *BufferList;
1029 ClockLatency clocktime;
1030 ALuint64 srcclock;
1031 ALint ivals[3];
1032 ALboolean err;
1034 switch(prop)
1036 case AL_GAIN:
1037 *values = Source->Gain;
1038 return AL_TRUE;
1040 case AL_PITCH:
1041 *values = Source->Pitch;
1042 return AL_TRUE;
1044 case AL_MAX_DISTANCE:
1045 *values = Source->MaxDistance;
1046 return AL_TRUE;
1048 case AL_ROLLOFF_FACTOR:
1049 *values = Source->RollOffFactor;
1050 return AL_TRUE;
1052 case AL_REFERENCE_DISTANCE:
1053 *values = Source->RefDistance;
1054 return AL_TRUE;
1056 case AL_CONE_INNER_ANGLE:
1057 *values = Source->InnerAngle;
1058 return AL_TRUE;
1060 case AL_CONE_OUTER_ANGLE:
1061 *values = Source->OuterAngle;
1062 return AL_TRUE;
1064 case AL_MIN_GAIN:
1065 *values = Source->MinGain;
1066 return AL_TRUE;
1068 case AL_MAX_GAIN:
1069 *values = Source->MaxGain;
1070 return AL_TRUE;
1072 case AL_CONE_OUTER_GAIN:
1073 *values = Source->OuterGain;
1074 return AL_TRUE;
1076 case AL_SEC_OFFSET:
1077 case AL_SAMPLE_OFFSET:
1078 case AL_BYTE_OFFSET:
1079 *values = GetSourceOffset(Source, prop, device);
1080 return AL_TRUE;
1082 case AL_CONE_OUTER_GAINHF:
1083 *values = Source->OuterGainHF;
1084 return AL_TRUE;
1086 case AL_AIR_ABSORPTION_FACTOR:
1087 *values = Source->AirAbsorptionFactor;
1088 return AL_TRUE;
1090 case AL_ROOM_ROLLOFF_FACTOR:
1091 *values = Source->RoomRolloffFactor;
1092 return AL_TRUE;
1094 case AL_DOPPLER_FACTOR:
1095 *values = Source->DopplerFactor;
1096 return AL_TRUE;
1098 case AL_SEC_LENGTH_SOFT:
1099 ReadLock(&Source->queue_lock);
1100 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1101 *values = 0;
1102 else
1104 ALint length = 0;
1105 ALsizei freq = 1;
1106 do {
1107 ALbuffer *buffer = BufferList->buffer;
1108 if(buffer && buffer->SampleLen > 0)
1110 freq = buffer->Frequency;
1111 length += buffer->SampleLen;
1113 } while((BufferList=BufferList->next) != NULL);
1114 *values = (ALdouble)length / (ALdouble)freq;
1116 ReadUnlock(&Source->queue_lock);
1117 return AL_TRUE;
1119 case AL_SOURCE_RADIUS:
1120 *values = Source->Radius;
1121 return AL_TRUE;
1123 case AL_STEREO_ANGLES:
1124 values[0] = Source->StereoPan[0];
1125 values[1] = Source->StereoPan[1];
1126 return AL_TRUE;
1128 case AL_SEC_OFFSET_LATENCY_SOFT:
1129 /* Get the source offset with the clock time first. Then get the
1130 * clock time with the device latency. Order is important.
1132 values[0] = GetSourceSecOffset(Source, device, &srcclock);
1133 clocktime = V0(device->Backend,getClockLatency)();
1134 if(srcclock == (ALuint64)clocktime.ClockTime)
1135 values[1] = (ALdouble)clocktime.Latency / 1000000000.0;
1136 else
1138 /* If the clock time incremented, reduce the latency by that
1139 * much since it's that much closer to the source offset it got
1140 * earlier.
1142 ALuint64 diff = clocktime.ClockTime - srcclock;
1143 values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) /
1144 1000000000.0;
1146 return AL_TRUE;
1148 case AL_POSITION:
1149 values[0] = Source->Position[0];
1150 values[1] = Source->Position[1];
1151 values[2] = Source->Position[2];
1152 return AL_TRUE;
1154 case AL_VELOCITY:
1155 values[0] = Source->Velocity[0];
1156 values[1] = Source->Velocity[1];
1157 values[2] = Source->Velocity[2];
1158 return AL_TRUE;
1160 case AL_DIRECTION:
1161 values[0] = Source->Direction[0];
1162 values[1] = Source->Direction[1];
1163 values[2] = Source->Direction[2];
1164 return AL_TRUE;
1166 case AL_ORIENTATION:
1167 values[0] = Source->Orientation[0][0];
1168 values[1] = Source->Orientation[0][1];
1169 values[2] = Source->Orientation[0][2];
1170 values[3] = Source->Orientation[1][0];
1171 values[4] = Source->Orientation[1][1];
1172 values[5] = Source->Orientation[1][2];
1173 return AL_TRUE;
1175 /* 1x int */
1176 case AL_SOURCE_RELATIVE:
1177 case AL_LOOPING:
1178 case AL_SOURCE_STATE:
1179 case AL_BUFFERS_QUEUED:
1180 case AL_BUFFERS_PROCESSED:
1181 case AL_SOURCE_TYPE:
1182 case AL_DIRECT_FILTER_GAINHF_AUTO:
1183 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1184 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1185 case AL_DIRECT_CHANNELS_SOFT:
1186 case AL_BYTE_LENGTH_SOFT:
1187 case AL_SAMPLE_LENGTH_SOFT:
1188 case AL_DISTANCE_MODEL:
1189 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1190 *values = (ALdouble)ivals[0];
1191 return err;
1193 case AL_BUFFER:
1194 case AL_DIRECT_FILTER:
1195 case AL_AUXILIARY_SEND_FILTER:
1196 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1197 break;
1200 ERR("Unexpected property: 0x%04x\n", prop);
1201 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1204 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1206 ALbufferlistitem *BufferList;
1207 ALdouble dvals[6];
1208 ALboolean err;
1210 switch(prop)
1212 case AL_SOURCE_RELATIVE:
1213 *values = Source->HeadRelative;
1214 return AL_TRUE;
1216 case AL_LOOPING:
1217 *values = ATOMIC_LOAD_SEQ(&Source->looping);
1218 return AL_TRUE;
1220 case AL_BUFFER:
1221 ReadLock(&Source->queue_lock);
1222 BufferList = (Source->SourceType == AL_STATIC) ?
1223 ATOMIC_LOAD_SEQ(&Source->queue) :
1224 ATOMIC_LOAD_SEQ(&Source->current_buffer);
1225 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1226 ReadUnlock(&Source->queue_lock);
1227 return AL_TRUE;
1229 case AL_SOURCE_STATE:
1230 *values = ATOMIC_LOAD_SEQ(&Source->state);
1231 return AL_TRUE;
1233 case AL_BYTE_LENGTH_SOFT:
1234 ReadLock(&Source->queue_lock);
1235 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1236 *values = 0;
1237 else
1239 ALint length = 0;
1240 do {
1241 ALbuffer *buffer = BufferList->buffer;
1242 if(buffer && buffer->SampleLen > 0)
1244 ALuint byte_align, sample_align;
1245 if(buffer->OriginalType == UserFmtIMA4)
1247 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1248 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1249 sample_align = buffer->OriginalAlign;
1251 else if(buffer->OriginalType == UserFmtMSADPCM)
1253 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1254 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1255 sample_align = buffer->OriginalAlign;
1257 else
1259 ALsizei align = buffer->OriginalAlign;
1260 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1261 sample_align = buffer->OriginalAlign;
1264 length += buffer->SampleLen / sample_align * byte_align;
1266 } while((BufferList=BufferList->next) != NULL);
1267 *values = length;
1269 ReadUnlock(&Source->queue_lock);
1270 return AL_TRUE;
1272 case AL_SAMPLE_LENGTH_SOFT:
1273 ReadLock(&Source->queue_lock);
1274 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1275 *values = 0;
1276 else
1278 ALint length = 0;
1279 do {
1280 ALbuffer *buffer = BufferList->buffer;
1281 if(buffer) length += buffer->SampleLen;
1282 } while((BufferList=BufferList->next) != NULL);
1283 *values = length;
1285 ReadUnlock(&Source->queue_lock);
1286 return AL_TRUE;
1288 case AL_BUFFERS_QUEUED:
1289 ReadLock(&Source->queue_lock);
1290 if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue)))
1291 *values = 0;
1292 else
1294 ALsizei count = 0;
1295 do {
1296 ++count;
1297 } while((BufferList=BufferList->next) != NULL);
1298 *values = count;
1300 ReadUnlock(&Source->queue_lock);
1301 return AL_TRUE;
1303 case AL_BUFFERS_PROCESSED:
1304 ReadLock(&Source->queue_lock);
1305 if(ATOMIC_LOAD_SEQ(&Source->looping) || Source->SourceType != AL_STREAMING)
1307 /* Buffers on a looping source are in a perpetual state of
1308 * PENDING, so don't report any as PROCESSED */
1309 *values = 0;
1311 else
1313 const ALbufferlistitem *BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
1314 const ALbufferlistitem *Current = ATOMIC_LOAD_SEQ(&Source->current_buffer);
1315 ALsizei played = 0;
1316 while(BufferList && BufferList != Current)
1318 played++;
1319 BufferList = BufferList->next;
1321 *values = played;
1323 ReadUnlock(&Source->queue_lock);
1324 return AL_TRUE;
1326 case AL_SOURCE_TYPE:
1327 *values = Source->SourceType;
1328 return AL_TRUE;
1330 case AL_DIRECT_FILTER_GAINHF_AUTO:
1331 *values = Source->DryGainHFAuto;
1332 return AL_TRUE;
1334 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1335 *values = Source->WetGainAuto;
1336 return AL_TRUE;
1338 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1339 *values = Source->WetGainHFAuto;
1340 return AL_TRUE;
1342 case AL_DIRECT_CHANNELS_SOFT:
1343 *values = Source->DirectChannels;
1344 return AL_TRUE;
1346 case AL_DISTANCE_MODEL:
1347 *values = Source->DistanceModel;
1348 return AL_TRUE;
1350 /* 1x float/double */
1351 case AL_CONE_INNER_ANGLE:
1352 case AL_CONE_OUTER_ANGLE:
1353 case AL_PITCH:
1354 case AL_GAIN:
1355 case AL_MIN_GAIN:
1356 case AL_MAX_GAIN:
1357 case AL_REFERENCE_DISTANCE:
1358 case AL_ROLLOFF_FACTOR:
1359 case AL_CONE_OUTER_GAIN:
1360 case AL_MAX_DISTANCE:
1361 case AL_SEC_OFFSET:
1362 case AL_SAMPLE_OFFSET:
1363 case AL_BYTE_OFFSET:
1364 case AL_DOPPLER_FACTOR:
1365 case AL_AIR_ABSORPTION_FACTOR:
1366 case AL_ROOM_ROLLOFF_FACTOR:
1367 case AL_CONE_OUTER_GAINHF:
1368 case AL_SEC_LENGTH_SOFT:
1369 case AL_SOURCE_RADIUS:
1370 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1371 *values = (ALint)dvals[0];
1372 return err;
1374 /* 3x float/double */
1375 case AL_POSITION:
1376 case AL_VELOCITY:
1377 case AL_DIRECTION:
1378 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1380 values[0] = (ALint)dvals[0];
1381 values[1] = (ALint)dvals[1];
1382 values[2] = (ALint)dvals[2];
1384 return err;
1386 /* 6x float/double */
1387 case AL_ORIENTATION:
1388 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1390 values[0] = (ALint)dvals[0];
1391 values[1] = (ALint)dvals[1];
1392 values[2] = (ALint)dvals[2];
1393 values[3] = (ALint)dvals[3];
1394 values[4] = (ALint)dvals[4];
1395 values[5] = (ALint)dvals[5];
1397 return err;
1399 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1400 break; /* i64 only */
1401 case AL_SEC_OFFSET_LATENCY_SOFT:
1402 break; /* Double only */
1403 case AL_STEREO_ANGLES:
1404 break; /* Float/double only */
1406 case AL_DIRECT_FILTER:
1407 case AL_AUXILIARY_SEND_FILTER:
1408 break; /* ??? */
1411 ERR("Unexpected property: 0x%04x\n", prop);
1412 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1415 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1417 ALCdevice *device = Context->Device;
1418 ClockLatency clocktime;
1419 ALuint64 srcclock;
1420 ALdouble dvals[6];
1421 ALint ivals[3];
1422 ALboolean err;
1424 switch(prop)
1426 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1427 /* Get the source offset with the clock time first. Then get the
1428 * clock time with the device latency. Order is important.
1430 values[0] = GetSourceSampleOffset(Source, device, &srcclock);
1431 clocktime = V0(device->Backend,getClockLatency)();
1432 if(srcclock == (ALuint64)clocktime.ClockTime)
1433 values[1] = clocktime.Latency;
1434 else
1436 /* If the clock time incremented, reduce the latency by that
1437 * much since it's that much closer to the source offset it got
1438 * earlier.
1440 ALuint64 diff = clocktime.ClockTime - srcclock;
1441 values[1] = clocktime.Latency - minu64(clocktime.Latency, diff);
1443 return AL_TRUE;
1445 /* 1x float/double */
1446 case AL_CONE_INNER_ANGLE:
1447 case AL_CONE_OUTER_ANGLE:
1448 case AL_PITCH:
1449 case AL_GAIN:
1450 case AL_MIN_GAIN:
1451 case AL_MAX_GAIN:
1452 case AL_REFERENCE_DISTANCE:
1453 case AL_ROLLOFF_FACTOR:
1454 case AL_CONE_OUTER_GAIN:
1455 case AL_MAX_DISTANCE:
1456 case AL_SEC_OFFSET:
1457 case AL_SAMPLE_OFFSET:
1458 case AL_BYTE_OFFSET:
1459 case AL_DOPPLER_FACTOR:
1460 case AL_AIR_ABSORPTION_FACTOR:
1461 case AL_ROOM_ROLLOFF_FACTOR:
1462 case AL_CONE_OUTER_GAINHF:
1463 case AL_SEC_LENGTH_SOFT:
1464 case AL_SOURCE_RADIUS:
1465 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1466 *values = (ALint64)dvals[0];
1467 return err;
1469 /* 3x float/double */
1470 case AL_POSITION:
1471 case AL_VELOCITY:
1472 case AL_DIRECTION:
1473 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1475 values[0] = (ALint64)dvals[0];
1476 values[1] = (ALint64)dvals[1];
1477 values[2] = (ALint64)dvals[2];
1479 return err;
1481 /* 6x float/double */
1482 case AL_ORIENTATION:
1483 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1485 values[0] = (ALint64)dvals[0];
1486 values[1] = (ALint64)dvals[1];
1487 values[2] = (ALint64)dvals[2];
1488 values[3] = (ALint64)dvals[3];
1489 values[4] = (ALint64)dvals[4];
1490 values[5] = (ALint64)dvals[5];
1492 return err;
1494 /* 1x int */
1495 case AL_SOURCE_RELATIVE:
1496 case AL_LOOPING:
1497 case AL_SOURCE_STATE:
1498 case AL_BUFFERS_QUEUED:
1499 case AL_BUFFERS_PROCESSED:
1500 case AL_BYTE_LENGTH_SOFT:
1501 case AL_SAMPLE_LENGTH_SOFT:
1502 case AL_SOURCE_TYPE:
1503 case AL_DIRECT_FILTER_GAINHF_AUTO:
1504 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1505 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1506 case AL_DIRECT_CHANNELS_SOFT:
1507 case AL_DISTANCE_MODEL:
1508 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1509 *values = ivals[0];
1510 return err;
1512 /* 1x uint */
1513 case AL_BUFFER:
1514 case AL_DIRECT_FILTER:
1515 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1516 *values = (ALuint)ivals[0];
1517 return err;
1519 /* 3x uint */
1520 case AL_AUXILIARY_SEND_FILTER:
1521 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1523 values[0] = (ALuint)ivals[0];
1524 values[1] = (ALuint)ivals[1];
1525 values[2] = (ALuint)ivals[2];
1527 return err;
1529 case AL_SEC_OFFSET_LATENCY_SOFT:
1530 break; /* Double only */
1531 case AL_STEREO_ANGLES:
1532 break; /* Float/double only */
1535 ERR("Unexpected property: 0x%04x\n", prop);
1536 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1540 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1542 ALCcontext *context;
1543 ALsizei cur = 0;
1544 ALenum err;
1546 context = GetContextRef();
1547 if(!context) return;
1549 if(!(n >= 0))
1550 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1551 for(cur = 0;cur < n;cur++)
1553 ALsource *source = al_calloc(16, sizeof(ALsource));
1554 if(!source)
1556 alDeleteSources(cur, sources);
1557 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1559 InitSourceParams(source);
1561 err = NewThunkEntry(&source->id);
1562 if(err == AL_NO_ERROR)
1563 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1564 if(err != AL_NO_ERROR)
1566 FreeThunkEntry(source->id);
1567 memset(source, 0, sizeof(ALsource));
1568 al_free(source);
1570 alDeleteSources(cur, sources);
1571 SET_ERROR_AND_GOTO(context, err, done);
1574 sources[cur] = source->id;
1577 done:
1578 ALCcontext_DecRef(context);
1582 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1584 ALCcontext *context;
1585 ALsource *Source;
1586 ALsizei i;
1588 context = GetContextRef();
1589 if(!context) return;
1591 LockSourcesWrite(context);
1592 if(!(n >= 0))
1593 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1595 /* Check that all Sources are valid */
1596 for(i = 0;i < n;i++)
1598 if(LookupSource(context, sources[i]) == NULL)
1599 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1601 for(i = 0;i < n;i++)
1603 ALvoice *voice;
1605 if((Source=RemoveSource(context, sources[i])) == NULL)
1606 continue;
1607 FreeThunkEntry(Source->id);
1609 ALCdevice_Lock(context->Device);
1610 voice = GetSourceVoice(Source, context);
1611 if(voice) voice->Source = NULL;
1612 ALCdevice_Unlock(context->Device);
1614 DeinitSource(Source);
1616 memset(Source, 0, sizeof(*Source));
1617 al_free(Source);
1620 done:
1621 UnlockSourcesWrite(context);
1622 ALCcontext_DecRef(context);
1626 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1628 ALCcontext *context;
1629 ALboolean ret;
1631 context = GetContextRef();
1632 if(!context) return AL_FALSE;
1634 LockSourcesRead(context);
1635 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1636 UnlockSourcesRead(context);
1638 ALCcontext_DecRef(context);
1640 return ret;
1644 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1646 ALCcontext *Context;
1647 ALsource *Source;
1649 Context = GetContextRef();
1650 if(!Context) return;
1652 WriteLock(&Context->PropLock);
1653 LockSourcesRead(Context);
1654 if((Source=LookupSource(Context, source)) == NULL)
1655 alSetError(Context, AL_INVALID_NAME);
1656 else if(!(FloatValsByProp(param) == 1))
1657 alSetError(Context, AL_INVALID_ENUM);
1658 else
1659 SetSourcefv(Source, Context, param, &value);
1660 UnlockSourcesRead(Context);
1661 WriteUnlock(&Context->PropLock);
1663 ALCcontext_DecRef(Context);
1666 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1668 ALCcontext *Context;
1669 ALsource *Source;
1671 Context = GetContextRef();
1672 if(!Context) return;
1674 WriteLock(&Context->PropLock);
1675 LockSourcesRead(Context);
1676 if((Source=LookupSource(Context, source)) == NULL)
1677 alSetError(Context, AL_INVALID_NAME);
1678 else if(!(FloatValsByProp(param) == 3))
1679 alSetError(Context, AL_INVALID_ENUM);
1680 else
1682 ALfloat fvals[3] = { value1, value2, value3 };
1683 SetSourcefv(Source, Context, param, fvals);
1685 UnlockSourcesRead(Context);
1686 WriteUnlock(&Context->PropLock);
1688 ALCcontext_DecRef(Context);
1691 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1693 ALCcontext *Context;
1694 ALsource *Source;
1696 Context = GetContextRef();
1697 if(!Context) return;
1699 WriteLock(&Context->PropLock);
1700 LockSourcesRead(Context);
1701 if((Source=LookupSource(Context, source)) == NULL)
1702 alSetError(Context, AL_INVALID_NAME);
1703 else if(!values)
1704 alSetError(Context, AL_INVALID_VALUE);
1705 else if(!(FloatValsByProp(param) > 0))
1706 alSetError(Context, AL_INVALID_ENUM);
1707 else
1708 SetSourcefv(Source, Context, param, values);
1709 UnlockSourcesRead(Context);
1710 WriteUnlock(&Context->PropLock);
1712 ALCcontext_DecRef(Context);
1716 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1718 ALCcontext *Context;
1719 ALsource *Source;
1721 Context = GetContextRef();
1722 if(!Context) return;
1724 WriteLock(&Context->PropLock);
1725 LockSourcesRead(Context);
1726 if((Source=LookupSource(Context, source)) == NULL)
1727 alSetError(Context, AL_INVALID_NAME);
1728 else if(!(DoubleValsByProp(param) == 1))
1729 alSetError(Context, AL_INVALID_ENUM);
1730 else
1732 ALfloat fval = (ALfloat)value;
1733 SetSourcefv(Source, Context, param, &fval);
1735 UnlockSourcesRead(Context);
1736 WriteUnlock(&Context->PropLock);
1738 ALCcontext_DecRef(Context);
1741 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1743 ALCcontext *Context;
1744 ALsource *Source;
1746 Context = GetContextRef();
1747 if(!Context) return;
1749 WriteLock(&Context->PropLock);
1750 LockSourcesRead(Context);
1751 if((Source=LookupSource(Context, source)) == NULL)
1752 alSetError(Context, AL_INVALID_NAME);
1753 else if(!(DoubleValsByProp(param) == 3))
1754 alSetError(Context, AL_INVALID_ENUM);
1755 else
1757 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1758 SetSourcefv(Source, Context, param, fvals);
1760 UnlockSourcesRead(Context);
1761 WriteUnlock(&Context->PropLock);
1763 ALCcontext_DecRef(Context);
1766 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1768 ALCcontext *Context;
1769 ALsource *Source;
1770 ALint count;
1772 Context = GetContextRef();
1773 if(!Context) return;
1775 WriteLock(&Context->PropLock);
1776 LockSourcesRead(Context);
1777 if((Source=LookupSource(Context, source)) == NULL)
1778 alSetError(Context, AL_INVALID_NAME);
1779 else if(!values)
1780 alSetError(Context, AL_INVALID_VALUE);
1781 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1782 alSetError(Context, AL_INVALID_ENUM);
1783 else
1785 ALfloat fvals[6];
1786 ALint i;
1788 for(i = 0;i < count;i++)
1789 fvals[i] = (ALfloat)values[i];
1790 SetSourcefv(Source, Context, param, fvals);
1792 UnlockSourcesRead(Context);
1793 WriteUnlock(&Context->PropLock);
1795 ALCcontext_DecRef(Context);
1799 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1801 ALCcontext *Context;
1802 ALsource *Source;
1804 Context = GetContextRef();
1805 if(!Context) return;
1807 WriteLock(&Context->PropLock);
1808 LockSourcesRead(Context);
1809 if((Source=LookupSource(Context, source)) == NULL)
1810 alSetError(Context, AL_INVALID_NAME);
1811 else if(!(IntValsByProp(param) == 1))
1812 alSetError(Context, AL_INVALID_ENUM);
1813 else
1814 SetSourceiv(Source, Context, param, &value);
1815 UnlockSourcesRead(Context);
1816 WriteUnlock(&Context->PropLock);
1818 ALCcontext_DecRef(Context);
1821 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1823 ALCcontext *Context;
1824 ALsource *Source;
1826 Context = GetContextRef();
1827 if(!Context) return;
1829 WriteLock(&Context->PropLock);
1830 LockSourcesRead(Context);
1831 if((Source=LookupSource(Context, source)) == NULL)
1832 alSetError(Context, AL_INVALID_NAME);
1833 else if(!(IntValsByProp(param) == 3))
1834 alSetError(Context, AL_INVALID_ENUM);
1835 else
1837 ALint ivals[3] = { value1, value2, value3 };
1838 SetSourceiv(Source, Context, param, ivals);
1840 UnlockSourcesRead(Context);
1841 WriteUnlock(&Context->PropLock);
1843 ALCcontext_DecRef(Context);
1846 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1848 ALCcontext *Context;
1849 ALsource *Source;
1851 Context = GetContextRef();
1852 if(!Context) return;
1854 WriteLock(&Context->PropLock);
1855 LockSourcesRead(Context);
1856 if((Source=LookupSource(Context, source)) == NULL)
1857 alSetError(Context, AL_INVALID_NAME);
1858 else if(!values)
1859 alSetError(Context, AL_INVALID_VALUE);
1860 else if(!(IntValsByProp(param) > 0))
1861 alSetError(Context, AL_INVALID_ENUM);
1862 else
1863 SetSourceiv(Source, Context, param, values);
1864 UnlockSourcesRead(Context);
1865 WriteUnlock(&Context->PropLock);
1867 ALCcontext_DecRef(Context);
1871 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1873 ALCcontext *Context;
1874 ALsource *Source;
1876 Context = GetContextRef();
1877 if(!Context) return;
1879 WriteLock(&Context->PropLock);
1880 LockSourcesRead(Context);
1881 if((Source=LookupSource(Context, source)) == NULL)
1882 alSetError(Context, AL_INVALID_NAME);
1883 else if(!(Int64ValsByProp(param) == 1))
1884 alSetError(Context, AL_INVALID_ENUM);
1885 else
1886 SetSourcei64v(Source, Context, param, &value);
1887 UnlockSourcesRead(Context);
1888 WriteUnlock(&Context->PropLock);
1890 ALCcontext_DecRef(Context);
1893 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1895 ALCcontext *Context;
1896 ALsource *Source;
1898 Context = GetContextRef();
1899 if(!Context) return;
1901 WriteLock(&Context->PropLock);
1902 LockSourcesRead(Context);
1903 if((Source=LookupSource(Context, source)) == NULL)
1904 alSetError(Context, AL_INVALID_NAME);
1905 else if(!(Int64ValsByProp(param) == 3))
1906 alSetError(Context, AL_INVALID_ENUM);
1907 else
1909 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1910 SetSourcei64v(Source, Context, param, i64vals);
1912 UnlockSourcesRead(Context);
1913 WriteUnlock(&Context->PropLock);
1915 ALCcontext_DecRef(Context);
1918 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1920 ALCcontext *Context;
1921 ALsource *Source;
1923 Context = GetContextRef();
1924 if(!Context) return;
1926 WriteLock(&Context->PropLock);
1927 LockSourcesRead(Context);
1928 if((Source=LookupSource(Context, source)) == NULL)
1929 alSetError(Context, AL_INVALID_NAME);
1930 else if(!values)
1931 alSetError(Context, AL_INVALID_VALUE);
1932 else if(!(Int64ValsByProp(param) > 0))
1933 alSetError(Context, AL_INVALID_ENUM);
1934 else
1935 SetSourcei64v(Source, Context, param, values);
1936 UnlockSourcesRead(Context);
1937 WriteUnlock(&Context->PropLock);
1939 ALCcontext_DecRef(Context);
1943 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1945 ALCcontext *Context;
1946 ALsource *Source;
1948 Context = GetContextRef();
1949 if(!Context) return;
1951 ReadLock(&Context->PropLock);
1952 LockSourcesRead(Context);
1953 if((Source=LookupSource(Context, source)) == NULL)
1954 alSetError(Context, AL_INVALID_NAME);
1955 else if(!value)
1956 alSetError(Context, AL_INVALID_VALUE);
1957 else if(!(FloatValsByProp(param) == 1))
1958 alSetError(Context, AL_INVALID_ENUM);
1959 else
1961 ALdouble dval;
1962 if(GetSourcedv(Source, Context, param, &dval))
1963 *value = (ALfloat)dval;
1965 UnlockSourcesRead(Context);
1966 ReadUnlock(&Context->PropLock);
1968 ALCcontext_DecRef(Context);
1972 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1974 ALCcontext *Context;
1975 ALsource *Source;
1977 Context = GetContextRef();
1978 if(!Context) return;
1980 ReadLock(&Context->PropLock);
1981 LockSourcesRead(Context);
1982 if((Source=LookupSource(Context, source)) == NULL)
1983 alSetError(Context, AL_INVALID_NAME);
1984 else if(!(value1 && value2 && value3))
1985 alSetError(Context, AL_INVALID_VALUE);
1986 else if(!(FloatValsByProp(param) == 3))
1987 alSetError(Context, AL_INVALID_ENUM);
1988 else
1990 ALdouble dvals[3];
1991 if(GetSourcedv(Source, Context, param, dvals))
1993 *value1 = (ALfloat)dvals[0];
1994 *value2 = (ALfloat)dvals[1];
1995 *value3 = (ALfloat)dvals[2];
1998 UnlockSourcesRead(Context);
1999 ReadUnlock(&Context->PropLock);
2001 ALCcontext_DecRef(Context);
2005 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
2007 ALCcontext *Context;
2008 ALsource *Source;
2009 ALint count;
2011 Context = GetContextRef();
2012 if(!Context) return;
2014 ReadLock(&Context->PropLock);
2015 LockSourcesRead(Context);
2016 if((Source=LookupSource(Context, source)) == NULL)
2017 alSetError(Context, AL_INVALID_NAME);
2018 else if(!values)
2019 alSetError(Context, AL_INVALID_VALUE);
2020 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
2021 alSetError(Context, AL_INVALID_ENUM);
2022 else
2024 ALdouble dvals[6];
2025 if(GetSourcedv(Source, Context, param, dvals))
2027 ALint i;
2028 for(i = 0;i < count;i++)
2029 values[i] = (ALfloat)dvals[i];
2032 UnlockSourcesRead(Context);
2033 ReadUnlock(&Context->PropLock);
2035 ALCcontext_DecRef(Context);
2039 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
2041 ALCcontext *Context;
2042 ALsource *Source;
2044 Context = GetContextRef();
2045 if(!Context) return;
2047 ReadLock(&Context->PropLock);
2048 LockSourcesRead(Context);
2049 if((Source=LookupSource(Context, source)) == NULL)
2050 alSetError(Context, AL_INVALID_NAME);
2051 else if(!value)
2052 alSetError(Context, AL_INVALID_VALUE);
2053 else if(!(DoubleValsByProp(param) == 1))
2054 alSetError(Context, AL_INVALID_ENUM);
2055 else
2056 GetSourcedv(Source, Context, param, value);
2057 UnlockSourcesRead(Context);
2058 ReadUnlock(&Context->PropLock);
2060 ALCcontext_DecRef(Context);
2063 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
2065 ALCcontext *Context;
2066 ALsource *Source;
2068 Context = GetContextRef();
2069 if(!Context) return;
2071 ReadLock(&Context->PropLock);
2072 LockSourcesRead(Context);
2073 if((Source=LookupSource(Context, source)) == NULL)
2074 alSetError(Context, AL_INVALID_NAME);
2075 else if(!(value1 && value2 && value3))
2076 alSetError(Context, AL_INVALID_VALUE);
2077 else if(!(DoubleValsByProp(param) == 3))
2078 alSetError(Context, AL_INVALID_ENUM);
2079 else
2081 ALdouble dvals[3];
2082 if(GetSourcedv(Source, Context, param, dvals))
2084 *value1 = dvals[0];
2085 *value2 = dvals[1];
2086 *value3 = dvals[2];
2089 UnlockSourcesRead(Context);
2090 ReadUnlock(&Context->PropLock);
2092 ALCcontext_DecRef(Context);
2095 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
2097 ALCcontext *Context;
2098 ALsource *Source;
2100 Context = GetContextRef();
2101 if(!Context) return;
2103 ReadLock(&Context->PropLock);
2104 LockSourcesRead(Context);
2105 if((Source=LookupSource(Context, source)) == NULL)
2106 alSetError(Context, AL_INVALID_NAME);
2107 else if(!values)
2108 alSetError(Context, AL_INVALID_VALUE);
2109 else if(!(DoubleValsByProp(param) > 0))
2110 alSetError(Context, AL_INVALID_ENUM);
2111 else
2112 GetSourcedv(Source, Context, param, values);
2113 UnlockSourcesRead(Context);
2114 ReadUnlock(&Context->PropLock);
2116 ALCcontext_DecRef(Context);
2120 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2122 ALCcontext *Context;
2123 ALsource *Source;
2125 Context = GetContextRef();
2126 if(!Context) return;
2128 ReadLock(&Context->PropLock);
2129 LockSourcesRead(Context);
2130 if((Source=LookupSource(Context, source)) == NULL)
2131 alSetError(Context, AL_INVALID_NAME);
2132 else if(!value)
2133 alSetError(Context, AL_INVALID_VALUE);
2134 else if(!(IntValsByProp(param) == 1))
2135 alSetError(Context, AL_INVALID_ENUM);
2136 else
2137 GetSourceiv(Source, Context, param, value);
2138 UnlockSourcesRead(Context);
2139 ReadUnlock(&Context->PropLock);
2141 ALCcontext_DecRef(Context);
2145 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2147 ALCcontext *Context;
2148 ALsource *Source;
2150 Context = GetContextRef();
2151 if(!Context) return;
2153 ReadLock(&Context->PropLock);
2154 LockSourcesRead(Context);
2155 if((Source=LookupSource(Context, source)) == NULL)
2156 alSetError(Context, AL_INVALID_NAME);
2157 else if(!(value1 && value2 && value3))
2158 alSetError(Context, AL_INVALID_VALUE);
2159 else if(!(IntValsByProp(param) == 3))
2160 alSetError(Context, AL_INVALID_ENUM);
2161 else
2163 ALint ivals[3];
2164 if(GetSourceiv(Source, Context, param, ivals))
2166 *value1 = ivals[0];
2167 *value2 = ivals[1];
2168 *value3 = ivals[2];
2171 UnlockSourcesRead(Context);
2172 ReadUnlock(&Context->PropLock);
2174 ALCcontext_DecRef(Context);
2178 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2180 ALCcontext *Context;
2181 ALsource *Source;
2183 Context = GetContextRef();
2184 if(!Context) return;
2186 ReadLock(&Context->PropLock);
2187 LockSourcesRead(Context);
2188 if((Source=LookupSource(Context, source)) == NULL)
2189 alSetError(Context, AL_INVALID_NAME);
2190 else if(!values)
2191 alSetError(Context, AL_INVALID_VALUE);
2192 else if(!(IntValsByProp(param) > 0))
2193 alSetError(Context, AL_INVALID_ENUM);
2194 else
2195 GetSourceiv(Source, Context, param, values);
2196 UnlockSourcesRead(Context);
2197 ReadUnlock(&Context->PropLock);
2199 ALCcontext_DecRef(Context);
2203 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2205 ALCcontext *Context;
2206 ALsource *Source;
2208 Context = GetContextRef();
2209 if(!Context) return;
2211 ReadLock(&Context->PropLock);
2212 LockSourcesRead(Context);
2213 if((Source=LookupSource(Context, source)) == NULL)
2214 alSetError(Context, AL_INVALID_NAME);
2215 else if(!value)
2216 alSetError(Context, AL_INVALID_VALUE);
2217 else if(!(Int64ValsByProp(param) == 1))
2218 alSetError(Context, AL_INVALID_ENUM);
2219 else
2220 GetSourcei64v(Source, Context, param, value);
2221 UnlockSourcesRead(Context);
2222 ReadUnlock(&Context->PropLock);
2224 ALCcontext_DecRef(Context);
2227 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2229 ALCcontext *Context;
2230 ALsource *Source;
2232 Context = GetContextRef();
2233 if(!Context) return;
2235 ReadLock(&Context->PropLock);
2236 LockSourcesRead(Context);
2237 if((Source=LookupSource(Context, source)) == NULL)
2238 alSetError(Context, AL_INVALID_NAME);
2239 else if(!(value1 && value2 && value3))
2240 alSetError(Context, AL_INVALID_VALUE);
2241 else if(!(Int64ValsByProp(param) == 3))
2242 alSetError(Context, AL_INVALID_ENUM);
2243 else
2245 ALint64 i64vals[3];
2246 if(GetSourcei64v(Source, Context, param, i64vals))
2248 *value1 = i64vals[0];
2249 *value2 = i64vals[1];
2250 *value3 = i64vals[2];
2253 UnlockSourcesRead(Context);
2254 ReadUnlock(&Context->PropLock);
2256 ALCcontext_DecRef(Context);
2259 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2261 ALCcontext *Context;
2262 ALsource *Source;
2264 Context = GetContextRef();
2265 if(!Context) return;
2267 ReadLock(&Context->PropLock);
2268 LockSourcesRead(Context);
2269 if((Source=LookupSource(Context, source)) == NULL)
2270 alSetError(Context, AL_INVALID_NAME);
2271 else if(!values)
2272 alSetError(Context, AL_INVALID_VALUE);
2273 else if(!(Int64ValsByProp(param) > 0))
2274 alSetError(Context, AL_INVALID_ENUM);
2275 else
2276 GetSourcei64v(Source, Context, param, values);
2277 UnlockSourcesRead(Context);
2278 ReadUnlock(&Context->PropLock);
2280 ALCcontext_DecRef(Context);
2284 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2286 alSourcePlayv(1, &source);
2288 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2290 ALCcontext *context;
2291 ALsource *source;
2292 ALsizei i;
2294 context = GetContextRef();
2295 if(!context) return;
2297 LockSourcesRead(context);
2298 if(!(n >= 0))
2299 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2300 for(i = 0;i < n;i++)
2302 if(!LookupSource(context, sources[i]))
2303 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2306 ALCdevice_Lock(context->Device);
2307 while(n > context->MaxVoices-context->VoiceCount)
2309 ALsizei newcount = context->MaxVoices << 1;
2310 if(context->MaxVoices >= newcount)
2312 ALCdevice_Unlock(context->Device);
2313 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2315 AllocateVoices(context, newcount, context->Device->NumAuxSends);
2318 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll)
2320 for(i = 0;i < n;i++)
2322 source = LookupSource(context, sources[i]);
2323 source->new_state = AL_PLAYING;
2326 else
2328 for(i = 0;i < n;i++)
2330 source = LookupSource(context, sources[i]);
2331 SetSourceState(source, context, AL_PLAYING);
2334 ALCdevice_Unlock(context->Device);
2336 done:
2337 UnlockSourcesRead(context);
2338 ALCcontext_DecRef(context);
2341 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2343 alSourcePausev(1, &source);
2345 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2347 ALCcontext *context;
2348 ALsource *source;
2349 ALsizei i;
2351 context = GetContextRef();
2352 if(!context) return;
2354 LockSourcesRead(context);
2355 if(!(n >= 0))
2356 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2357 for(i = 0;i < n;i++)
2359 if(!LookupSource(context, sources[i]))
2360 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2363 ALCdevice_Lock(context->Device);
2364 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
2366 for(i = 0;i < n;i++)
2368 source = LookupSource(context, sources[i]);
2369 source->new_state = AL_PAUSED;
2372 else
2374 for(i = 0;i < n;i++)
2376 source = LookupSource(context, sources[i]);
2377 SetSourceState(source, context, AL_PAUSED);
2380 ALCdevice_Unlock(context->Device);
2382 done:
2383 UnlockSourcesRead(context);
2384 ALCcontext_DecRef(context);
2387 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2389 alSourceStopv(1, &source);
2391 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2393 ALCcontext *context;
2394 ALsource *source;
2395 ALsizei i;
2397 context = GetContextRef();
2398 if(!context) return;
2400 LockSourcesRead(context);
2401 if(!(n >= 0))
2402 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2403 for(i = 0;i < n;i++)
2405 if(!LookupSource(context, sources[i]))
2406 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2409 ALCdevice_Lock(context->Device);
2410 for(i = 0;i < n;i++)
2412 source = LookupSource(context, sources[i]);
2413 source->new_state = AL_NONE;
2414 SetSourceState(source, context, AL_STOPPED);
2416 ALCdevice_Unlock(context->Device);
2418 done:
2419 UnlockSourcesRead(context);
2420 ALCcontext_DecRef(context);
2423 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2425 alSourceRewindv(1, &source);
2427 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2429 ALCcontext *context;
2430 ALsource *source;
2431 ALsizei i;
2433 context = GetContextRef();
2434 if(!context) return;
2436 LockSourcesRead(context);
2437 if(!(n >= 0))
2438 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2439 for(i = 0;i < n;i++)
2441 if(!LookupSource(context, sources[i]))
2442 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2445 ALCdevice_Lock(context->Device);
2446 for(i = 0;i < n;i++)
2448 source = LookupSource(context, sources[i]);
2449 source->new_state = AL_NONE;
2450 SetSourceState(source, context, AL_INITIAL);
2452 ALCdevice_Unlock(context->Device);
2454 done:
2455 UnlockSourcesRead(context);
2456 ALCcontext_DecRef(context);
2460 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2462 ALCdevice *device;
2463 ALCcontext *context;
2464 ALsource *source;
2465 ALsizei i;
2466 ALbufferlistitem *BufferListStart;
2467 ALbufferlistitem *BufferList;
2468 ALbuffer *BufferFmt = NULL;
2470 if(nb == 0)
2471 return;
2473 context = GetContextRef();
2474 if(!context) return;
2476 device = context->Device;
2478 LockSourcesRead(context);
2479 if(!(nb >= 0))
2480 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2481 if((source=LookupSource(context, src)) == NULL)
2482 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2484 WriteLock(&source->queue_lock);
2485 if(source->SourceType == AL_STATIC)
2487 WriteUnlock(&source->queue_lock);
2488 /* Can't queue on a Static Source */
2489 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2492 /* Check for a valid Buffer, for its frequency and format */
2493 BufferList = ATOMIC_LOAD_SEQ(&source->queue);
2494 while(BufferList)
2496 if(BufferList->buffer)
2498 BufferFmt = BufferList->buffer;
2499 break;
2501 BufferList = BufferList->next;
2504 LockBuffersRead(device);
2505 BufferListStart = NULL;
2506 BufferList = NULL;
2507 for(i = 0;i < nb;i++)
2509 ALbuffer *buffer = NULL;
2510 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2512 WriteUnlock(&source->queue_lock);
2513 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2516 if(!BufferListStart)
2518 BufferListStart = malloc(sizeof(ALbufferlistitem));
2519 BufferList = BufferListStart;
2521 else
2523 BufferList->next = malloc(sizeof(ALbufferlistitem));
2524 BufferList = BufferList->next;
2526 BufferList->buffer = buffer;
2527 BufferList->next = NULL;
2528 if(!buffer) continue;
2530 /* Hold a read lock on each buffer being queued while checking all
2531 * provided buffers. This is done so other threads don't see an extra
2532 * reference on some buffers if this operation ends up failing. */
2533 ReadLock(&buffer->lock);
2534 IncrementRef(&buffer->ref);
2536 if(BufferFmt == NULL)
2538 BufferFmt = buffer;
2540 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2541 source->SampleSize = BytesFromFmt(buffer->FmtType);
2543 else if(BufferFmt->Frequency != buffer->Frequency ||
2544 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2545 BufferFmt->OriginalType != buffer->OriginalType)
2547 WriteUnlock(&source->queue_lock);
2548 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2550 buffer_error:
2551 /* A buffer failed (invalid ID or format), so unlock and release
2552 * each buffer we had. */
2553 while(BufferListStart)
2555 ALbufferlistitem *next = BufferListStart->next;
2556 if((buffer=BufferListStart->buffer) != NULL)
2558 DecrementRef(&buffer->ref);
2559 ReadUnlock(&buffer->lock);
2561 free(BufferListStart);
2562 BufferListStart = next;
2564 UnlockBuffersRead(device);
2565 goto done;
2568 /* All buffers good, unlock them now. */
2569 BufferList = BufferListStart;
2570 while(BufferList != NULL)
2572 ALbuffer *buffer = BufferList->buffer;
2573 if(buffer) ReadUnlock(&buffer->lock);
2574 BufferList = BufferList->next;
2576 UnlockBuffersRead(device);
2578 /* Source is now streaming */
2579 source->SourceType = AL_STREAMING;
2581 BufferList = NULL;
2582 if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem*, &source->queue,
2583 &BufferList, BufferListStart))
2585 /* Queue head is not NULL, append to the end of the queue */
2586 while(BufferList->next != NULL)
2587 BufferList = BufferList->next;
2588 BufferList->next = BufferListStart;
2590 /* If the current buffer was at the end (NULL), put it at the start of the newly queued
2591 * buffers.
2593 BufferList = NULL;
2594 ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem*, &source->current_buffer,
2595 &BufferList, BufferListStart);
2596 WriteUnlock(&source->queue_lock);
2598 done:
2599 UnlockSourcesRead(context);
2600 ALCcontext_DecRef(context);
2603 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2605 ALCcontext *context;
2606 ALsource *source;
2607 ALbufferlistitem *OldHead;
2608 ALbufferlistitem *OldTail;
2609 ALbufferlistitem *Current;
2610 ALsizei i = 0;
2612 if(nb == 0)
2613 return;
2615 context = GetContextRef();
2616 if(!context) return;
2618 LockSourcesRead(context);
2619 if(!(nb >= 0))
2620 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2622 if((source=LookupSource(context, src)) == NULL)
2623 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2625 WriteLock(&source->queue_lock);
2626 if(ATOMIC_LOAD_SEQ(&source->looping) || source->SourceType != AL_STREAMING)
2628 WriteUnlock(&source->queue_lock);
2629 /* Trying to unqueue buffers on a looping or non-streaming source. */
2630 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2633 /* Find the new buffer queue head */
2634 OldTail = ATOMIC_LOAD_SEQ(&source->queue);
2635 Current = ATOMIC_LOAD_SEQ(&source->current_buffer);
2636 if(OldTail != Current)
2638 for(i = 1;i < nb;i++)
2640 ALbufferlistitem *next = OldTail->next;
2641 if(!next || next == Current) break;
2642 OldTail = next;
2645 if(i != nb)
2647 WriteUnlock(&source->queue_lock);
2648 /* Trying to unqueue pending buffers. */
2649 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2652 /* Swap it, and cut the new head from the old. */
2653 OldHead = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &source->queue, OldTail->next);
2654 if(OldTail->next)
2656 ALCdevice *device = context->Device;
2657 uint count;
2659 /* Once the active mix (if any) is done, it's safe to cut the old tail
2660 * from the new head.
2662 if(((count=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
2664 while(count == ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))
2665 althrd_yield();
2667 ATOMIC_THREAD_FENCE(almemory_order_acq_rel);
2668 OldTail->next = NULL;
2670 WriteUnlock(&source->queue_lock);
2672 while(OldHead != NULL)
2674 ALbufferlistitem *next = OldHead->next;
2675 ALbuffer *buffer = OldHead->buffer;
2677 if(!buffer)
2678 *(buffers++) = 0;
2679 else
2681 *(buffers++) = buffer->id;
2682 DecrementRef(&buffer->ref);
2685 free(OldHead);
2686 OldHead = next;
2689 done:
2690 UnlockSourcesRead(context);
2691 ALCcontext_DecRef(context);
2695 static void InitSourceParams(ALsource *Source)
2697 ALuint i;
2699 RWLockInit(&Source->queue_lock);
2701 Source->InnerAngle = 360.0f;
2702 Source->OuterAngle = 360.0f;
2703 Source->Pitch = 1.0f;
2704 Source->Position[0] = 0.0f;
2705 Source->Position[1] = 0.0f;
2706 Source->Position[2] = 0.0f;
2707 Source->Velocity[0] = 0.0f;
2708 Source->Velocity[1] = 0.0f;
2709 Source->Velocity[2] = 0.0f;
2710 Source->Direction[0] = 0.0f;
2711 Source->Direction[1] = 0.0f;
2712 Source->Direction[2] = 0.0f;
2713 Source->Orientation[0][0] = 0.0f;
2714 Source->Orientation[0][1] = 0.0f;
2715 Source->Orientation[0][2] = -1.0f;
2716 Source->Orientation[1][0] = 0.0f;
2717 Source->Orientation[1][1] = 1.0f;
2718 Source->Orientation[1][2] = 0.0f;
2719 Source->RefDistance = 1.0f;
2720 Source->MaxDistance = FLT_MAX;
2721 Source->RollOffFactor = 1.0f;
2722 Source->Gain = 1.0f;
2723 Source->MinGain = 0.0f;
2724 Source->MaxGain = 1.0f;
2725 Source->OuterGain = 0.0f;
2726 Source->OuterGainHF = 1.0f;
2728 Source->DryGainHFAuto = AL_TRUE;
2729 Source->WetGainAuto = AL_TRUE;
2730 Source->WetGainHFAuto = AL_TRUE;
2731 Source->AirAbsorptionFactor = 0.0f;
2732 Source->RoomRolloffFactor = 0.0f;
2733 Source->DopplerFactor = 1.0f;
2734 Source->DirectChannels = AL_FALSE;
2736 Source->StereoPan[0] = DEG2RAD( 30.0f);
2737 Source->StereoPan[1] = DEG2RAD(-30.0f);
2739 Source->Radius = 0.0f;
2741 Source->DistanceModel = DefaultDistanceModel;
2743 Source->Direct.Gain = 1.0f;
2744 Source->Direct.GainHF = 1.0f;
2745 Source->Direct.HFReference = LOWPASSFREQREF;
2746 Source->Direct.GainLF = 1.0f;
2747 Source->Direct.LFReference = HIGHPASSFREQREF;
2748 for(i = 0;i < MAX_SENDS;i++)
2750 Source->Send[i].Slot = NULL;
2751 Source->Send[i].Gain = 1.0f;
2752 Source->Send[i].GainHF = 1.0f;
2753 Source->Send[i].HFReference = LOWPASSFREQREF;
2754 Source->Send[i].GainLF = 1.0f;
2755 Source->Send[i].LFReference = HIGHPASSFREQREF;
2758 Source->Offset = 0.0;
2759 Source->OffsetType = AL_NONE;
2760 Source->SourceType = AL_UNDETERMINED;
2761 ATOMIC_INIT(&Source->state, AL_INITIAL);
2762 Source->new_state = AL_NONE;
2764 ATOMIC_INIT(&Source->queue, NULL);
2765 ATOMIC_INIT(&Source->current_buffer, NULL);
2767 ATOMIC_INIT(&Source->position, 0);
2768 ATOMIC_INIT(&Source->position_fraction, 0);
2770 ATOMIC_INIT(&Source->looping, AL_FALSE);
2772 Source->NeedsUpdate = AL_TRUE;
2774 ATOMIC_INIT(&Source->Update, NULL);
2775 ATOMIC_INIT(&Source->FreeList, NULL);
2778 static void DeinitSource(ALsource *source)
2780 ALbufferlistitem *BufferList;
2781 struct ALsourceProps *props;
2782 size_t count = 0;
2783 size_t i;
2785 props = ATOMIC_LOAD_SEQ(&source->Update);
2786 if(props) al_free(props);
2788 props = ATOMIC_LOAD(&source->FreeList, almemory_order_relaxed);
2789 while(props)
2791 struct ALsourceProps *next;
2792 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2793 al_free(props);
2794 props = next;
2795 ++count;
2797 /* This is excessively spammy if it traces every source destruction, so
2798 * just warn if it was unexpectedly large.
2800 if(count > 3)
2801 WARN("Freed "SZFMT" Source property objects\n", count);
2803 BufferList = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &source->queue, NULL);
2804 while(BufferList != NULL)
2806 ALbufferlistitem *next = BufferList->next;
2807 if(BufferList->buffer != NULL)
2808 DecrementRef(&BufferList->buffer->ref);
2809 free(BufferList);
2810 BufferList = next;
2813 for(i = 0;i < MAX_SENDS;i++)
2815 if(source->Send[i].Slot)
2816 DecrementRef(&source->Send[i].Slot->ref);
2817 source->Send[i].Slot = NULL;
2821 static void UpdateSourceProps(ALsource *source, ALuint num_sends)
2823 struct ALsourceProps *props;
2824 size_t i;
2826 /* Get an unused property container, or allocate a new one as needed. */
2827 props = ATOMIC_LOAD(&source->FreeList, almemory_order_acquire);
2828 if(!props)
2829 props = al_calloc(16, offsetof(struct ALsourceProps, Send[num_sends]));
2830 else
2832 struct ALsourceProps *next;
2833 do {
2834 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2835 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*,
2836 &source->FreeList, &props, next, almemory_order_acq_rel,
2837 almemory_order_acquire) == 0);
2840 /* Copy in current property values. */
2841 ATOMIC_STORE(&props->Pitch, source->Pitch, almemory_order_relaxed);
2842 ATOMIC_STORE(&props->Gain, source->Gain, almemory_order_relaxed);
2843 ATOMIC_STORE(&props->OuterGain, source->OuterGain, almemory_order_relaxed);
2844 ATOMIC_STORE(&props->MinGain, source->MinGain, almemory_order_relaxed);
2845 ATOMIC_STORE(&props->MaxGain, source->MaxGain, almemory_order_relaxed);
2846 ATOMIC_STORE(&props->InnerAngle, source->InnerAngle, almemory_order_relaxed);
2847 ATOMIC_STORE(&props->OuterAngle, source->OuterAngle, almemory_order_relaxed);
2848 ATOMIC_STORE(&props->RefDistance, source->RefDistance, almemory_order_relaxed);
2849 ATOMIC_STORE(&props->MaxDistance, source->MaxDistance, almemory_order_relaxed);
2850 ATOMIC_STORE(&props->RollOffFactor, source->RollOffFactor, almemory_order_relaxed);
2851 for(i = 0;i < 3;i++)
2852 ATOMIC_STORE(&props->Position[i], source->Position[i], almemory_order_relaxed);
2853 for(i = 0;i < 3;i++)
2854 ATOMIC_STORE(&props->Velocity[i], source->Velocity[i], almemory_order_relaxed);
2855 for(i = 0;i < 3;i++)
2856 ATOMIC_STORE(&props->Direction[i], source->Direction[i], almemory_order_relaxed);
2857 for(i = 0;i < 2;i++)
2859 size_t j;
2860 for(j = 0;j < 3;j++)
2861 ATOMIC_STORE(&props->Orientation[i][j], source->Orientation[i][j],
2862 almemory_order_relaxed);
2864 ATOMIC_STORE(&props->HeadRelative, source->HeadRelative, almemory_order_relaxed);
2865 ATOMIC_STORE(&props->DistanceModel, source->DistanceModel, almemory_order_relaxed);
2866 ATOMIC_STORE(&props->DirectChannels, source->DirectChannels, almemory_order_relaxed);
2868 ATOMIC_STORE(&props->DryGainHFAuto, source->DryGainHFAuto, almemory_order_relaxed);
2869 ATOMIC_STORE(&props->WetGainAuto, source->WetGainAuto, almemory_order_relaxed);
2870 ATOMIC_STORE(&props->WetGainHFAuto, source->WetGainHFAuto, almemory_order_relaxed);
2871 ATOMIC_STORE(&props->OuterGainHF, source->OuterGainHF, almemory_order_relaxed);
2873 ATOMIC_STORE(&props->AirAbsorptionFactor, source->AirAbsorptionFactor, almemory_order_relaxed);
2874 ATOMIC_STORE(&props->RoomRolloffFactor, source->RoomRolloffFactor, almemory_order_relaxed);
2875 ATOMIC_STORE(&props->DopplerFactor, source->DopplerFactor, almemory_order_relaxed);
2877 ATOMIC_STORE(&props->StereoPan[0], source->StereoPan[0], almemory_order_relaxed);
2878 ATOMIC_STORE(&props->StereoPan[1], source->StereoPan[1], almemory_order_relaxed);
2880 ATOMIC_STORE(&props->Radius, source->Radius, almemory_order_relaxed);
2882 ATOMIC_STORE(&props->Direct.Gain, source->Direct.Gain, almemory_order_relaxed);
2883 ATOMIC_STORE(&props->Direct.GainHF, source->Direct.GainHF, almemory_order_relaxed);
2884 ATOMIC_STORE(&props->Direct.HFReference, source->Direct.HFReference, almemory_order_relaxed);
2885 ATOMIC_STORE(&props->Direct.GainLF, source->Direct.GainLF, almemory_order_relaxed);
2886 ATOMIC_STORE(&props->Direct.LFReference, source->Direct.LFReference, almemory_order_relaxed);
2888 for(i = 0;i < num_sends;i++)
2890 ATOMIC_STORE(&props->Send[i].Slot, source->Send[i].Slot, almemory_order_relaxed);
2891 ATOMIC_STORE(&props->Send[i].Gain, source->Send[i].Gain, almemory_order_relaxed);
2892 ATOMIC_STORE(&props->Send[i].GainHF, source->Send[i].GainHF, almemory_order_relaxed);
2893 ATOMIC_STORE(&props->Send[i].HFReference, source->Send[i].HFReference,
2894 almemory_order_relaxed);
2895 ATOMIC_STORE(&props->Send[i].GainLF, source->Send[i].GainLF, almemory_order_relaxed);
2896 ATOMIC_STORE(&props->Send[i].LFReference, source->Send[i].LFReference,
2897 almemory_order_relaxed);
2900 /* Set the new container for updating internal parameters. */
2901 props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, props, almemory_order_acq_rel);
2902 if(props)
2904 /* If there was an unused update container, put it back in the
2905 * freelist.
2907 ATOMIC_REPLACE_HEAD(struct ALsourceProps*, &source->FreeList, props);
2911 void UpdateAllSourceProps(ALCcontext *context)
2913 ALuint num_sends = context->Device->NumAuxSends;
2914 ALsizei pos;
2916 for(pos = 0;pos < context->VoiceCount;pos++)
2918 ALvoice *voice = context->Voices[pos];
2919 ALsource *source = voice->Source;
2920 if(source != NULL && source->NeedsUpdate && IsPlayingOrPaused(source))
2922 source->NeedsUpdate = AL_FALSE;
2923 UpdateSourceProps(source, num_sends);
2929 /* SetSourceState
2931 * Sets the source's new play state given its current state.
2933 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2935 WriteLock(&Source->queue_lock);
2936 if(state == AL_PLAYING)
2938 ALCdevice *device = Context->Device;
2939 ALbufferlistitem *BufferList;
2940 ALboolean discontinuity;
2941 ALvoice *voice = NULL;
2942 ALsizei i;
2944 /* Check that there is a queue containing at least one valid, non zero
2945 * length Buffer. */
2946 BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
2947 while(BufferList)
2949 ALbuffer *buffer;
2950 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2951 break;
2952 BufferList = BufferList->next;
2955 if(ATOMIC_EXCHANGE(ALenum, &Source->state, AL_PLAYING, almemory_order_acq_rel) == AL_PAUSED)
2956 discontinuity = AL_FALSE;
2957 else
2959 ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed);
2960 ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed);
2961 ATOMIC_STORE(&Source->position_fraction, 0, almemory_order_release);
2962 discontinuity = AL_TRUE;
2965 // Check if an Offset has been set
2966 if(Source->OffsetType != AL_NONE)
2968 ApplyOffset(Source);
2969 /* discontinuity = AL_TRUE;??? */
2972 /* If there's nothing to play, or device is disconnected, go right to
2973 * stopped */
2974 if(!BufferList || !device->Connected)
2975 goto do_stop;
2977 /* Make sure this source isn't already active, and if not, look for an
2978 * unused voice to put it in.
2980 voice = GetSourceVoice(Source, Context);
2981 if(voice == NULL)
2983 for(i = 0;i < Context->VoiceCount;i++)
2985 if(Context->Voices[i]->Source == NULL)
2987 voice = Context->Voices[i];
2988 voice->Source = Source;
2989 break;
2992 if(voice == NULL)
2994 voice = Context->Voices[Context->VoiceCount++];
2995 voice->Source = Source;
2997 discontinuity = AL_TRUE;
3000 if(discontinuity)
3002 /* Clear previous samples if playback is discontinuous. */
3003 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
3005 /* Clear the stepping value so the mixer knows not to mix this
3006 * until the update gets applied.
3008 voice->Step = 0;
3011 voice->Moving = AL_FALSE;
3012 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
3014 ALsizei j;
3015 for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
3016 voice->Direct.Params[i].Hrtf.State.History[j] = 0.0f;
3017 for(j = 0;j < HRIR_LENGTH;j++)
3019 voice->Direct.Params[i].Hrtf.State.Values[j][0] = 0.0f;
3020 voice->Direct.Params[i].Hrtf.State.Values[j][1] = 0.0f;
3024 Source->NeedsUpdate = AL_FALSE;
3025 UpdateSourceProps(Source, device->NumAuxSends);
3027 else if(state == AL_PAUSED)
3029 ALenum playing = AL_PLAYING;
3030 ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum, &Source->state, &playing, AL_PAUSED);
3032 else if(state == AL_STOPPED)
3034 do_stop:
3035 if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL)
3037 ATOMIC_STORE(&Source->state, AL_STOPPED, almemory_order_relaxed);
3038 ATOMIC_STORE_SEQ(&Source->current_buffer, NULL);
3040 Source->OffsetType = AL_NONE;
3041 Source->Offset = 0.0;
3043 else if(state == AL_INITIAL)
3045 if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL)
3047 ATOMIC_STORE(&Source->state, AL_INITIAL, almemory_order_relaxed);
3048 ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD_SEQ(&Source->queue),
3049 almemory_order_relaxed);
3050 ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed);
3051 ATOMIC_STORE_SEQ(&Source->position_fraction, 0);
3053 Source->OffsetType = AL_NONE;
3054 Source->Offset = 0.0;
3056 WriteUnlock(&Source->queue_lock);
3059 /* GetSourceSampleOffset
3061 * Gets the current read offset for the given Source, in 32.32 fixed-point
3062 * samples. The offset is relative to the start of the queue (not the start of
3063 * the current buffer).
3065 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime)
3067 const ALbufferlistitem *BufferList;
3068 const ALbufferlistitem *Current;
3069 ALuint64 readPos;
3070 ALuint refcount;
3072 ReadLock(&Source->queue_lock);
3073 if(!IsPlayingOrPaused(Source))
3075 ReadUnlock(&Source->queue_lock);
3076 do {
3077 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3078 althrd_yield();
3079 *clocktime = GetDeviceClockTime(device);
3080 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3081 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3082 return 0;
3085 do {
3086 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3087 althrd_yield();
3088 *clocktime = GetDeviceClockTime(device);
3090 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3091 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3093 readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << 32;
3094 readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed) <<
3095 (32-FRACTIONBITS);
3096 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3097 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3098 while(BufferList && BufferList != Current)
3100 if(BufferList->buffer)
3101 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
3102 BufferList = BufferList->next;
3105 ReadUnlock(&Source->queue_lock);
3106 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
3109 /* GetSourceSecOffset
3111 * Gets the current read offset for the given Source, in seconds. The offset is
3112 * relative to the start of the queue (not the start of the current buffer).
3114 static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime)
3116 const ALbufferlistitem *BufferList;
3117 const ALbufferlistitem *Current;
3118 const ALbuffer *Buffer = NULL;
3119 ALuint64 readPos;
3120 ALuint refcount;
3122 ReadLock(&Source->queue_lock);
3123 if(!IsPlayingOrPaused(Source))
3125 ReadUnlock(&Source->queue_lock);
3126 do {
3127 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3128 althrd_yield();
3129 *clocktime = GetDeviceClockTime(device);
3130 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3131 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3132 return 0.0;
3135 do {
3136 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3137 althrd_yield();
3138 *clocktime = GetDeviceClockTime(device);
3140 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3141 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3143 readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed)<<FRACTIONBITS;
3144 readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed);
3145 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3146 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3147 while(BufferList && BufferList != Current)
3149 const ALbuffer *buffer = BufferList->buffer;
3150 if(buffer != NULL)
3152 if(!Buffer) Buffer = buffer;
3153 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
3155 BufferList = BufferList->next;
3158 while(BufferList && !Buffer)
3160 Buffer = BufferList->buffer;
3161 BufferList = BufferList->next;
3163 assert(Buffer != NULL);
3165 ReadUnlock(&Source->queue_lock);
3166 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
3169 /* GetSourceOffset
3171 * Gets the current read offset for the given Source, in the appropriate format
3172 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3173 * queue (not the start of the current buffer).
3175 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device)
3177 const ALbufferlistitem *BufferList;
3178 const ALbufferlistitem *Current;
3179 const ALbuffer *Buffer = NULL;
3180 ALboolean readFin = AL_FALSE;
3181 ALuint readPos, readPosFrac;
3182 ALuint totalBufferLen;
3183 ALdouble offset = 0.0;
3184 ALboolean looping;
3185 ALuint refcount;
3187 ReadLock(&Source->queue_lock);
3188 if(!IsPlayingOrPaused(Source))
3190 ReadUnlock(&Source->queue_lock);
3191 return 0.0;
3194 totalBufferLen = 0;
3195 do {
3196 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3197 althrd_yield();
3198 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3199 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3201 readPos = ATOMIC_LOAD(&Source->position, almemory_order_relaxed);
3202 readPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed);
3204 looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed);
3205 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3206 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3208 while(BufferList != NULL)
3210 const ALbuffer *buffer;
3211 readFin = readFin || (BufferList == Current);
3212 if((buffer=BufferList->buffer) != NULL)
3214 if(!Buffer) Buffer = buffer;
3215 totalBufferLen += buffer->SampleLen;
3216 if(!readFin) readPos += buffer->SampleLen;
3218 BufferList = BufferList->next;
3220 assert(Buffer != NULL);
3222 if(looping)
3223 readPos %= totalBufferLen;
3224 else
3226 /* Wrap back to 0 */
3227 if(readPos >= totalBufferLen)
3228 readPos = readPosFrac = 0;
3231 switch(name)
3233 case AL_SEC_OFFSET:
3234 offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
3235 break;
3237 case AL_SAMPLE_OFFSET:
3238 offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
3239 break;
3241 case AL_BYTE_OFFSET:
3242 if(Buffer->OriginalType == UserFmtIMA4)
3244 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3245 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3246 ALuint FrameBlockSize = Buffer->OriginalAlign;
3248 /* Round down to nearest ADPCM block */
3249 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3251 else if(Buffer->OriginalType == UserFmtMSADPCM)
3253 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3254 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3255 ALuint FrameBlockSize = Buffer->OriginalAlign;
3257 /* Round down to nearest ADPCM block */
3258 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3260 else
3262 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3263 offset = (ALdouble)(readPos * FrameSize);
3265 break;
3268 ReadUnlock(&Source->queue_lock);
3269 return offset;
3273 /* ApplyOffset
3275 * Apply the stored playback offset to the Source. This function will update
3276 * the number of buffers "played" given the stored offset.
3278 ALboolean ApplyOffset(ALsource *Source)
3280 ALbufferlistitem *BufferList;
3281 const ALbuffer *Buffer;
3282 ALuint bufferLen, totalBufferLen;
3283 ALuint offset=0, frac=0;
3285 /* Get sample frame offset */
3286 if(!GetSampleOffset(Source, &offset, &frac))
3287 return AL_FALSE;
3289 totalBufferLen = 0;
3290 BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
3291 while(BufferList && totalBufferLen <= offset)
3293 Buffer = BufferList->buffer;
3294 bufferLen = Buffer ? Buffer->SampleLen : 0;
3296 if(bufferLen > offset-totalBufferLen)
3298 /* Offset is in this buffer */
3299 ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed);
3301 ATOMIC_STORE(&Source->position, offset - totalBufferLen, almemory_order_relaxed);
3302 ATOMIC_STORE(&Source->position_fraction, frac, almemory_order_release);
3303 return AL_TRUE;
3306 totalBufferLen += bufferLen;
3308 BufferList = BufferList->next;
3311 /* Offset is out of range of the queue */
3312 return AL_FALSE;
3316 /* GetSampleOffset
3318 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3319 * or Second offset supplied by the application). This takes into account the
3320 * fact that the buffer format may have been modifed since.
3322 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
3324 const ALbuffer *Buffer = NULL;
3325 const ALbufferlistitem *BufferList;
3326 ALdouble dbloff, dblfrac;
3328 /* Find the first valid Buffer in the Queue */
3329 BufferList = ATOMIC_LOAD_SEQ(&Source->queue);
3330 while(BufferList)
3332 if(BufferList->buffer)
3334 Buffer = BufferList->buffer;
3335 break;
3337 BufferList = BufferList->next;
3339 if(!Buffer)
3341 Source->OffsetType = AL_NONE;
3342 Source->Offset = 0.0;
3343 return AL_FALSE;
3346 switch(Source->OffsetType)
3348 case AL_BYTE_OFFSET:
3349 /* Determine the ByteOffset (and ensure it is block aligned) */
3350 *offset = (ALuint)Source->Offset;
3351 if(Buffer->OriginalType == UserFmtIMA4)
3353 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3354 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3355 *offset *= Buffer->OriginalAlign;
3357 else if(Buffer->OriginalType == UserFmtMSADPCM)
3359 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3360 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3361 *offset *= Buffer->OriginalAlign;
3363 else
3364 *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3365 *frac = 0;
3366 break;
3368 case AL_SAMPLE_OFFSET:
3369 dblfrac = modf(Source->Offset, &dbloff);
3370 *offset = (ALuint)mind(dbloff, UINT_MAX);
3371 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3372 break;
3374 case AL_SEC_OFFSET:
3375 dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
3376 *offset = (ALuint)mind(dbloff, UINT_MAX);
3377 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3378 break;
3380 Source->OffsetType = AL_NONE;
3381 Source->Offset = 0.0;
3383 return AL_TRUE;
3387 /* ReleaseALSources
3389 * Destroys all sources in the source map.
3391 ALvoid ReleaseALSources(ALCcontext *Context)
3393 ALsizei pos;
3394 for(pos = 0;pos < Context->SourceMap.size;pos++)
3396 ALsource *temp = Context->SourceMap.values[pos];
3397 Context->SourceMap.values[pos] = NULL;
3399 DeinitSource(temp);
3401 FreeThunkEntry(temp->id);
3402 memset(temp, 0, sizeof(*temp));
3403 al_free(temp);