Track the buffer's mapped section
[openal-soft.git] / OpenAL32 / alSource.c
blob8b3cb3058b4829270166933b44244ccad8d68034
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, ALCcontext *context);
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,
123 /* AL_SOFT_source_spatialize */
124 srcSpatialize = AL_SOURCE_SPATIALIZE_SOFT,
126 /* ALC_SOFT_device_clock */
127 srcSampleOffsetClockSOFT = AL_SAMPLE_OFFSET_CLOCK_SOFT,
128 srcSecOffsetClockSOFT = AL_SEC_OFFSET_CLOCK_SOFT,
129 } SourceProp;
131 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
132 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
133 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
135 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
136 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
137 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
139 static inline ALvoice *GetSourceVoice(const ALsource *source, const ALCcontext *context)
141 ALvoice **voice = context->Voices;
142 ALvoice **voice_end = voice + context->VoiceCount;
143 while(voice != voice_end)
145 if(ATOMIC_LOAD(&(*voice)->Source, almemory_order_acquire) == source)
146 return *voice;
147 ++voice;
149 return NULL;
153 * Returns if the last known state for the source was playing or paused. Does
154 * not sync with the mixer voice.
156 static inline bool IsPlayingOrPaused(ALsource *source)
158 ALenum state = ATOMIC_LOAD(&source->state, almemory_order_acquire);
159 return state == AL_PLAYING || state == AL_PAUSED;
163 * Returns an updated source state using the matching voice's status (or lack
164 * thereof).
166 static inline ALenum GetSourceState(ALsource *source, ALvoice *voice)
168 if(!voice)
170 ALenum state = AL_PLAYING;
171 if(ATOMIC_COMPARE_EXCHANGE_STRONG(&source->state, &state, AL_STOPPED,
172 almemory_order_acq_rel, almemory_order_acquire))
173 return AL_STOPPED;
174 return state;
176 return ATOMIC_LOAD(&source->state, almemory_order_acquire);
180 * Returns if the source should specify an update, given the context's
181 * deferring state and the source's last known state.
183 static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context)
185 return !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) &&
186 IsPlayingOrPaused(source);
189 static ALint FloatValsByProp(ALenum prop)
191 if(prop != (ALenum)((SourceProp)prop))
192 return 0;
193 switch((SourceProp)prop)
195 case AL_PITCH:
196 case AL_GAIN:
197 case AL_MIN_GAIN:
198 case AL_MAX_GAIN:
199 case AL_MAX_DISTANCE:
200 case AL_ROLLOFF_FACTOR:
201 case AL_DOPPLER_FACTOR:
202 case AL_CONE_OUTER_GAIN:
203 case AL_SEC_OFFSET:
204 case AL_SAMPLE_OFFSET:
205 case AL_BYTE_OFFSET:
206 case AL_CONE_INNER_ANGLE:
207 case AL_CONE_OUTER_ANGLE:
208 case AL_REFERENCE_DISTANCE:
209 case AL_CONE_OUTER_GAINHF:
210 case AL_AIR_ABSORPTION_FACTOR:
211 case AL_ROOM_ROLLOFF_FACTOR:
212 case AL_DIRECT_FILTER_GAINHF_AUTO:
213 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
214 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
215 case AL_DIRECT_CHANNELS_SOFT:
216 case AL_DISTANCE_MODEL:
217 case AL_SOURCE_RELATIVE:
218 case AL_LOOPING:
219 case AL_SOURCE_STATE:
220 case AL_BUFFERS_QUEUED:
221 case AL_BUFFERS_PROCESSED:
222 case AL_SOURCE_TYPE:
223 case AL_BYTE_LENGTH_SOFT:
224 case AL_SAMPLE_LENGTH_SOFT:
225 case AL_SEC_LENGTH_SOFT:
226 case AL_SOURCE_RADIUS:
227 case AL_SOURCE_RESAMPLER_SOFT:
228 case AL_SOURCE_SPATIALIZE_SOFT:
229 return 1;
231 case AL_STEREO_ANGLES:
232 return 2;
234 case AL_POSITION:
235 case AL_VELOCITY:
236 case AL_DIRECTION:
237 return 3;
239 case AL_ORIENTATION:
240 return 6;
242 case AL_SEC_OFFSET_LATENCY_SOFT:
243 case AL_SEC_OFFSET_CLOCK_SOFT:
244 break; /* Double only */
246 case AL_BUFFER:
247 case AL_DIRECT_FILTER:
248 case AL_AUXILIARY_SEND_FILTER:
249 break; /* i/i64 only */
250 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
251 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
252 break; /* i64 only */
254 return 0;
256 static ALint DoubleValsByProp(ALenum prop)
258 if(prop != (ALenum)((SourceProp)prop))
259 return 0;
260 switch((SourceProp)prop)
262 case AL_PITCH:
263 case AL_GAIN:
264 case AL_MIN_GAIN:
265 case AL_MAX_GAIN:
266 case AL_MAX_DISTANCE:
267 case AL_ROLLOFF_FACTOR:
268 case AL_DOPPLER_FACTOR:
269 case AL_CONE_OUTER_GAIN:
270 case AL_SEC_OFFSET:
271 case AL_SAMPLE_OFFSET:
272 case AL_BYTE_OFFSET:
273 case AL_CONE_INNER_ANGLE:
274 case AL_CONE_OUTER_ANGLE:
275 case AL_REFERENCE_DISTANCE:
276 case AL_CONE_OUTER_GAINHF:
277 case AL_AIR_ABSORPTION_FACTOR:
278 case AL_ROOM_ROLLOFF_FACTOR:
279 case AL_DIRECT_FILTER_GAINHF_AUTO:
280 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
281 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
282 case AL_DIRECT_CHANNELS_SOFT:
283 case AL_DISTANCE_MODEL:
284 case AL_SOURCE_RELATIVE:
285 case AL_LOOPING:
286 case AL_SOURCE_STATE:
287 case AL_BUFFERS_QUEUED:
288 case AL_BUFFERS_PROCESSED:
289 case AL_SOURCE_TYPE:
290 case AL_BYTE_LENGTH_SOFT:
291 case AL_SAMPLE_LENGTH_SOFT:
292 case AL_SEC_LENGTH_SOFT:
293 case AL_SOURCE_RADIUS:
294 case AL_SOURCE_RESAMPLER_SOFT:
295 case AL_SOURCE_SPATIALIZE_SOFT:
296 return 1;
298 case AL_SEC_OFFSET_LATENCY_SOFT:
299 case AL_SEC_OFFSET_CLOCK_SOFT:
300 case AL_STEREO_ANGLES:
301 return 2;
303 case AL_POSITION:
304 case AL_VELOCITY:
305 case AL_DIRECTION:
306 return 3;
308 case AL_ORIENTATION:
309 return 6;
311 case AL_BUFFER:
312 case AL_DIRECT_FILTER:
313 case AL_AUXILIARY_SEND_FILTER:
314 break; /* i/i64 only */
315 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
316 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
317 break; /* i64 only */
319 return 0;
322 static ALint IntValsByProp(ALenum prop)
324 if(prop != (ALenum)((SourceProp)prop))
325 return 0;
326 switch((SourceProp)prop)
328 case AL_PITCH:
329 case AL_GAIN:
330 case AL_MIN_GAIN:
331 case AL_MAX_GAIN:
332 case AL_MAX_DISTANCE:
333 case AL_ROLLOFF_FACTOR:
334 case AL_DOPPLER_FACTOR:
335 case AL_CONE_OUTER_GAIN:
336 case AL_SEC_OFFSET:
337 case AL_SAMPLE_OFFSET:
338 case AL_BYTE_OFFSET:
339 case AL_CONE_INNER_ANGLE:
340 case AL_CONE_OUTER_ANGLE:
341 case AL_REFERENCE_DISTANCE:
342 case AL_CONE_OUTER_GAINHF:
343 case AL_AIR_ABSORPTION_FACTOR:
344 case AL_ROOM_ROLLOFF_FACTOR:
345 case AL_DIRECT_FILTER_GAINHF_AUTO:
346 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
347 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
348 case AL_DIRECT_CHANNELS_SOFT:
349 case AL_DISTANCE_MODEL:
350 case AL_SOURCE_RELATIVE:
351 case AL_LOOPING:
352 case AL_BUFFER:
353 case AL_SOURCE_STATE:
354 case AL_BUFFERS_QUEUED:
355 case AL_BUFFERS_PROCESSED:
356 case AL_SOURCE_TYPE:
357 case AL_DIRECT_FILTER:
358 case AL_BYTE_LENGTH_SOFT:
359 case AL_SAMPLE_LENGTH_SOFT:
360 case AL_SEC_LENGTH_SOFT:
361 case AL_SOURCE_RADIUS:
362 case AL_SOURCE_RESAMPLER_SOFT:
363 case AL_SOURCE_SPATIALIZE_SOFT:
364 return 1;
366 case AL_POSITION:
367 case AL_VELOCITY:
368 case AL_DIRECTION:
369 case AL_AUXILIARY_SEND_FILTER:
370 return 3;
372 case AL_ORIENTATION:
373 return 6;
375 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
376 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
377 break; /* i64 only */
378 case AL_SEC_OFFSET_LATENCY_SOFT:
379 case AL_SEC_OFFSET_CLOCK_SOFT:
380 break; /* Double only */
381 case AL_STEREO_ANGLES:
382 break; /* Float/double only */
384 return 0;
386 static ALint Int64ValsByProp(ALenum prop)
388 if(prop != (ALenum)((SourceProp)prop))
389 return 0;
390 switch((SourceProp)prop)
392 case AL_PITCH:
393 case AL_GAIN:
394 case AL_MIN_GAIN:
395 case AL_MAX_GAIN:
396 case AL_MAX_DISTANCE:
397 case AL_ROLLOFF_FACTOR:
398 case AL_DOPPLER_FACTOR:
399 case AL_CONE_OUTER_GAIN:
400 case AL_SEC_OFFSET:
401 case AL_SAMPLE_OFFSET:
402 case AL_BYTE_OFFSET:
403 case AL_CONE_INNER_ANGLE:
404 case AL_CONE_OUTER_ANGLE:
405 case AL_REFERENCE_DISTANCE:
406 case AL_CONE_OUTER_GAINHF:
407 case AL_AIR_ABSORPTION_FACTOR:
408 case AL_ROOM_ROLLOFF_FACTOR:
409 case AL_DIRECT_FILTER_GAINHF_AUTO:
410 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
411 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
412 case AL_DIRECT_CHANNELS_SOFT:
413 case AL_DISTANCE_MODEL:
414 case AL_SOURCE_RELATIVE:
415 case AL_LOOPING:
416 case AL_BUFFER:
417 case AL_SOURCE_STATE:
418 case AL_BUFFERS_QUEUED:
419 case AL_BUFFERS_PROCESSED:
420 case AL_SOURCE_TYPE:
421 case AL_DIRECT_FILTER:
422 case AL_BYTE_LENGTH_SOFT:
423 case AL_SAMPLE_LENGTH_SOFT:
424 case AL_SEC_LENGTH_SOFT:
425 case AL_SOURCE_RADIUS:
426 case AL_SOURCE_RESAMPLER_SOFT:
427 case AL_SOURCE_SPATIALIZE_SOFT:
428 return 1;
430 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
431 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
432 return 2;
434 case AL_POSITION:
435 case AL_VELOCITY:
436 case AL_DIRECTION:
437 case AL_AUXILIARY_SEND_FILTER:
438 return 3;
440 case AL_ORIENTATION:
441 return 6;
443 case AL_SEC_OFFSET_LATENCY_SOFT:
444 case AL_SEC_OFFSET_CLOCK_SOFT:
445 break; /* Double only */
446 case AL_STEREO_ANGLES:
447 break; /* Float/double only */
449 return 0;
453 #define CHECKVAL(x) do { \
454 if(!(x)) \
455 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
456 } while(0)
458 #define DO_UPDATEPROPS() do { \
459 ALvoice *voice; \
460 if(SourceShouldUpdate(Source, Context) && \
461 (voice=GetSourceVoice(Source, Context)) != NULL) \
462 UpdateSourceProps(Source, voice, device->NumAuxSends, Context); \
463 else \
464 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \
465 } while(0)
467 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
469 ALCdevice *device = Context->Device;
470 ALint ival;
472 switch(prop)
474 case AL_BYTE_LENGTH_SOFT:
475 case AL_SAMPLE_LENGTH_SOFT:
476 case AL_SEC_LENGTH_SOFT:
477 case AL_SEC_OFFSET_LATENCY_SOFT:
478 case AL_SEC_OFFSET_CLOCK_SOFT:
479 /* Query only */
480 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
482 case AL_PITCH:
483 CHECKVAL(*values >= 0.0f);
485 Source->Pitch = *values;
486 DO_UPDATEPROPS();
487 return AL_TRUE;
489 case AL_CONE_INNER_ANGLE:
490 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
492 Source->InnerAngle = *values;
493 DO_UPDATEPROPS();
494 return AL_TRUE;
496 case AL_CONE_OUTER_ANGLE:
497 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
499 Source->OuterAngle = *values;
500 DO_UPDATEPROPS();
501 return AL_TRUE;
503 case AL_GAIN:
504 CHECKVAL(*values >= 0.0f);
506 Source->Gain = *values;
507 DO_UPDATEPROPS();
508 return AL_TRUE;
510 case AL_MAX_DISTANCE:
511 CHECKVAL(*values >= 0.0f);
513 Source->MaxDistance = *values;
514 DO_UPDATEPROPS();
515 return AL_TRUE;
517 case AL_ROLLOFF_FACTOR:
518 CHECKVAL(*values >= 0.0f);
520 Source->RolloffFactor = *values;
521 DO_UPDATEPROPS();
522 return AL_TRUE;
524 case AL_REFERENCE_DISTANCE:
525 CHECKVAL(*values >= 0.0f);
527 Source->RefDistance = *values;
528 DO_UPDATEPROPS();
529 return AL_TRUE;
531 case AL_MIN_GAIN:
532 CHECKVAL(*values >= 0.0f);
534 Source->MinGain = *values;
535 DO_UPDATEPROPS();
536 return AL_TRUE;
538 case AL_MAX_GAIN:
539 CHECKVAL(*values >= 0.0f);
541 Source->MaxGain = *values;
542 DO_UPDATEPROPS();
543 return AL_TRUE;
545 case AL_CONE_OUTER_GAIN:
546 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
548 Source->OuterGain = *values;
549 DO_UPDATEPROPS();
550 return AL_TRUE;
552 case AL_CONE_OUTER_GAINHF:
553 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
555 Source->OuterGainHF = *values;
556 DO_UPDATEPROPS();
557 return AL_TRUE;
559 case AL_AIR_ABSORPTION_FACTOR:
560 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
562 Source->AirAbsorptionFactor = *values;
563 DO_UPDATEPROPS();
564 return AL_TRUE;
566 case AL_ROOM_ROLLOFF_FACTOR:
567 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
569 Source->RoomRolloffFactor = *values;
570 DO_UPDATEPROPS();
571 return AL_TRUE;
573 case AL_DOPPLER_FACTOR:
574 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
576 Source->DopplerFactor = *values;
577 DO_UPDATEPROPS();
578 return AL_TRUE;
580 case AL_SEC_OFFSET:
581 case AL_SAMPLE_OFFSET:
582 case AL_BYTE_OFFSET:
583 CHECKVAL(*values >= 0.0f);
585 Source->OffsetType = prop;
586 Source->Offset = *values;
588 if(IsPlayingOrPaused(Source))
590 ALvoice *voice;
592 ALCdevice_Lock(Context->Device);
593 /* Double-check that the source is still playing while we have
594 * the lock.
596 voice = GetSourceVoice(Source, Context);
597 if(voice)
599 WriteLock(&Source->queue_lock);
600 if(ApplyOffset(Source, voice) == AL_FALSE)
602 WriteUnlock(&Source->queue_lock);
603 ALCdevice_Unlock(Context->Device);
604 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
606 WriteUnlock(&Source->queue_lock);
608 ALCdevice_Unlock(Context->Device);
610 return AL_TRUE;
612 case AL_SOURCE_RADIUS:
613 CHECKVAL(*values >= 0.0f && isfinite(*values));
615 Source->Radius = *values;
616 DO_UPDATEPROPS();
617 return AL_TRUE;
619 case AL_STEREO_ANGLES:
620 CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
622 Source->StereoPan[0] = values[0];
623 Source->StereoPan[1] = values[1];
624 DO_UPDATEPROPS();
625 return AL_TRUE;
628 case AL_POSITION:
629 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
631 Source->Position[0] = values[0];
632 Source->Position[1] = values[1];
633 Source->Position[2] = values[2];
634 DO_UPDATEPROPS();
635 return AL_TRUE;
637 case AL_VELOCITY:
638 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
640 Source->Velocity[0] = values[0];
641 Source->Velocity[1] = values[1];
642 Source->Velocity[2] = values[2];
643 DO_UPDATEPROPS();
644 return AL_TRUE;
646 case AL_DIRECTION:
647 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
649 Source->Direction[0] = values[0];
650 Source->Direction[1] = values[1];
651 Source->Direction[2] = values[2];
652 DO_UPDATEPROPS();
653 return AL_TRUE;
655 case AL_ORIENTATION:
656 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
657 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
659 Source->Orientation[0][0] = values[0];
660 Source->Orientation[0][1] = values[1];
661 Source->Orientation[0][2] = values[2];
662 Source->Orientation[1][0] = values[3];
663 Source->Orientation[1][1] = values[4];
664 Source->Orientation[1][2] = values[5];
665 DO_UPDATEPROPS();
666 return AL_TRUE;
669 case AL_SOURCE_RELATIVE:
670 case AL_LOOPING:
671 case AL_SOURCE_STATE:
672 case AL_SOURCE_TYPE:
673 case AL_DISTANCE_MODEL:
674 case AL_DIRECT_FILTER_GAINHF_AUTO:
675 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
676 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
677 case AL_DIRECT_CHANNELS_SOFT:
678 case AL_SOURCE_RESAMPLER_SOFT:
679 case AL_SOURCE_SPATIALIZE_SOFT:
680 ival = (ALint)values[0];
681 return SetSourceiv(Source, Context, prop, &ival);
683 case AL_BUFFERS_QUEUED:
684 case AL_BUFFERS_PROCESSED:
685 ival = (ALint)((ALuint)values[0]);
686 return SetSourceiv(Source, Context, prop, &ival);
688 case AL_BUFFER:
689 case AL_DIRECT_FILTER:
690 case AL_AUXILIARY_SEND_FILTER:
691 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
692 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
693 break;
696 ERR("Unexpected property: 0x%04x\n", prop);
697 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
700 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
702 ALCdevice *device = Context->Device;
703 ALbuffer *buffer = NULL;
704 ALfilter *filter = NULL;
705 ALeffectslot *slot = NULL;
706 ALbufferlistitem *oldlist;
707 ALfloat fvals[6];
709 switch(prop)
711 case AL_SOURCE_STATE:
712 case AL_SOURCE_TYPE:
713 case AL_BUFFERS_QUEUED:
714 case AL_BUFFERS_PROCESSED:
715 case AL_BYTE_LENGTH_SOFT:
716 case AL_SAMPLE_LENGTH_SOFT:
717 case AL_SEC_LENGTH_SOFT:
718 /* Query only */
719 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
721 case AL_SOURCE_RELATIVE:
722 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
724 Source->HeadRelative = (ALboolean)*values;
725 DO_UPDATEPROPS();
726 return AL_TRUE;
728 case AL_LOOPING:
729 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
731 WriteLock(&Source->queue_lock);
732 Source->Looping = (ALboolean)*values;
733 if(IsPlayingOrPaused(Source))
735 ALvoice *voice = GetSourceVoice(Source, Context);
736 if(voice)
738 if(Source->Looping)
739 ATOMIC_STORE(&voice->loop_buffer, Source->queue, almemory_order_release);
740 else
741 ATOMIC_STORE(&voice->loop_buffer, NULL, almemory_order_release);
743 /* If the source is playing, wait for the current mix to finish
744 * to ensure it isn't currently looping back or reaching the
745 * end.
747 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
748 althrd_yield();
751 WriteUnlock(&Source->queue_lock);
752 return AL_TRUE;
754 case AL_BUFFER:
755 LockBuffersRead(device);
756 if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
758 UnlockBuffersRead(device);
759 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
762 WriteLock(&Source->queue_lock);
763 if(buffer && buffer->MappedAccess != 0 &&
764 !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
766 WriteUnlock(&Source->queue_lock);
767 UnlockBuffersRead(device);
768 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
770 else
772 ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context));
773 if(state == AL_PLAYING || state == AL_PAUSED)
775 WriteUnlock(&Source->queue_lock);
776 UnlockBuffersRead(device);
777 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
781 oldlist = Source->queue;
782 if(buffer != NULL)
784 /* Add the selected buffer to a one-item queue */
785 ALbufferlistitem *newlist = al_calloc(DEF_ALIGN,
786 FAM_SIZE(ALbufferlistitem, buffers, 1));
787 ATOMIC_INIT(&newlist->next, NULL);
788 newlist->num_buffers = 1;
789 newlist->buffers[0] = buffer;
790 IncrementRef(&buffer->ref);
792 /* Source is now Static */
793 Source->SourceType = AL_STATIC;
794 Source->queue = newlist;
796 else
798 /* Source is now Undetermined */
799 Source->SourceType = AL_UNDETERMINED;
800 Source->queue = NULL;
802 WriteUnlock(&Source->queue_lock);
803 UnlockBuffersRead(device);
805 /* Delete all elements in the previous queue */
806 while(oldlist != NULL)
808 ALsizei i;
809 ALbufferlistitem *temp = oldlist;
810 oldlist = ATOMIC_LOAD(&temp->next, almemory_order_relaxed);
812 for(i = 0;i < temp->num_buffers;i++)
814 if(temp->buffers[i])
815 DecrementRef(&temp->buffers[i]->ref);
817 al_free(temp);
819 return AL_TRUE;
821 case AL_SEC_OFFSET:
822 case AL_SAMPLE_OFFSET:
823 case AL_BYTE_OFFSET:
824 CHECKVAL(*values >= 0);
826 Source->OffsetType = prop;
827 Source->Offset = *values;
829 if(IsPlayingOrPaused(Source))
831 ALvoice *voice;
833 ALCdevice_Lock(Context->Device);
834 voice = GetSourceVoice(Source, Context);
835 if(voice)
837 WriteLock(&Source->queue_lock);
838 if(ApplyOffset(Source, voice) == AL_FALSE)
840 WriteUnlock(&Source->queue_lock);
841 ALCdevice_Unlock(Context->Device);
842 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
844 WriteUnlock(&Source->queue_lock);
846 ALCdevice_Unlock(Context->Device);
848 return AL_TRUE;
850 case AL_DIRECT_FILTER:
851 LockFiltersRead(device);
852 if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
854 UnlockFiltersRead(device);
855 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
858 if(!filter)
860 Source->Direct.Gain = 1.0f;
861 Source->Direct.GainHF = 1.0f;
862 Source->Direct.HFReference = LOWPASSFREQREF;
863 Source->Direct.GainLF = 1.0f;
864 Source->Direct.LFReference = HIGHPASSFREQREF;
866 else
868 Source->Direct.Gain = filter->Gain;
869 Source->Direct.GainHF = filter->GainHF;
870 Source->Direct.HFReference = filter->HFReference;
871 Source->Direct.GainLF = filter->GainLF;
872 Source->Direct.LFReference = filter->LFReference;
874 UnlockFiltersRead(device);
875 DO_UPDATEPROPS();
876 return AL_TRUE;
878 case AL_DIRECT_FILTER_GAINHF_AUTO:
879 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
881 Source->DryGainHFAuto = *values;
882 DO_UPDATEPROPS();
883 return AL_TRUE;
885 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
886 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
888 Source->WetGainAuto = *values;
889 DO_UPDATEPROPS();
890 return AL_TRUE;
892 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
893 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
895 Source->WetGainHFAuto = *values;
896 DO_UPDATEPROPS();
897 return AL_TRUE;
899 case AL_DIRECT_CHANNELS_SOFT:
900 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
902 Source->DirectChannels = *values;
903 DO_UPDATEPROPS();
904 return AL_TRUE;
906 case AL_DISTANCE_MODEL:
907 CHECKVAL(*values == AL_NONE ||
908 *values == AL_INVERSE_DISTANCE ||
909 *values == AL_INVERSE_DISTANCE_CLAMPED ||
910 *values == AL_LINEAR_DISTANCE ||
911 *values == AL_LINEAR_DISTANCE_CLAMPED ||
912 *values == AL_EXPONENT_DISTANCE ||
913 *values == AL_EXPONENT_DISTANCE_CLAMPED);
915 Source->DistanceModel = *values;
916 if(Context->SourceDistanceModel)
917 DO_UPDATEPROPS();
918 return AL_TRUE;
920 case AL_SOURCE_RESAMPLER_SOFT:
921 CHECKVAL(*values >= 0 && *values <= ResamplerMax);
923 Source->Resampler = *values;
924 DO_UPDATEPROPS();
925 return AL_TRUE;
927 case AL_SOURCE_SPATIALIZE_SOFT:
928 CHECKVAL(*values >= AL_FALSE && *values <= AL_AUTO_SOFT);
930 Source->Spatialize = *values;
931 DO_UPDATEPROPS();
932 return AL_TRUE;
935 case AL_AUXILIARY_SEND_FILTER:
936 LockEffectSlotsRead(Context);
937 LockFiltersRead(device);
938 if(!((ALuint)values[1] < (ALuint)device->NumAuxSends &&
939 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
940 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
942 UnlockFiltersRead(device);
943 UnlockEffectSlotsRead(Context);
944 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
947 if(!filter)
949 /* Disable filter */
950 Source->Send[values[1]].Gain = 1.0f;
951 Source->Send[values[1]].GainHF = 1.0f;
952 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
953 Source->Send[values[1]].GainLF = 1.0f;
954 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
956 else
958 Source->Send[values[1]].Gain = filter->Gain;
959 Source->Send[values[1]].GainHF = filter->GainHF;
960 Source->Send[values[1]].HFReference = filter->HFReference;
961 Source->Send[values[1]].GainLF = filter->GainLF;
962 Source->Send[values[1]].LFReference = filter->LFReference;
964 UnlockFiltersRead(device);
966 if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source))
968 ALvoice *voice;
969 /* Add refcount on the new slot, and release the previous slot */
970 if(slot) IncrementRef(&slot->ref);
971 if(Source->Send[values[1]].Slot)
972 DecrementRef(&Source->Send[values[1]].Slot->ref);
973 Source->Send[values[1]].Slot = slot;
975 /* We must force an update if the auxiliary slot changed on an
976 * active source, in case the slot is about to be deleted.
978 if((voice=GetSourceVoice(Source, Context)) != NULL)
979 UpdateSourceProps(Source, voice, device->NumAuxSends, Context);
980 else
981 ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release);
983 else
985 if(slot) IncrementRef(&slot->ref);
986 if(Source->Send[values[1]].Slot)
987 DecrementRef(&Source->Send[values[1]].Slot->ref);
988 Source->Send[values[1]].Slot = slot;
989 DO_UPDATEPROPS();
991 UnlockEffectSlotsRead(Context);
993 return AL_TRUE;
996 /* 1x float */
997 case AL_CONE_INNER_ANGLE:
998 case AL_CONE_OUTER_ANGLE:
999 case AL_PITCH:
1000 case AL_GAIN:
1001 case AL_MIN_GAIN:
1002 case AL_MAX_GAIN:
1003 case AL_REFERENCE_DISTANCE:
1004 case AL_ROLLOFF_FACTOR:
1005 case AL_CONE_OUTER_GAIN:
1006 case AL_MAX_DISTANCE:
1007 case AL_DOPPLER_FACTOR:
1008 case AL_CONE_OUTER_GAINHF:
1009 case AL_AIR_ABSORPTION_FACTOR:
1010 case AL_ROOM_ROLLOFF_FACTOR:
1011 case AL_SOURCE_RADIUS:
1012 fvals[0] = (ALfloat)*values;
1013 return SetSourcefv(Source, Context, (int)prop, fvals);
1015 /* 3x float */
1016 case AL_POSITION:
1017 case AL_VELOCITY:
1018 case AL_DIRECTION:
1019 fvals[0] = (ALfloat)values[0];
1020 fvals[1] = (ALfloat)values[1];
1021 fvals[2] = (ALfloat)values[2];
1022 return SetSourcefv(Source, Context, (int)prop, fvals);
1024 /* 6x float */
1025 case AL_ORIENTATION:
1026 fvals[0] = (ALfloat)values[0];
1027 fvals[1] = (ALfloat)values[1];
1028 fvals[2] = (ALfloat)values[2];
1029 fvals[3] = (ALfloat)values[3];
1030 fvals[4] = (ALfloat)values[4];
1031 fvals[5] = (ALfloat)values[5];
1032 return SetSourcefv(Source, Context, (int)prop, fvals);
1034 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1035 case AL_SEC_OFFSET_LATENCY_SOFT:
1036 case AL_SEC_OFFSET_CLOCK_SOFT:
1037 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
1038 case AL_STEREO_ANGLES:
1039 break;
1042 ERR("Unexpected property: 0x%04x\n", prop);
1043 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1046 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
1048 ALfloat fvals[6];
1049 ALint ivals[3];
1051 switch(prop)
1053 case AL_SOURCE_TYPE:
1054 case AL_BUFFERS_QUEUED:
1055 case AL_BUFFERS_PROCESSED:
1056 case AL_SOURCE_STATE:
1057 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1058 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
1059 case AL_BYTE_LENGTH_SOFT:
1060 case AL_SAMPLE_LENGTH_SOFT:
1061 case AL_SEC_LENGTH_SOFT:
1062 /* Query only */
1063 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
1066 /* 1x int */
1067 case AL_SOURCE_RELATIVE:
1068 case AL_LOOPING:
1069 case AL_SEC_OFFSET:
1070 case AL_SAMPLE_OFFSET:
1071 case AL_BYTE_OFFSET:
1072 case AL_DIRECT_FILTER_GAINHF_AUTO:
1073 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1074 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1075 case AL_DIRECT_CHANNELS_SOFT:
1076 case AL_DISTANCE_MODEL:
1077 case AL_SOURCE_RESAMPLER_SOFT:
1078 case AL_SOURCE_SPATIALIZE_SOFT:
1079 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
1081 ivals[0] = (ALint)*values;
1082 return SetSourceiv(Source, Context, (int)prop, ivals);
1084 /* 1x uint */
1085 case AL_BUFFER:
1086 case AL_DIRECT_FILTER:
1087 CHECKVAL(*values <= UINT_MAX && *values >= 0);
1089 ivals[0] = (ALuint)*values;
1090 return SetSourceiv(Source, Context, (int)prop, ivals);
1092 /* 3x uint */
1093 case AL_AUXILIARY_SEND_FILTER:
1094 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
1095 values[1] <= UINT_MAX && values[1] >= 0 &&
1096 values[2] <= UINT_MAX && values[2] >= 0);
1098 ivals[0] = (ALuint)values[0];
1099 ivals[1] = (ALuint)values[1];
1100 ivals[2] = (ALuint)values[2];
1101 return SetSourceiv(Source, Context, (int)prop, ivals);
1103 /* 1x float */
1104 case AL_CONE_INNER_ANGLE:
1105 case AL_CONE_OUTER_ANGLE:
1106 case AL_PITCH:
1107 case AL_GAIN:
1108 case AL_MIN_GAIN:
1109 case AL_MAX_GAIN:
1110 case AL_REFERENCE_DISTANCE:
1111 case AL_ROLLOFF_FACTOR:
1112 case AL_CONE_OUTER_GAIN:
1113 case AL_MAX_DISTANCE:
1114 case AL_DOPPLER_FACTOR:
1115 case AL_CONE_OUTER_GAINHF:
1116 case AL_AIR_ABSORPTION_FACTOR:
1117 case AL_ROOM_ROLLOFF_FACTOR:
1118 case AL_SOURCE_RADIUS:
1119 fvals[0] = (ALfloat)*values;
1120 return SetSourcefv(Source, Context, (int)prop, fvals);
1122 /* 3x float */
1123 case AL_POSITION:
1124 case AL_VELOCITY:
1125 case AL_DIRECTION:
1126 fvals[0] = (ALfloat)values[0];
1127 fvals[1] = (ALfloat)values[1];
1128 fvals[2] = (ALfloat)values[2];
1129 return SetSourcefv(Source, Context, (int)prop, fvals);
1131 /* 6x float */
1132 case AL_ORIENTATION:
1133 fvals[0] = (ALfloat)values[0];
1134 fvals[1] = (ALfloat)values[1];
1135 fvals[2] = (ALfloat)values[2];
1136 fvals[3] = (ALfloat)values[3];
1137 fvals[4] = (ALfloat)values[4];
1138 fvals[5] = (ALfloat)values[5];
1139 return SetSourcefv(Source, Context, (int)prop, fvals);
1141 case AL_SEC_OFFSET_LATENCY_SOFT:
1142 case AL_SEC_OFFSET_CLOCK_SOFT:
1143 case AL_STEREO_ANGLES:
1144 break;
1147 ERR("Unexpected property: 0x%04x\n", prop);
1148 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1151 #undef CHECKVAL
1154 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
1156 ALCdevice *device = Context->Device;
1157 ALbufferlistitem *BufferList;
1158 ClockLatency clocktime;
1159 ALuint64 srcclock;
1160 ALint ivals[3];
1161 ALboolean err;
1163 switch(prop)
1165 case AL_GAIN:
1166 *values = Source->Gain;
1167 return AL_TRUE;
1169 case AL_PITCH:
1170 *values = Source->Pitch;
1171 return AL_TRUE;
1173 case AL_MAX_DISTANCE:
1174 *values = Source->MaxDistance;
1175 return AL_TRUE;
1177 case AL_ROLLOFF_FACTOR:
1178 *values = Source->RolloffFactor;
1179 return AL_TRUE;
1181 case AL_REFERENCE_DISTANCE:
1182 *values = Source->RefDistance;
1183 return AL_TRUE;
1185 case AL_CONE_INNER_ANGLE:
1186 *values = Source->InnerAngle;
1187 return AL_TRUE;
1189 case AL_CONE_OUTER_ANGLE:
1190 *values = Source->OuterAngle;
1191 return AL_TRUE;
1193 case AL_MIN_GAIN:
1194 *values = Source->MinGain;
1195 return AL_TRUE;
1197 case AL_MAX_GAIN:
1198 *values = Source->MaxGain;
1199 return AL_TRUE;
1201 case AL_CONE_OUTER_GAIN:
1202 *values = Source->OuterGain;
1203 return AL_TRUE;
1205 case AL_SEC_OFFSET:
1206 case AL_SAMPLE_OFFSET:
1207 case AL_BYTE_OFFSET:
1208 *values = GetSourceOffset(Source, prop, Context);
1209 return AL_TRUE;
1211 case AL_CONE_OUTER_GAINHF:
1212 *values = Source->OuterGainHF;
1213 return AL_TRUE;
1215 case AL_AIR_ABSORPTION_FACTOR:
1216 *values = Source->AirAbsorptionFactor;
1217 return AL_TRUE;
1219 case AL_ROOM_ROLLOFF_FACTOR:
1220 *values = Source->RoomRolloffFactor;
1221 return AL_TRUE;
1223 case AL_DOPPLER_FACTOR:
1224 *values = Source->DopplerFactor;
1225 return AL_TRUE;
1227 case AL_SEC_LENGTH_SOFT:
1228 ReadLock(&Source->queue_lock);
1229 if(!(BufferList=Source->queue))
1230 *values = 0;
1231 else
1233 ALint length = 0;
1234 ALsizei freq = 1;
1235 do {
1236 ALsizei max_len = 0;
1237 ALsizei i;
1238 for(i = 0;i < BufferList->num_buffers;i++)
1240 ALbuffer *buffer = BufferList->buffers[i];
1241 if(buffer && buffer->SampleLen > 0)
1243 freq = buffer->Frequency;
1244 max_len = maxi(max_len, buffer->SampleLen);
1247 length += max_len;
1248 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
1249 } while(BufferList != NULL);
1250 *values = (ALdouble)length / (ALdouble)freq;
1252 ReadUnlock(&Source->queue_lock);
1253 return AL_TRUE;
1255 case AL_SOURCE_RADIUS:
1256 *values = Source->Radius;
1257 return AL_TRUE;
1259 case AL_STEREO_ANGLES:
1260 values[0] = Source->StereoPan[0];
1261 values[1] = Source->StereoPan[1];
1262 return AL_TRUE;
1264 case AL_SEC_OFFSET_LATENCY_SOFT:
1265 /* Get the source offset with the clock time first. Then get the
1266 * clock time with the device latency. Order is important.
1268 values[0] = GetSourceSecOffset(Source, Context, &srcclock);
1269 clocktime = V0(device->Backend,getClockLatency)();
1270 if(srcclock == (ALuint64)clocktime.ClockTime)
1271 values[1] = (ALdouble)clocktime.Latency / 1000000000.0;
1272 else
1274 /* If the clock time incremented, reduce the latency by that
1275 * much since it's that much closer to the source offset it got
1276 * earlier.
1278 ALuint64 diff = clocktime.ClockTime - srcclock;
1279 values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) /
1280 1000000000.0;
1282 return AL_TRUE;
1284 case AL_SEC_OFFSET_CLOCK_SOFT:
1285 values[0] = GetSourceSecOffset(Source, Context, &srcclock);
1286 values[1] = srcclock / 1000000000.0;
1287 return AL_TRUE;
1289 case AL_POSITION:
1290 values[0] = Source->Position[0];
1291 values[1] = Source->Position[1];
1292 values[2] = Source->Position[2];
1293 return AL_TRUE;
1295 case AL_VELOCITY:
1296 values[0] = Source->Velocity[0];
1297 values[1] = Source->Velocity[1];
1298 values[2] = Source->Velocity[2];
1299 return AL_TRUE;
1301 case AL_DIRECTION:
1302 values[0] = Source->Direction[0];
1303 values[1] = Source->Direction[1];
1304 values[2] = Source->Direction[2];
1305 return AL_TRUE;
1307 case AL_ORIENTATION:
1308 values[0] = Source->Orientation[0][0];
1309 values[1] = Source->Orientation[0][1];
1310 values[2] = Source->Orientation[0][2];
1311 values[3] = Source->Orientation[1][0];
1312 values[4] = Source->Orientation[1][1];
1313 values[5] = Source->Orientation[1][2];
1314 return AL_TRUE;
1316 /* 1x int */
1317 case AL_SOURCE_RELATIVE:
1318 case AL_LOOPING:
1319 case AL_SOURCE_STATE:
1320 case AL_BUFFERS_QUEUED:
1321 case AL_BUFFERS_PROCESSED:
1322 case AL_SOURCE_TYPE:
1323 case AL_DIRECT_FILTER_GAINHF_AUTO:
1324 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1325 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1326 case AL_DIRECT_CHANNELS_SOFT:
1327 case AL_BYTE_LENGTH_SOFT:
1328 case AL_SAMPLE_LENGTH_SOFT:
1329 case AL_DISTANCE_MODEL:
1330 case AL_SOURCE_RESAMPLER_SOFT:
1331 case AL_SOURCE_SPATIALIZE_SOFT:
1332 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1333 *values = (ALdouble)ivals[0];
1334 return err;
1336 case AL_BUFFER:
1337 case AL_DIRECT_FILTER:
1338 case AL_AUXILIARY_SEND_FILTER:
1339 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1340 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
1341 break;
1344 ERR("Unexpected property: 0x%04x\n", prop);
1345 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1348 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1350 ALbufferlistitem *BufferList;
1351 ALdouble dvals[6];
1352 ALboolean err;
1354 switch(prop)
1356 case AL_SOURCE_RELATIVE:
1357 *values = Source->HeadRelative;
1358 return AL_TRUE;
1360 case AL_LOOPING:
1361 *values = Source->Looping;
1362 return AL_TRUE;
1364 case AL_BUFFER:
1365 ReadLock(&Source->queue_lock);
1366 BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : NULL;
1367 *values = (BufferList && BufferList->num_buffers >= 1 && BufferList->buffers[0]) ?
1368 BufferList->buffers[0]->id : 0;
1369 ReadUnlock(&Source->queue_lock);
1370 return AL_TRUE;
1372 case AL_SOURCE_STATE:
1373 *values = GetSourceState(Source, GetSourceVoice(Source, Context));
1374 return AL_TRUE;
1376 case AL_BYTE_LENGTH_SOFT:
1377 ReadLock(&Source->queue_lock);
1378 if(!(BufferList=Source->queue))
1379 *values = 0;
1380 else
1382 ALint length = 0;
1383 do {
1384 ALsizei max_len = 0;
1385 ALsizei i;
1386 for(i = 0;i < BufferList->num_buffers;i++)
1388 ALbuffer *buffer = BufferList->buffers[i];
1389 if(buffer && buffer->SampleLen > 0)
1391 ALuint byte_align, sample_align;
1392 if(buffer->OriginalType == UserFmtIMA4)
1394 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1395 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1396 sample_align = buffer->OriginalAlign;
1398 else if(buffer->OriginalType == UserFmtMSADPCM)
1400 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1401 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1402 sample_align = buffer->OriginalAlign;
1404 else
1406 ALsizei align = buffer->OriginalAlign;
1407 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1408 sample_align = buffer->OriginalAlign;
1411 max_len = maxi(max_len, buffer->SampleLen / sample_align * byte_align);
1414 length += max_len;
1416 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
1417 } while(BufferList != NULL);
1418 *values = length;
1420 ReadUnlock(&Source->queue_lock);
1421 return AL_TRUE;
1423 case AL_SAMPLE_LENGTH_SOFT:
1424 ReadLock(&Source->queue_lock);
1425 if(!(BufferList=Source->queue))
1426 *values = 0;
1427 else
1429 ALint length = 0;
1430 do {
1431 ALsizei max_len = 0;
1432 ALsizei i;
1433 for(i = 0;i < BufferList->num_buffers;i++)
1435 ALbuffer *buffer = BufferList->buffers[i];
1436 if(buffer) max_len = maxi(max_len, buffer->SampleLen);
1438 length += max_len;
1439 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
1440 } while(BufferList != NULL);
1441 *values = length;
1443 ReadUnlock(&Source->queue_lock);
1444 return AL_TRUE;
1446 case AL_BUFFERS_QUEUED:
1447 ReadLock(&Source->queue_lock);
1448 if(!(BufferList=Source->queue))
1449 *values = 0;
1450 else
1452 ALsizei count = 0;
1453 do {
1454 ++count;
1455 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
1456 } while(BufferList != NULL);
1457 *values = count;
1459 ReadUnlock(&Source->queue_lock);
1460 return AL_TRUE;
1462 case AL_BUFFERS_PROCESSED:
1463 ReadLock(&Source->queue_lock);
1464 if(Source->Looping || Source->SourceType != AL_STREAMING)
1466 /* Buffers on a looping source are in a perpetual state of
1467 * PENDING, so don't report any as PROCESSED */
1468 *values = 0;
1470 else
1472 const ALbufferlistitem *BufferList = Source->queue;
1473 const ALbufferlistitem *Current = NULL;
1474 ALsizei played = 0;
1475 ALvoice *voice;
1477 if((voice=GetSourceVoice(Source, Context)) != NULL)
1478 Current = ATOMIC_LOAD_SEQ(&voice->current_buffer);
1479 else if(ATOMIC_LOAD_SEQ(&Source->state) == AL_INITIAL)
1480 Current = BufferList;
1482 while(BufferList && BufferList != Current)
1484 played++;
1485 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
1486 almemory_order_relaxed);
1488 *values = played;
1490 ReadUnlock(&Source->queue_lock);
1491 return AL_TRUE;
1493 case AL_SOURCE_TYPE:
1494 *values = Source->SourceType;
1495 return AL_TRUE;
1497 case AL_DIRECT_FILTER_GAINHF_AUTO:
1498 *values = Source->DryGainHFAuto;
1499 return AL_TRUE;
1501 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1502 *values = Source->WetGainAuto;
1503 return AL_TRUE;
1505 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1506 *values = Source->WetGainHFAuto;
1507 return AL_TRUE;
1509 case AL_DIRECT_CHANNELS_SOFT:
1510 *values = Source->DirectChannels;
1511 return AL_TRUE;
1513 case AL_DISTANCE_MODEL:
1514 *values = Source->DistanceModel;
1515 return AL_TRUE;
1517 case AL_SOURCE_RESAMPLER_SOFT:
1518 *values = Source->Resampler;
1519 return AL_TRUE;
1521 case AL_SOURCE_SPATIALIZE_SOFT:
1522 *values = Source->Spatialize;
1523 return AL_TRUE;
1525 /* 1x float/double */
1526 case AL_CONE_INNER_ANGLE:
1527 case AL_CONE_OUTER_ANGLE:
1528 case AL_PITCH:
1529 case AL_GAIN:
1530 case AL_MIN_GAIN:
1531 case AL_MAX_GAIN:
1532 case AL_REFERENCE_DISTANCE:
1533 case AL_ROLLOFF_FACTOR:
1534 case AL_CONE_OUTER_GAIN:
1535 case AL_MAX_DISTANCE:
1536 case AL_SEC_OFFSET:
1537 case AL_SAMPLE_OFFSET:
1538 case AL_BYTE_OFFSET:
1539 case AL_DOPPLER_FACTOR:
1540 case AL_AIR_ABSORPTION_FACTOR:
1541 case AL_ROOM_ROLLOFF_FACTOR:
1542 case AL_CONE_OUTER_GAINHF:
1543 case AL_SEC_LENGTH_SOFT:
1544 case AL_SOURCE_RADIUS:
1545 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1546 *values = (ALint)dvals[0];
1547 return err;
1549 /* 3x float/double */
1550 case AL_POSITION:
1551 case AL_VELOCITY:
1552 case AL_DIRECTION:
1553 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1555 values[0] = (ALint)dvals[0];
1556 values[1] = (ALint)dvals[1];
1557 values[2] = (ALint)dvals[2];
1559 return err;
1561 /* 6x float/double */
1562 case AL_ORIENTATION:
1563 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1565 values[0] = (ALint)dvals[0];
1566 values[1] = (ALint)dvals[1];
1567 values[2] = (ALint)dvals[2];
1568 values[3] = (ALint)dvals[3];
1569 values[4] = (ALint)dvals[4];
1570 values[5] = (ALint)dvals[5];
1572 return err;
1574 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1575 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
1576 break; /* i64 only */
1577 case AL_SEC_OFFSET_LATENCY_SOFT:
1578 case AL_SEC_OFFSET_CLOCK_SOFT:
1579 break; /* Double only */
1580 case AL_STEREO_ANGLES:
1581 break; /* Float/double only */
1583 case AL_DIRECT_FILTER:
1584 case AL_AUXILIARY_SEND_FILTER:
1585 break; /* ??? */
1588 ERR("Unexpected property: 0x%04x\n", prop);
1589 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1592 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1594 ALCdevice *device = Context->Device;
1595 ClockLatency clocktime;
1596 ALuint64 srcclock;
1597 ALdouble dvals[6];
1598 ALint ivals[3];
1599 ALboolean err;
1601 switch(prop)
1603 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1604 /* Get the source offset with the clock time first. Then get the
1605 * clock time with the device latency. Order is important.
1607 values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
1608 clocktime = V0(device->Backend,getClockLatency)();
1609 if(srcclock == (ALuint64)clocktime.ClockTime)
1610 values[1] = clocktime.Latency;
1611 else
1613 /* If the clock time incremented, reduce the latency by that
1614 * much since it's that much closer to the source offset it got
1615 * earlier.
1617 ALuint64 diff = clocktime.ClockTime - srcclock;
1618 values[1] = clocktime.Latency - minu64(clocktime.Latency, diff);
1620 return AL_TRUE;
1622 case AL_SAMPLE_OFFSET_CLOCK_SOFT:
1623 values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
1624 values[1] = srcclock;
1625 return AL_TRUE;
1627 /* 1x float/double */
1628 case AL_CONE_INNER_ANGLE:
1629 case AL_CONE_OUTER_ANGLE:
1630 case AL_PITCH:
1631 case AL_GAIN:
1632 case AL_MIN_GAIN:
1633 case AL_MAX_GAIN:
1634 case AL_REFERENCE_DISTANCE:
1635 case AL_ROLLOFF_FACTOR:
1636 case AL_CONE_OUTER_GAIN:
1637 case AL_MAX_DISTANCE:
1638 case AL_SEC_OFFSET:
1639 case AL_SAMPLE_OFFSET:
1640 case AL_BYTE_OFFSET:
1641 case AL_DOPPLER_FACTOR:
1642 case AL_AIR_ABSORPTION_FACTOR:
1643 case AL_ROOM_ROLLOFF_FACTOR:
1644 case AL_CONE_OUTER_GAINHF:
1645 case AL_SEC_LENGTH_SOFT:
1646 case AL_SOURCE_RADIUS:
1647 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1648 *values = (ALint64)dvals[0];
1649 return err;
1651 /* 3x float/double */
1652 case AL_POSITION:
1653 case AL_VELOCITY:
1654 case AL_DIRECTION:
1655 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1657 values[0] = (ALint64)dvals[0];
1658 values[1] = (ALint64)dvals[1];
1659 values[2] = (ALint64)dvals[2];
1661 return err;
1663 /* 6x float/double */
1664 case AL_ORIENTATION:
1665 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1667 values[0] = (ALint64)dvals[0];
1668 values[1] = (ALint64)dvals[1];
1669 values[2] = (ALint64)dvals[2];
1670 values[3] = (ALint64)dvals[3];
1671 values[4] = (ALint64)dvals[4];
1672 values[5] = (ALint64)dvals[5];
1674 return err;
1676 /* 1x int */
1677 case AL_SOURCE_RELATIVE:
1678 case AL_LOOPING:
1679 case AL_SOURCE_STATE:
1680 case AL_BUFFERS_QUEUED:
1681 case AL_BUFFERS_PROCESSED:
1682 case AL_BYTE_LENGTH_SOFT:
1683 case AL_SAMPLE_LENGTH_SOFT:
1684 case AL_SOURCE_TYPE:
1685 case AL_DIRECT_FILTER_GAINHF_AUTO:
1686 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1687 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1688 case AL_DIRECT_CHANNELS_SOFT:
1689 case AL_DISTANCE_MODEL:
1690 case AL_SOURCE_RESAMPLER_SOFT:
1691 case AL_SOURCE_SPATIALIZE_SOFT:
1692 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1693 *values = ivals[0];
1694 return err;
1696 /* 1x uint */
1697 case AL_BUFFER:
1698 case AL_DIRECT_FILTER:
1699 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1700 *values = (ALuint)ivals[0];
1701 return err;
1703 /* 3x uint */
1704 case AL_AUXILIARY_SEND_FILTER:
1705 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1707 values[0] = (ALuint)ivals[0];
1708 values[1] = (ALuint)ivals[1];
1709 values[2] = (ALuint)ivals[2];
1711 return err;
1713 case AL_SEC_OFFSET_LATENCY_SOFT:
1714 case AL_SEC_OFFSET_CLOCK_SOFT:
1715 break; /* Double only */
1716 case AL_STEREO_ANGLES:
1717 break; /* Float/double only */
1720 ERR("Unexpected property: 0x%04x\n", prop);
1721 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1725 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1727 ALCdevice *device;
1728 ALCcontext *context;
1729 ALsizei cur = 0;
1730 ALenum err;
1732 context = GetContextRef();
1733 if(!context) return;
1735 if(!(n >= 0))
1736 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1737 device = context->Device;
1738 for(cur = 0;cur < n;cur++)
1740 ALsource *source = al_calloc(16, sizeof(ALsource));
1741 if(!source)
1743 alDeleteSources(cur, sources);
1744 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1746 InitSourceParams(source, device->NumAuxSends);
1748 err = NewThunkEntry(&source->id);
1749 if(err == AL_NO_ERROR)
1750 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1751 if(err != AL_NO_ERROR)
1753 FreeThunkEntry(source->id);
1754 memset(source, 0, sizeof(ALsource));
1755 al_free(source);
1757 alDeleteSources(cur, sources);
1758 SET_ERROR_AND_GOTO(context, err, done);
1761 sources[cur] = source->id;
1764 done:
1765 ALCcontext_DecRef(context);
1769 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1771 ALCdevice *device;
1772 ALCcontext *context;
1773 ALsource *Source;
1774 ALsizei i;
1776 context = GetContextRef();
1777 if(!context) return;
1779 LockSourcesWrite(context);
1780 if(!(n >= 0))
1781 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1783 /* Check that all Sources are valid */
1784 for(i = 0;i < n;i++)
1786 if(LookupSource(context, sources[i]) == NULL)
1787 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1789 device = context->Device;
1790 for(i = 0;i < n;i++)
1792 ALvoice *voice;
1794 if((Source=RemoveSource(context, sources[i])) == NULL)
1795 continue;
1796 FreeThunkEntry(Source->id);
1798 ALCdevice_Lock(device);
1799 if((voice=GetSourceVoice(Source, context)) != NULL)
1801 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
1802 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
1804 ALCdevice_Unlock(device);
1806 DeinitSource(Source, device->NumAuxSends);
1808 memset(Source, 0, sizeof(*Source));
1809 al_free(Source);
1812 done:
1813 UnlockSourcesWrite(context);
1814 ALCcontext_DecRef(context);
1818 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1820 ALCcontext *context;
1821 ALboolean ret;
1823 context = GetContextRef();
1824 if(!context) return AL_FALSE;
1826 LockSourcesRead(context);
1827 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1828 UnlockSourcesRead(context);
1830 ALCcontext_DecRef(context);
1832 return ret;
1836 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1838 ALCcontext *Context;
1839 ALsource *Source;
1841 Context = GetContextRef();
1842 if(!Context) return;
1844 WriteLock(&Context->PropLock);
1845 LockSourcesRead(Context);
1846 if((Source=LookupSource(Context, source)) == NULL)
1847 alSetError(Context, AL_INVALID_NAME);
1848 else if(!(FloatValsByProp(param) == 1))
1849 alSetError(Context, AL_INVALID_ENUM);
1850 else
1851 SetSourcefv(Source, Context, param, &value);
1852 UnlockSourcesRead(Context);
1853 WriteUnlock(&Context->PropLock);
1855 ALCcontext_DecRef(Context);
1858 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1860 ALCcontext *Context;
1861 ALsource *Source;
1863 Context = GetContextRef();
1864 if(!Context) return;
1866 WriteLock(&Context->PropLock);
1867 LockSourcesRead(Context);
1868 if((Source=LookupSource(Context, source)) == NULL)
1869 alSetError(Context, AL_INVALID_NAME);
1870 else if(!(FloatValsByProp(param) == 3))
1871 alSetError(Context, AL_INVALID_ENUM);
1872 else
1874 ALfloat fvals[3] = { value1, value2, value3 };
1875 SetSourcefv(Source, Context, param, fvals);
1877 UnlockSourcesRead(Context);
1878 WriteUnlock(&Context->PropLock);
1880 ALCcontext_DecRef(Context);
1883 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1885 ALCcontext *Context;
1886 ALsource *Source;
1888 Context = GetContextRef();
1889 if(!Context) return;
1891 WriteLock(&Context->PropLock);
1892 LockSourcesRead(Context);
1893 if((Source=LookupSource(Context, source)) == NULL)
1894 alSetError(Context, AL_INVALID_NAME);
1895 else if(!values)
1896 alSetError(Context, AL_INVALID_VALUE);
1897 else if(!(FloatValsByProp(param) > 0))
1898 alSetError(Context, AL_INVALID_ENUM);
1899 else
1900 SetSourcefv(Source, Context, param, values);
1901 UnlockSourcesRead(Context);
1902 WriteUnlock(&Context->PropLock);
1904 ALCcontext_DecRef(Context);
1908 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1910 ALCcontext *Context;
1911 ALsource *Source;
1913 Context = GetContextRef();
1914 if(!Context) return;
1916 WriteLock(&Context->PropLock);
1917 LockSourcesRead(Context);
1918 if((Source=LookupSource(Context, source)) == NULL)
1919 alSetError(Context, AL_INVALID_NAME);
1920 else if(!(DoubleValsByProp(param) == 1))
1921 alSetError(Context, AL_INVALID_ENUM);
1922 else
1924 ALfloat fval = (ALfloat)value;
1925 SetSourcefv(Source, Context, param, &fval);
1927 UnlockSourcesRead(Context);
1928 WriteUnlock(&Context->PropLock);
1930 ALCcontext_DecRef(Context);
1933 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1935 ALCcontext *Context;
1936 ALsource *Source;
1938 Context = GetContextRef();
1939 if(!Context) return;
1941 WriteLock(&Context->PropLock);
1942 LockSourcesRead(Context);
1943 if((Source=LookupSource(Context, source)) == NULL)
1944 alSetError(Context, AL_INVALID_NAME);
1945 else if(!(DoubleValsByProp(param) == 3))
1946 alSetError(Context, AL_INVALID_ENUM);
1947 else
1949 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1950 SetSourcefv(Source, Context, param, fvals);
1952 UnlockSourcesRead(Context);
1953 WriteUnlock(&Context->PropLock);
1955 ALCcontext_DecRef(Context);
1958 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1960 ALCcontext *Context;
1961 ALsource *Source;
1962 ALint count;
1964 Context = GetContextRef();
1965 if(!Context) return;
1967 WriteLock(&Context->PropLock);
1968 LockSourcesRead(Context);
1969 if((Source=LookupSource(Context, source)) == NULL)
1970 alSetError(Context, AL_INVALID_NAME);
1971 else if(!values)
1972 alSetError(Context, AL_INVALID_VALUE);
1973 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1974 alSetError(Context, AL_INVALID_ENUM);
1975 else
1977 ALfloat fvals[6];
1978 ALint i;
1980 for(i = 0;i < count;i++)
1981 fvals[i] = (ALfloat)values[i];
1982 SetSourcefv(Source, Context, param, fvals);
1984 UnlockSourcesRead(Context);
1985 WriteUnlock(&Context->PropLock);
1987 ALCcontext_DecRef(Context);
1991 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1993 ALCcontext *Context;
1994 ALsource *Source;
1996 Context = GetContextRef();
1997 if(!Context) return;
1999 WriteLock(&Context->PropLock);
2000 LockSourcesRead(Context);
2001 if((Source=LookupSource(Context, source)) == NULL)
2002 alSetError(Context, AL_INVALID_NAME);
2003 else if(!(IntValsByProp(param) == 1))
2004 alSetError(Context, AL_INVALID_ENUM);
2005 else
2006 SetSourceiv(Source, Context, param, &value);
2007 UnlockSourcesRead(Context);
2008 WriteUnlock(&Context->PropLock);
2010 ALCcontext_DecRef(Context);
2013 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
2015 ALCcontext *Context;
2016 ALsource *Source;
2018 Context = GetContextRef();
2019 if(!Context) return;
2021 WriteLock(&Context->PropLock);
2022 LockSourcesRead(Context);
2023 if((Source=LookupSource(Context, source)) == NULL)
2024 alSetError(Context, AL_INVALID_NAME);
2025 else if(!(IntValsByProp(param) == 3))
2026 alSetError(Context, AL_INVALID_ENUM);
2027 else
2029 ALint ivals[3] = { value1, value2, value3 };
2030 SetSourceiv(Source, Context, param, ivals);
2032 UnlockSourcesRead(Context);
2033 WriteUnlock(&Context->PropLock);
2035 ALCcontext_DecRef(Context);
2038 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
2040 ALCcontext *Context;
2041 ALsource *Source;
2043 Context = GetContextRef();
2044 if(!Context) return;
2046 WriteLock(&Context->PropLock);
2047 LockSourcesRead(Context);
2048 if((Source=LookupSource(Context, source)) == NULL)
2049 alSetError(Context, AL_INVALID_NAME);
2050 else if(!values)
2051 alSetError(Context, AL_INVALID_VALUE);
2052 else if(!(IntValsByProp(param) > 0))
2053 alSetError(Context, AL_INVALID_ENUM);
2054 else
2055 SetSourceiv(Source, Context, param, values);
2056 UnlockSourcesRead(Context);
2057 WriteUnlock(&Context->PropLock);
2059 ALCcontext_DecRef(Context);
2063 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
2065 ALCcontext *Context;
2066 ALsource *Source;
2068 Context = GetContextRef();
2069 if(!Context) return;
2071 WriteLock(&Context->PropLock);
2072 LockSourcesRead(Context);
2073 if((Source=LookupSource(Context, source)) == NULL)
2074 alSetError(Context, AL_INVALID_NAME);
2075 else if(!(Int64ValsByProp(param) == 1))
2076 alSetError(Context, AL_INVALID_ENUM);
2077 else
2078 SetSourcei64v(Source, Context, param, &value);
2079 UnlockSourcesRead(Context);
2080 WriteUnlock(&Context->PropLock);
2082 ALCcontext_DecRef(Context);
2085 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
2087 ALCcontext *Context;
2088 ALsource *Source;
2090 Context = GetContextRef();
2091 if(!Context) return;
2093 WriteLock(&Context->PropLock);
2094 LockSourcesRead(Context);
2095 if((Source=LookupSource(Context, source)) == NULL)
2096 alSetError(Context, AL_INVALID_NAME);
2097 else if(!(Int64ValsByProp(param) == 3))
2098 alSetError(Context, AL_INVALID_ENUM);
2099 else
2101 ALint64SOFT i64vals[3] = { value1, value2, value3 };
2102 SetSourcei64v(Source, Context, param, i64vals);
2104 UnlockSourcesRead(Context);
2105 WriteUnlock(&Context->PropLock);
2107 ALCcontext_DecRef(Context);
2110 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
2112 ALCcontext *Context;
2113 ALsource *Source;
2115 Context = GetContextRef();
2116 if(!Context) return;
2118 WriteLock(&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(!(Int64ValsByProp(param) > 0))
2125 alSetError(Context, AL_INVALID_ENUM);
2126 else
2127 SetSourcei64v(Source, Context, param, values);
2128 UnlockSourcesRead(Context);
2129 WriteUnlock(&Context->PropLock);
2131 ALCcontext_DecRef(Context);
2135 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
2137 ALCcontext *Context;
2138 ALsource *Source;
2140 Context = GetContextRef();
2141 if(!Context) return;
2143 ReadLock(&Context->PropLock);
2144 LockSourcesRead(Context);
2145 if((Source=LookupSource(Context, source)) == NULL)
2146 alSetError(Context, AL_INVALID_NAME);
2147 else if(!value)
2148 alSetError(Context, AL_INVALID_VALUE);
2149 else if(!(FloatValsByProp(param) == 1))
2150 alSetError(Context, AL_INVALID_ENUM);
2151 else
2153 ALdouble dval;
2154 if(GetSourcedv(Source, Context, param, &dval))
2155 *value = (ALfloat)dval;
2157 UnlockSourcesRead(Context);
2158 ReadUnlock(&Context->PropLock);
2160 ALCcontext_DecRef(Context);
2164 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
2166 ALCcontext *Context;
2167 ALsource *Source;
2169 Context = GetContextRef();
2170 if(!Context) return;
2172 ReadLock(&Context->PropLock);
2173 LockSourcesRead(Context);
2174 if((Source=LookupSource(Context, source)) == NULL)
2175 alSetError(Context, AL_INVALID_NAME);
2176 else if(!(value1 && value2 && value3))
2177 alSetError(Context, AL_INVALID_VALUE);
2178 else if(!(FloatValsByProp(param) == 3))
2179 alSetError(Context, AL_INVALID_ENUM);
2180 else
2182 ALdouble dvals[3];
2183 if(GetSourcedv(Source, Context, param, dvals))
2185 *value1 = (ALfloat)dvals[0];
2186 *value2 = (ALfloat)dvals[1];
2187 *value3 = (ALfloat)dvals[2];
2190 UnlockSourcesRead(Context);
2191 ReadUnlock(&Context->PropLock);
2193 ALCcontext_DecRef(Context);
2197 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
2199 ALCcontext *Context;
2200 ALsource *Source;
2201 ALint count;
2203 Context = GetContextRef();
2204 if(!Context) return;
2206 ReadLock(&Context->PropLock);
2207 LockSourcesRead(Context);
2208 if((Source=LookupSource(Context, source)) == NULL)
2209 alSetError(Context, AL_INVALID_NAME);
2210 else if(!values)
2211 alSetError(Context, AL_INVALID_VALUE);
2212 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
2213 alSetError(Context, AL_INVALID_ENUM);
2214 else
2216 ALdouble dvals[6];
2217 if(GetSourcedv(Source, Context, param, dvals))
2219 ALint i;
2220 for(i = 0;i < count;i++)
2221 values[i] = (ALfloat)dvals[i];
2224 UnlockSourcesRead(Context);
2225 ReadUnlock(&Context->PropLock);
2227 ALCcontext_DecRef(Context);
2231 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
2233 ALCcontext *Context;
2234 ALsource *Source;
2236 Context = GetContextRef();
2237 if(!Context) return;
2239 ReadLock(&Context->PropLock);
2240 LockSourcesRead(Context);
2241 if((Source=LookupSource(Context, source)) == NULL)
2242 alSetError(Context, AL_INVALID_NAME);
2243 else if(!value)
2244 alSetError(Context, AL_INVALID_VALUE);
2245 else if(!(DoubleValsByProp(param) == 1))
2246 alSetError(Context, AL_INVALID_ENUM);
2247 else
2248 GetSourcedv(Source, Context, param, value);
2249 UnlockSourcesRead(Context);
2250 ReadUnlock(&Context->PropLock);
2252 ALCcontext_DecRef(Context);
2255 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
2257 ALCcontext *Context;
2258 ALsource *Source;
2260 Context = GetContextRef();
2261 if(!Context) return;
2263 ReadLock(&Context->PropLock);
2264 LockSourcesRead(Context);
2265 if((Source=LookupSource(Context, source)) == NULL)
2266 alSetError(Context, AL_INVALID_NAME);
2267 else if(!(value1 && value2 && value3))
2268 alSetError(Context, AL_INVALID_VALUE);
2269 else if(!(DoubleValsByProp(param) == 3))
2270 alSetError(Context, AL_INVALID_ENUM);
2271 else
2273 ALdouble dvals[3];
2274 if(GetSourcedv(Source, Context, param, dvals))
2276 *value1 = dvals[0];
2277 *value2 = dvals[1];
2278 *value3 = dvals[2];
2281 UnlockSourcesRead(Context);
2282 ReadUnlock(&Context->PropLock);
2284 ALCcontext_DecRef(Context);
2287 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
2289 ALCcontext *Context;
2290 ALsource *Source;
2292 Context = GetContextRef();
2293 if(!Context) return;
2295 ReadLock(&Context->PropLock);
2296 LockSourcesRead(Context);
2297 if((Source=LookupSource(Context, source)) == NULL)
2298 alSetError(Context, AL_INVALID_NAME);
2299 else if(!values)
2300 alSetError(Context, AL_INVALID_VALUE);
2301 else if(!(DoubleValsByProp(param) > 0))
2302 alSetError(Context, AL_INVALID_ENUM);
2303 else
2304 GetSourcedv(Source, Context, param, values);
2305 UnlockSourcesRead(Context);
2306 ReadUnlock(&Context->PropLock);
2308 ALCcontext_DecRef(Context);
2312 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2314 ALCcontext *Context;
2315 ALsource *Source;
2317 Context = GetContextRef();
2318 if(!Context) return;
2320 ReadLock(&Context->PropLock);
2321 LockSourcesRead(Context);
2322 if((Source=LookupSource(Context, source)) == NULL)
2323 alSetError(Context, AL_INVALID_NAME);
2324 else if(!value)
2325 alSetError(Context, AL_INVALID_VALUE);
2326 else if(!(IntValsByProp(param) == 1))
2327 alSetError(Context, AL_INVALID_ENUM);
2328 else
2329 GetSourceiv(Source, Context, param, value);
2330 UnlockSourcesRead(Context);
2331 ReadUnlock(&Context->PropLock);
2333 ALCcontext_DecRef(Context);
2337 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2339 ALCcontext *Context;
2340 ALsource *Source;
2342 Context = GetContextRef();
2343 if(!Context) return;
2345 ReadLock(&Context->PropLock);
2346 LockSourcesRead(Context);
2347 if((Source=LookupSource(Context, source)) == NULL)
2348 alSetError(Context, AL_INVALID_NAME);
2349 else if(!(value1 && value2 && value3))
2350 alSetError(Context, AL_INVALID_VALUE);
2351 else if(!(IntValsByProp(param) == 3))
2352 alSetError(Context, AL_INVALID_ENUM);
2353 else
2355 ALint ivals[3];
2356 if(GetSourceiv(Source, Context, param, ivals))
2358 *value1 = ivals[0];
2359 *value2 = ivals[1];
2360 *value3 = ivals[2];
2363 UnlockSourcesRead(Context);
2364 ReadUnlock(&Context->PropLock);
2366 ALCcontext_DecRef(Context);
2370 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2372 ALCcontext *Context;
2373 ALsource *Source;
2375 Context = GetContextRef();
2376 if(!Context) return;
2378 ReadLock(&Context->PropLock);
2379 LockSourcesRead(Context);
2380 if((Source=LookupSource(Context, source)) == NULL)
2381 alSetError(Context, AL_INVALID_NAME);
2382 else if(!values)
2383 alSetError(Context, AL_INVALID_VALUE);
2384 else if(!(IntValsByProp(param) > 0))
2385 alSetError(Context, AL_INVALID_ENUM);
2386 else
2387 GetSourceiv(Source, Context, param, values);
2388 UnlockSourcesRead(Context);
2389 ReadUnlock(&Context->PropLock);
2391 ALCcontext_DecRef(Context);
2395 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2397 ALCcontext *Context;
2398 ALsource *Source;
2400 Context = GetContextRef();
2401 if(!Context) return;
2403 ReadLock(&Context->PropLock);
2404 LockSourcesRead(Context);
2405 if((Source=LookupSource(Context, source)) == NULL)
2406 alSetError(Context, AL_INVALID_NAME);
2407 else if(!value)
2408 alSetError(Context, AL_INVALID_VALUE);
2409 else if(!(Int64ValsByProp(param) == 1))
2410 alSetError(Context, AL_INVALID_ENUM);
2411 else
2412 GetSourcei64v(Source, Context, param, value);
2413 UnlockSourcesRead(Context);
2414 ReadUnlock(&Context->PropLock);
2416 ALCcontext_DecRef(Context);
2419 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2421 ALCcontext *Context;
2422 ALsource *Source;
2424 Context = GetContextRef();
2425 if(!Context) return;
2427 ReadLock(&Context->PropLock);
2428 LockSourcesRead(Context);
2429 if((Source=LookupSource(Context, source)) == NULL)
2430 alSetError(Context, AL_INVALID_NAME);
2431 else if(!(value1 && value2 && value3))
2432 alSetError(Context, AL_INVALID_VALUE);
2433 else if(!(Int64ValsByProp(param) == 3))
2434 alSetError(Context, AL_INVALID_ENUM);
2435 else
2437 ALint64 i64vals[3];
2438 if(GetSourcei64v(Source, Context, param, i64vals))
2440 *value1 = i64vals[0];
2441 *value2 = i64vals[1];
2442 *value3 = i64vals[2];
2445 UnlockSourcesRead(Context);
2446 ReadUnlock(&Context->PropLock);
2448 ALCcontext_DecRef(Context);
2451 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2453 ALCcontext *Context;
2454 ALsource *Source;
2456 Context = GetContextRef();
2457 if(!Context) return;
2459 ReadLock(&Context->PropLock);
2460 LockSourcesRead(Context);
2461 if((Source=LookupSource(Context, source)) == NULL)
2462 alSetError(Context, AL_INVALID_NAME);
2463 else if(!values)
2464 alSetError(Context, AL_INVALID_VALUE);
2465 else if(!(Int64ValsByProp(param) > 0))
2466 alSetError(Context, AL_INVALID_ENUM);
2467 else
2468 GetSourcei64v(Source, Context, param, values);
2469 UnlockSourcesRead(Context);
2470 ReadUnlock(&Context->PropLock);
2472 ALCcontext_DecRef(Context);
2476 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2478 alSourcePlayv(1, &source);
2480 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2482 ALCcontext *context;
2483 ALCdevice *device;
2484 ALsource *source;
2485 ALvoice *voice;
2486 ALsizei i, j;
2488 context = GetContextRef();
2489 if(!context) return;
2491 LockSourcesRead(context);
2492 if(!(n >= 0))
2493 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2494 for(i = 0;i < n;i++)
2496 if(!LookupSource(context, sources[i]))
2497 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2500 device = context->Device;
2501 ALCdevice_Lock(device);
2502 /* If the device is disconnected, go right to stopped. */
2503 if(!device->Connected)
2505 for(i = 0;i < n;i++)
2507 source = LookupSource(context, sources[i]);
2508 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2510 ALCdevice_Unlock(device);
2511 goto done;
2514 while(n > context->MaxVoices-context->VoiceCount)
2516 ALsizei newcount = context->MaxVoices << 1;
2517 if(context->MaxVoices >= newcount)
2519 ALCdevice_Unlock(device);
2520 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2522 AllocateVoices(context, newcount, device->NumAuxSends);
2525 for(i = 0;i < n;i++)
2527 ALbufferlistitem *BufferList;
2528 ALbuffer *buffer = NULL;
2529 bool start_fading = false;
2530 ALsizei s;
2532 source = LookupSource(context, sources[i]);
2533 WriteLock(&source->queue_lock);
2534 /* Check that there is a queue containing at least one valid, non zero
2535 * length Buffer.
2537 BufferList = source->queue;
2538 while(BufferList)
2540 ALsizei b;
2541 for(b = 0;b < BufferList->num_buffers;b++)
2543 buffer = BufferList->buffers[b];
2544 if(buffer && buffer->SampleLen > 0) break;
2546 if(buffer && buffer->SampleLen > 0) break;
2547 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
2550 /* If there's nothing to play, go right to stopped. */
2551 if(!BufferList)
2553 /* NOTE: A source without any playable buffers should not have an
2554 * ALvoice since it shouldn't be in a playing or paused state. So
2555 * there's no need to look up its voice and clear the source.
2557 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2558 source->OffsetType = AL_NONE;
2559 source->Offset = 0.0;
2560 goto finish_play;
2563 voice = GetSourceVoice(source, context);
2564 switch(GetSourceState(source, voice))
2566 case AL_PLAYING:
2567 assert(voice != NULL);
2568 /* A source that's already playing is restarted from the beginning. */
2569 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
2570 ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
2571 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release);
2572 goto finish_play;
2574 case AL_PAUSED:
2575 assert(voice != NULL);
2576 /* A source that's paused simply resumes. */
2577 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
2578 ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release);
2579 goto finish_play;
2581 default:
2582 break;
2585 /* Make sure this source isn't already active, and if not, look for an
2586 * unused voice to put it in.
2588 assert(voice == NULL);
2589 for(j = 0;j < context->VoiceCount;j++)
2591 if(ATOMIC_LOAD(&context->Voices[j]->Source, almemory_order_acquire) == NULL)
2593 voice = context->Voices[j];
2594 break;
2597 if(voice == NULL)
2598 voice = context->Voices[context->VoiceCount++];
2599 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2601 ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acquire);
2602 UpdateSourceProps(source, voice, device->NumAuxSends, context);
2604 /* A source that's not playing or paused has any offset applied when it
2605 * starts playing.
2607 if(source->Looping)
2608 ATOMIC_STORE(&voice->loop_buffer, source->queue, almemory_order_relaxed);
2609 else
2610 ATOMIC_STORE(&voice->loop_buffer, NULL, almemory_order_relaxed);
2611 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed);
2612 ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed);
2613 ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed);
2614 if(source->OffsetType != AL_NONE)
2616 ApplyOffset(source, voice);
2617 start_fading = ATOMIC_LOAD(&voice->position, almemory_order_relaxed) != 0 ||
2618 ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) != 0 ||
2619 ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed) != BufferList;
2622 voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2623 voice->SampleSize = BytesFromFmt(buffer->FmtType);
2625 /* Clear previous samples. */
2626 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
2628 /* Clear the stepping value so the mixer knows not to mix this until
2629 * the update gets applied.
2631 voice->Step = 0;
2633 voice->Flags = start_fading ? VOICE_IS_FADING : 0;
2634 if(source->SourceType == AL_STATIC) voice->Flags |= VOICE_IS_STATIC;
2635 memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*voice->NumChannels);
2636 for(s = 0;s < device->NumAuxSends;s++)
2637 memset(voice->Send[s].Params, 0, sizeof(voice->Send[s].Params[0])*voice->NumChannels);
2638 if(device->AvgSpeakerDist > 0.0f)
2640 ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC /
2641 (device->AvgSpeakerDist * device->Frequency);
2642 for(j = 0;j < voice->NumChannels;j++)
2644 NfcFilterCreate1(&voice->Direct.Params[j].NFCtrlFilter[0], 0.0f, w1);
2645 NfcFilterCreate2(&voice->Direct.Params[j].NFCtrlFilter[1], 0.0f, w1);
2646 NfcFilterCreate3(&voice->Direct.Params[j].NFCtrlFilter[2], 0.0f, w1);
2650 ATOMIC_STORE(&voice->Source, source, almemory_order_relaxed);
2651 ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
2652 ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release);
2653 finish_play:
2654 WriteUnlock(&source->queue_lock);
2656 ALCdevice_Unlock(device);
2658 done:
2659 UnlockSourcesRead(context);
2660 ALCcontext_DecRef(context);
2663 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2665 alSourcePausev(1, &source);
2667 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2669 ALCcontext *context;
2670 ALCdevice *device;
2671 ALsource *source;
2672 ALvoice *voice;
2673 ALsizei i;
2675 context = GetContextRef();
2676 if(!context) return;
2678 LockSourcesRead(context);
2679 if(!(n >= 0))
2680 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2681 for(i = 0;i < n;i++)
2683 if(!LookupSource(context, sources[i]))
2684 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2687 device = context->Device;
2688 ALCdevice_Lock(device);
2689 for(i = 0;i < n;i++)
2691 source = LookupSource(context, sources[i]);
2692 WriteLock(&source->queue_lock);
2693 if((voice=GetSourceVoice(source, context)) != NULL)
2695 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2696 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2697 althrd_yield();
2699 if(GetSourceState(source, voice) == AL_PLAYING)
2700 ATOMIC_STORE(&source->state, AL_PAUSED, almemory_order_release);
2701 WriteUnlock(&source->queue_lock);
2703 ALCdevice_Unlock(device);
2705 done:
2706 UnlockSourcesRead(context);
2707 ALCcontext_DecRef(context);
2710 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2712 alSourceStopv(1, &source);
2714 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2716 ALCcontext *context;
2717 ALCdevice *device;
2718 ALsource *source;
2719 ALvoice *voice;
2720 ALsizei i;
2722 context = GetContextRef();
2723 if(!context) return;
2725 LockSourcesRead(context);
2726 if(!(n >= 0))
2727 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2728 for(i = 0;i < n;i++)
2730 if(!LookupSource(context, sources[i]))
2731 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2734 device = context->Device;
2735 ALCdevice_Lock(device);
2736 for(i = 0;i < n;i++)
2738 source = LookupSource(context, sources[i]);
2739 WriteLock(&source->queue_lock);
2740 if((voice=GetSourceVoice(source, context)) != NULL)
2742 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
2743 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2744 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2745 althrd_yield();
2747 if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL)
2748 ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
2749 source->OffsetType = AL_NONE;
2750 source->Offset = 0.0;
2751 WriteUnlock(&source->queue_lock);
2753 ALCdevice_Unlock(device);
2755 done:
2756 UnlockSourcesRead(context);
2757 ALCcontext_DecRef(context);
2760 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2762 alSourceRewindv(1, &source);
2764 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2766 ALCcontext *context;
2767 ALCdevice *device;
2768 ALsource *source;
2769 ALvoice *voice;
2770 ALsizei i;
2772 context = GetContextRef();
2773 if(!context) return;
2775 LockSourcesRead(context);
2776 if(!(n >= 0))
2777 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2778 for(i = 0;i < n;i++)
2780 if(!LookupSource(context, sources[i]))
2781 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2784 device = context->Device;
2785 ALCdevice_Lock(device);
2786 for(i = 0;i < n;i++)
2788 source = LookupSource(context, sources[i]);
2789 WriteLock(&source->queue_lock);
2790 if((voice=GetSourceVoice(source, context)) != NULL)
2792 ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
2793 ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
2794 while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
2795 althrd_yield();
2797 if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL)
2798 ATOMIC_STORE(&source->state, AL_INITIAL, almemory_order_relaxed);
2799 source->OffsetType = AL_NONE;
2800 source->Offset = 0.0;
2801 WriteUnlock(&source->queue_lock);
2803 ALCdevice_Unlock(device);
2805 done:
2806 UnlockSourcesRead(context);
2807 ALCcontext_DecRef(context);
2811 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2813 ALCdevice *device;
2814 ALCcontext *context;
2815 ALsource *source;
2816 ALsizei i;
2817 ALbufferlistitem *BufferListStart;
2818 ALbufferlistitem *BufferList;
2819 ALbuffer *BufferFmt = NULL;
2821 if(nb == 0)
2822 return;
2824 context = GetContextRef();
2825 if(!context) return;
2827 device = context->Device;
2829 LockSourcesRead(context);
2830 if(!(nb >= 0))
2831 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2832 if((source=LookupSource(context, src)) == NULL)
2833 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2835 WriteLock(&source->queue_lock);
2836 if(source->SourceType == AL_STATIC)
2838 WriteUnlock(&source->queue_lock);
2839 /* Can't queue on a Static Source */
2840 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2843 /* Check for a valid Buffer, for its frequency and format */
2844 BufferList = source->queue;
2845 while(BufferList)
2847 for(i = 0;i < BufferList->num_buffers;i++)
2849 if((BufferFmt=BufferList->buffers[i]) != NULL)
2850 break;
2852 if(BufferFmt) break;
2853 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
2856 LockBuffersRead(device);
2857 BufferListStart = NULL;
2858 BufferList = NULL;
2859 for(i = 0;i < nb;i++)
2861 ALbuffer *buffer = NULL;
2862 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2864 WriteUnlock(&source->queue_lock);
2865 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2868 if(!BufferListStart)
2870 BufferListStart = al_calloc(DEF_ALIGN,
2871 FAM_SIZE(ALbufferlistitem, buffers, 1));
2872 BufferList = BufferListStart;
2874 else
2876 ALbufferlistitem *item = al_calloc(DEF_ALIGN,
2877 FAM_SIZE(ALbufferlistitem, buffers, 1));
2878 ATOMIC_STORE(&BufferList->next, item, almemory_order_relaxed);
2879 BufferList = item;
2881 ATOMIC_INIT(&BufferList->next, NULL);
2882 BufferList->num_buffers = 1;
2883 BufferList->buffers[0] = buffer;
2884 if(!buffer) continue;
2886 /* Hold a read lock on each buffer being queued while checking all
2887 * provided buffers. This is done so other threads don't see an extra
2888 * reference on some buffers if this operation ends up failing. */
2889 ReadLock(&buffer->lock);
2890 IncrementRef(&buffer->ref);
2892 if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
2894 WriteUnlock(&source->queue_lock);
2895 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2898 if(BufferFmt == NULL)
2899 BufferFmt = buffer;
2900 else if(BufferFmt->Frequency != buffer->Frequency ||
2901 BufferFmt->FmtChannels != buffer->FmtChannels ||
2902 BufferFmt->OriginalType != buffer->OriginalType)
2904 WriteUnlock(&source->queue_lock);
2905 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2907 buffer_error:
2908 /* A buffer failed (invalid ID or format), so unlock and release
2909 * each buffer we had. */
2910 while(BufferListStart)
2912 ALbufferlistitem *next = ATOMIC_LOAD(&BufferListStart->next,
2913 almemory_order_relaxed);
2914 for(i = 0;i < BufferListStart->num_buffers;i++)
2916 if((buffer=BufferListStart->buffers[i]) != NULL)
2918 DecrementRef(&buffer->ref);
2919 ReadUnlock(&buffer->lock);
2922 al_free(BufferListStart);
2923 BufferListStart = next;
2925 UnlockBuffersRead(device);
2926 goto done;
2929 /* All buffers good, unlock them now. */
2930 BufferList = BufferListStart;
2931 while(BufferList != NULL)
2933 for(i = 0;i < BufferList->num_buffers;i++)
2935 ALbuffer *buffer = BufferList->buffers[i];
2936 if(buffer) ReadUnlock(&buffer->lock);
2938 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
2940 UnlockBuffersRead(device);
2942 /* Source is now streaming */
2943 source->SourceType = AL_STREAMING;
2945 if(!(BufferList=source->queue))
2946 source->queue = BufferListStart;
2947 else
2949 ALbufferlistitem *next;
2950 while((next=ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed)) != NULL)
2951 BufferList = next;
2952 ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release);
2954 WriteUnlock(&source->queue_lock);
2956 done:
2957 UnlockSourcesRead(context);
2958 ALCcontext_DecRef(context);
2961 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2963 ALCcontext *context;
2964 ALsource *source;
2965 ALbufferlistitem *OldHead;
2966 ALbufferlistitem *OldTail;
2967 ALbufferlistitem *Current;
2968 ALvoice *voice;
2969 ALsizei i = 0;
2971 context = GetContextRef();
2972 if(!context) return;
2974 LockSourcesRead(context);
2975 if(!(nb >= 0))
2976 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2978 if((source=LookupSource(context, src)) == NULL)
2979 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2981 /* Nothing to unqueue. */
2982 if(nb == 0) goto done;
2984 WriteLock(&source->queue_lock);
2985 if(source->Looping || source->SourceType != AL_STREAMING)
2987 WriteUnlock(&source->queue_lock);
2988 /* Trying to unqueue buffers on a looping or non-streaming source. */
2989 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2992 /* Find the new buffer queue head */
2993 OldTail = source->queue;
2994 Current = NULL;
2995 if((voice=GetSourceVoice(source, context)) != NULL)
2996 Current = ATOMIC_LOAD_SEQ(&voice->current_buffer);
2997 else if(ATOMIC_LOAD_SEQ(&source->state) == AL_INITIAL)
2998 Current = OldTail;
2999 if(OldTail != Current && OldTail->num_buffers == 1)
3001 for(i = 1;i < nb;i++)
3003 ALbufferlistitem *next = ATOMIC_LOAD(&OldTail->next, almemory_order_relaxed);
3004 if(!next || next == Current || next->num_buffers != 1) break;
3005 OldTail = next;
3008 if(i != nb)
3010 WriteUnlock(&source->queue_lock);
3011 /* Trying to unqueue pending buffers. */
3012 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
3015 /* Swap it, and cut the new head from the old. */
3016 OldHead = source->queue;
3017 source->queue = ATOMIC_EXCHANGE_PTR(&OldTail->next, NULL, almemory_order_acq_rel);
3018 WriteUnlock(&source->queue_lock);
3020 while(OldHead != NULL)
3022 ALbufferlistitem *next = ATOMIC_LOAD(&OldHead->next, almemory_order_relaxed);
3023 ALbuffer *buffer = OldHead->buffers[0];
3025 if(!buffer)
3026 *(buffers++) = 0;
3027 else
3029 *(buffers++) = buffer->id;
3030 DecrementRef(&buffer->ref);
3033 al_free(OldHead);
3034 OldHead = next;
3037 done:
3038 UnlockSourcesRead(context);
3039 ALCcontext_DecRef(context);
3043 static void InitSourceParams(ALsource *Source, ALsizei num_sends)
3045 ALsizei i;
3047 RWLockInit(&Source->queue_lock);
3049 Source->InnerAngle = 360.0f;
3050 Source->OuterAngle = 360.0f;
3051 Source->Pitch = 1.0f;
3052 Source->Position[0] = 0.0f;
3053 Source->Position[1] = 0.0f;
3054 Source->Position[2] = 0.0f;
3055 Source->Velocity[0] = 0.0f;
3056 Source->Velocity[1] = 0.0f;
3057 Source->Velocity[2] = 0.0f;
3058 Source->Direction[0] = 0.0f;
3059 Source->Direction[1] = 0.0f;
3060 Source->Direction[2] = 0.0f;
3061 Source->Orientation[0][0] = 0.0f;
3062 Source->Orientation[0][1] = 0.0f;
3063 Source->Orientation[0][2] = -1.0f;
3064 Source->Orientation[1][0] = 0.0f;
3065 Source->Orientation[1][1] = 1.0f;
3066 Source->Orientation[1][2] = 0.0f;
3067 Source->RefDistance = 1.0f;
3068 Source->MaxDistance = FLT_MAX;
3069 Source->RolloffFactor = 1.0f;
3070 Source->Gain = 1.0f;
3071 Source->MinGain = 0.0f;
3072 Source->MaxGain = 1.0f;
3073 Source->OuterGain = 0.0f;
3074 Source->OuterGainHF = 1.0f;
3076 Source->DryGainHFAuto = AL_TRUE;
3077 Source->WetGainAuto = AL_TRUE;
3078 Source->WetGainHFAuto = AL_TRUE;
3079 Source->AirAbsorptionFactor = 0.0f;
3080 Source->RoomRolloffFactor = 0.0f;
3081 Source->DopplerFactor = 1.0f;
3082 Source->HeadRelative = AL_FALSE;
3083 Source->Looping = AL_FALSE;
3084 Source->DistanceModel = DefaultDistanceModel;
3085 Source->Resampler = ResamplerDefault;
3086 Source->DirectChannels = AL_FALSE;
3087 Source->Spatialize = SpatializeAuto;
3089 Source->StereoPan[0] = DEG2RAD( 30.0f);
3090 Source->StereoPan[1] = DEG2RAD(-30.0f);
3092 Source->Radius = 0.0f;
3094 Source->Direct.Gain = 1.0f;
3095 Source->Direct.GainHF = 1.0f;
3096 Source->Direct.HFReference = LOWPASSFREQREF;
3097 Source->Direct.GainLF = 1.0f;
3098 Source->Direct.LFReference = HIGHPASSFREQREF;
3099 Source->Send = al_calloc(16, num_sends*sizeof(Source->Send[0]));
3100 for(i = 0;i < num_sends;i++)
3102 Source->Send[i].Slot = NULL;
3103 Source->Send[i].Gain = 1.0f;
3104 Source->Send[i].GainHF = 1.0f;
3105 Source->Send[i].HFReference = LOWPASSFREQREF;
3106 Source->Send[i].GainLF = 1.0f;
3107 Source->Send[i].LFReference = HIGHPASSFREQREF;
3110 Source->Offset = 0.0;
3111 Source->OffsetType = AL_NONE;
3112 Source->SourceType = AL_UNDETERMINED;
3113 ATOMIC_INIT(&Source->state, AL_INITIAL);
3115 Source->queue = NULL;
3117 /* No way to do an 'init' here, so just test+set with relaxed ordering and
3118 * ignore the test.
3120 ATOMIC_FLAG_TEST_AND_SET(&Source->PropsClean, almemory_order_relaxed);
3123 static void DeinitSource(ALsource *source, ALsizei num_sends)
3125 ALbufferlistitem *BufferList;
3126 ALsizei i;
3128 BufferList = source->queue;
3129 while(BufferList != NULL)
3131 ALbufferlistitem *next = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
3132 for(i = 0;i < BufferList->num_buffers;i++)
3134 if(BufferList->buffers[i] != NULL)
3135 DecrementRef(&BufferList->buffers[i]->ref);
3137 al_free(BufferList);
3138 BufferList = next;
3140 source->queue = NULL;
3142 if(source->Send)
3144 for(i = 0;i < num_sends;i++)
3146 if(source->Send[i].Slot)
3147 DecrementRef(&source->Send[i].Slot->ref);
3148 source->Send[i].Slot = NULL;
3150 al_free(source->Send);
3151 source->Send = NULL;
3155 static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends, ALCcontext *context)
3157 struct ALvoiceProps *props;
3158 ALsizei i;
3160 /* Get an unused property container, or allocate a new one as needed. */
3161 props = ATOMIC_LOAD(&context->FreeVoiceProps, almemory_order_acquire);
3162 if(!props)
3163 props = al_calloc(16, FAM_SIZE(struct ALvoiceProps, Send, num_sends));
3164 else
3166 struct ALvoiceProps *next;
3167 do {
3168 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
3169 } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeVoiceProps, &props, next,
3170 almemory_order_acq_rel, almemory_order_acquire) == 0);
3173 /* Copy in current property values. */
3174 props->Pitch = source->Pitch;
3175 props->Gain = source->Gain;
3176 props->OuterGain = source->OuterGain;
3177 props->MinGain = source->MinGain;
3178 props->MaxGain = source->MaxGain;
3179 props->InnerAngle = source->InnerAngle;
3180 props->OuterAngle = source->OuterAngle;
3181 props->RefDistance = source->RefDistance;
3182 props->MaxDistance = source->MaxDistance;
3183 props->RolloffFactor = source->RolloffFactor;
3184 for(i = 0;i < 3;i++)
3185 props->Position[i] = source->Position[i];
3186 for(i = 0;i < 3;i++)
3187 props->Velocity[i] = source->Velocity[i];
3188 for(i = 0;i < 3;i++)
3189 props->Direction[i] = source->Direction[i];
3190 for(i = 0;i < 2;i++)
3192 ALsizei j;
3193 for(j = 0;j < 3;j++)
3194 props->Orientation[i][j] = source->Orientation[i][j];
3196 props->HeadRelative = source->HeadRelative;
3197 props->DistanceModel = source->DistanceModel;
3198 props->Resampler = source->Resampler;
3199 props->DirectChannels = source->DirectChannels;
3200 props->SpatializeMode = source->Spatialize;
3202 props->DryGainHFAuto = source->DryGainHFAuto;
3203 props->WetGainAuto = source->WetGainAuto;
3204 props->WetGainHFAuto = source->WetGainHFAuto;
3205 props->OuterGainHF = source->OuterGainHF;
3207 props->AirAbsorptionFactor = source->AirAbsorptionFactor;
3208 props->RoomRolloffFactor = source->RoomRolloffFactor;
3209 props->DopplerFactor = source->DopplerFactor;
3211 props->StereoPan[0] = source->StereoPan[0];
3212 props->StereoPan[1] = source->StereoPan[1];
3214 props->Radius = source->Radius;
3216 props->Direct.Gain = source->Direct.Gain;
3217 props->Direct.GainHF = source->Direct.GainHF;
3218 props->Direct.HFReference = source->Direct.HFReference;
3219 props->Direct.GainLF = source->Direct.GainLF;
3220 props->Direct.LFReference = source->Direct.LFReference;
3222 for(i = 0;i < num_sends;i++)
3224 props->Send[i].Slot = source->Send[i].Slot;
3225 props->Send[i].Gain = source->Send[i].Gain;
3226 props->Send[i].GainHF = source->Send[i].GainHF;
3227 props->Send[i].HFReference = source->Send[i].HFReference;
3228 props->Send[i].GainLF = source->Send[i].GainLF;
3229 props->Send[i].LFReference = source->Send[i].LFReference;
3232 /* Set the new container for updating internal parameters. */
3233 props = ATOMIC_EXCHANGE_PTR(&voice->Update, props, almemory_order_acq_rel);
3234 if(props)
3236 /* If there was an unused update container, put it back in the
3237 * freelist.
3239 ATOMIC_REPLACE_HEAD(struct ALvoiceProps*, &context->FreeVoiceProps, props);
3243 void UpdateAllSourceProps(ALCcontext *context)
3245 ALsizei num_sends = context->Device->NumAuxSends;
3246 ALsizei pos;
3248 for(pos = 0;pos < context->VoiceCount;pos++)
3250 ALvoice *voice = context->Voices[pos];
3251 ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire);
3252 if(source && !ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acq_rel))
3253 UpdateSourceProps(source, voice, num_sends, context);
3258 /* GetSourceSampleOffset
3260 * Gets the current read offset for the given Source, in 32.32 fixed-point
3261 * samples. The offset is relative to the start of the queue (not the start of
3262 * the current buffer).
3264 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3266 ALCdevice *device = context->Device;
3267 const ALbufferlistitem *Current;
3268 ALuint64 readPos;
3269 ALuint refcount;
3270 ALvoice *voice;
3272 ReadLock(&Source->queue_lock);
3273 do {
3274 Current = NULL;
3275 readPos = 0;
3276 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3277 althrd_yield();
3278 *clocktime = GetDeviceClockTime(device);
3280 voice = GetSourceVoice(Source, context);
3281 if(voice)
3283 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3285 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << 32;
3286 readPos |= (ALuint64)ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) <<
3287 (32-FRACTIONBITS);
3289 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3290 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3292 if(voice)
3294 const ALbufferlistitem *BufferList = Source->queue;
3295 while(BufferList && BufferList != Current)
3297 ALsizei max_len = 0;
3298 ALsizei i;
3300 for(i = 0;i < BufferList->num_buffers;i++)
3302 ALbuffer *buffer = BufferList->buffers[i];
3303 if(buffer) max_len = maxi(max_len, buffer->SampleLen);
3305 readPos += (ALuint64)max_len << 32;
3306 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3307 almemory_order_relaxed);
3309 readPos = minu64(readPos, U64(0x7fffffffffffffff));
3312 ReadUnlock(&Source->queue_lock);
3313 return (ALint64)readPos;
3316 /* GetSourceSecOffset
3318 * Gets the current read offset for the given Source, in seconds. The offset is
3319 * relative to the start of the queue (not the start of the current buffer).
3321 static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime)
3323 ALCdevice *device = context->Device;
3324 const ALbufferlistitem *Current;
3325 ALuint64 readPos;
3326 ALuint refcount;
3327 ALdouble offset;
3328 ALvoice *voice;
3330 ReadLock(&Source->queue_lock);
3331 do {
3332 Current = NULL;
3333 readPos = 0;
3334 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3335 althrd_yield();
3336 *clocktime = GetDeviceClockTime(device);
3338 voice = GetSourceVoice(Source, context);
3339 if(voice)
3341 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3343 readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) <<
3344 FRACTIONBITS;
3345 readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3347 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3348 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3350 offset = 0.0;
3351 if(voice)
3353 const ALbufferlistitem *BufferList = Source->queue;
3354 const ALbuffer *BufferFmt = NULL;
3355 while(BufferList && BufferList != Current)
3357 ALsizei max_len = 0;
3358 ALsizei i;
3360 for(i = 0;i < BufferList->num_buffers;i++)
3362 ALbuffer *buffer = BufferList->buffers[i];
3363 if(buffer)
3365 if(!BufferFmt) BufferFmt = buffer;
3366 max_len = maxi(max_len, buffer->SampleLen);
3369 readPos += (ALuint64)max_len << FRACTIONBITS;
3370 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3371 almemory_order_relaxed);
3374 while(BufferList && !BufferFmt)
3376 ALsizei i;
3377 for(i = 0;i < BufferList->num_buffers && !BufferFmt;i++)
3378 BufferFmt = BufferList->buffers[i];
3379 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3380 almemory_order_relaxed);
3382 assert(BufferFmt != NULL);
3384 offset = (ALdouble)readPos / (ALdouble)FRACTIONONE /
3385 (ALdouble)BufferFmt->Frequency;
3388 ReadUnlock(&Source->queue_lock);
3389 return offset;
3392 /* GetSourceOffset
3394 * Gets the current read offset for the given Source, in the appropriate format
3395 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3396 * queue (not the start of the current buffer).
3398 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context)
3400 ALCdevice *device = context->Device;
3401 const ALbufferlistitem *Current;
3402 ALuint readPos;
3403 ALsizei readPosFrac;
3404 ALuint refcount;
3405 ALdouble offset;
3406 ALvoice *voice;
3408 ReadLock(&Source->queue_lock);
3409 do {
3410 Current = NULL;
3411 readPos = readPosFrac = 0;
3412 while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
3413 althrd_yield();
3414 voice = GetSourceVoice(Source, context);
3415 if(voice)
3417 Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
3419 readPos = ATOMIC_LOAD(&voice->position, almemory_order_relaxed);
3420 readPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
3422 ATOMIC_THREAD_FENCE(almemory_order_acquire);
3423 } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
3425 offset = 0.0;
3426 if(voice)
3428 const ALbufferlistitem *BufferList = Source->queue;
3429 const ALbuffer *BufferFmt = NULL;
3430 ALboolean readFin = AL_FALSE;
3431 ALuint totalBufferLen = 0;
3433 while(BufferList != NULL)
3435 ALsizei max_len = 0;
3436 ALsizei i;
3438 readFin = readFin || (BufferList == Current);
3439 for(i = 0;i < BufferList->num_buffers;i++)
3441 ALbuffer *buffer = BufferList->buffers[i];
3442 if(buffer)
3444 if(!BufferFmt) BufferFmt = buffer;
3445 max_len = maxi(max_len, buffer->SampleLen);
3448 totalBufferLen += max_len;
3449 if(!readFin) readPos += max_len;
3451 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3452 almemory_order_relaxed);
3454 assert(BufferFmt != NULL);
3456 if(Source->Looping)
3457 readPos %= totalBufferLen;
3458 else
3460 /* Wrap back to 0 */
3461 if(readPos >= totalBufferLen)
3462 readPos = readPosFrac = 0;
3465 offset = 0.0;
3466 switch(name)
3468 case AL_SEC_OFFSET:
3469 offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE) / BufferFmt->Frequency;
3470 break;
3472 case AL_SAMPLE_OFFSET:
3473 offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
3474 break;
3476 case AL_BYTE_OFFSET:
3477 if(BufferFmt->OriginalType == UserFmtIMA4)
3479 ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
3480 ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels);
3481 ALuint FrameBlockSize = BufferFmt->OriginalAlign;
3483 /* Round down to nearest ADPCM block */
3484 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3486 else if(BufferFmt->OriginalType == UserFmtMSADPCM)
3488 ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
3489 ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels);
3490 ALuint FrameBlockSize = BufferFmt->OriginalAlign;
3492 /* Round down to nearest ADPCM block */
3493 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3495 else
3497 ALuint FrameSize = FrameSizeFromFmt(BufferFmt->FmtChannels,
3498 BufferFmt->FmtType);
3499 offset = (ALdouble)(readPos * FrameSize);
3501 break;
3505 ReadUnlock(&Source->queue_lock);
3506 return offset;
3510 /* ApplyOffset
3512 * Apply the stored playback offset to the Source. This function will update
3513 * the number of buffers "played" given the stored offset.
3515 static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice)
3517 ALbufferlistitem *BufferList;
3518 ALuint bufferLen, totalBufferLen;
3519 ALuint offset = 0;
3520 ALsizei frac = 0;
3522 /* Get sample frame offset */
3523 if(!GetSampleOffset(Source, &offset, &frac))
3524 return AL_FALSE;
3526 totalBufferLen = 0;
3527 BufferList = Source->queue;
3528 while(BufferList && totalBufferLen <= offset)
3530 ALsizei max_len = 0;
3531 ALsizei i;
3533 for(i = 0;i < BufferList->num_buffers;i++)
3535 ALbuffer *buffer = BufferList->buffers[i];
3536 if(buffer) max_len = maxi(max_len, buffer->SampleLen);
3538 bufferLen = max_len;
3540 if(bufferLen > offset-totalBufferLen)
3542 /* Offset is in this buffer */
3543 ATOMIC_STORE(&voice->position, offset - totalBufferLen, almemory_order_relaxed);
3544 ATOMIC_STORE(&voice->position_fraction, frac, almemory_order_relaxed);
3545 ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_release);
3546 return AL_TRUE;
3549 totalBufferLen += bufferLen;
3551 BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed);
3554 /* Offset is out of range of the queue */
3555 return AL_FALSE;
3559 /* GetSampleOffset
3561 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3562 * or Second offset supplied by the application). This takes into account the
3563 * fact that the buffer format may have been modifed since.
3565 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac)
3567 const ALbuffer *BufferFmt = NULL;
3568 const ALbufferlistitem *BufferList;
3569 ALdouble dbloff, dblfrac;
3571 /* Find the first valid Buffer in the Queue */
3572 BufferList = Source->queue;
3573 while(BufferList)
3575 ALsizei i;
3576 for(i = 0;i < BufferList->num_buffers && !BufferFmt;i++)
3577 BufferFmt = BufferList->buffers[i];
3578 if(BufferFmt) break;
3579 BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next,
3580 almemory_order_relaxed);
3582 if(!BufferFmt)
3584 Source->OffsetType = AL_NONE;
3585 Source->Offset = 0.0;
3586 return AL_FALSE;
3589 switch(Source->OffsetType)
3591 case AL_BYTE_OFFSET:
3592 /* Determine the ByteOffset (and ensure it is block aligned) */
3593 *offset = (ALuint)Source->Offset;
3594 if(BufferFmt->OriginalType == UserFmtIMA4)
3596 ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
3597 *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels);
3598 *offset *= BufferFmt->OriginalAlign;
3600 else if(BufferFmt->OriginalType == UserFmtMSADPCM)
3602 ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
3603 *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels);
3604 *offset *= BufferFmt->OriginalAlign;
3606 else
3607 *offset /= FrameSizeFromFmt(BufferFmt->FmtChannels, BufferFmt->FmtType);
3608 *frac = 0;
3609 break;
3611 case AL_SAMPLE_OFFSET:
3612 dblfrac = modf(Source->Offset, &dbloff);
3613 *offset = (ALuint)mind(dbloff, UINT_MAX);
3614 *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3615 break;
3617 case AL_SEC_OFFSET:
3618 dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff);
3619 *offset = (ALuint)mind(dbloff, UINT_MAX);
3620 *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3621 break;
3623 Source->OffsetType = AL_NONE;
3624 Source->Offset = 0.0;
3626 return AL_TRUE;
3630 /* ReleaseALSources
3632 * Destroys all sources in the source map.
3634 ALvoid ReleaseALSources(ALCcontext *Context)
3636 ALCdevice *device = Context->Device;
3637 ALsizei pos;
3638 for(pos = 0;pos < Context->SourceMap.size;pos++)
3640 ALsource *temp = Context->SourceMap.values[pos];
3641 Context->SourceMap.values[pos] = NULL;
3643 DeinitSource(temp, device->NumAuxSends);
3645 FreeThunkEntry(temp->id);
3646 memset(temp, 0, sizeof(*temp));
3647 al_free(temp);