Set a voice as 'moving' if it starts/resumes at an offset
[openal-soft.git] / OpenAL32 / alSource.c
blob3720ce4933b248bf5754afec3efca0007e0c8889
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <math.h>
26 #include <float.h>
28 #include "AL/al.h"
29 #include "AL/alc.h"
30 #include "alMain.h"
31 #include "alError.h"
32 #include "alSource.h"
33 #include "alBuffer.h"
34 #include "alThunk.h"
35 #include "alAuxEffectSlot.h"
37 #include "backends/base.h"
39 #include "threads.h"
40 #include "almalloc.h"
43 extern inline void LockSourcesRead(ALCcontext *context);
44 extern inline void UnlockSourcesRead(ALCcontext *context);
45 extern inline void LockSourcesWrite(ALCcontext *context);
46 extern inline void UnlockSourcesWrite(ALCcontext *context);
47 extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
48 extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
50 static void InitSourceParams(ALsource *Source, ALsizei num_sends);
51 static void DeinitSource(ALsource *source, ALsizei num_sends);
52 static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends);
53 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime);
54 static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime);
55 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context);
56 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac);
57 static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice);
59 typedef enum SourceProp {
60 srcPitch = AL_PITCH,
61 srcGain = AL_GAIN,
62 srcMinGain = AL_MIN_GAIN,
63 srcMaxGain = AL_MAX_GAIN,
64 srcMaxDistance = AL_MAX_DISTANCE,
65 srcRolloffFactor = AL_ROLLOFF_FACTOR,
66 srcDopplerFactor = AL_DOPPLER_FACTOR,
67 srcConeOuterGain = AL_CONE_OUTER_GAIN,
68 srcSecOffset = AL_SEC_OFFSET,
69 srcSampleOffset = AL_SAMPLE_OFFSET,
70 srcByteOffset = AL_BYTE_OFFSET,
71 srcConeInnerAngle = AL_CONE_INNER_ANGLE,
72 srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
73 srcRefDistance = AL_REFERENCE_DISTANCE,
75 srcPosition = AL_POSITION,
76 srcVelocity = AL_VELOCITY,
77 srcDirection = AL_DIRECTION,
79 srcSourceRelative = AL_SOURCE_RELATIVE,
80 srcLooping = AL_LOOPING,
81 srcBuffer = AL_BUFFER,
82 srcSourceState = AL_SOURCE_STATE,
83 srcBuffersQueued = AL_BUFFERS_QUEUED,
84 srcBuffersProcessed = AL_BUFFERS_PROCESSED,
85 srcSourceType = AL_SOURCE_TYPE,
87 /* ALC_EXT_EFX */
88 srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
89 srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
90 srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
91 srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
92 srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
93 srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
94 srcDirectFilter = AL_DIRECT_FILTER,
95 srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
97 /* AL_SOFT_direct_channels */
98 srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
100 /* AL_EXT_source_distance_model */
101 srcDistanceModel = AL_DISTANCE_MODEL,
103 srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
104 srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
105 srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
107 /* AL_SOFT_source_latency */
108 srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
109 srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
111 /* AL_EXT_STEREO_ANGLES */
112 srcAngles = AL_STEREO_ANGLES,
114 /* AL_EXT_SOURCE_RADIUS */
115 srcRadius = AL_SOURCE_RADIUS,
117 /* AL_EXT_BFORMAT */
118 srcOrientation = AL_ORIENTATION,
120 /* AL_SOFT_source_resampler */
121 srcResampler = AL_SOURCE_RESAMPLER_SOFT,
122 } SourceProp;
124 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
125 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
126 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
128 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
129 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
130 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
132 static inline ALvoice *GetSourceVoice(const ALsource *source, const ALCcontext *context)
134 ALvoice **voice = context->Voices;
135 ALvoice **voice_end = voice + context->VoiceCount;
136 while(voice != voice_end)
138 if(ATOMIC_LOAD(&(*voice)->Source, almemory_order_acquire) == source)
139 return *voice;
140 ++voice;
142 return NULL;
146 * Returns if the last known state for the source was playing or paused. Does
147 * not sync with the mixer voice.
149 static inline bool IsPlayingOrPaused(ALsource *source)
151 ALenum state = ATOMIC_LOAD(&source->state, almemory_order_acquire);
152 return state == AL_PLAYING || state == AL_PAUSED;
156 * Returns an updated source state using the matching voice's status (or lack
157 * thereof).
159 static inline ALenum GetSourceState(ALsource *source, ALvoice *voice)
161 if(!voice)
163 ALenum state = AL_PLAYING;
164 if(ATOMIC_COMPARE_EXCHANGE_STRONG(&source->state, &state, AL_STOPPED,
165 almemory_order_acq_rel, almemory_order_acquire))
166 return AL_STOPPED;
167 return state;
169 return ATOMIC_LOAD(&source->state, almemory_order_acquire);
173 * Returns if the source should specify an update, given the context's
174 * deferring state and the source's last known state.
176 static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context)
178 return !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) &&
179 IsPlayingOrPaused(source);
182 static ALint FloatValsByProp(ALenum prop)
184 if(prop != (ALenum)((SourceProp)prop))
185 return 0;
186 switch((SourceProp)prop)
188 case AL_PITCH:
189 case AL_GAIN:
190 case AL_MIN_GAIN:
191 case AL_MAX_GAIN:
192 case AL_MAX_DISTANCE:
193 case AL_ROLLOFF_FACTOR:
194 case AL_DOPPLER_FACTOR:
195 case AL_CONE_OUTER_GAIN:
196 case AL_SEC_OFFSET:
197 case AL_SAMPLE_OFFSET:
198 case AL_BYTE_OFFSET:
199 case AL_CONE_INNER_ANGLE:
200 case AL_CONE_OUTER_ANGLE:
201 case AL_REFERENCE_DISTANCE:
202 case AL_CONE_OUTER_GAINHF:
203 case AL_AIR_ABSORPTION_FACTOR:
204 case AL_ROOM_ROLLOFF_FACTOR:
205 case AL_DIRECT_FILTER_GAINHF_AUTO:
206 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
207 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
208 case AL_DIRECT_CHANNELS_SOFT:
209 case AL_DISTANCE_MODEL:
210 case AL_SOURCE_RELATIVE:
211 case AL_LOOPING:
212 case AL_SOURCE_STATE:
213 case AL_BUFFERS_QUEUED:
214 case AL_BUFFERS_PROCESSED:
215 case AL_SOURCE_TYPE:
216 case AL_BYTE_LENGTH_SOFT:
217 case AL_SAMPLE_LENGTH_SOFT:
218 case AL_SEC_LENGTH_SOFT:
219 case AL_SOURCE_RADIUS:
220 case AL_SOURCE_RESAMPLER_SOFT:
221 return 1;
223 case AL_STEREO_ANGLES:
224 return 2;
226 case AL_POSITION:
227 case AL_VELOCITY:
228 case AL_DIRECTION:
229 return 3;
231 case AL_ORIENTATION:
232 return 6;
234 case AL_SEC_OFFSET_LATENCY_SOFT:
235 break; /* Double only */
237 case AL_BUFFER:
238 case AL_DIRECT_FILTER:
239 case AL_AUXILIARY_SEND_FILTER:
240 break; /* i/i64 only */
241 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
242 break; /* i64 only */
244 return 0;
246 static ALint DoubleValsByProp(ALenum prop)
248 if(prop != (ALenum)((SourceProp)prop))
249 return 0;
250 switch((SourceProp)prop)
252 case AL_PITCH:
253 case AL_GAIN:
254 case AL_MIN_GAIN:
255 case AL_MAX_GAIN:
256 case AL_MAX_DISTANCE:
257 case AL_ROLLOFF_FACTOR:
258 case AL_DOPPLER_FACTOR:
259 case AL_CONE_OUTER_GAIN:
260 case AL_SEC_OFFSET:
261 case AL_SAMPLE_OFFSET:
262 case AL_BYTE_OFFSET:
263 case AL_CONE_INNER_ANGLE:
264 case AL_CONE_OUTER_ANGLE:
265 case AL_REFERENCE_DISTANCE:
266 case AL_CONE_OUTER_GAINHF:
267 case AL_AIR_ABSORPTION_FACTOR:
268 case AL_ROOM_ROLLOFF_FACTOR:
269 case AL_DIRECT_FILTER_GAINHF_AUTO:
270 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
271 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
272 case AL_DIRECT_CHANNELS_SOFT:
273 case AL_DISTANCE_MODEL:
274 case AL_SOURCE_RELATIVE:
275 case AL_LOOPING:
276 case AL_SOURCE_STATE:
277 case AL_BUFFERS_QUEUED:
278 case AL_BUFFERS_PROCESSED:
279 case AL_SOURCE_TYPE:
280 case AL_BYTE_LENGTH_SOFT:
281 case AL_SAMPLE_LENGTH_SOFT:
282 case AL_SEC_LENGTH_SOFT:
283 case AL_SOURCE_RADIUS:
284 case AL_SOURCE_RESAMPLER_SOFT:
285 return 1;
287 case AL_SEC_OFFSET_LATENCY_SOFT:
288 case AL_STEREO_ANGLES:
289 return 2;
291 case AL_POSITION:
292 case AL_VELOCITY:
293 case AL_DIRECTION:
294 return 3;
296 case AL_ORIENTATION:
297 return 6;
299 case AL_BUFFER:
300 case AL_DIRECT_FILTER:
301 case AL_AUXILIARY_SEND_FILTER:
302 break; /* i/i64 only */
303 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
304 break; /* i64 only */
306 return 0;
309 static ALint IntValsByProp(ALenum prop)
311 if(prop != (ALenum)((SourceProp)prop))
312 return 0;
313 switch((SourceProp)prop)
315 case AL_PITCH:
316 case AL_GAIN:
317 case AL_MIN_GAIN:
318 case AL_MAX_GAIN:
319 case AL_MAX_DISTANCE:
320 case AL_ROLLOFF_FACTOR:
321 case AL_DOPPLER_FACTOR:
322 case AL_CONE_OUTER_GAIN:
323 case AL_SEC_OFFSET:
324 case AL_SAMPLE_OFFSET:
325 case AL_BYTE_OFFSET:
326 case AL_CONE_INNER_ANGLE:
327 case AL_CONE_OUTER_ANGLE:
328 case AL_REFERENCE_DISTANCE:
329 case AL_CONE_OUTER_GAINHF:
330 case AL_AIR_ABSORPTION_FACTOR:
331 case AL_ROOM_ROLLOFF_FACTOR:
332 case AL_DIRECT_FILTER_GAINHF_AUTO:
333 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
334 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
335 case AL_DIRECT_CHANNELS_SOFT:
336 case AL_DISTANCE_MODEL:
337 case AL_SOURCE_RELATIVE:
338 case AL_LOOPING:
339 case AL_BUFFER:
340 case AL_SOURCE_STATE:
341 case AL_BUFFERS_QUEUED:
342 case AL_BUFFERS_PROCESSED:
343 case AL_SOURCE_TYPE:
344 case AL_DIRECT_FILTER:
345 case AL_BYTE_LENGTH_SOFT:
346 case AL_SAMPLE_LENGTH_SOFT:
347 case AL_SEC_LENGTH_SOFT:
348 case AL_SOURCE_RADIUS:
349 case AL_SOURCE_RESAMPLER_SOFT:
350 return 1;
352 case AL_POSITION:
353 case AL_VELOCITY:
354 case AL_DIRECTION:
355 case AL_AUXILIARY_SEND_FILTER:
356 return 3;
358 case AL_ORIENTATION:
359 return 6;
361 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
362 break; /* i64 only */
363 case AL_SEC_OFFSET_LATENCY_SOFT:
364 break; /* Double only */
365 case AL_STEREO_ANGLES:
366 break; /* Float/double only */
368 return 0;
370 static ALint Int64ValsByProp(ALenum prop)
372 if(prop != (ALenum)((SourceProp)prop))
373 return 0;
374 switch((SourceProp)prop)
376 case AL_PITCH:
377 case AL_GAIN:
378 case AL_MIN_GAIN:
379 case AL_MAX_GAIN:
380 case AL_MAX_DISTANCE:
381 case AL_ROLLOFF_FACTOR:
382 case AL_DOPPLER_FACTOR:
383 case AL_CONE_OUTER_GAIN:
384 case AL_SEC_OFFSET:
385 case AL_SAMPLE_OFFSET:
386 case AL_BYTE_OFFSET:
387 case AL_CONE_INNER_ANGLE:
388 case AL_CONE_OUTER_ANGLE:
389 case AL_REFERENCE_DISTANCE:
390 case AL_CONE_OUTER_GAINHF:
391 case AL_AIR_ABSORPTION_FACTOR:
392 case AL_ROOM_ROLLOFF_FACTOR:
393 case AL_DIRECT_FILTER_GAINHF_AUTO:
394 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
395 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
396 case AL_DIRECT_CHANNELS_SOFT:
397 case AL_DISTANCE_MODEL:
398 case AL_SOURCE_RELATIVE:
399 case AL_LOOPING:
400 case AL_BUFFER:
401 case AL_SOURCE_STATE:
402 case AL_BUFFERS_QUEUED:
403 case AL_BUFFERS_PROCESSED:
404 case AL_SOURCE_TYPE:
405 case AL_DIRECT_FILTER:
406 case AL_BYTE_LENGTH_SOFT:
407 case AL_SAMPLE_LENGTH_SOFT:
408 case AL_SEC_LENGTH_SOFT:
409 case AL_SOURCE_RADIUS:
410 case AL_SOURCE_RESAMPLER_SOFT:
411 return 1;
413 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
414 return 2;
416 case AL_POSITION:
417 case AL_VELOCITY:
418 case AL_DIRECTION:
419 case AL_AUXILIARY_SEND_FILTER:
420 return 3;
422 case AL_ORIENTATION:
423 return 6;
425 case AL_SEC_OFFSET_LATENCY_SOFT:
426 break; /* Double only */
427 case AL_STEREO_ANGLES:
428 break; /* Float/double only */
430 return 0;
434 #define CHECKVAL(x) do { \
435 if(!(x)) \
436 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
437 } while(0)
439 #define DO_UPDATEPROPS() do { \
440 ALvoice *voice; \
441 if(SourceShouldUpdate(Source, Context) && \
442 (voice=GetSourceVoice(Source, Context)) != NULL) \
443 UpdateSourceProps(Source, voice, device->NumAuxSends); \
444 else \
445 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \
446 } while(0)
448 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
450 ALCdevice *device = Context->Device;
451 ALint ival;
453 switch(prop)
455 case AL_BYTE_LENGTH_SOFT:
456 case AL_SAMPLE_LENGTH_SOFT:
457 case AL_SEC_LENGTH_SOFT:
458 case AL_SEC_OFFSET_LATENCY_SOFT:
459 /* Query only */
460 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
462 case AL_PITCH:
463 CHECKVAL(*values >= 0.0f);
465 Source->Pitch = *values;
466 DO_UPDATEPROPS();
467 return AL_TRUE;
469 case AL_CONE_INNER_ANGLE:
470 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
472 Source->InnerAngle = *values;
473 DO_UPDATEPROPS();
474 return AL_TRUE;
476 case AL_CONE_OUTER_ANGLE:
477 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
479 Source->OuterAngle = *values;
480 DO_UPDATEPROPS();
481 return AL_TRUE;
483 case AL_GAIN:
484 CHECKVAL(*values >= 0.0f);
486 Source->Gain = *values;
487 DO_UPDATEPROPS();
488 return AL_TRUE;
490 case AL_MAX_DISTANCE:
491 CHECKVAL(*values >= 0.0f);
493 Source->MaxDistance = *values;
494 DO_UPDATEPROPS();
495 return AL_TRUE;
497 case AL_ROLLOFF_FACTOR:
498 CHECKVAL(*values >= 0.0f);
500 Source->RollOffFactor = *values;
501 DO_UPDATEPROPS();
502 return AL_TRUE;
504 case AL_REFERENCE_DISTANCE:
505 CHECKVAL(*values >= 0.0f);
507 Source->RefDistance = *values;
508 DO_UPDATEPROPS();
509 return AL_TRUE;
511 case AL_MIN_GAIN:
512 CHECKVAL(*values >= 0.0f);
514 Source->MinGain = *values;
515 DO_UPDATEPROPS();
516 return AL_TRUE;
518 case AL_MAX_GAIN:
519 CHECKVAL(*values >= 0.0f);
521 Source->MaxGain = *values;
522 DO_UPDATEPROPS();
523 return AL_TRUE;
525 case AL_CONE_OUTER_GAIN:
526 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
528 Source->OuterGain = *values;
529 DO_UPDATEPROPS();
530 return AL_TRUE;
532 case AL_CONE_OUTER_GAINHF:
533 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
535 Source->OuterGainHF = *values;
536 DO_UPDATEPROPS();
537 return AL_TRUE;
539 case AL_AIR_ABSORPTION_FACTOR:
540 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
542 Source->AirAbsorptionFactor = *values;
543 DO_UPDATEPROPS();
544 return AL_TRUE;
546 case AL_ROOM_ROLLOFF_FACTOR:
547 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
549 Source->RoomRolloffFactor = *values;
550 DO_UPDATEPROPS();
551 return AL_TRUE;
553 case AL_DOPPLER_FACTOR:
554 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
556 Source->DopplerFactor = *values;
557 DO_UPDATEPROPS();
558 return AL_TRUE;
560 case AL_SEC_OFFSET:
561 case AL_SAMPLE_OFFSET:
562 case AL_BYTE_OFFSET:
563 CHECKVAL(*values >= 0.0f);
565 Source->OffsetType = prop;
566 Source->Offset = *values;
568 if(IsPlayingOrPaused(Source))
570 ALvoice *voice;
572 ALCdevice_Lock(Context->Device);
573 /* Double-check that the source is still playing while we have
574 * the lock.
576 voice = GetSourceVoice(Source, Context);
577 if(voice)
579 WriteLock(&Source->queue_lock);
580 if(ApplyOffset(Source, voice) == AL_FALSE)
582 WriteUnlock(&Source->queue_lock);
583 ALCdevice_Unlock(Context->Device);
584 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
586 WriteUnlock(&Source->queue_lock);
588 ALCdevice_Unlock(Context->Device);
590 return AL_TRUE;
592 case AL_SOURCE_RADIUS:
593 CHECKVAL(*values >= 0.0f && isfinite(*values));
595 Source->Radius = *values;
596 DO_UPDATEPROPS();
597 return AL_TRUE;
599 case AL_STEREO_ANGLES:
600 CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
602 Source->StereoPan[0] = values[0];
603 Source->StereoPan[1] = values[1];
604 DO_UPDATEPROPS();
605 return AL_TRUE;
608 case AL_POSITION:
609 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
611 Source->Position[0] = values[0];
612 Source->Position[1] = values[1];
613 Source->Position[2] = values[2];
614 DO_UPDATEPROPS();
615 return AL_TRUE;
617 case AL_VELOCITY:
618 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
620 Source->Velocity[0] = values[0];
621 Source->Velocity[1] = values[1];
622 Source->Velocity[2] = values[2];
623 DO_UPDATEPROPS();
624 return AL_TRUE;
626 case AL_DIRECTION:
627 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
629 Source->Direction[0] = values[0];
630 Source->Direction[1] = values[1];
631 Source->Direction[2] = values[2];
632 DO_UPDATEPROPS();
633 return AL_TRUE;
635 case AL_ORIENTATION:
636 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
637 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
639 Source->Orientation[0][0] = values[0];
640 Source->Orientation[0][1] = values[1];
641 Source->Orientation[0][2] = values[2];
642 Source->Orientation[1][0] = values[3];
643 Source->Orientation[1][1] = values[4];
644 Source->Orientation[1][2] = values[5];
645 DO_UPDATEPROPS();
646 return AL_TRUE;
649 case AL_SOURCE_RELATIVE:
650 case AL_LOOPING:
651 case AL_SOURCE_STATE:
652 case AL_SOURCE_TYPE:
653 case AL_DISTANCE_MODEL:
654 case AL_DIRECT_FILTER_GAINHF_AUTO:
655 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
656 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
657 case AL_DIRECT_CHANNELS_SOFT:
658 case AL_SOURCE_RESAMPLER_SOFT:
659 ival = (ALint)values[0];
660 return SetSourceiv(Source, Context, prop, &ival);
662 case AL_BUFFERS_QUEUED:
663 case AL_BUFFERS_PROCESSED:
664 ival = (ALint)((ALuint)values[0]);
665 return SetSourceiv(Source, Context, prop, &ival);
667 case AL_BUFFER:
668 case AL_DIRECT_FILTER:
669 case AL_AUXILIARY_SEND_FILTER:
670 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
671 break;
674 ERR("Unexpected property: 0x%04x\n", prop);
675 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
678 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
680 ALCdevice *device = Context->Device;
681 ALbuffer *buffer = NULL;
682 ALfilter *filter = NULL;
683 ALeffectslot *slot = NULL;
684 ALbufferlistitem *oldlist;
685 ALfloat fvals[6];
687 switch(prop)
689 case AL_SOURCE_STATE:
690 case AL_SOURCE_TYPE:
691 case AL_BUFFERS_QUEUED:
692 case AL_BUFFERS_PROCESSED:
693 case AL_BYTE_LENGTH_SOFT:
694 case AL_SAMPLE_LENGTH_SOFT:
695 case AL_SEC_LENGTH_SOFT:
696 /* Query only */
697 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
699 case AL_SOURCE_RELATIVE:
700 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
702 Source->HeadRelative = (ALboolean)*values;
703 DO_UPDATEPROPS();
704 return AL_TRUE;
706 case AL_LOOPING:
707 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
709 WriteLock(&Source->queue_lock);
710 Source->Looping = (ALboolean)*values;
711 if(IsPlayingOrPaused(Source))
713 ALvoice *voice = GetSourceVoice(Source, Context);
714 if(voice)
716 if(Source->Looping)
717 ATOMIC_STORE(&voice->loop_buffer, Source->queue, almemory_order_release);
718 else
719 ATOMIC_STORE(&voice->loop_buffer, NULL, almemory_order_release);
721 /* If the source is playing, wait for the current mix to finish
722 * to ensure it isn't currently looping back or reaching the
723 * end.
725 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
726 althrd_yield();
729 WriteUnlock(&Source->queue_lock);
730 return AL_TRUE;
732 case AL_BUFFER:
733 LockBuffersRead(device);
734 if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
736 UnlockBuffersRead(device);
737 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
740 WriteLock(&Source->queue_lock);
742 ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context));
743 if(state == AL_PLAYING || state == AL_PAUSED)
745 WriteUnlock(&Source->queue_lock);
746 UnlockBuffersRead(device);
747 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
751 oldlist = Source->queue;
752 if(buffer != NULL)
754 /* Add the selected buffer to a one-item queue */
755 ALbufferlistitem *newlist = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
756 newlist->buffer = buffer;
757 ATOMIC_INIT(&newlist->next, NULL);
758 IncrementRef(&buffer->ref);
760 /* Source is now Static */
761 Source->SourceType = AL_STATIC;
762 Source->queue = newlist;
764 else
766 /* Source is now Undetermined */
767 Source->SourceType = AL_UNDETERMINED;
768 Source->queue = NULL;
770 WriteUnlock(&Source->queue_lock);
771 UnlockBuffersRead(device);
773 /* Delete all elements in the previous queue */
774 while(oldlist != NULL)
776 ALbufferlistitem *temp = oldlist;
777 oldlist = ATOMIC_LOAD(&temp->next, almemory_order_relaxed);
779 if(temp->buffer)
780 DecrementRef(&temp->buffer->ref);
781 al_free(temp);
783 return AL_TRUE;
785 case AL_SEC_OFFSET:
786 case AL_SAMPLE_OFFSET:
787 case AL_BYTE_OFFSET:
788 CHECKVAL(*values >= 0);
790 Source->OffsetType = prop;
791 Source->Offset = *values;
793 if(IsPlayingOrPaused(Source))
795 ALvoice *voice;
797 ALCdevice_Lock(Context->Device);
798 voice = GetSourceVoice(Source, Context);
799 if(voice)
801 WriteLock(&Source->queue_lock);
802 if(ApplyOffset(Source, voice) == AL_FALSE)
804 WriteUnlock(&Source->queue_lock);
805 ALCdevice_Unlock(Context->Device);
806 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
808 WriteUnlock(&Source->queue_lock);
810 ALCdevice_Unlock(Context->Device);
812 return AL_TRUE;
814 case AL_DIRECT_FILTER:
815 LockFiltersRead(device);
816 if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
818 UnlockFiltersRead(device);
819 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
822 if(!filter)
824 Source->Direct.Gain = 1.0f;
825 Source->Direct.GainHF = 1.0f;
826 Source->Direct.HFReference = LOWPASSFREQREF;
827 Source->Direct.GainLF = 1.0f;
828 Source->Direct.LFReference = HIGHPASSFREQREF;
830 else
832 Source->Direct.Gain = filter->Gain;
833 Source->Direct.GainHF = filter->GainHF;
834 Source->Direct.HFReference = filter->HFReference;
835 Source->Direct.GainLF = filter->GainLF;
836 Source->Direct.LFReference = filter->LFReference;
838 UnlockFiltersRead(device);
839 DO_UPDATEPROPS();
840 return AL_TRUE;
842 case AL_DIRECT_FILTER_GAINHF_AUTO:
843 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
845 Source->DryGainHFAuto = *values;
846 DO_UPDATEPROPS();
847 return AL_TRUE;
849 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
850 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
852 Source->WetGainAuto = *values;
853 DO_UPDATEPROPS();
854 return AL_TRUE;
856 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
857 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
859 Source->WetGainHFAuto = *values;
860 DO_UPDATEPROPS();
861 return AL_TRUE;
863 case AL_DIRECT_CHANNELS_SOFT:
864 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
866 Source->DirectChannels = *values;
867 DO_UPDATEPROPS();
868 return AL_TRUE;
870 case AL_DISTANCE_MODEL:
871 CHECKVAL(*values == AL_NONE ||
872 *values == AL_INVERSE_DISTANCE ||
873 *values == AL_INVERSE_DISTANCE_CLAMPED ||
874 *values == AL_LINEAR_DISTANCE ||
875 *values == AL_LINEAR_DISTANCE_CLAMPED ||
876 *values == AL_EXPONENT_DISTANCE ||
877 *values == AL_EXPONENT_DISTANCE_CLAMPED);
879 Source->DistanceModel = *values;
880 if(Context->SourceDistanceModel)
881 DO_UPDATEPROPS();
882 return AL_TRUE;
884 case AL_SOURCE_RESAMPLER_SOFT:
885 CHECKVAL(*values >= 0 && *values <= ResamplerMax);
887 Source->Resampler = *values;
888 DO_UPDATEPROPS();
889 return AL_TRUE;
892 case AL_AUXILIARY_SEND_FILTER:
893 LockEffectSlotsRead(Context);
894 LockFiltersRead(device);
895 if(!((ALuint)values[1] < (ALuint)device->NumAuxSends &&
896 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
897 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
899 UnlockFiltersRead(device);
900 UnlockEffectSlotsRead(Context);
901 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
904 if(!filter)
906 /* Disable filter */
907 Source->Send[values[1]].Gain = 1.0f;
908 Source->Send[values[1]].GainHF = 1.0f;
909 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
910 Source->Send[values[1]].GainLF = 1.0f;
911 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
913 else
915 Source->Send[values[1]].Gain = filter->Gain;
916 Source->Send[values[1]].GainHF = filter->GainHF;
917 Source->Send[values[1]].HFReference = filter->HFReference;
918 Source->Send[values[1]].GainLF = filter->GainLF;
919 Source->Send[values[1]].LFReference = filter->LFReference;
921 UnlockFiltersRead(device);
923 if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source))
925 ALvoice *voice;
926 /* Add refcount on the new slot, and release the previous slot */
927 if(slot) IncrementRef(&slot->ref);
928 if(Source->Send[values[1]].Slot)
929 DecrementRef(&Source->Send[values[1]].Slot->ref);
930 Source->Send[values[1]].Slot = slot;
932 /* We must force an update if the auxiliary slot changed on an
933 * active source, in case the slot is about to be deleted.
935 if((voice=GetSourceVoice(Source, Context)) != NULL)
936 UpdateSourceProps(Source, voice, device->NumAuxSends);
937 else
938 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release);
940 else
942 if(slot) IncrementRef(&slot->ref);
943 if(Source->Send[values[1]].Slot)
944 DecrementRef(&Source->Send[values[1]].Slot->ref);
945 Source->Send[values[1]].Slot = slot;
946 DO_UPDATEPROPS();
948 UnlockEffectSlotsRead(Context);
950 return AL_TRUE;
953 /* 1x float */
954 case AL_CONE_INNER_ANGLE:
955 case AL_CONE_OUTER_ANGLE:
956 case AL_PITCH:
957 case AL_GAIN:
958 case AL_MIN_GAIN:
959 case AL_MAX_GAIN:
960 case AL_REFERENCE_DISTANCE:
961 case AL_ROLLOFF_FACTOR:
962 case AL_CONE_OUTER_GAIN:
963 case AL_MAX_DISTANCE:
964 case AL_DOPPLER_FACTOR:
965 case AL_CONE_OUTER_GAINHF:
966 case AL_AIR_ABSORPTION_FACTOR:
967 case AL_ROOM_ROLLOFF_FACTOR:
968 case AL_SOURCE_RADIUS:
969 fvals[0] = (ALfloat)*values;
970 return SetSourcefv(Source, Context, (int)prop, fvals);
972 /* 3x float */
973 case AL_POSITION:
974 case AL_VELOCITY:
975 case AL_DIRECTION:
976 fvals[0] = (ALfloat)values[0];
977 fvals[1] = (ALfloat)values[1];
978 fvals[2] = (ALfloat)values[2];
979 return SetSourcefv(Source, Context, (int)prop, fvals);
981 /* 6x float */
982 case AL_ORIENTATION:
983 fvals[0] = (ALfloat)values[0];
984 fvals[1] = (ALfloat)values[1];
985 fvals[2] = (ALfloat)values[2];
986 fvals[3] = (ALfloat)values[3];
987 fvals[4] = (ALfloat)values[4];
988 fvals[5] = (ALfloat)values[5];
989 return SetSourcefv(Source, Context, (int)prop, fvals);
991 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
992 case AL_SEC_OFFSET_LATENCY_SOFT:
993 case AL_STEREO_ANGLES:
994 break;
997 ERR("Unexpected property: 0x%04x\n", prop);
998 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1001 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
1003 ALfloat fvals[6];
1004 ALint ivals[3];
1006 switch(prop)
1008 case AL_SOURCE_TYPE:
1009 case AL_BUFFERS_QUEUED:
1010 case AL_BUFFERS_PROCESSED:
1011 case AL_SOURCE_STATE:
1012 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1013 case AL_BYTE_LENGTH_SOFT:
1014 case AL_SAMPLE_LENGTH_SOFT:
1015 case AL_SEC_LENGTH_SOFT:
1016 /* Query only */
1017 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
1020 /* 1x int */
1021 case AL_SOURCE_RELATIVE:
1022 case AL_LOOPING:
1023 case AL_SEC_OFFSET:
1024 case AL_SAMPLE_OFFSET:
1025 case AL_BYTE_OFFSET:
1026 case AL_DIRECT_FILTER_GAINHF_AUTO:
1027 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1028 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1029 case AL_DIRECT_CHANNELS_SOFT:
1030 case AL_DISTANCE_MODEL:
1031 case AL_SOURCE_RESAMPLER_SOFT:
1032 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
1034 ivals[0] = (ALint)*values;
1035 return SetSourceiv(Source, Context, (int)prop, ivals);
1037 /* 1x uint */
1038 case AL_BUFFER:
1039 case AL_DIRECT_FILTER:
1040 CHECKVAL(*values <= UINT_MAX && *values >= 0);
1042 ivals[0] = (ALuint)*values;
1043 return SetSourceiv(Source, Context, (int)prop, ivals);
1045 /* 3x uint */
1046 case AL_AUXILIARY_SEND_FILTER:
1047 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
1048 values[1] <= UINT_MAX && values[1] >= 0 &&
1049 values[2] <= UINT_MAX && values[2] >= 0);
1051 ivals[0] = (ALuint)values[0];
1052 ivals[1] = (ALuint)values[1];
1053 ivals[2] = (ALuint)values[2];
1054 return SetSourceiv(Source, Context, (int)prop, ivals);
1056 /* 1x float */
1057 case AL_CONE_INNER_ANGLE:
1058 case AL_CONE_OUTER_ANGLE:
1059 case AL_PITCH:
1060 case AL_GAIN:
1061 case AL_MIN_GAIN:
1062 case AL_MAX_GAIN:
1063 case AL_REFERENCE_DISTANCE:
1064 case AL_ROLLOFF_FACTOR:
1065 case AL_CONE_OUTER_GAIN:
1066 case AL_MAX_DISTANCE:
1067 case AL_DOPPLER_FACTOR:
1068 case AL_CONE_OUTER_GAINHF:
1069 case AL_AIR_ABSORPTION_FACTOR:
1070 case AL_ROOM_ROLLOFF_FACTOR:
1071 case AL_SOURCE_RADIUS:
1072 fvals[0] = (ALfloat)*values;
1073 return SetSourcefv(Source, Context, (int)prop, fvals);
1075 /* 3x float */
1076 case AL_POSITION:
1077 case AL_VELOCITY:
1078 case AL_DIRECTION:
1079 fvals[0] = (ALfloat)values[0];
1080 fvals[1] = (ALfloat)values[1];
1081 fvals[2] = (ALfloat)values[2];
1082 return SetSourcefv(Source, Context, (int)prop, fvals);
1084 /* 6x float */
1085 case AL_ORIENTATION:
1086 fvals[0] = (ALfloat)values[0];
1087 fvals[1] = (ALfloat)values[1];
1088 fvals[2] = (ALfloat)values[2];
1089 fvals[3] = (ALfloat)values[3];
1090 fvals[4] = (ALfloat)values[4];
1091 fvals[5] = (ALfloat)values[5];
1092 return SetSourcefv(Source, Context, (int)prop, fvals);
1094 case AL_SEC_OFFSET_LATENCY_SOFT:
1095 case AL_STEREO_ANGLES:
1096 break;
1099 ERR("Unexpected property: 0x%04x\n", prop);
1100 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1103 #undef CHECKVAL
1106 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
1108 ALCdevice *device = Context->Device;
1109 ALbufferlistitem *BufferList;
1110 ClockLatency clocktime;
1111 ALuint64 srcclock;
1112 ALint ivals[3];
1113 ALboolean err;
1115 switch(prop)
1117 case AL_GAIN:
1118 *values = Source->Gain;
1119 return AL_TRUE;
1121 case AL_PITCH:
1122 *values = Source->Pitch;
1123 return AL_TRUE;
1125 case AL_MAX_DISTANCE:
1126 *values = Source->MaxDistance;
1127 return AL_TRUE;
1129 case AL_ROLLOFF_FACTOR:
1130 *values = Source->RollOffFactor;
1131 return AL_TRUE;
1133 case AL_REFERENCE_DISTANCE:
1134 *values = Source->RefDistance;
1135 return AL_TRUE;
1137 case AL_CONE_INNER_ANGLE:
1138 *values = Source->InnerAngle;
1139 return AL_TRUE;
1141 case AL_CONE_OUTER_ANGLE:
1142 *values = Source->OuterAngle;
1143 return AL_TRUE;
1145 case AL_MIN_GAIN:
1146 *values = Source->MinGain;
1147 return AL_TRUE;
1149 case AL_MAX_GAIN:
1150 *values = Source->MaxGain;
1151 return AL_TRUE;
1153 case AL_CONE_OUTER_GAIN:
1154 *values = Source->OuterGain;
1155 return AL_TRUE;
1157 case AL_SEC_OFFSET:
1158 case AL_SAMPLE_OFFSET:
1159 case AL_BYTE_OFFSET:
1160 *values = GetSourceOffset(Source, prop, Context);
1161 return AL_TRUE;
1163 case AL_CONE_OUTER_GAINHF:
1164 *values = Source->OuterGainHF;
1165 return AL_TRUE;
1167 case AL_AIR_ABSORPTION_FACTOR:
1168 *values = Source->AirAbsorptionFactor;
1169 return AL_TRUE;
1171 case AL_ROOM_ROLLOFF_FACTOR:
1172 *values = Source->RoomRolloffFactor;
1173 return AL_TRUE;
1175 case AL_DOPPLER_FACTOR:
1176 *values = Source->DopplerFactor;
1177 return AL_TRUE;
1179 case AL_SEC_LENGTH_SOFT:
1180 ReadLock(&Source->queue_lock);
1181 if(!(BufferList=Source->queue))
1182 *values = 0;
1183 else
1185 ALint length = 0;
1186 ALsizei freq = 1;
1187 do {
1188 ALbuffer *buffer = BufferList->buffer;
1189 if(buffer && buffer->SampleLen > 0)
1191 freq = buffer->Frequency;
1192 length += buffer->SampleLen;
1194 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
1195 } while(BufferList != NULL);
1196 *values = (ALdouble)length / (ALdouble)freq;
1198 ReadUnlock(&Source->queue_lock);
1199 return AL_TRUE;
1201 case AL_SOURCE_RADIUS:
1202 *values = Source->Radius;
1203 return AL_TRUE;
1205 case AL_STEREO_ANGLES:
1206 values[0] = Source->StereoPan[0];
1207 values[1] = Source->StereoPan[1];
1208 return AL_TRUE;
1210 case AL_SEC_OFFSET_LATENCY_SOFT:
1211 /* Get the source offset with the clock time first. Then get the
1212 * clock time with the device latency. Order is important.
1214 values[0] = GetSourceSecOffset(Source, Context, &srcclock);
1215 clocktime = V0(device->Backend,getClockLatency)();
1216 if(srcclock == (ALuint64)clocktime.ClockTime)
1217 values[1] = (ALdouble)clocktime.Latency / 1000000000.0;
1218 else
1220 /* If the clock time incremented, reduce the latency by that
1221 * much since it's that much closer to the source offset it got
1222 * earlier.
1224 ALuint64 diff = clocktime.ClockTime - srcclock;
1225 values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) /
1226 1000000000.0;
1228 return AL_TRUE;
1230 case AL_POSITION:
1231 values[0] = Source->Position[0];
1232 values[1] = Source->Position[1];
1233 values[2] = Source->Position[2];
1234 return AL_TRUE;
1236 case AL_VELOCITY:
1237 values[0] = Source->Velocity[0];
1238 values[1] = Source->Velocity[1];
1239 values[2] = Source->Velocity[2];
1240 return AL_TRUE;
1242 case AL_DIRECTION:
1243 values[0] = Source->Direction[0];
1244 values[1] = Source->Direction[1];
1245 values[2] = Source->Direction[2];
1246 return AL_TRUE;
1248 case AL_ORIENTATION:
1249 values[0] = Source->Orientation[0][0];
1250 values[1] = Source->Orientation[0][1];
1251 values[2] = Source->Orientation[0][2];
1252 values[3] = Source->Orientation[1][0];
1253 values[4] = Source->Orientation[1][1];
1254 values[5] = Source->Orientation[1][2];
1255 return AL_TRUE;
1257 /* 1x int */
1258 case AL_SOURCE_RELATIVE:
1259 case AL_LOOPING:
1260 case AL_SOURCE_STATE:
1261 case AL_BUFFERS_QUEUED:
1262 case AL_BUFFERS_PROCESSED:
1263 case AL_SOURCE_TYPE:
1264 case AL_DIRECT_FILTER_GAINHF_AUTO:
1265 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1266 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1267 case AL_DIRECT_CHANNELS_SOFT:
1268 case AL_BYTE_LENGTH_SOFT:
1269 case AL_SAMPLE_LENGTH_SOFT:
1270 case AL_DISTANCE_MODEL:
1271 case AL_SOURCE_RESAMPLER_SOFT:
1272 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1273 *values = (ALdouble)ivals[0];
1274 return err;
1276 case AL_BUFFER:
1277 case AL_DIRECT_FILTER:
1278 case AL_AUXILIARY_SEND_FILTER:
1279 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1280 break;
1283 ERR("Unexpected property: 0x%04x\n", prop);
1284 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1287 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1289 ALbufferlistitem *BufferList;
1290 ALdouble dvals[6];
1291 ALboolean err;
1293 switch(prop)
1295 case AL_SOURCE_RELATIVE:
1296 *values = Source->HeadRelative;
1297 return AL_TRUE;
1299 case AL_LOOPING:
1300 *values = Source->Looping;
1301 return AL_TRUE;
1303 case AL_BUFFER:
1304 ReadLock(&Source->queue_lock);
1305 BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : NULL;
1306 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1307 ReadUnlock(&Source->queue_lock);
1308 return AL_TRUE;
1310 case AL_SOURCE_STATE:
1311 *values = GetSourceState(Source, GetSourceVoice(Source, Context));
1312 return AL_TRUE;
1314 case AL_BYTE_LENGTH_SOFT:
1315 ReadLock(&Source->queue_lock);
1316 if(!(BufferList=Source->queue))
1317 *values = 0;
1318 else
1320 ALint length = 0;
1321 do {
1322 ALbuffer *buffer = BufferList->buffer;
1323 if(buffer && buffer->SampleLen > 0)
1325 ALuint byte_align, sample_align;
1326 if(buffer->OriginalType == UserFmtIMA4)
1328 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1329 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1330 sample_align = buffer->OriginalAlign;
1332 else if(buffer->OriginalType == UserFmtMSADPCM)
1334 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1335 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1336 sample_align = buffer->OriginalAlign;
1338 else
1340 ALsizei align = buffer->OriginalAlign;
1341 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1342 sample_align = buffer->OriginalAlign;
1345 length += buffer->SampleLen / sample_align * byte_align;
1347 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
1348 } while(BufferList != NULL);
1349 *values = length;
1351 ReadUnlock(&Source->queue_lock);
1352 return AL_TRUE;
1354 case AL_SAMPLE_LENGTH_SOFT:
1355 ReadLock(&Source->queue_lock);
1356 if(!(BufferList=Source->queue))
1357 *values = 0;
1358 else
1360 ALint length = 0;
1361 do {
1362 ALbuffer *buffer = BufferList->buffer;
1363 if(buffer) length += buffer->SampleLen;
1364 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
1365 } while(BufferList != NULL);
1366 *values = length;
1368 ReadUnlock(&Source->queue_lock);
1369 return AL_TRUE;
1371 case AL_BUFFERS_QUEUED:
1372 ReadLock(&Source->queue_lock);
1373 if(!(BufferList=Source->queue))
1374 *values = 0;
1375 else
1377 ALsizei count = 0;
1378 do {
1379 ++count;
1380 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
1381 } while(BufferList != NULL);
1382 *values = count;
1384 ReadUnlock(&Source->queue_lock);
1385 return AL_TRUE;
1387 case AL_BUFFERS_PROCESSED:
1388 ReadLock(&Source->queue_lock);
1389 if(Source->Looping || Source->SourceType != AL_STREAMING)
1391 /* Buffers on a looping source are in a perpetual state of
1392 * PENDING, so don't report any as PROCESSED */
1393 *values = 0;
1395 else
1397 const ALbufferlistitem *BufferList = Source->queue;
1398 const ALbufferlistitem *Current = NULL;
1399 ALsizei played = 0;
1400 ALvoice *voice;
1402 if((voice=GetSourceVoice(Source, Context)) != NULL)
1403 Current = ATOMIC_LOAD_SEQ(&voice->current_buffer);
1404 else if(ATOMIC_LOAD_SEQ(&Source->state) == AL_INITIAL)
1405 Current = BufferList;
1407 while(BufferList && BufferList != Current)
1409 played++;
1410 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
1411 almemory_order_relaxed);
1413 *values = played;
1415 ReadUnlock(&Source->queue_lock);
1416 return AL_TRUE;
1418 case AL_SOURCE_TYPE:
1419 *values = Source->SourceType;
1420 return AL_TRUE;
1422 case AL_DIRECT_FILTER_GAINHF_AUTO:
1423 *values = Source->DryGainHFAuto;
1424 return AL_TRUE;
1426 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1427 *values = Source->WetGainAuto;
1428 return AL_TRUE;
1430 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1431 *values = Source->WetGainHFAuto;
1432 return AL_TRUE;
1434 case AL_DIRECT_CHANNELS_SOFT:
1435 *values = Source->DirectChannels;
1436 return AL_TRUE;
1438 case AL_DISTANCE_MODEL:
1439 *values = Source->DistanceModel;
1440 return AL_TRUE;
1442 case AL_SOURCE_RESAMPLER_SOFT:
1443 *values = Source->Resampler;
1444 return AL_TRUE;
1446 /* 1x float/double */
1447 case AL_CONE_INNER_ANGLE:
1448 case AL_CONE_OUTER_ANGLE:
1449 case AL_PITCH:
1450 case AL_GAIN:
1451 case AL_MIN_GAIN:
1452 case AL_MAX_GAIN:
1453 case AL_REFERENCE_DISTANCE:
1454 case AL_ROLLOFF_FACTOR:
1455 case AL_CONE_OUTER_GAIN:
1456 case AL_MAX_DISTANCE:
1457 case AL_SEC_OFFSET:
1458 case AL_SAMPLE_OFFSET:
1459 case AL_BYTE_OFFSET:
1460 case AL_DOPPLER_FACTOR:
1461 case AL_AIR_ABSORPTION_FACTOR:
1462 case AL_ROOM_ROLLOFF_FACTOR:
1463 case AL_CONE_OUTER_GAINHF:
1464 case AL_SEC_LENGTH_SOFT:
1465 case AL_SOURCE_RADIUS:
1466 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1467 *values = (ALint)dvals[0];
1468 return err;
1470 /* 3x float/double */
1471 case AL_POSITION:
1472 case AL_VELOCITY:
1473 case AL_DIRECTION:
1474 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1476 values[0] = (ALint)dvals[0];
1477 values[1] = (ALint)dvals[1];
1478 values[2] = (ALint)dvals[2];
1480 return err;
1482 /* 6x float/double */
1483 case AL_ORIENTATION:
1484 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1486 values[0] = (ALint)dvals[0];
1487 values[1] = (ALint)dvals[1];
1488 values[2] = (ALint)dvals[2];
1489 values[3] = (ALint)dvals[3];
1490 values[4] = (ALint)dvals[4];
1491 values[5] = (ALint)dvals[5];
1493 return err;
1495 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1496 break; /* i64 only */
1497 case AL_SEC_OFFSET_LATENCY_SOFT:
1498 break; /* Double only */
1499 case AL_STEREO_ANGLES:
1500 break; /* Float/double only */
1502 case AL_DIRECT_FILTER:
1503 case AL_AUXILIARY_SEND_FILTER:
1504 break; /* ??? */
1507 ERR("Unexpected property: 0x%04x\n", prop);
1508 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1511 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1513 ALCdevice *device = Context->Device;
1514 ClockLatency clocktime;
1515 ALuint64 srcclock;
1516 ALdouble dvals[6];
1517 ALint ivals[3];
1518 ALboolean err;
1520 switch(prop)
1522 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1523 /* Get the source offset with the clock time first. Then get the
1524 * clock time with the device latency. Order is important.
1526 values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
1527 clocktime = V0(device->Backend,getClockLatency)();
1528 if(srcclock == (ALuint64)clocktime.ClockTime)
1529 values[1] = clocktime.Latency;
1530 else
1532 /* If the clock time incremented, reduce the latency by that
1533 * much since it's that much closer to the source offset it got
1534 * earlier.
1536 ALuint64 diff = clocktime.ClockTime - srcclock;
1537 values[1] = clocktime.Latency - minu64(clocktime.Latency, diff);
1539 return AL_TRUE;
1541 /* 1x float/double */
1542 case AL_CONE_INNER_ANGLE:
1543 case AL_CONE_OUTER_ANGLE:
1544 case AL_PITCH:
1545 case AL_GAIN:
1546 case AL_MIN_GAIN:
1547 case AL_MAX_GAIN:
1548 case AL_REFERENCE_DISTANCE:
1549 case AL_ROLLOFF_FACTOR:
1550 case AL_CONE_OUTER_GAIN:
1551 case AL_MAX_DISTANCE:
1552 case AL_SEC_OFFSET:
1553 case AL_SAMPLE_OFFSET:
1554 case AL_BYTE_OFFSET:
1555 case AL_DOPPLER_FACTOR:
1556 case AL_AIR_ABSORPTION_FACTOR:
1557 case AL_ROOM_ROLLOFF_FACTOR:
1558 case AL_CONE_OUTER_GAINHF:
1559 case AL_SEC_LENGTH_SOFT:
1560 case AL_SOURCE_RADIUS:
1561 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1562 *values = (ALint64)dvals[0];
1563 return err;
1565 /* 3x float/double */
1566 case AL_POSITION:
1567 case AL_VELOCITY:
1568 case AL_DIRECTION:
1569 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1571 values[0] = (ALint64)dvals[0];
1572 values[1] = (ALint64)dvals[1];
1573 values[2] = (ALint64)dvals[2];
1575 return err;
1577 /* 6x float/double */
1578 case AL_ORIENTATION:
1579 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1581 values[0] = (ALint64)dvals[0];
1582 values[1] = (ALint64)dvals[1];
1583 values[2] = (ALint64)dvals[2];
1584 values[3] = (ALint64)dvals[3];
1585 values[4] = (ALint64)dvals[4];
1586 values[5] = (ALint64)dvals[5];
1588 return err;
1590 /* 1x int */
1591 case AL_SOURCE_RELATIVE:
1592 case AL_LOOPING:
1593 case AL_SOURCE_STATE:
1594 case AL_BUFFERS_QUEUED:
1595 case AL_BUFFERS_PROCESSED:
1596 case AL_BYTE_LENGTH_SOFT:
1597 case AL_SAMPLE_LENGTH_SOFT:
1598 case AL_SOURCE_TYPE:
1599 case AL_DIRECT_FILTER_GAINHF_AUTO:
1600 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1601 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1602 case AL_DIRECT_CHANNELS_SOFT:
1603 case AL_DISTANCE_MODEL:
1604 case AL_SOURCE_RESAMPLER_SOFT:
1605 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1606 *values = ivals[0];
1607 return err;
1609 /* 1x uint */
1610 case AL_BUFFER:
1611 case AL_DIRECT_FILTER:
1612 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1613 *values = (ALuint)ivals[0];
1614 return err;
1616 /* 3x uint */
1617 case AL_AUXILIARY_SEND_FILTER:
1618 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1620 values[0] = (ALuint)ivals[0];
1621 values[1] = (ALuint)ivals[1];
1622 values[2] = (ALuint)ivals[2];
1624 return err;
1626 case AL_SEC_OFFSET_LATENCY_SOFT:
1627 break; /* Double only */
1628 case AL_STEREO_ANGLES:
1629 break; /* Float/double only */
1632 ERR("Unexpected property: 0x%04x\n", prop);
1633 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1637 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1639 ALCdevice *device;
1640 ALCcontext *context;
1641 ALsizei cur = 0;
1642 ALenum err;
1644 context = GetContextRef();
1645 if(!context) return;
1647 if(!(n >= 0))
1648 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1649 device = context->Device;
1650 for(cur = 0;cur < n;cur++)
1652 ALsource *source = al_calloc(16, sizeof(ALsource));
1653 if(!source)
1655 alDeleteSources(cur, sources);
1656 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1658 InitSourceParams(source, device->NumAuxSends);
1660 err = NewThunkEntry(&source->id);
1661 if(err == AL_NO_ERROR)
1662 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1663 if(err != AL_NO_ERROR)
1665 FreeThunkEntry(source->id);
1666 memset(source, 0, sizeof(ALsource));
1667 al_free(source);
1669 alDeleteSources(cur, sources);
1670 SET_ERROR_AND_GOTO(context, err, done);
1673 sources[cur] = source->id;
1676 done:
1677 ALCcontext_DecRef(context);
1681 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1683 ALCdevice *device;
1684 ALCcontext *context;
1685 ALsource *Source;
1686 ALsizei i;
1688 context = GetContextRef();
1689 if(!context) return;
1691 LockSourcesWrite(context);
1692 if(!(n >= 0))
1693 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1695 /* Check that all Sources are valid */
1696 for(i = 0;i < n;i++)
1698 if(LookupSource(context, sources[i]) == NULL)
1699 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1701 device = context->Device;
1702 for(i = 0;i < n;i++)
1704 ALvoice *voice;
1706 if((Source=RemoveSource(context, sources[i])) == NULL)
1707 continue;
1708 FreeThunkEntry(Source->id);
1710 ALCdevice_Lock(device);
1711 if((voice=GetSourceVoice(Source, context)) != NULL)
1713 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
1714 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
1716 ALCdevice_Unlock(device);
1718 DeinitSource(Source, device->NumAuxSends);
1720 memset(Source, 0, sizeof(*Source));
1721 al_free(Source);
1724 done:
1725 UnlockSourcesWrite(context);
1726 ALCcontext_DecRef(context);
1730 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1732 ALCcontext *context;
1733 ALboolean ret;
1735 context = GetContextRef();
1736 if(!context) return AL_FALSE;
1738 LockSourcesRead(context);
1739 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1740 UnlockSourcesRead(context);
1742 ALCcontext_DecRef(context);
1744 return ret;
1748 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1750 ALCcontext *Context;
1751 ALsource *Source;
1753 Context = GetContextRef();
1754 if(!Context) return;
1756 WriteLock(&Context->PropLock);
1757 LockSourcesRead(Context);
1758 if((Source=LookupSource(Context, source)) == NULL)
1759 alSetError(Context, AL_INVALID_NAME);
1760 else if(!(FloatValsByProp(param) == 1))
1761 alSetError(Context, AL_INVALID_ENUM);
1762 else
1763 SetSourcefv(Source, Context, param, &value);
1764 UnlockSourcesRead(Context);
1765 WriteUnlock(&Context->PropLock);
1767 ALCcontext_DecRef(Context);
1770 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1772 ALCcontext *Context;
1773 ALsource *Source;
1775 Context = GetContextRef();
1776 if(!Context) return;
1778 WriteLock(&Context->PropLock);
1779 LockSourcesRead(Context);
1780 if((Source=LookupSource(Context, source)) == NULL)
1781 alSetError(Context, AL_INVALID_NAME);
1782 else if(!(FloatValsByProp(param) == 3))
1783 alSetError(Context, AL_INVALID_ENUM);
1784 else
1786 ALfloat fvals[3] = { value1, value2, value3 };
1787 SetSourcefv(Source, Context, param, fvals);
1789 UnlockSourcesRead(Context);
1790 WriteUnlock(&Context->PropLock);
1792 ALCcontext_DecRef(Context);
1795 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1797 ALCcontext *Context;
1798 ALsource *Source;
1800 Context = GetContextRef();
1801 if(!Context) return;
1803 WriteLock(&Context->PropLock);
1804 LockSourcesRead(Context);
1805 if((Source=LookupSource(Context, source)) == NULL)
1806 alSetError(Context, AL_INVALID_NAME);
1807 else if(!values)
1808 alSetError(Context, AL_INVALID_VALUE);
1809 else if(!(FloatValsByProp(param) > 0))
1810 alSetError(Context, AL_INVALID_ENUM);
1811 else
1812 SetSourcefv(Source, Context, param, values);
1813 UnlockSourcesRead(Context);
1814 WriteUnlock(&Context->PropLock);
1816 ALCcontext_DecRef(Context);
1820 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1822 ALCcontext *Context;
1823 ALsource *Source;
1825 Context = GetContextRef();
1826 if(!Context) return;
1828 WriteLock(&Context->PropLock);
1829 LockSourcesRead(Context);
1830 if((Source=LookupSource(Context, source)) == NULL)
1831 alSetError(Context, AL_INVALID_NAME);
1832 else if(!(DoubleValsByProp(param) == 1))
1833 alSetError(Context, AL_INVALID_ENUM);
1834 else
1836 ALfloat fval = (ALfloat)value;
1837 SetSourcefv(Source, Context, param, &fval);
1839 UnlockSourcesRead(Context);
1840 WriteUnlock(&Context->PropLock);
1842 ALCcontext_DecRef(Context);
1845 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1847 ALCcontext *Context;
1848 ALsource *Source;
1850 Context = GetContextRef();
1851 if(!Context) return;
1853 WriteLock(&Context->PropLock);
1854 LockSourcesRead(Context);
1855 if((Source=LookupSource(Context, source)) == NULL)
1856 alSetError(Context, AL_INVALID_NAME);
1857 else if(!(DoubleValsByProp(param) == 3))
1858 alSetError(Context, AL_INVALID_ENUM);
1859 else
1861 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1862 SetSourcefv(Source, Context, param, fvals);
1864 UnlockSourcesRead(Context);
1865 WriteUnlock(&Context->PropLock);
1867 ALCcontext_DecRef(Context);
1870 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1872 ALCcontext *Context;
1873 ALsource *Source;
1874 ALint count;
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(!values)
1884 alSetError(Context, AL_INVALID_VALUE);
1885 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1886 alSetError(Context, AL_INVALID_ENUM);
1887 else
1889 ALfloat fvals[6];
1890 ALint i;
1892 for(i = 0;i < count;i++)
1893 fvals[i] = (ALfloat)values[i];
1894 SetSourcefv(Source, Context, param, fvals);
1896 UnlockSourcesRead(Context);
1897 WriteUnlock(&Context->PropLock);
1899 ALCcontext_DecRef(Context);
1903 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1905 ALCcontext *Context;
1906 ALsource *Source;
1908 Context = GetContextRef();
1909 if(!Context) return;
1911 WriteLock(&Context->PropLock);
1912 LockSourcesRead(Context);
1913 if((Source=LookupSource(Context, source)) == NULL)
1914 alSetError(Context, AL_INVALID_NAME);
1915 else if(!(IntValsByProp(param) == 1))
1916 alSetError(Context, AL_INVALID_ENUM);
1917 else
1918 SetSourceiv(Source, Context, param, &value);
1919 UnlockSourcesRead(Context);
1920 WriteUnlock(&Context->PropLock);
1922 ALCcontext_DecRef(Context);
1925 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1927 ALCcontext *Context;
1928 ALsource *Source;
1930 Context = GetContextRef();
1931 if(!Context) return;
1933 WriteLock(&Context->PropLock);
1934 LockSourcesRead(Context);
1935 if((Source=LookupSource(Context, source)) == NULL)
1936 alSetError(Context, AL_INVALID_NAME);
1937 else if(!(IntValsByProp(param) == 3))
1938 alSetError(Context, AL_INVALID_ENUM);
1939 else
1941 ALint ivals[3] = { value1, value2, value3 };
1942 SetSourceiv(Source, Context, param, ivals);
1944 UnlockSourcesRead(Context);
1945 WriteUnlock(&Context->PropLock);
1947 ALCcontext_DecRef(Context);
1950 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1952 ALCcontext *Context;
1953 ALsource *Source;
1955 Context = GetContextRef();
1956 if(!Context) return;
1958 WriteLock(&Context->PropLock);
1959 LockSourcesRead(Context);
1960 if((Source=LookupSource(Context, source)) == NULL)
1961 alSetError(Context, AL_INVALID_NAME);
1962 else if(!values)
1963 alSetError(Context, AL_INVALID_VALUE);
1964 else if(!(IntValsByProp(param) > 0))
1965 alSetError(Context, AL_INVALID_ENUM);
1966 else
1967 SetSourceiv(Source, Context, param, values);
1968 UnlockSourcesRead(Context);
1969 WriteUnlock(&Context->PropLock);
1971 ALCcontext_DecRef(Context);
1975 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1977 ALCcontext *Context;
1978 ALsource *Source;
1980 Context = GetContextRef();
1981 if(!Context) return;
1983 WriteLock(&Context->PropLock);
1984 LockSourcesRead(Context);
1985 if((Source=LookupSource(Context, source)) == NULL)
1986 alSetError(Context, AL_INVALID_NAME);
1987 else if(!(Int64ValsByProp(param) == 1))
1988 alSetError(Context, AL_INVALID_ENUM);
1989 else
1990 SetSourcei64v(Source, Context, param, &value);
1991 UnlockSourcesRead(Context);
1992 WriteUnlock(&Context->PropLock);
1994 ALCcontext_DecRef(Context);
1997 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1999 ALCcontext *Context;
2000 ALsource *Source;
2002 Context = GetContextRef();
2003 if(!Context) return;
2005 WriteLock(&Context->PropLock);
2006 LockSourcesRead(Context);
2007 if((Source=LookupSource(Context, source)) == NULL)
2008 alSetError(Context, AL_INVALID_NAME);
2009 else if(!(Int64ValsByProp(param) == 3))
2010 alSetError(Context, AL_INVALID_ENUM);
2011 else
2013 ALint64SOFT i64vals[3] = { value1, value2, value3 };
2014 SetSourcei64v(Source, Context, param, i64vals);
2016 UnlockSourcesRead(Context);
2017 WriteUnlock(&Context->PropLock);
2019 ALCcontext_DecRef(Context);
2022 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
2024 ALCcontext *Context;
2025 ALsource *Source;
2027 Context = GetContextRef();
2028 if(!Context) return;
2030 WriteLock(&Context->PropLock);
2031 LockSourcesRead(Context);
2032 if((Source=LookupSource(Context, source)) == NULL)
2033 alSetError(Context, AL_INVALID_NAME);
2034 else if(!values)
2035 alSetError(Context, AL_INVALID_VALUE);
2036 else if(!(Int64ValsByProp(param) > 0))
2037 alSetError(Context, AL_INVALID_ENUM);
2038 else
2039 SetSourcei64v(Source, Context, param, values);
2040 UnlockSourcesRead(Context);
2041 WriteUnlock(&Context->PropLock);
2043 ALCcontext_DecRef(Context);
2047 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
2049 ALCcontext *Context;
2050 ALsource *Source;
2052 Context = GetContextRef();
2053 if(!Context) return;
2055 ReadLock(&Context->PropLock);
2056 LockSourcesRead(Context);
2057 if((Source=LookupSource(Context, source)) == NULL)
2058 alSetError(Context, AL_INVALID_NAME);
2059 else if(!value)
2060 alSetError(Context, AL_INVALID_VALUE);
2061 else if(!(FloatValsByProp(param) == 1))
2062 alSetError(Context, AL_INVALID_ENUM);
2063 else
2065 ALdouble dval;
2066 if(GetSourcedv(Source, Context, param, &dval))
2067 *value = (ALfloat)dval;
2069 UnlockSourcesRead(Context);
2070 ReadUnlock(&Context->PropLock);
2072 ALCcontext_DecRef(Context);
2076 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
2078 ALCcontext *Context;
2079 ALsource *Source;
2081 Context = GetContextRef();
2082 if(!Context) return;
2084 ReadLock(&Context->PropLock);
2085 LockSourcesRead(Context);
2086 if((Source=LookupSource(Context, source)) == NULL)
2087 alSetError(Context, AL_INVALID_NAME);
2088 else if(!(value1 && value2 && value3))
2089 alSetError(Context, AL_INVALID_VALUE);
2090 else if(!(FloatValsByProp(param) == 3))
2091 alSetError(Context, AL_INVALID_ENUM);
2092 else
2094 ALdouble dvals[3];
2095 if(GetSourcedv(Source, Context, param, dvals))
2097 *value1 = (ALfloat)dvals[0];
2098 *value2 = (ALfloat)dvals[1];
2099 *value3 = (ALfloat)dvals[2];
2102 UnlockSourcesRead(Context);
2103 ReadUnlock(&Context->PropLock);
2105 ALCcontext_DecRef(Context);
2109 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
2111 ALCcontext *Context;
2112 ALsource *Source;
2113 ALint count;
2115 Context = GetContextRef();
2116 if(!Context) return;
2118 ReadLock(&Context->PropLock);
2119 LockSourcesRead(Context);
2120 if((Source=LookupSource(Context, source)) == NULL)
2121 alSetError(Context, AL_INVALID_NAME);
2122 else if(!values)
2123 alSetError(Context, AL_INVALID_VALUE);
2124 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
2125 alSetError(Context, AL_INVALID_ENUM);
2126 else
2128 ALdouble dvals[6];
2129 if(GetSourcedv(Source, Context, param, dvals))
2131 ALint i;
2132 for(i = 0;i < count;i++)
2133 values[i] = (ALfloat)dvals[i];
2136 UnlockSourcesRead(Context);
2137 ReadUnlock(&Context->PropLock);
2139 ALCcontext_DecRef(Context);
2143 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
2145 ALCcontext *Context;
2146 ALsource *Source;
2148 Context = GetContextRef();
2149 if(!Context) return;
2151 ReadLock(&Context->PropLock);
2152 LockSourcesRead(Context);
2153 if((Source=LookupSource(Context, source)) == NULL)
2154 alSetError(Context, AL_INVALID_NAME);
2155 else if(!value)
2156 alSetError(Context, AL_INVALID_VALUE);
2157 else if(!(DoubleValsByProp(param) == 1))
2158 alSetError(Context, AL_INVALID_ENUM);
2159 else
2160 GetSourcedv(Source, Context, param, value);
2161 UnlockSourcesRead(Context);
2162 ReadUnlock(&Context->PropLock);
2164 ALCcontext_DecRef(Context);
2167 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
2169 ALCcontext *Context;
2170 ALsource *Source;
2172 Context = GetContextRef();
2173 if(!Context) return;
2175 ReadLock(&Context->PropLock);
2176 LockSourcesRead(Context);
2177 if((Source=LookupSource(Context, source)) == NULL)
2178 alSetError(Context, AL_INVALID_NAME);
2179 else if(!(value1 && value2 && value3))
2180 alSetError(Context, AL_INVALID_VALUE);
2181 else if(!(DoubleValsByProp(param) == 3))
2182 alSetError(Context, AL_INVALID_ENUM);
2183 else
2185 ALdouble dvals[3];
2186 if(GetSourcedv(Source, Context, param, dvals))
2188 *value1 = dvals[0];
2189 *value2 = dvals[1];
2190 *value3 = dvals[2];
2193 UnlockSourcesRead(Context);
2194 ReadUnlock(&Context->PropLock);
2196 ALCcontext_DecRef(Context);
2199 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
2201 ALCcontext *Context;
2202 ALsource *Source;
2204 Context = GetContextRef();
2205 if(!Context) return;
2207 ReadLock(&Context->PropLock);
2208 LockSourcesRead(Context);
2209 if((Source=LookupSource(Context, source)) == NULL)
2210 alSetError(Context, AL_INVALID_NAME);
2211 else if(!values)
2212 alSetError(Context, AL_INVALID_VALUE);
2213 else if(!(DoubleValsByProp(param) > 0))
2214 alSetError(Context, AL_INVALID_ENUM);
2215 else
2216 GetSourcedv(Source, Context, param, values);
2217 UnlockSourcesRead(Context);
2218 ReadUnlock(&Context->PropLock);
2220 ALCcontext_DecRef(Context);
2224 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2226 ALCcontext *Context;
2227 ALsource *Source;
2229 Context = GetContextRef();
2230 if(!Context) return;
2232 ReadLock(&Context->PropLock);
2233 LockSourcesRead(Context);
2234 if((Source=LookupSource(Context, source)) == NULL)
2235 alSetError(Context, AL_INVALID_NAME);
2236 else if(!value)
2237 alSetError(Context, AL_INVALID_VALUE);
2238 else if(!(IntValsByProp(param) == 1))
2239 alSetError(Context, AL_INVALID_ENUM);
2240 else
2241 GetSourceiv(Source, Context, param, value);
2242 UnlockSourcesRead(Context);
2243 ReadUnlock(&Context->PropLock);
2245 ALCcontext_DecRef(Context);
2249 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2251 ALCcontext *Context;
2252 ALsource *Source;
2254 Context = GetContextRef();
2255 if(!Context) return;
2257 ReadLock(&Context->PropLock);
2258 LockSourcesRead(Context);
2259 if((Source=LookupSource(Context, source)) == NULL)
2260 alSetError(Context, AL_INVALID_NAME);
2261 else if(!(value1 && value2 && value3))
2262 alSetError(Context, AL_INVALID_VALUE);
2263 else if(!(IntValsByProp(param) == 3))
2264 alSetError(Context, AL_INVALID_ENUM);
2265 else
2267 ALint ivals[3];
2268 if(GetSourceiv(Source, Context, param, ivals))
2270 *value1 = ivals[0];
2271 *value2 = ivals[1];
2272 *value3 = ivals[2];
2275 UnlockSourcesRead(Context);
2276 ReadUnlock(&Context->PropLock);
2278 ALCcontext_DecRef(Context);
2282 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2284 ALCcontext *Context;
2285 ALsource *Source;
2287 Context = GetContextRef();
2288 if(!Context) return;
2290 ReadLock(&Context->PropLock);
2291 LockSourcesRead(Context);
2292 if((Source=LookupSource(Context, source)) == NULL)
2293 alSetError(Context, AL_INVALID_NAME);
2294 else if(!values)
2295 alSetError(Context, AL_INVALID_VALUE);
2296 else if(!(IntValsByProp(param) > 0))
2297 alSetError(Context, AL_INVALID_ENUM);
2298 else
2299 GetSourceiv(Source, Context, param, values);
2300 UnlockSourcesRead(Context);
2301 ReadUnlock(&Context->PropLock);
2303 ALCcontext_DecRef(Context);
2307 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2309 ALCcontext *Context;
2310 ALsource *Source;
2312 Context = GetContextRef();
2313 if(!Context) return;
2315 ReadLock(&Context->PropLock);
2316 LockSourcesRead(Context);
2317 if((Source=LookupSource(Context, source)) == NULL)
2318 alSetError(Context, AL_INVALID_NAME);
2319 else if(!value)
2320 alSetError(Context, AL_INVALID_VALUE);
2321 else if(!(Int64ValsByProp(param) == 1))
2322 alSetError(Context, AL_INVALID_ENUM);
2323 else
2324 GetSourcei64v(Source, Context, param, value);
2325 UnlockSourcesRead(Context);
2326 ReadUnlock(&Context->PropLock);
2328 ALCcontext_DecRef(Context);
2331 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2333 ALCcontext *Context;
2334 ALsource *Source;
2336 Context = GetContextRef();
2337 if(!Context) return;
2339 ReadLock(&Context->PropLock);
2340 LockSourcesRead(Context);
2341 if((Source=LookupSource(Context, source)) == NULL)
2342 alSetError(Context, AL_INVALID_NAME);
2343 else if(!(value1 && value2 && value3))
2344 alSetError(Context, AL_INVALID_VALUE);
2345 else if(!(Int64ValsByProp(param) == 3))
2346 alSetError(Context, AL_INVALID_ENUM);
2347 else
2349 ALint64 i64vals[3];
2350 if(GetSourcei64v(Source, Context, param, i64vals))
2352 *value1 = i64vals[0];
2353 *value2 = i64vals[1];
2354 *value3 = i64vals[2];
2357 UnlockSourcesRead(Context);
2358 ReadUnlock(&Context->PropLock);
2360 ALCcontext_DecRef(Context);
2363 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2365 ALCcontext *Context;
2366 ALsource *Source;
2368 Context = GetContextRef();
2369 if(!Context) return;
2371 ReadLock(&Context->PropLock);
2372 LockSourcesRead(Context);
2373 if((Source=LookupSource(Context, source)) == NULL)
2374 alSetError(Context, AL_INVALID_NAME);
2375 else if(!values)
2376 alSetError(Context, AL_INVALID_VALUE);
2377 else if(!(Int64ValsByProp(param) > 0))
2378 alSetError(Context, AL_INVALID_ENUM);
2379 else
2380 GetSourcei64v(Source, Context, param, values);
2381 UnlockSourcesRead(Context);
2382 ReadUnlock(&Context->PropLock);
2384 ALCcontext_DecRef(Context);
2388 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2390 alSourcePlayv(1, &source);
2392 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2394 ALCcontext *context;
2395 ALCdevice *device;
2396 ALsource *source;
2397 ALvoice *voice;
2398 ALsizei i, j;
2400 context = GetContextRef();
2401 if(!context) return;
2403 LockSourcesRead(context);
2404 if(!(n >= 0))
2405 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2406 for(i = 0;i < n;i++)
2408 if(!LookupSource(context, sources[i]))
2409 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2412 device = context->Device;
2413 ALCdevice_Lock(device);
2414 /* If the device is disconnected, go right to stopped. */
2415 if(!device->Connected)
2417 for(i = 0;i < n;i++)
2419 source = LookupSource(context, sources[i]);
2420 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2422 ALCdevice_Unlock(device);
2423 goto done;
2426 while(n > context->MaxVoices-context->VoiceCount)
2428 ALsizei newcount = context->MaxVoices << 1;
2429 if(context->MaxVoices >= newcount)
2431 ALCdevice_Unlock(device);
2432 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2434 AllocateVoices(context, newcount, device->NumAuxSends);
2437 for(i = 0;i < n;i++)
2439 ALbufferlistitem *BufferList;
2440 ALbuffer *buffer = NULL;
2441 bool start_moving = false;
2442 ALsizei s;
2444 source = LookupSource(context, sources[i]);
2445 WriteLock(&source->queue_lock);
2446 /* Check that there is a queue containing at least one valid, non zero
2447 * length Buffer.
2449 BufferList = source->queue;
2450 while(BufferList)
2452 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2453 break;
2454 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
2457 /* If there's nothing to play, go right to stopped. */
2458 if(!BufferList)
2460 /* NOTE: A source without any playable buffers should not have an
2461 * ALvoice since it shouldn't be in a playing or paused state. So
2462 * there's no need to look up its voice and clear the source.
2464 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2465 source->OffsetType = AL_NONE;
2466 source->Offset = 0.0;
2467 goto finish_play;
2470 voice = GetSourceVoice(source, context);
2471 switch(GetSourceState(source, voice))
2473 case AL_PLAYING:
2474 assert(voice != NULL);
2475 /* A source that's already playing is restarted from the beginning. */
2476 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
2477 ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
2478 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release);
2479 goto finish_play;
2481 case AL_PAUSED:
2482 assert(voice != NULL);
2483 /* A source that's paused simply resumes. Clear its mixing
2484 * parameters and mark it as 'moving' so it fades in from
2485 * silence.
2487 voice->Step = 0;
2488 voice->Flags |= VOICE_IS_MOVING;
2489 memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*
2490 voice->NumChannels);
2491 for(s = 0;s < device->NumAuxSends;s++)
2492 memset(voice->Send[s].Params, 0, sizeof(voice->Send[s].Params[0])*
2493 voice->NumChannels);
2494 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
2495 ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release);
2496 goto finish_play;
2498 default:
2499 break;
2502 /* Make sure this source isn't already active, and if not, look for an
2503 * unused voice to put it in.
2505 assert(voice == NULL);
2506 for(j = 0;j < context->VoiceCount;j++)
2508 if(ATOMIC_LOAD(&context->Voices[j]->Source, almemory_order_acquire) == NULL)
2510 voice = context->Voices[j];
2511 break;
2514 if(voice == NULL)
2515 voice = context->Voices[context->VoiceCount++];
2516 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2518 ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acquire);
2519 UpdateSourceProps(source, voice, device->NumAuxSends);
2521 /* A source that's not playing or paused has any offset applied when it
2522 * starts playing.
2524 if(source->Looping)
2525 ATOMIC_STORE(&voice->loop_buffer, source->queue, almemory_order_relaxed);
2526 else
2527 ATOMIC_STORE(&voice->loop_buffer, NULL, almemory_order_relaxed);
2528 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
2529 ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
2530 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed);
2531 if(source->OffsetType != AL_NONE)
2533 ApplyOffset(source, voice);
2534 start_moving = ATOMIC_LOAD(&voice->position, almemory_order_relaxed) != 0 ||
2535 ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) != 0 ||
2536 ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed) != BufferList;
2539 voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2540 voice->SampleSize = BytesFromFmt(buffer->FmtType);
2542 /* Clear previous samples. */
2543 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
2545 /* Clear the stepping value so the mixer knows not to mix this until
2546 * the update gets applied.
2548 voice->Step = 0;
2550 voice->Flags = start_moving ? VOICE_IS_MOVING : 0;
2551 memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*voice->NumChannels);
2552 for(s = 0;s < device->NumAuxSends;s++)
2553 memset(voice->Send[s].Params, 0, sizeof(voice->Send[s].Params[0])*voice->NumChannels);
2554 if(device->AvgSpeakerDist > 0.0f)
2556 ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC /
2557 (device->AvgSpeakerDist * device->Frequency);
2558 for(j = 0;j < voice->NumChannels;j++)
2560 NfcFilterCreate1(&voice->Direct.Params[j].NFCtrlFilter[0], 0.0f, w1);
2561 NfcFilterCreate2(&voice->Direct.Params[j].NFCtrlFilter[1], 0.0f, w1);
2562 NfcFilterCreate3(&voice->Direct.Params[j].NFCtrlFilter[2], 0.0f, w1);
2566 ATOMIC_STORE(&voice->Source, source, almemory_order_relaxed);
2567 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
2568 ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release);
2569 finish_play:
2570 WriteUnlock(&source->queue_lock);
2572 ALCdevice_Unlock(device);
2574 done:
2575 UnlockSourcesRead(context);
2576 ALCcontext_DecRef(context);
2579 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2581 alSourcePausev(1, &source);
2583 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2585 ALCcontext *context;
2586 ALCdevice *device;
2587 ALsource *source;
2588 ALvoice *voice;
2589 ALsizei i;
2591 context = GetContextRef();
2592 if(!context) return;
2594 LockSourcesRead(context);
2595 if(!(n >= 0))
2596 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2597 for(i = 0;i < n;i++)
2599 if(!LookupSource(context, sources[i]))
2600 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2603 device = context->Device;
2604 ALCdevice_Lock(device);
2605 for(i = 0;i < n;i++)
2607 source = LookupSource(context, sources[i]);
2608 WriteLock(&source->queue_lock);
2609 if((voice=GetSourceVoice(source, context)) != NULL)
2611 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2612 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2613 althrd_yield();
2615 if(GetSourceState(source, voice) == AL_PLAYING)
2616 ATOMIC_STORE(&source->state, AL_PAUSED, almemory_order_release);
2617 WriteUnlock(&source->queue_lock);
2619 ALCdevice_Unlock(device);
2621 done:
2622 UnlockSourcesRead(context);
2623 ALCcontext_DecRef(context);
2626 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2628 alSourceStopv(1, &source);
2630 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2632 ALCcontext *context;
2633 ALCdevice *device;
2634 ALsource *source;
2635 ALvoice *voice;
2636 ALsizei i;
2638 context = GetContextRef();
2639 if(!context) return;
2641 LockSourcesRead(context);
2642 if(!(n >= 0))
2643 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2644 for(i = 0;i < n;i++)
2646 if(!LookupSource(context, sources[i]))
2647 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2650 device = context->Device;
2651 ALCdevice_Lock(device);
2652 for(i = 0;i < n;i++)
2654 source = LookupSource(context, sources[i]);
2655 WriteLock(&source->queue_lock);
2656 if((voice=GetSourceVoice(source, context)) != NULL)
2658 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
2659 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2660 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2661 althrd_yield();
2663 if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL)
2664 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2665 source->OffsetType = AL_NONE;
2666 source->Offset = 0.0;
2667 WriteUnlock(&source->queue_lock);
2669 ALCdevice_Unlock(device);
2671 done:
2672 UnlockSourcesRead(context);
2673 ALCcontext_DecRef(context);
2676 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2678 alSourceRewindv(1, &source);
2680 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2682 ALCcontext *context;
2683 ALCdevice *device;
2684 ALsource *source;
2685 ALvoice *voice;
2686 ALsizei i;
2688 context = GetContextRef();
2689 if(!context) return;
2691 LockSourcesRead(context);
2692 if(!(n >= 0))
2693 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2694 for(i = 0;i < n;i++)
2696 if(!LookupSource(context, sources[i]))
2697 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2700 device = context->Device;
2701 ALCdevice_Lock(device);
2702 for(i = 0;i < n;i++)
2704 source = LookupSource(context, sources[i]);
2705 WriteLock(&source->queue_lock);
2706 if((voice=GetSourceVoice(source, context)) != NULL)
2708 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
2709 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2710 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2711 althrd_yield();
2713 if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL)
2714 ATOMIC_STORE(&source->state, AL_INITIAL, almemory_order_relaxed);
2715 source->OffsetType = AL_NONE;
2716 source->Offset = 0.0;
2717 WriteUnlock(&source->queue_lock);
2719 ALCdevice_Unlock(device);
2721 done:
2722 UnlockSourcesRead(context);
2723 ALCcontext_DecRef(context);
2727 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2729 ALCdevice *device;
2730 ALCcontext *context;
2731 ALsource *source;
2732 ALsizei i;
2733 ALbufferlistitem *BufferListStart;
2734 ALbufferlistitem *BufferList;
2735 ALbuffer *BufferFmt = NULL;
2737 if(nb == 0)
2738 return;
2740 context = GetContextRef();
2741 if(!context) return;
2743 device = context->Device;
2745 LockSourcesRead(context);
2746 if(!(nb >= 0))
2747 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2748 if((source=LookupSource(context, src)) == NULL)
2749 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2751 WriteLock(&source->queue_lock);
2752 if(source->SourceType == AL_STATIC)
2754 WriteUnlock(&source->queue_lock);
2755 /* Can't queue on a Static Source */
2756 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2759 /* Check for a valid Buffer, for its frequency and format */
2760 BufferList = source->queue;
2761 while(BufferList)
2763 if(BufferList->buffer)
2765 BufferFmt = BufferList->buffer;
2766 break;
2768 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
2771 LockBuffersRead(device);
2772 BufferListStart = NULL;
2773 BufferList = NULL;
2774 for(i = 0;i < nb;i++)
2776 ALbuffer *buffer = NULL;
2777 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2779 WriteUnlock(&source->queue_lock);
2780 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2783 if(!BufferListStart)
2785 BufferListStart = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
2786 BufferList = BufferListStart;
2788 else
2790 ALbufferlistitem *item = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem));
2791 ATOMIC_STORE(&BufferList->next, item, almemory_order_relaxed);
2792 BufferList = item;
2794 BufferList->buffer = buffer;
2795 ATOMIC_INIT(&BufferList->next, NULL);
2796 if(!buffer) continue;
2798 /* Hold a read lock on each buffer being queued while checking all
2799 * provided buffers. This is done so other threads don't see an extra
2800 * reference on some buffers if this operation ends up failing. */
2801 ReadLock(&buffer->lock);
2802 IncrementRef(&buffer->ref);
2804 if(BufferFmt == NULL)
2805 BufferFmt = buffer;
2806 else if(BufferFmt->Frequency != buffer->Frequency ||
2807 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2808 BufferFmt->OriginalType != buffer->OriginalType)
2810 WriteUnlock(&source->queue_lock);
2811 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2813 buffer_error:
2814 /* A buffer failed (invalid ID or format), so unlock and release
2815 * each buffer we had. */
2816 while(BufferListStart)
2818 ALbufferlistitem *next = ATOMIC_LOAD(&BufferListStart->next,
2819 almemory_order_relaxed);
2820 if((buffer=BufferListStart->buffer) != NULL)
2822 DecrementRef(&buffer->ref);
2823 ReadUnlock(&buffer->lock);
2825 al_free(BufferListStart);
2826 BufferListStart = next;
2828 UnlockBuffersRead(device);
2829 goto done;
2832 /* All buffers good, unlock them now. */
2833 BufferList = BufferListStart;
2834 while(BufferList != NULL)
2836 ALbuffer *buffer = BufferList->buffer;
2837 if(buffer) ReadUnlock(&buffer->lock);
2838 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
2840 UnlockBuffersRead(device);
2842 /* Source is now streaming */
2843 source->SourceType = AL_STREAMING;
2845 if(!(BufferList=source->queue))
2846 source->queue = BufferListStart;
2847 else
2849 ALbufferlistitem *next;
2850 while((next=ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed)) != NULL)
2851 BufferList = next;
2852 ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release);
2854 WriteUnlock(&source->queue_lock);
2856 done:
2857 UnlockSourcesRead(context);
2858 ALCcontext_DecRef(context);
2861 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2863 ALCcontext *context;
2864 ALsource *source;
2865 ALbufferlistitem *OldHead;
2866 ALbufferlistitem *OldTail;
2867 ALbufferlistitem *Current;
2868 ALvoice *voice;
2869 ALsizei i = 0;
2871 context = GetContextRef();
2872 if(!context) return;
2874 LockSourcesRead(context);
2875 if(!(nb >= 0))
2876 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2878 if((source=LookupSource(context, src)) == NULL)
2879 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2881 /* Nothing to unqueue. */
2882 if(nb == 0) goto done;
2884 WriteLock(&source->queue_lock);
2885 if(source->Looping || source->SourceType != AL_STREAMING)
2887 WriteUnlock(&source->queue_lock);
2888 /* Trying to unqueue buffers on a looping or non-streaming source. */
2889 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2892 /* Find the new buffer queue head */
2893 OldTail = source->queue;
2894 Current = NULL;
2895 if((voice=GetSourceVoice(source, context)) != NULL)
2896 Current = ATOMIC_LOAD_SEQ(&voice->current_buffer);
2897 else if(ATOMIC_LOAD_SEQ(&source->state) == AL_INITIAL)
2898 Current = OldTail;
2899 if(OldTail != Current)
2901 for(i = 1;i < nb;i++)
2903 ALbufferlistitem *next = ATOMIC_LOAD(&OldTail->next, almemory_order_relaxed);
2904 if(!next || next == Current) break;
2905 OldTail = next;
2908 if(i != nb)
2910 WriteUnlock(&source->queue_lock);
2911 /* Trying to unqueue pending buffers. */
2912 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2915 /* Swap it, and cut the new head from the old. */
2916 OldHead = source->queue;
2917 source->queue = ATOMIC_EXCHANGE_PTR(&OldTail->next, NULL, almemory_order_acq_rel);
2918 WriteUnlock(&source->queue_lock);
2920 while(OldHead != NULL)
2922 ALbufferlistitem *next = ATOMIC_LOAD(&OldHead->next, almemory_order_relaxed);
2923 ALbuffer *buffer = OldHead->buffer;
2925 if(!buffer)
2926 *(buffers++) = 0;
2927 else
2929 *(buffers++) = buffer->id;
2930 DecrementRef(&buffer->ref);
2933 al_free(OldHead);
2934 OldHead = next;
2937 done:
2938 UnlockSourcesRead(context);
2939 ALCcontext_DecRef(context);
2943 static void InitSourceParams(ALsource *Source, ALsizei num_sends)
2945 ALsizei i;
2947 RWLockInit(&Source->queue_lock);
2949 Source->InnerAngle = 360.0f;
2950 Source->OuterAngle = 360.0f;
2951 Source->Pitch = 1.0f;
2952 Source->Position[0] = 0.0f;
2953 Source->Position[1] = 0.0f;
2954 Source->Position[2] = 0.0f;
2955 Source->Velocity[0] = 0.0f;
2956 Source->Velocity[1] = 0.0f;
2957 Source->Velocity[2] = 0.0f;
2958 Source->Direction[0] = 0.0f;
2959 Source->Direction[1] = 0.0f;
2960 Source->Direction[2] = 0.0f;
2961 Source->Orientation[0][0] = 0.0f;
2962 Source->Orientation[0][1] = 0.0f;
2963 Source->Orientation[0][2] = -1.0f;
2964 Source->Orientation[1][0] = 0.0f;
2965 Source->Orientation[1][1] = 1.0f;
2966 Source->Orientation[1][2] = 0.0f;
2967 Source->RefDistance = 1.0f;
2968 Source->MaxDistance = FLT_MAX;
2969 Source->RollOffFactor = 1.0f;
2970 Source->Gain = 1.0f;
2971 Source->MinGain = 0.0f;
2972 Source->MaxGain = 1.0f;
2973 Source->OuterGain = 0.0f;
2974 Source->OuterGainHF = 1.0f;
2976 Source->DryGainHFAuto = AL_TRUE;
2977 Source->WetGainAuto = AL_TRUE;
2978 Source->WetGainHFAuto = AL_TRUE;
2979 Source->AirAbsorptionFactor = 0.0f;
2980 Source->RoomRolloffFactor = 0.0f;
2981 Source->DopplerFactor = 1.0f;
2982 Source->HeadRelative = AL_FALSE;
2983 Source->Looping = AL_FALSE;
2984 Source->DistanceModel = DefaultDistanceModel;
2985 Source->Resampler = ResamplerDefault;
2986 Source->DirectChannels = AL_FALSE;
2988 Source->StereoPan[0] = DEG2RAD( 30.0f);
2989 Source->StereoPan[1] = DEG2RAD(-30.0f);
2991 Source->Radius = 0.0f;
2993 Source->Direct.Gain = 1.0f;
2994 Source->Direct.GainHF = 1.0f;
2995 Source->Direct.HFReference = LOWPASSFREQREF;
2996 Source->Direct.GainLF = 1.0f;
2997 Source->Direct.LFReference = HIGHPASSFREQREF;
2998 Source->Send = al_calloc(16, num_sends*sizeof(Source->Send[0]));
2999 for(i = 0;i < num_sends;i++)
3001 Source->Send[i].Slot = NULL;
3002 Source->Send[i].Gain = 1.0f;
3003 Source->Send[i].GainHF = 1.0f;
3004 Source->Send[i].HFReference = LOWPASSFREQREF;
3005 Source->Send[i].GainLF = 1.0f;
3006 Source->Send[i].LFReference = HIGHPASSFREQREF;
3009 Source->Offset = 0.0;
3010 Source->OffsetType = AL_NONE;
3011 Source->SourceType = AL_UNDETERMINED;
3012 ATOMIC_INIT(&Source->state, AL_INITIAL);
3014 Source->queue = NULL;
3016 /* No way to do an 'init' here, so just test+set with relaxed ordering and
3017 * ignore the test.
3019 ATOMIC_FLAG_TEST_AND_SET(&Source->PropsClean, almemory_order_relaxed);
3022 static void DeinitSource(ALsource *source, ALsizei num_sends)
3024 ALbufferlistitem *BufferList;
3025 ALsizei i;
3027 BufferList = source->queue;
3028 while(BufferList != NULL)
3030 ALbufferlistitem *next = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
3031 if(BufferList->buffer != NULL)
3032 DecrementRef(&BufferList->buffer->ref);
3033 al_free(BufferList);
3034 BufferList = next;
3036 source->queue = NULL;
3038 if(source->Send)
3040 for(i = 0;i < num_sends;i++)
3042 if(source->Send[i].Slot)
3043 DecrementRef(&source->Send[i].Slot->ref);
3044 source->Send[i].Slot = NULL;
3046 al_free(source->Send);
3047 source->Send = NULL;
3051 static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends)
3053 struct ALvoiceProps *props;
3054 ALsizei i;
3056 /* Get an unused property container, or allocate a new one as needed. */
3057 props = ATOMIC_LOAD(&voice->FreeList, almemory_order_acquire);
3058 if(!props)
3059 props = al_calloc(16, FAM_SIZE(struct ALvoiceProps, Send, num_sends));
3060 else
3062 struct ALvoiceProps *next;
3063 do {
3064 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
3065 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&voice->FreeList, &props, next,
3066 almemory_order_acq_rel, almemory_order_acquire) == 0);
3069 /* Copy in current property values. */
3070 props->Pitch = source->Pitch;
3071 props->Gain = source->Gain;
3072 props->OuterGain = source->OuterGain;
3073 props->MinGain = source->MinGain;
3074 props->MaxGain = source->MaxGain;
3075 props->InnerAngle = source->InnerAngle;
3076 props->OuterAngle = source->OuterAngle;
3077 props->RefDistance = source->RefDistance;
3078 props->MaxDistance = source->MaxDistance;
3079 props->RollOffFactor = source->RollOffFactor;
3080 for(i = 0;i < 3;i++)
3081 props->Position[i] = source->Position[i];
3082 for(i = 0;i < 3;i++)
3083 props->Velocity[i] = source->Velocity[i];
3084 for(i = 0;i < 3;i++)
3085 props->Direction[i] = source->Direction[i];
3086 for(i = 0;i < 2;i++)
3088 ALsizei j;
3089 for(j = 0;j < 3;j++)
3090 props->Orientation[i][j] = source->Orientation[i][j];
3092 props->HeadRelative = source->HeadRelative;
3093 props->DistanceModel = source->DistanceModel;
3094 props->Resampler = source->Resampler;
3095 props->DirectChannels = source->DirectChannels;
3097 props->DryGainHFAuto = source->DryGainHFAuto;
3098 props->WetGainAuto = source->WetGainAuto;
3099 props->WetGainHFAuto = source->WetGainHFAuto;
3100 props->OuterGainHF = source->OuterGainHF;
3102 props->AirAbsorptionFactor = source->AirAbsorptionFactor;
3103 props->RoomRolloffFactor = source->RoomRolloffFactor;
3104 props->DopplerFactor = source->DopplerFactor;
3106 props->StereoPan[0] = source->StereoPan[0];
3107 props->StereoPan[1] = source->StereoPan[1];
3109 props->Radius = source->Radius;
3111 props->Direct.Gain = source->Direct.Gain;
3112 props->Direct.GainHF = source->Direct.GainHF;
3113 props->Direct.HFReference = source->Direct.HFReference;
3114 props->Direct.GainLF = source->Direct.GainLF;
3115 props->Direct.LFReference = source->Direct.LFReference;
3117 for(i = 0;i < num_sends;i++)
3119 props->Send[i].Slot = source->Send[i].Slot;
3120 props->Send[i].Gain = source->Send[i].Gain;
3121 props->Send[i].GainHF = source->Send[i].GainHF;
3122 props->Send[i].HFReference = source->Send[i].HFReference;
3123 props->Send[i].GainLF = source->Send[i].GainLF;
3124 props->Send[i].LFReference = source->Send[i].LFReference;
3127 /* Set the new container for updating internal parameters. */
3128 props = ATOMIC_EXCHANGE_PTR(&voice->Update, props, almemory_order_acq_rel);
3129 if(props)
3131 /* If there was an unused update container, put it back in the
3132 * freelist.
3134 ATOMIC_REPLACE_HEAD(struct ALvoiceProps*, &voice->FreeList, props);
3138 void UpdateAllSourceProps(ALCcontext *context)
3140 ALsizei num_sends = context->Device->NumAuxSends;
3141 ALsizei pos;
3143 for(pos = 0;pos < context->VoiceCount;pos++)
3145 ALvoice *voice = context->Voices[pos];
3146 ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire);
3147 if(source && !ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acq_rel))
3148 UpdateSourceProps(source, voice, num_sends);
3153 /* GetSourceSampleOffset
3155 * Gets the current read offset for the given Source, in 32.32 fixed-point
3156 * samples. The offset is relative to the start of the queue (not the start of
3157 * the current buffer).
3159 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3161 ALCdevice *device = context->Device;
3162 const ALbufferlistitem *Current;
3163 ALuint64 readPos;
3164 ALuint refcount;
3165 ALvoice *voice;
3167 ReadLock(&Source->queue_lock);
3168 do {
3169 Current = NULL;
3170 readPos = 0;
3171 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3172 althrd_yield();
3173 *clocktime = GetDeviceClockTime(device);
3175 voice = GetSourceVoice(Source, context);
3176 if(voice)
3178 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3180 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << 32;
3181 readPos |= (ALuint64)ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) <<
3182 (32-FRACTIONBITS);
3184 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3185 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3187 if(voice)
3189 const ALbufferlistitem *BufferList = Source->queue;
3190 while(BufferList && BufferList != Current)
3192 if(BufferList->buffer)
3193 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
3194 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3195 almemory_order_relaxed);
3197 readPos = minu64(readPos, U64(0x7fffffffffffffff));
3200 ReadUnlock(&Source->queue_lock);
3201 return (ALint64)readPos;
3204 /* GetSourceSecOffset
3206 * Gets the current read offset for the given Source, in seconds. The offset is
3207 * relative to the start of the queue (not the start of the current buffer).
3209 static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3211 ALCdevice *device = context->Device;
3212 const ALbufferlistitem *Current;
3213 ALuint64 readPos;
3214 ALuint refcount;
3215 ALdouble offset;
3216 ALvoice *voice;
3218 ReadLock(&Source->queue_lock);
3219 do {
3220 Current = NULL;
3221 readPos = 0;
3222 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3223 althrd_yield();
3224 *clocktime = GetDeviceClockTime(device);
3226 voice = GetSourceVoice(Source, context);
3227 if(voice)
3229 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3231 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) <<
3232 FRACTIONBITS;
3233 readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3235 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3236 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3238 offset = 0.0;
3239 if(voice)
3241 const ALbufferlistitem *BufferList = Source->queue;
3242 const ALbuffer *BufferFmt = NULL;
3243 while(BufferList && BufferList != Current)
3245 const ALbuffer *buffer = BufferList->buffer;
3246 if(buffer != NULL)
3248 if(!BufferFmt) BufferFmt = buffer;
3249 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
3251 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3252 almemory_order_relaxed);
3255 while(BufferList && !BufferFmt)
3257 BufferFmt = BufferList->buffer;
3258 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3259 almemory_order_relaxed);
3261 assert(BufferFmt != NULL);
3263 offset = (ALdouble)readPos / (ALdouble)FRACTIONONE /
3264 (ALdouble)BufferFmt->Frequency;
3267 ReadUnlock(&Source->queue_lock);
3268 return offset;
3271 /* GetSourceOffset
3273 * Gets the current read offset for the given Source, in the appropriate format
3274 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3275 * queue (not the start of the current buffer).
3277 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context)
3279 ALCdevice *device = context->Device;
3280 const ALbufferlistitem *Current;
3281 ALuint readPos;
3282 ALsizei readPosFrac;
3283 ALuint refcount;
3284 ALdouble offset;
3285 ALvoice *voice;
3287 ReadLock(&Source->queue_lock);
3288 do {
3289 Current = NULL;
3290 readPos = readPosFrac = 0;
3291 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3292 althrd_yield();
3293 voice = GetSourceVoice(Source, context);
3294 if(voice)
3296 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3298 readPos = ATOMIC_LOAD(&voice->position, almemory_order_relaxed);
3299 readPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3301 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3302 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3304 offset = 0.0;
3305 if(voice)
3307 const ALbufferlistitem *BufferList = Source->queue;
3308 const ALbuffer *BufferFmt = NULL;
3309 ALboolean readFin = AL_FALSE;
3310 ALuint totalBufferLen = 0;
3312 while(BufferList != NULL)
3314 const ALbuffer *buffer;
3315 readFin = readFin || (BufferList == Current);
3316 if((buffer=BufferList->buffer) != NULL)
3318 if(!BufferFmt) BufferFmt = buffer;
3319 totalBufferLen += buffer->SampleLen;
3320 if(!readFin) readPos += buffer->SampleLen;
3322 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3323 almemory_order_relaxed);
3325 assert(BufferFmt != NULL);
3327 if(Source->Looping)
3328 readPos %= totalBufferLen;
3329 else
3331 /* Wrap back to 0 */
3332 if(readPos >= totalBufferLen)
3333 readPos = readPosFrac = 0;
3336 offset = 0.0;
3337 switch(name)
3339 case AL_SEC_OFFSET:
3340 offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE) / BufferFmt->Frequency;
3341 break;
3343 case AL_SAMPLE_OFFSET:
3344 offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
3345 break;
3347 case AL_BYTE_OFFSET:
3348 if(BufferFmt->OriginalType == UserFmtIMA4)
3350 ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
3351 ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels);
3352 ALuint FrameBlockSize = BufferFmt->OriginalAlign;
3354 /* Round down to nearest ADPCM block */
3355 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3357 else if(BufferFmt->OriginalType == UserFmtMSADPCM)
3359 ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
3360 ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels);
3361 ALuint FrameBlockSize = BufferFmt->OriginalAlign;
3363 /* Round down to nearest ADPCM block */
3364 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3366 else
3368 ALuint FrameSize = FrameSizeFromUserFmt(BufferFmt->OriginalChannels,
3369 BufferFmt->OriginalType);
3370 offset = (ALdouble)(readPos * FrameSize);
3372 break;
3376 ReadUnlock(&Source->queue_lock);
3377 return offset;
3381 /* ApplyOffset
3383 * Apply the stored playback offset to the Source. This function will update
3384 * the number of buffers "played" given the stored offset.
3386 static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice)
3388 ALbufferlistitem *BufferList;
3389 const ALbuffer *Buffer;
3390 ALuint bufferLen, totalBufferLen;
3391 ALuint offset = 0;
3392 ALsizei frac = 0;
3394 /* Get sample frame offset */
3395 if(!GetSampleOffset(Source, &offset, &frac))
3396 return AL_FALSE;
3398 totalBufferLen = 0;
3399 BufferList = Source->queue;
3400 while(BufferList && totalBufferLen <= offset)
3402 Buffer = BufferList->buffer;
3403 bufferLen = Buffer ? Buffer->SampleLen : 0;
3405 if(bufferLen > offset-totalBufferLen)
3407 /* Offset is in this buffer */
3408 ATOMIC_STORE(&voice->position, offset - totalBufferLen, almemory_order_relaxed);
3409 ATOMIC_STORE(&voice->position_fraction, frac, almemory_order_relaxed);
3410 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_release);
3411 return AL_TRUE;
3414 totalBufferLen += bufferLen;
3416 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
3419 /* Offset is out of range of the queue */
3420 return AL_FALSE;
3424 /* GetSampleOffset
3426 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3427 * or Second offset supplied by the application). This takes into account the
3428 * fact that the buffer format may have been modifed since.
3430 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac)
3432 const ALbuffer *BufferFmt = NULL;
3433 const ALbufferlistitem *BufferList;
3434 ALdouble dbloff, dblfrac;
3436 /* Find the first valid Buffer in the Queue */
3437 BufferList = Source->queue;
3438 while(BufferList)
3440 if((BufferFmt=BufferList->buffer) != NULL)
3441 break;
3442 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3443 almemory_order_relaxed);
3445 if(!BufferFmt)
3447 Source->OffsetType = AL_NONE;
3448 Source->Offset = 0.0;
3449 return AL_FALSE;
3452 switch(Source->OffsetType)
3454 case AL_BYTE_OFFSET:
3455 /* Determine the ByteOffset (and ensure it is block aligned) */
3456 *offset = (ALuint)Source->Offset;
3457 if(BufferFmt->OriginalType == UserFmtIMA4)
3459 ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
3460 *offset /= align * ChannelsFromUserFmt(BufferFmt->OriginalChannels);
3461 *offset *= BufferFmt->OriginalAlign;
3463 else if(BufferFmt->OriginalType == UserFmtMSADPCM)
3465 ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
3466 *offset /= align * ChannelsFromUserFmt(BufferFmt->OriginalChannels);
3467 *offset *= BufferFmt->OriginalAlign;
3469 else
3470 *offset /= FrameSizeFromUserFmt(BufferFmt->OriginalChannels,
3471 BufferFmt->OriginalType);
3472 *frac = 0;
3473 break;
3475 case AL_SAMPLE_OFFSET:
3476 dblfrac = modf(Source->Offset, &dbloff);
3477 *offset = (ALuint)mind(dbloff, UINT_MAX);
3478 *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3479 break;
3481 case AL_SEC_OFFSET:
3482 dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff);
3483 *offset = (ALuint)mind(dbloff, UINT_MAX);
3484 *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3485 break;
3487 Source->OffsetType = AL_NONE;
3488 Source->Offset = 0.0;
3490 return AL_TRUE;
3494 /* ReleaseALSources
3496 * Destroys all sources in the source map.
3498 ALvoid ReleaseALSources(ALCcontext *Context)
3500 ALCdevice *device = Context->Device;
3501 ALsizei pos;
3502 for(pos = 0;pos < Context->SourceMap.size;pos++)
3504 ALsource *temp = Context->SourceMap.values[pos];
3505 Context->SourceMap.values[pos] = NULL;
3507 DeinitSource(temp, device->NumAuxSends);
3509 FreeThunkEntry(temp->id);
3510 memset(temp, 0, sizeof(*temp));
3511 al_free(temp);