Use the source's offset type to determine if there's an offset
[openal-soft.git] / OpenAL32 / alSource.c
blob749f2ec4283a3c68bae7814373d9f0b2f00c36f7
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 struct ALsource *LookupSource(ALCcontext *context, ALuint id);
44 extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
46 static ALvoid InitSourceParams(ALsource *Source);
47 static ALint64 GetSourceSampleOffset(ALsource *Source);
48 static ALdouble GetSourceSecOffset(ALsource *Source);
49 static ALdouble GetSourceOffset(ALsource *Source, ALenum name);
50 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac);
52 typedef enum SourceProp {
53 srcPitch = AL_PITCH,
54 srcGain = AL_GAIN,
55 srcMinGain = AL_MIN_GAIN,
56 srcMaxGain = AL_MAX_GAIN,
57 srcMaxDistance = AL_MAX_DISTANCE,
58 srcRolloffFactor = AL_ROLLOFF_FACTOR,
59 srcDopplerFactor = AL_DOPPLER_FACTOR,
60 srcConeOuterGain = AL_CONE_OUTER_GAIN,
61 srcSecOffset = AL_SEC_OFFSET,
62 srcSampleOffset = AL_SAMPLE_OFFSET,
63 srcByteOffset = AL_BYTE_OFFSET,
64 srcConeInnerAngle = AL_CONE_INNER_ANGLE,
65 srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
66 srcRefDistance = AL_REFERENCE_DISTANCE,
68 srcPosition = AL_POSITION,
69 srcVelocity = AL_VELOCITY,
70 srcDirection = AL_DIRECTION,
72 srcSourceRelative = AL_SOURCE_RELATIVE,
73 srcLooping = AL_LOOPING,
74 srcBuffer = AL_BUFFER,
75 srcSourceState = AL_SOURCE_STATE,
76 srcBuffersQueued = AL_BUFFERS_QUEUED,
77 srcBuffersProcessed = AL_BUFFERS_PROCESSED,
78 srcSourceType = AL_SOURCE_TYPE,
80 /* ALC_EXT_EFX */
81 srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
82 srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
83 srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
84 srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
85 srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
86 srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
87 srcDirectFilter = AL_DIRECT_FILTER,
88 srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
90 /* AL_SOFT_direct_channels */
91 srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
93 /* AL_EXT_source_distance_model */
94 srcDistanceModel = AL_DISTANCE_MODEL,
96 srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
97 srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
98 srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
100 /* AL_SOFT_source_latency */
101 srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
102 srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
104 /* AL_EXT_STEREO_ANGLES */
105 srcAngles = AL_STEREO_ANGLES,
107 /* AL_EXT_SOURCE_RADIUS */
108 srcRadius = AL_SOURCE_RADIUS,
110 /* AL_EXT_BFORMAT */
111 srcOrientation = AL_ORIENTATION,
112 } SourceProp;
114 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
115 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
116 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
118 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
119 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
120 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
122 static ALint FloatValsByProp(ALenum prop)
124 if(prop != (ALenum)((SourceProp)prop))
125 return 0;
126 switch((SourceProp)prop)
128 case AL_PITCH:
129 case AL_GAIN:
130 case AL_MIN_GAIN:
131 case AL_MAX_GAIN:
132 case AL_MAX_DISTANCE:
133 case AL_ROLLOFF_FACTOR:
134 case AL_DOPPLER_FACTOR:
135 case AL_CONE_OUTER_GAIN:
136 case AL_SEC_OFFSET:
137 case AL_SAMPLE_OFFSET:
138 case AL_BYTE_OFFSET:
139 case AL_CONE_INNER_ANGLE:
140 case AL_CONE_OUTER_ANGLE:
141 case AL_REFERENCE_DISTANCE:
142 case AL_CONE_OUTER_GAINHF:
143 case AL_AIR_ABSORPTION_FACTOR:
144 case AL_ROOM_ROLLOFF_FACTOR:
145 case AL_DIRECT_FILTER_GAINHF_AUTO:
146 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
147 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
148 case AL_DIRECT_CHANNELS_SOFT:
149 case AL_DISTANCE_MODEL:
150 case AL_SOURCE_RELATIVE:
151 case AL_LOOPING:
152 case AL_SOURCE_STATE:
153 case AL_BUFFERS_QUEUED:
154 case AL_BUFFERS_PROCESSED:
155 case AL_SOURCE_TYPE:
156 case AL_BYTE_LENGTH_SOFT:
157 case AL_SAMPLE_LENGTH_SOFT:
158 case AL_SEC_LENGTH_SOFT:
159 case AL_SOURCE_RADIUS:
160 return 1;
162 case AL_STEREO_ANGLES:
163 return 2;
165 case AL_POSITION:
166 case AL_VELOCITY:
167 case AL_DIRECTION:
168 return 3;
170 case AL_ORIENTATION:
171 return 6;
173 case AL_SEC_OFFSET_LATENCY_SOFT:
174 break; /* Double only */
176 case AL_BUFFER:
177 case AL_DIRECT_FILTER:
178 case AL_AUXILIARY_SEND_FILTER:
179 break; /* i/i64 only */
180 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
181 break; /* i64 only */
183 return 0;
185 static ALint DoubleValsByProp(ALenum prop)
187 if(prop != (ALenum)((SourceProp)prop))
188 return 0;
189 switch((SourceProp)prop)
191 case AL_PITCH:
192 case AL_GAIN:
193 case AL_MIN_GAIN:
194 case AL_MAX_GAIN:
195 case AL_MAX_DISTANCE:
196 case AL_ROLLOFF_FACTOR:
197 case AL_DOPPLER_FACTOR:
198 case AL_CONE_OUTER_GAIN:
199 case AL_SEC_OFFSET:
200 case AL_SAMPLE_OFFSET:
201 case AL_BYTE_OFFSET:
202 case AL_CONE_INNER_ANGLE:
203 case AL_CONE_OUTER_ANGLE:
204 case AL_REFERENCE_DISTANCE:
205 case AL_CONE_OUTER_GAINHF:
206 case AL_AIR_ABSORPTION_FACTOR:
207 case AL_ROOM_ROLLOFF_FACTOR:
208 case AL_DIRECT_FILTER_GAINHF_AUTO:
209 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
210 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
211 case AL_DIRECT_CHANNELS_SOFT:
212 case AL_DISTANCE_MODEL:
213 case AL_SOURCE_RELATIVE:
214 case AL_LOOPING:
215 case AL_SOURCE_STATE:
216 case AL_BUFFERS_QUEUED:
217 case AL_BUFFERS_PROCESSED:
218 case AL_SOURCE_TYPE:
219 case AL_BYTE_LENGTH_SOFT:
220 case AL_SAMPLE_LENGTH_SOFT:
221 case AL_SEC_LENGTH_SOFT:
222 case AL_SOURCE_RADIUS:
223 return 1;
225 case AL_SEC_OFFSET_LATENCY_SOFT:
226 case AL_STEREO_ANGLES:
227 return 2;
229 case AL_POSITION:
230 case AL_VELOCITY:
231 case AL_DIRECTION:
232 return 3;
234 case AL_ORIENTATION:
235 return 6;
237 case AL_BUFFER:
238 case AL_DIRECT_FILTER:
239 case AL_AUXILIARY_SEND_FILTER:
240 break; /* i/i64 only */
241 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
242 break; /* i64 only */
244 return 0;
247 static ALint IntValsByProp(ALenum prop)
249 if(prop != (ALenum)((SourceProp)prop))
250 return 0;
251 switch((SourceProp)prop)
253 case AL_PITCH:
254 case AL_GAIN:
255 case AL_MIN_GAIN:
256 case AL_MAX_GAIN:
257 case AL_MAX_DISTANCE:
258 case AL_ROLLOFF_FACTOR:
259 case AL_DOPPLER_FACTOR:
260 case AL_CONE_OUTER_GAIN:
261 case AL_SEC_OFFSET:
262 case AL_SAMPLE_OFFSET:
263 case AL_BYTE_OFFSET:
264 case AL_CONE_INNER_ANGLE:
265 case AL_CONE_OUTER_ANGLE:
266 case AL_REFERENCE_DISTANCE:
267 case AL_CONE_OUTER_GAINHF:
268 case AL_AIR_ABSORPTION_FACTOR:
269 case AL_ROOM_ROLLOFF_FACTOR:
270 case AL_DIRECT_FILTER_GAINHF_AUTO:
271 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
272 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
273 case AL_DIRECT_CHANNELS_SOFT:
274 case AL_DISTANCE_MODEL:
275 case AL_SOURCE_RELATIVE:
276 case AL_LOOPING:
277 case AL_BUFFER:
278 case AL_SOURCE_STATE:
279 case AL_BUFFERS_QUEUED:
280 case AL_BUFFERS_PROCESSED:
281 case AL_SOURCE_TYPE:
282 case AL_DIRECT_FILTER:
283 case AL_BYTE_LENGTH_SOFT:
284 case AL_SAMPLE_LENGTH_SOFT:
285 case AL_SEC_LENGTH_SOFT:
286 case AL_SOURCE_RADIUS:
287 return 1;
289 case AL_POSITION:
290 case AL_VELOCITY:
291 case AL_DIRECTION:
292 case AL_AUXILIARY_SEND_FILTER:
293 return 3;
295 case AL_ORIENTATION:
296 return 6;
298 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
299 break; /* i64 only */
300 case AL_SEC_OFFSET_LATENCY_SOFT:
301 break; /* Double only */
302 case AL_STEREO_ANGLES:
303 break; /* Float/double only */
305 return 0;
307 static ALint Int64ValsByProp(ALenum prop)
309 if(prop != (ALenum)((SourceProp)prop))
310 return 0;
311 switch((SourceProp)prop)
313 case AL_PITCH:
314 case AL_GAIN:
315 case AL_MIN_GAIN:
316 case AL_MAX_GAIN:
317 case AL_MAX_DISTANCE:
318 case AL_ROLLOFF_FACTOR:
319 case AL_DOPPLER_FACTOR:
320 case AL_CONE_OUTER_GAIN:
321 case AL_SEC_OFFSET:
322 case AL_SAMPLE_OFFSET:
323 case AL_BYTE_OFFSET:
324 case AL_CONE_INNER_ANGLE:
325 case AL_CONE_OUTER_ANGLE:
326 case AL_REFERENCE_DISTANCE:
327 case AL_CONE_OUTER_GAINHF:
328 case AL_AIR_ABSORPTION_FACTOR:
329 case AL_ROOM_ROLLOFF_FACTOR:
330 case AL_DIRECT_FILTER_GAINHF_AUTO:
331 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
332 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
333 case AL_DIRECT_CHANNELS_SOFT:
334 case AL_DISTANCE_MODEL:
335 case AL_SOURCE_RELATIVE:
336 case AL_LOOPING:
337 case AL_BUFFER:
338 case AL_SOURCE_STATE:
339 case AL_BUFFERS_QUEUED:
340 case AL_BUFFERS_PROCESSED:
341 case AL_SOURCE_TYPE:
342 case AL_DIRECT_FILTER:
343 case AL_BYTE_LENGTH_SOFT:
344 case AL_SAMPLE_LENGTH_SOFT:
345 case AL_SEC_LENGTH_SOFT:
346 case AL_SOURCE_RADIUS:
347 return 1;
349 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
350 return 2;
352 case AL_POSITION:
353 case AL_VELOCITY:
354 case AL_DIRECTION:
355 case AL_AUXILIARY_SEND_FILTER:
356 return 3;
358 case AL_ORIENTATION:
359 return 6;
361 case AL_SEC_OFFSET_LATENCY_SOFT:
362 break; /* Double only */
363 case AL_STEREO_ANGLES:
364 break; /* Float/double only */
366 return 0;
370 #define CHECKVAL(x) do { \
371 if(!(x)) \
372 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
373 } while(0)
375 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
377 ALint ival;
379 switch(prop)
381 case AL_BYTE_LENGTH_SOFT:
382 case AL_SAMPLE_LENGTH_SOFT:
383 case AL_SEC_LENGTH_SOFT:
384 case AL_SEC_OFFSET_LATENCY_SOFT:
385 /* Query only */
386 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
388 case AL_PITCH:
389 CHECKVAL(*values >= 0.0f);
391 Source->Pitch = *values;
392 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
393 return AL_TRUE;
395 case AL_CONE_INNER_ANGLE:
396 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
398 Source->InnerAngle = *values;
399 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
400 return AL_TRUE;
402 case AL_CONE_OUTER_ANGLE:
403 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
405 Source->OuterAngle = *values;
406 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
407 return AL_TRUE;
409 case AL_GAIN:
410 CHECKVAL(*values >= 0.0f);
412 Source->Gain = *values;
413 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
414 return AL_TRUE;
416 case AL_MAX_DISTANCE:
417 CHECKVAL(*values >= 0.0f);
419 Source->MaxDistance = *values;
420 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
421 return AL_TRUE;
423 case AL_ROLLOFF_FACTOR:
424 CHECKVAL(*values >= 0.0f);
426 Source->RollOffFactor = *values;
427 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
428 return AL_TRUE;
430 case AL_REFERENCE_DISTANCE:
431 CHECKVAL(*values >= 0.0f);
433 Source->RefDistance = *values;
434 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
435 return AL_TRUE;
437 case AL_MIN_GAIN:
438 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
440 Source->MinGain = *values;
441 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
442 return AL_TRUE;
444 case AL_MAX_GAIN:
445 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
447 Source->MaxGain = *values;
448 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
449 return AL_TRUE;
451 case AL_CONE_OUTER_GAIN:
452 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
454 Source->OuterGain = *values;
455 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
456 return AL_TRUE;
458 case AL_CONE_OUTER_GAINHF:
459 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
461 Source->OuterGainHF = *values;
462 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
463 return AL_TRUE;
465 case AL_AIR_ABSORPTION_FACTOR:
466 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
468 Source->AirAbsorptionFactor = *values;
469 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
470 return AL_TRUE;
472 case AL_ROOM_ROLLOFF_FACTOR:
473 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
475 Source->RoomRolloffFactor = *values;
476 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
477 return AL_TRUE;
479 case AL_DOPPLER_FACTOR:
480 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
482 Source->DopplerFactor = *values;
483 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
484 return AL_TRUE;
486 case AL_SEC_OFFSET:
487 case AL_SAMPLE_OFFSET:
488 case AL_BYTE_OFFSET:
489 CHECKVAL(*values >= 0.0f);
491 LockContext(Context);
492 Source->OffsetType = prop;
493 Source->Offset = *values;
495 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
496 !Context->DeferUpdates)
498 WriteLock(&Source->queue_lock);
499 if(ApplyOffset(Source) == AL_FALSE)
501 WriteUnlock(&Source->queue_lock);
502 UnlockContext(Context);
503 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
505 WriteUnlock(&Source->queue_lock);
507 UnlockContext(Context);
508 return AL_TRUE;
510 case AL_SOURCE_RADIUS:
511 CHECKVAL(*values >= 0.0f && isfinite(*values));
513 Source->Radius = *values;
514 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
515 return AL_TRUE;
517 case AL_STEREO_ANGLES:
518 CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
520 LockContext(Context);
521 Source->StereoPan[0] = values[0];
522 Source->StereoPan[1] = values[1];
523 UnlockContext(Context);
524 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
525 return AL_TRUE;
528 case AL_POSITION:
529 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
531 LockContext(Context);
532 aluVectorSet(&Source->Position, values[0], values[1], values[2], 1.0f);
533 UnlockContext(Context);
534 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
535 return AL_TRUE;
537 case AL_VELOCITY:
538 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
540 LockContext(Context);
541 aluVectorSet(&Source->Velocity, values[0], values[1], values[2], 0.0f);
542 UnlockContext(Context);
543 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
544 return AL_TRUE;
546 case AL_DIRECTION:
547 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
549 LockContext(Context);
550 aluVectorSet(&Source->Direction, values[0], values[1], values[2], 0.0f);
551 UnlockContext(Context);
552 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
553 return AL_TRUE;
555 case AL_ORIENTATION:
556 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
557 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
559 LockContext(Context);
560 Source->Orientation[0][0] = values[0];
561 Source->Orientation[0][1] = values[1];
562 Source->Orientation[0][2] = values[2];
563 Source->Orientation[1][0] = values[3];
564 Source->Orientation[1][1] = values[4];
565 Source->Orientation[1][2] = values[5];
566 UnlockContext(Context);
567 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
568 return AL_TRUE;
571 case AL_SOURCE_RELATIVE:
572 case AL_LOOPING:
573 case AL_SOURCE_STATE:
574 case AL_SOURCE_TYPE:
575 case AL_DISTANCE_MODEL:
576 case AL_DIRECT_FILTER_GAINHF_AUTO:
577 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
578 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
579 case AL_DIRECT_CHANNELS_SOFT:
580 ival = (ALint)values[0];
581 return SetSourceiv(Source, Context, prop, &ival);
583 case AL_BUFFERS_QUEUED:
584 case AL_BUFFERS_PROCESSED:
585 ival = (ALint)((ALuint)values[0]);
586 return SetSourceiv(Source, Context, prop, &ival);
588 case AL_BUFFER:
589 case AL_DIRECT_FILTER:
590 case AL_AUXILIARY_SEND_FILTER:
591 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
592 break;
595 ERR("Unexpected property: 0x%04x\n", prop);
596 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
599 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
601 ALCdevice *device = Context->Device;
602 ALbuffer *buffer = NULL;
603 ALfilter *filter = NULL;
604 ALeffectslot *slot = NULL;
605 ALbufferlistitem *oldlist;
606 ALbufferlistitem *newlist;
607 ALfloat fvals[6];
609 switch(prop)
611 case AL_SOURCE_STATE:
612 case AL_SOURCE_TYPE:
613 case AL_BUFFERS_QUEUED:
614 case AL_BUFFERS_PROCESSED:
615 case AL_BYTE_LENGTH_SOFT:
616 case AL_SAMPLE_LENGTH_SOFT:
617 case AL_SEC_LENGTH_SOFT:
618 /* Query only */
619 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
621 case AL_SOURCE_RELATIVE:
622 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
624 Source->HeadRelative = (ALboolean)*values;
625 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
626 return AL_TRUE;
628 case AL_LOOPING:
629 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
631 Source->Looping = (ALboolean)*values;
632 return AL_TRUE;
634 case AL_BUFFER:
635 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
637 WriteLock(&Source->queue_lock);
638 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
640 WriteUnlock(&Source->queue_lock);
641 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
644 if(buffer != NULL)
646 /* Add the selected buffer to a one-item queue */
647 newlist = malloc(sizeof(ALbufferlistitem));
648 newlist->buffer = buffer;
649 newlist->next = NULL;
650 IncrementRef(&buffer->ref);
652 /* Source is now Static */
653 Source->SourceType = AL_STATIC;
655 ReadLock(&buffer->lock);
656 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
657 Source->SampleSize = BytesFromFmt(buffer->FmtType);
658 ReadUnlock(&buffer->lock);
660 else
662 /* Source is now Undetermined */
663 Source->SourceType = AL_UNDETERMINED;
664 newlist = NULL;
666 oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist);
667 ATOMIC_STORE(&Source->current_buffer, newlist);
668 WriteUnlock(&Source->queue_lock);
670 /* Delete all elements in the previous queue */
671 while(oldlist != NULL)
673 ALbufferlistitem *temp = oldlist;
674 oldlist = temp->next;
676 if(temp->buffer)
677 DecrementRef(&temp->buffer->ref);
678 free(temp);
680 return AL_TRUE;
682 case AL_SEC_OFFSET:
683 case AL_SAMPLE_OFFSET:
684 case AL_BYTE_OFFSET:
685 CHECKVAL(*values >= 0);
687 LockContext(Context);
688 Source->OffsetType = prop;
689 Source->Offset = *values;
691 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
692 !Context->DeferUpdates)
694 WriteLock(&Source->queue_lock);
695 if(ApplyOffset(Source) == AL_FALSE)
697 WriteUnlock(&Source->queue_lock);
698 UnlockContext(Context);
699 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
701 WriteUnlock(&Source->queue_lock);
703 UnlockContext(Context);
704 return AL_TRUE;
706 case AL_DIRECT_FILTER:
707 CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
709 LockContext(Context);
710 if(!filter)
712 Source->Direct.Gain = 1.0f;
713 Source->Direct.GainHF = 1.0f;
714 Source->Direct.HFReference = LOWPASSFREQREF;
715 Source->Direct.GainLF = 1.0f;
716 Source->Direct.LFReference = HIGHPASSFREQREF;
718 else
720 Source->Direct.Gain = filter->Gain;
721 Source->Direct.GainHF = filter->GainHF;
722 Source->Direct.HFReference = filter->HFReference;
723 Source->Direct.GainLF = filter->GainLF;
724 Source->Direct.LFReference = filter->LFReference;
726 UnlockContext(Context);
727 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
728 return AL_TRUE;
730 case AL_DIRECT_FILTER_GAINHF_AUTO:
731 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
733 Source->DryGainHFAuto = *values;
734 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
735 return AL_TRUE;
737 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
738 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
740 Source->WetGainAuto = *values;
741 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
742 return AL_TRUE;
744 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
745 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
747 Source->WetGainHFAuto = *values;
748 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
749 return AL_TRUE;
751 case AL_DIRECT_CHANNELS_SOFT:
752 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
754 Source->DirectChannels = *values;
755 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
756 return AL_TRUE;
758 case AL_DISTANCE_MODEL:
759 CHECKVAL(*values == AL_NONE ||
760 *values == AL_INVERSE_DISTANCE ||
761 *values == AL_INVERSE_DISTANCE_CLAMPED ||
762 *values == AL_LINEAR_DISTANCE ||
763 *values == AL_LINEAR_DISTANCE_CLAMPED ||
764 *values == AL_EXPONENT_DISTANCE ||
765 *values == AL_EXPONENT_DISTANCE_CLAMPED);
767 Source->DistanceModel = *values;
768 if(Context->SourceDistanceModel)
769 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
770 return AL_TRUE;
773 case AL_AUXILIARY_SEND_FILTER:
774 LockContext(Context);
775 if(!((ALuint)values[1] < device->NumAuxSends &&
776 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
777 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
779 UnlockContext(Context);
780 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
783 /* Add refcount on the new slot, and release the previous slot */
784 if(slot) IncrementRef(&slot->ref);
785 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
786 if(slot) DecrementRef(&slot->ref);
788 if(!filter)
790 /* Disable filter */
791 Source->Send[values[1]].Gain = 1.0f;
792 Source->Send[values[1]].GainHF = 1.0f;
793 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
794 Source->Send[values[1]].GainLF = 1.0f;
795 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
797 else
799 Source->Send[values[1]].Gain = filter->Gain;
800 Source->Send[values[1]].GainHF = filter->GainHF;
801 Source->Send[values[1]].HFReference = filter->HFReference;
802 Source->Send[values[1]].GainLF = filter->GainLF;
803 Source->Send[values[1]].LFReference = filter->LFReference;
805 UnlockContext(Context);
806 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
807 return AL_TRUE;
810 /* 1x float */
811 case AL_CONE_INNER_ANGLE:
812 case AL_CONE_OUTER_ANGLE:
813 case AL_PITCH:
814 case AL_GAIN:
815 case AL_MIN_GAIN:
816 case AL_MAX_GAIN:
817 case AL_REFERENCE_DISTANCE:
818 case AL_ROLLOFF_FACTOR:
819 case AL_CONE_OUTER_GAIN:
820 case AL_MAX_DISTANCE:
821 case AL_DOPPLER_FACTOR:
822 case AL_CONE_OUTER_GAINHF:
823 case AL_AIR_ABSORPTION_FACTOR:
824 case AL_ROOM_ROLLOFF_FACTOR:
825 case AL_SOURCE_RADIUS:
826 fvals[0] = (ALfloat)*values;
827 return SetSourcefv(Source, Context, (int)prop, fvals);
829 /* 3x float */
830 case AL_POSITION:
831 case AL_VELOCITY:
832 case AL_DIRECTION:
833 fvals[0] = (ALfloat)values[0];
834 fvals[1] = (ALfloat)values[1];
835 fvals[2] = (ALfloat)values[2];
836 return SetSourcefv(Source, Context, (int)prop, fvals);
838 /* 6x float */
839 case AL_ORIENTATION:
840 fvals[0] = (ALfloat)values[0];
841 fvals[1] = (ALfloat)values[1];
842 fvals[2] = (ALfloat)values[2];
843 fvals[3] = (ALfloat)values[3];
844 fvals[4] = (ALfloat)values[4];
845 fvals[5] = (ALfloat)values[5];
846 return SetSourcefv(Source, Context, (int)prop, fvals);
848 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
849 case AL_SEC_OFFSET_LATENCY_SOFT:
850 case AL_STEREO_ANGLES:
851 break;
854 ERR("Unexpected property: 0x%04x\n", prop);
855 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
858 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
860 ALfloat fvals[6];
861 ALint ivals[3];
863 switch(prop)
865 case AL_SOURCE_TYPE:
866 case AL_BUFFERS_QUEUED:
867 case AL_BUFFERS_PROCESSED:
868 case AL_SOURCE_STATE:
869 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
870 case AL_BYTE_LENGTH_SOFT:
871 case AL_SAMPLE_LENGTH_SOFT:
872 case AL_SEC_LENGTH_SOFT:
873 /* Query only */
874 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
877 /* 1x int */
878 case AL_SOURCE_RELATIVE:
879 case AL_LOOPING:
880 case AL_SEC_OFFSET:
881 case AL_SAMPLE_OFFSET:
882 case AL_BYTE_OFFSET:
883 case AL_DIRECT_FILTER_GAINHF_AUTO:
884 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
885 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
886 case AL_DIRECT_CHANNELS_SOFT:
887 case AL_DISTANCE_MODEL:
888 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
890 ivals[0] = (ALint)*values;
891 return SetSourceiv(Source, Context, (int)prop, ivals);
893 /* 1x uint */
894 case AL_BUFFER:
895 case AL_DIRECT_FILTER:
896 CHECKVAL(*values <= UINT_MAX && *values >= 0);
898 ivals[0] = (ALuint)*values;
899 return SetSourceiv(Source, Context, (int)prop, ivals);
901 /* 3x uint */
902 case AL_AUXILIARY_SEND_FILTER:
903 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
904 values[1] <= UINT_MAX && values[1] >= 0 &&
905 values[2] <= UINT_MAX && values[2] >= 0);
907 ivals[0] = (ALuint)values[0];
908 ivals[1] = (ALuint)values[1];
909 ivals[2] = (ALuint)values[2];
910 return SetSourceiv(Source, Context, (int)prop, ivals);
912 /* 1x float */
913 case AL_CONE_INNER_ANGLE:
914 case AL_CONE_OUTER_ANGLE:
915 case AL_PITCH:
916 case AL_GAIN:
917 case AL_MIN_GAIN:
918 case AL_MAX_GAIN:
919 case AL_REFERENCE_DISTANCE:
920 case AL_ROLLOFF_FACTOR:
921 case AL_CONE_OUTER_GAIN:
922 case AL_MAX_DISTANCE:
923 case AL_DOPPLER_FACTOR:
924 case AL_CONE_OUTER_GAINHF:
925 case AL_AIR_ABSORPTION_FACTOR:
926 case AL_ROOM_ROLLOFF_FACTOR:
927 case AL_SOURCE_RADIUS:
928 fvals[0] = (ALfloat)*values;
929 return SetSourcefv(Source, Context, (int)prop, fvals);
931 /* 3x float */
932 case AL_POSITION:
933 case AL_VELOCITY:
934 case AL_DIRECTION:
935 fvals[0] = (ALfloat)values[0];
936 fvals[1] = (ALfloat)values[1];
937 fvals[2] = (ALfloat)values[2];
938 return SetSourcefv(Source, Context, (int)prop, fvals);
940 /* 6x float */
941 case AL_ORIENTATION:
942 fvals[0] = (ALfloat)values[0];
943 fvals[1] = (ALfloat)values[1];
944 fvals[2] = (ALfloat)values[2];
945 fvals[3] = (ALfloat)values[3];
946 fvals[4] = (ALfloat)values[4];
947 fvals[5] = (ALfloat)values[5];
948 return SetSourcefv(Source, Context, (int)prop, fvals);
950 case AL_SEC_OFFSET_LATENCY_SOFT:
951 case AL_STEREO_ANGLES:
952 break;
955 ERR("Unexpected property: 0x%04x\n", prop);
956 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
959 #undef CHECKVAL
962 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
964 ALCdevice *device = Context->Device;
965 ALbufferlistitem *BufferList;
966 ALint ivals[3];
967 ALboolean err;
969 switch(prop)
971 case AL_GAIN:
972 *values = Source->Gain;
973 return AL_TRUE;
975 case AL_PITCH:
976 *values = Source->Pitch;
977 return AL_TRUE;
979 case AL_MAX_DISTANCE:
980 *values = Source->MaxDistance;
981 return AL_TRUE;
983 case AL_ROLLOFF_FACTOR:
984 *values = Source->RollOffFactor;
985 return AL_TRUE;
987 case AL_REFERENCE_DISTANCE:
988 *values = Source->RefDistance;
989 return AL_TRUE;
991 case AL_CONE_INNER_ANGLE:
992 *values = Source->InnerAngle;
993 return AL_TRUE;
995 case AL_CONE_OUTER_ANGLE:
996 *values = Source->OuterAngle;
997 return AL_TRUE;
999 case AL_MIN_GAIN:
1000 *values = Source->MinGain;
1001 return AL_TRUE;
1003 case AL_MAX_GAIN:
1004 *values = Source->MaxGain;
1005 return AL_TRUE;
1007 case AL_CONE_OUTER_GAIN:
1008 *values = Source->OuterGain;
1009 return AL_TRUE;
1011 case AL_SEC_OFFSET:
1012 case AL_SAMPLE_OFFSET:
1013 case AL_BYTE_OFFSET:
1014 LockContext(Context);
1015 *values = GetSourceOffset(Source, prop);
1016 UnlockContext(Context);
1017 return AL_TRUE;
1019 case AL_CONE_OUTER_GAINHF:
1020 *values = Source->OuterGainHF;
1021 return AL_TRUE;
1023 case AL_AIR_ABSORPTION_FACTOR:
1024 *values = Source->AirAbsorptionFactor;
1025 return AL_TRUE;
1027 case AL_ROOM_ROLLOFF_FACTOR:
1028 *values = Source->RoomRolloffFactor;
1029 return AL_TRUE;
1031 case AL_DOPPLER_FACTOR:
1032 *values = Source->DopplerFactor;
1033 return AL_TRUE;
1035 case AL_SEC_LENGTH_SOFT:
1036 ReadLock(&Source->queue_lock);
1037 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1038 *values = 0;
1039 else
1041 ALint length = 0;
1042 ALsizei freq = 1;
1043 do {
1044 ALbuffer *buffer = BufferList->buffer;
1045 if(buffer && buffer->SampleLen > 0)
1047 freq = buffer->Frequency;
1048 length += buffer->SampleLen;
1050 } while((BufferList=BufferList->next) != NULL);
1051 *values = (ALdouble)length / (ALdouble)freq;
1053 ReadUnlock(&Source->queue_lock);
1054 return AL_TRUE;
1056 case AL_SOURCE_RADIUS:
1057 *values = Source->Radius;
1058 return AL_TRUE;
1060 case AL_STEREO_ANGLES:
1061 LockContext(Context);
1062 values[0] = Source->StereoPan[0];
1063 values[1] = Source->StereoPan[1];
1064 UnlockContext(Context);
1065 return AL_TRUE;
1067 case AL_SEC_OFFSET_LATENCY_SOFT:
1068 LockContext(Context);
1069 values[0] = GetSourceSecOffset(Source);
1070 values[1] = (ALdouble)(V0(device->Backend,getLatency)()) /
1071 1000000000.0;
1072 UnlockContext(Context);
1073 return AL_TRUE;
1075 case AL_POSITION:
1076 LockContext(Context);
1077 values[0] = Source->Position.v[0];
1078 values[1] = Source->Position.v[1];
1079 values[2] = Source->Position.v[2];
1080 UnlockContext(Context);
1081 return AL_TRUE;
1083 case AL_VELOCITY:
1084 LockContext(Context);
1085 values[0] = Source->Velocity.v[0];
1086 values[1] = Source->Velocity.v[1];
1087 values[2] = Source->Velocity.v[2];
1088 UnlockContext(Context);
1089 return AL_TRUE;
1091 case AL_DIRECTION:
1092 LockContext(Context);
1093 values[0] = Source->Direction.v[0];
1094 values[1] = Source->Direction.v[1];
1095 values[2] = Source->Direction.v[2];
1096 UnlockContext(Context);
1097 return AL_TRUE;
1099 case AL_ORIENTATION:
1100 LockContext(Context);
1101 values[0] = Source->Orientation[0][0];
1102 values[1] = Source->Orientation[0][1];
1103 values[2] = Source->Orientation[0][2];
1104 values[3] = Source->Orientation[1][0];
1105 values[4] = Source->Orientation[1][1];
1106 values[5] = Source->Orientation[1][2];
1107 UnlockContext(Context);
1108 return AL_TRUE;
1110 /* 1x int */
1111 case AL_SOURCE_RELATIVE:
1112 case AL_LOOPING:
1113 case AL_SOURCE_STATE:
1114 case AL_BUFFERS_QUEUED:
1115 case AL_BUFFERS_PROCESSED:
1116 case AL_SOURCE_TYPE:
1117 case AL_DIRECT_FILTER_GAINHF_AUTO:
1118 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1119 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1120 case AL_DIRECT_CHANNELS_SOFT:
1121 case AL_BYTE_LENGTH_SOFT:
1122 case AL_SAMPLE_LENGTH_SOFT:
1123 case AL_DISTANCE_MODEL:
1124 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1125 *values = (ALdouble)ivals[0];
1126 return err;
1128 case AL_BUFFER:
1129 case AL_DIRECT_FILTER:
1130 case AL_AUXILIARY_SEND_FILTER:
1131 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1132 break;
1135 ERR("Unexpected property: 0x%04x\n", prop);
1136 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1139 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1141 ALbufferlistitem *BufferList;
1142 ALdouble dvals[6];
1143 ALboolean err;
1145 switch(prop)
1147 case AL_SOURCE_RELATIVE:
1148 *values = Source->HeadRelative;
1149 return AL_TRUE;
1151 case AL_LOOPING:
1152 *values = Source->Looping;
1153 return AL_TRUE;
1155 case AL_BUFFER:
1156 ReadLock(&Source->queue_lock);
1157 BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) :
1158 ATOMIC_LOAD(&Source->current_buffer);
1159 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1160 ReadUnlock(&Source->queue_lock);
1161 return AL_TRUE;
1163 case AL_SOURCE_STATE:
1164 *values = Source->state;
1165 return AL_TRUE;
1167 case AL_BYTE_LENGTH_SOFT:
1168 ReadLock(&Source->queue_lock);
1169 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1170 *values = 0;
1171 else
1173 ALint length = 0;
1174 do {
1175 ALbuffer *buffer = BufferList->buffer;
1176 if(buffer && buffer->SampleLen > 0)
1178 ALuint byte_align, sample_align;
1179 if(buffer->OriginalType == UserFmtIMA4)
1181 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1182 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1183 sample_align = buffer->OriginalAlign;
1185 else if(buffer->OriginalType == UserFmtMSADPCM)
1187 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1188 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1189 sample_align = buffer->OriginalAlign;
1191 else
1193 ALsizei align = buffer->OriginalAlign;
1194 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1195 sample_align = buffer->OriginalAlign;
1198 length += buffer->SampleLen / sample_align * byte_align;
1200 } while((BufferList=BufferList->next) != NULL);
1201 *values = length;
1203 ReadUnlock(&Source->queue_lock);
1204 return AL_TRUE;
1206 case AL_SAMPLE_LENGTH_SOFT:
1207 ReadLock(&Source->queue_lock);
1208 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1209 *values = 0;
1210 else
1212 ALint length = 0;
1213 do {
1214 ALbuffer *buffer = BufferList->buffer;
1215 if(buffer) length += buffer->SampleLen;
1216 } while((BufferList=BufferList->next) != NULL);
1217 *values = length;
1219 ReadUnlock(&Source->queue_lock);
1220 return AL_TRUE;
1222 case AL_BUFFERS_QUEUED:
1223 ReadLock(&Source->queue_lock);
1224 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1225 *values = 0;
1226 else
1228 ALsizei count = 0;
1229 do {
1230 ++count;
1231 } while((BufferList=BufferList->next) != NULL);
1232 *values = count;
1234 ReadUnlock(&Source->queue_lock);
1235 return AL_TRUE;
1237 case AL_BUFFERS_PROCESSED:
1238 ReadLock(&Source->queue_lock);
1239 if(Source->Looping || Source->SourceType != AL_STREAMING)
1241 /* Buffers on a looping source are in a perpetual state of
1242 * PENDING, so don't report any as PROCESSED */
1243 *values = 0;
1245 else
1247 const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue);
1248 const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer);
1249 ALsizei played = 0;
1250 while(BufferList && BufferList != Current)
1252 played++;
1253 BufferList = BufferList->next;
1255 *values = played;
1257 ReadUnlock(&Source->queue_lock);
1258 return AL_TRUE;
1260 case AL_SOURCE_TYPE:
1261 *values = Source->SourceType;
1262 return AL_TRUE;
1264 case AL_DIRECT_FILTER_GAINHF_AUTO:
1265 *values = Source->DryGainHFAuto;
1266 return AL_TRUE;
1268 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1269 *values = Source->WetGainAuto;
1270 return AL_TRUE;
1272 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1273 *values = Source->WetGainHFAuto;
1274 return AL_TRUE;
1276 case AL_DIRECT_CHANNELS_SOFT:
1277 *values = Source->DirectChannels;
1278 return AL_TRUE;
1280 case AL_DISTANCE_MODEL:
1281 *values = Source->DistanceModel;
1282 return AL_TRUE;
1284 /* 1x float/double */
1285 case AL_CONE_INNER_ANGLE:
1286 case AL_CONE_OUTER_ANGLE:
1287 case AL_PITCH:
1288 case AL_GAIN:
1289 case AL_MIN_GAIN:
1290 case AL_MAX_GAIN:
1291 case AL_REFERENCE_DISTANCE:
1292 case AL_ROLLOFF_FACTOR:
1293 case AL_CONE_OUTER_GAIN:
1294 case AL_MAX_DISTANCE:
1295 case AL_SEC_OFFSET:
1296 case AL_SAMPLE_OFFSET:
1297 case AL_BYTE_OFFSET:
1298 case AL_DOPPLER_FACTOR:
1299 case AL_AIR_ABSORPTION_FACTOR:
1300 case AL_ROOM_ROLLOFF_FACTOR:
1301 case AL_CONE_OUTER_GAINHF:
1302 case AL_SEC_LENGTH_SOFT:
1303 case AL_SOURCE_RADIUS:
1304 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1305 *values = (ALint)dvals[0];
1306 return err;
1308 /* 3x float/double */
1309 case AL_POSITION:
1310 case AL_VELOCITY:
1311 case AL_DIRECTION:
1312 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1314 values[0] = (ALint)dvals[0];
1315 values[1] = (ALint)dvals[1];
1316 values[2] = (ALint)dvals[2];
1318 return err;
1320 /* 6x float/double */
1321 case AL_ORIENTATION:
1322 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1324 values[0] = (ALint)dvals[0];
1325 values[1] = (ALint)dvals[1];
1326 values[2] = (ALint)dvals[2];
1327 values[3] = (ALint)dvals[3];
1328 values[4] = (ALint)dvals[4];
1329 values[5] = (ALint)dvals[5];
1331 return err;
1333 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1334 break; /* i64 only */
1335 case AL_SEC_OFFSET_LATENCY_SOFT:
1336 break; /* Double only */
1337 case AL_STEREO_ANGLES:
1338 break; /* Float/double only */
1340 case AL_DIRECT_FILTER:
1341 case AL_AUXILIARY_SEND_FILTER:
1342 break; /* ??? */
1345 ERR("Unexpected property: 0x%04x\n", prop);
1346 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1349 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1351 ALCdevice *device = Context->Device;
1352 ALdouble dvals[6];
1353 ALint ivals[3];
1354 ALboolean err;
1356 switch(prop)
1358 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1359 LockContext(Context);
1360 values[0] = GetSourceSampleOffset(Source);
1361 values[1] = V0(device->Backend,getLatency)();
1362 UnlockContext(Context);
1363 return AL_TRUE;
1365 /* 1x float/double */
1366 case AL_CONE_INNER_ANGLE:
1367 case AL_CONE_OUTER_ANGLE:
1368 case AL_PITCH:
1369 case AL_GAIN:
1370 case AL_MIN_GAIN:
1371 case AL_MAX_GAIN:
1372 case AL_REFERENCE_DISTANCE:
1373 case AL_ROLLOFF_FACTOR:
1374 case AL_CONE_OUTER_GAIN:
1375 case AL_MAX_DISTANCE:
1376 case AL_SEC_OFFSET:
1377 case AL_SAMPLE_OFFSET:
1378 case AL_BYTE_OFFSET:
1379 case AL_DOPPLER_FACTOR:
1380 case AL_AIR_ABSORPTION_FACTOR:
1381 case AL_ROOM_ROLLOFF_FACTOR:
1382 case AL_CONE_OUTER_GAINHF:
1383 case AL_SEC_LENGTH_SOFT:
1384 case AL_SOURCE_RADIUS:
1385 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1386 *values = (ALint64)dvals[0];
1387 return err;
1389 /* 3x float/double */
1390 case AL_POSITION:
1391 case AL_VELOCITY:
1392 case AL_DIRECTION:
1393 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1395 values[0] = (ALint64)dvals[0];
1396 values[1] = (ALint64)dvals[1];
1397 values[2] = (ALint64)dvals[2];
1399 return err;
1401 /* 6x float/double */
1402 case AL_ORIENTATION:
1403 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1405 values[0] = (ALint64)dvals[0];
1406 values[1] = (ALint64)dvals[1];
1407 values[2] = (ALint64)dvals[2];
1408 values[3] = (ALint64)dvals[3];
1409 values[4] = (ALint64)dvals[4];
1410 values[5] = (ALint64)dvals[5];
1412 return err;
1414 /* 1x int */
1415 case AL_SOURCE_RELATIVE:
1416 case AL_LOOPING:
1417 case AL_SOURCE_STATE:
1418 case AL_BUFFERS_QUEUED:
1419 case AL_BUFFERS_PROCESSED:
1420 case AL_BYTE_LENGTH_SOFT:
1421 case AL_SAMPLE_LENGTH_SOFT:
1422 case AL_SOURCE_TYPE:
1423 case AL_DIRECT_FILTER_GAINHF_AUTO:
1424 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1425 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1426 case AL_DIRECT_CHANNELS_SOFT:
1427 case AL_DISTANCE_MODEL:
1428 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1429 *values = ivals[0];
1430 return err;
1432 /* 1x uint */
1433 case AL_BUFFER:
1434 case AL_DIRECT_FILTER:
1435 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1436 *values = (ALuint)ivals[0];
1437 return err;
1439 /* 3x uint */
1440 case AL_AUXILIARY_SEND_FILTER:
1441 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1443 values[0] = (ALuint)ivals[0];
1444 values[1] = (ALuint)ivals[1];
1445 values[2] = (ALuint)ivals[2];
1447 return err;
1449 case AL_SEC_OFFSET_LATENCY_SOFT:
1450 break; /* Double only */
1451 case AL_STEREO_ANGLES:
1452 break; /* Float/double only */
1455 ERR("Unexpected property: 0x%04x\n", prop);
1456 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1460 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1462 ALCcontext *context;
1463 ALsizei cur = 0;
1464 ALenum err;
1466 context = GetContextRef();
1467 if(!context) return;
1469 if(!(n >= 0))
1470 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1471 for(cur = 0;cur < n;cur++)
1473 ALsource *source = al_calloc(16, sizeof(ALsource));
1474 if(!source)
1476 alDeleteSources(cur, sources);
1477 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1479 InitSourceParams(source);
1481 err = NewThunkEntry(&source->id);
1482 if(err == AL_NO_ERROR)
1483 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1484 if(err != AL_NO_ERROR)
1486 FreeThunkEntry(source->id);
1487 memset(source, 0, sizeof(ALsource));
1488 al_free(source);
1490 alDeleteSources(cur, sources);
1491 SET_ERROR_AND_GOTO(context, err, done);
1494 sources[cur] = source->id;
1497 done:
1498 ALCcontext_DecRef(context);
1502 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1504 ALCcontext *context;
1505 ALbufferlistitem *BufferList;
1506 ALsource *Source;
1507 ALsizei i, j;
1509 context = GetContextRef();
1510 if(!context) return;
1512 if(!(n >= 0))
1513 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1515 /* Check that all Sources are valid */
1516 for(i = 0;i < n;i++)
1518 if(LookupSource(context, sources[i]) == NULL)
1519 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1521 for(i = 0;i < n;i++)
1523 ALvoice *voice, *voice_end;
1525 if((Source=RemoveSource(context, sources[i])) == NULL)
1526 continue;
1527 FreeThunkEntry(Source->id);
1529 LockContext(context);
1530 voice = context->Voices;
1531 voice_end = voice + context->VoiceCount;
1532 while(voice != voice_end)
1534 ALsource *old = Source;
1535 if(COMPARE_EXCHANGE(&voice->Source, &old, NULL))
1536 break;
1537 voice++;
1539 UnlockContext(context);
1541 BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, NULL);
1542 while(BufferList != NULL)
1544 ALbufferlistitem *next = BufferList->next;
1545 if(BufferList->buffer != NULL)
1546 DecrementRef(&BufferList->buffer->ref);
1547 free(BufferList);
1548 BufferList = next;
1551 for(j = 0;j < MAX_SENDS;++j)
1553 if(Source->Send[j].Slot)
1554 DecrementRef(&Source->Send[j].Slot->ref);
1555 Source->Send[j].Slot = NULL;
1558 memset(Source, 0, sizeof(*Source));
1559 al_free(Source);
1562 done:
1563 ALCcontext_DecRef(context);
1567 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1569 ALCcontext *context;
1570 ALboolean ret;
1572 context = GetContextRef();
1573 if(!context) return AL_FALSE;
1575 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1577 ALCcontext_DecRef(context);
1579 return ret;
1583 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1585 ALCcontext *Context;
1586 ALsource *Source;
1588 Context = GetContextRef();
1589 if(!Context) return;
1591 if((Source=LookupSource(Context, source)) == NULL)
1592 alSetError(Context, AL_INVALID_NAME);
1593 else if(!(FloatValsByProp(param) == 1))
1594 alSetError(Context, AL_INVALID_ENUM);
1595 else
1596 SetSourcefv(Source, Context, param, &value);
1598 ALCcontext_DecRef(Context);
1601 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1603 ALCcontext *Context;
1604 ALsource *Source;
1606 Context = GetContextRef();
1607 if(!Context) return;
1609 if((Source=LookupSource(Context, source)) == NULL)
1610 alSetError(Context, AL_INVALID_NAME);
1611 else if(!(FloatValsByProp(param) == 3))
1612 alSetError(Context, AL_INVALID_ENUM);
1613 else
1615 ALfloat fvals[3] = { value1, value2, value3 };
1616 SetSourcefv(Source, Context, param, fvals);
1619 ALCcontext_DecRef(Context);
1622 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1624 ALCcontext *Context;
1625 ALsource *Source;
1627 Context = GetContextRef();
1628 if(!Context) return;
1630 if((Source=LookupSource(Context, source)) == NULL)
1631 alSetError(Context, AL_INVALID_NAME);
1632 else if(!values)
1633 alSetError(Context, AL_INVALID_VALUE);
1634 else if(!(FloatValsByProp(param) > 0))
1635 alSetError(Context, AL_INVALID_ENUM);
1636 else
1637 SetSourcefv(Source, Context, param, values);
1639 ALCcontext_DecRef(Context);
1643 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1645 ALCcontext *Context;
1646 ALsource *Source;
1648 Context = GetContextRef();
1649 if(!Context) return;
1651 if((Source=LookupSource(Context, source)) == NULL)
1652 alSetError(Context, AL_INVALID_NAME);
1653 else if(!(DoubleValsByProp(param) == 1))
1654 alSetError(Context, AL_INVALID_ENUM);
1655 else
1657 ALfloat fval = (ALfloat)value;
1658 SetSourcefv(Source, Context, param, &fval);
1661 ALCcontext_DecRef(Context);
1664 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1666 ALCcontext *Context;
1667 ALsource *Source;
1669 Context = GetContextRef();
1670 if(!Context) return;
1672 if((Source=LookupSource(Context, source)) == NULL)
1673 alSetError(Context, AL_INVALID_NAME);
1674 else if(!(DoubleValsByProp(param) == 3))
1675 alSetError(Context, AL_INVALID_ENUM);
1676 else
1678 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1679 SetSourcefv(Source, Context, param, fvals);
1682 ALCcontext_DecRef(Context);
1685 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1687 ALCcontext *Context;
1688 ALsource *Source;
1689 ALint count;
1691 Context = GetContextRef();
1692 if(!Context) return;
1694 if((Source=LookupSource(Context, source)) == NULL)
1695 alSetError(Context, AL_INVALID_NAME);
1696 else if(!values)
1697 alSetError(Context, AL_INVALID_VALUE);
1698 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1699 alSetError(Context, AL_INVALID_ENUM);
1700 else
1702 ALfloat fvals[6];
1703 ALint i;
1705 for(i = 0;i < count;i++)
1706 fvals[i] = (ALfloat)values[i];
1707 SetSourcefv(Source, Context, param, fvals);
1710 ALCcontext_DecRef(Context);
1714 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1716 ALCcontext *Context;
1717 ALsource *Source;
1719 Context = GetContextRef();
1720 if(!Context) return;
1722 if((Source=LookupSource(Context, source)) == NULL)
1723 alSetError(Context, AL_INVALID_NAME);
1724 else if(!(IntValsByProp(param) == 1))
1725 alSetError(Context, AL_INVALID_ENUM);
1726 else
1727 SetSourceiv(Source, Context, param, &value);
1729 ALCcontext_DecRef(Context);
1732 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1734 ALCcontext *Context;
1735 ALsource *Source;
1737 Context = GetContextRef();
1738 if(!Context) return;
1740 if((Source=LookupSource(Context, source)) == NULL)
1741 alSetError(Context, AL_INVALID_NAME);
1742 else if(!(IntValsByProp(param) == 3))
1743 alSetError(Context, AL_INVALID_ENUM);
1744 else
1746 ALint ivals[3] = { value1, value2, value3 };
1747 SetSourceiv(Source, Context, param, ivals);
1750 ALCcontext_DecRef(Context);
1753 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1755 ALCcontext *Context;
1756 ALsource *Source;
1758 Context = GetContextRef();
1759 if(!Context) return;
1761 if((Source=LookupSource(Context, source)) == NULL)
1762 alSetError(Context, AL_INVALID_NAME);
1763 else if(!values)
1764 alSetError(Context, AL_INVALID_VALUE);
1765 else if(!(IntValsByProp(param) > 0))
1766 alSetError(Context, AL_INVALID_ENUM);
1767 else
1768 SetSourceiv(Source, Context, param, values);
1770 ALCcontext_DecRef(Context);
1774 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1776 ALCcontext *Context;
1777 ALsource *Source;
1779 Context = GetContextRef();
1780 if(!Context) return;
1782 if((Source=LookupSource(Context, source)) == NULL)
1783 alSetError(Context, AL_INVALID_NAME);
1784 else if(!(Int64ValsByProp(param) == 1))
1785 alSetError(Context, AL_INVALID_ENUM);
1786 else
1787 SetSourcei64v(Source, Context, param, &value);
1789 ALCcontext_DecRef(Context);
1792 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1794 ALCcontext *Context;
1795 ALsource *Source;
1797 Context = GetContextRef();
1798 if(!Context) return;
1800 if((Source=LookupSource(Context, source)) == NULL)
1801 alSetError(Context, AL_INVALID_NAME);
1802 else if(!(Int64ValsByProp(param) == 3))
1803 alSetError(Context, AL_INVALID_ENUM);
1804 else
1806 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1807 SetSourcei64v(Source, Context, param, i64vals);
1810 ALCcontext_DecRef(Context);
1813 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1815 ALCcontext *Context;
1816 ALsource *Source;
1818 Context = GetContextRef();
1819 if(!Context) return;
1821 if((Source=LookupSource(Context, source)) == NULL)
1822 alSetError(Context, AL_INVALID_NAME);
1823 else if(!values)
1824 alSetError(Context, AL_INVALID_VALUE);
1825 else if(!(Int64ValsByProp(param) > 0))
1826 alSetError(Context, AL_INVALID_ENUM);
1827 else
1828 SetSourcei64v(Source, Context, param, values);
1830 ALCcontext_DecRef(Context);
1834 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1836 ALCcontext *Context;
1837 ALsource *Source;
1839 Context = GetContextRef();
1840 if(!Context) return;
1842 if((Source=LookupSource(Context, source)) == NULL)
1843 alSetError(Context, AL_INVALID_NAME);
1844 else if(!value)
1845 alSetError(Context, AL_INVALID_VALUE);
1846 else if(!(FloatValsByProp(param) == 1))
1847 alSetError(Context, AL_INVALID_ENUM);
1848 else
1850 ALdouble dval;
1851 if(GetSourcedv(Source, Context, param, &dval))
1852 *value = (ALfloat)dval;
1855 ALCcontext_DecRef(Context);
1859 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1861 ALCcontext *Context;
1862 ALsource *Source;
1864 Context = GetContextRef();
1865 if(!Context) return;
1867 if((Source=LookupSource(Context, source)) == NULL)
1868 alSetError(Context, AL_INVALID_NAME);
1869 else if(!(value1 && value2 && value3))
1870 alSetError(Context, AL_INVALID_VALUE);
1871 else if(!(FloatValsByProp(param) == 3))
1872 alSetError(Context, AL_INVALID_ENUM);
1873 else
1875 ALdouble dvals[3];
1876 if(GetSourcedv(Source, Context, param, dvals))
1878 *value1 = (ALfloat)dvals[0];
1879 *value2 = (ALfloat)dvals[1];
1880 *value3 = (ALfloat)dvals[2];
1884 ALCcontext_DecRef(Context);
1888 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1890 ALCcontext *Context;
1891 ALsource *Source;
1892 ALint count;
1894 Context = GetContextRef();
1895 if(!Context) return;
1897 if((Source=LookupSource(Context, source)) == NULL)
1898 alSetError(Context, AL_INVALID_NAME);
1899 else if(!values)
1900 alSetError(Context, AL_INVALID_VALUE);
1901 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
1902 alSetError(Context, AL_INVALID_ENUM);
1903 else
1905 ALdouble dvals[6];
1906 if(GetSourcedv(Source, Context, param, dvals))
1908 ALint i;
1909 for(i = 0;i < count;i++)
1910 values[i] = (ALfloat)dvals[i];
1914 ALCcontext_DecRef(Context);
1918 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1920 ALCcontext *Context;
1921 ALsource *Source;
1923 Context = GetContextRef();
1924 if(!Context) return;
1926 if((Source=LookupSource(Context, source)) == NULL)
1927 alSetError(Context, AL_INVALID_NAME);
1928 else if(!value)
1929 alSetError(Context, AL_INVALID_VALUE);
1930 else if(!(DoubleValsByProp(param) == 1))
1931 alSetError(Context, AL_INVALID_ENUM);
1932 else
1933 GetSourcedv(Source, Context, param, value);
1935 ALCcontext_DecRef(Context);
1938 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1940 ALCcontext *Context;
1941 ALsource *Source;
1943 Context = GetContextRef();
1944 if(!Context) return;
1946 if((Source=LookupSource(Context, source)) == NULL)
1947 alSetError(Context, AL_INVALID_NAME);
1948 else if(!(value1 && value2 && value3))
1949 alSetError(Context, AL_INVALID_VALUE);
1950 else if(!(DoubleValsByProp(param) == 3))
1951 alSetError(Context, AL_INVALID_ENUM);
1952 else
1954 ALdouble dvals[3];
1955 if(GetSourcedv(Source, Context, param, dvals))
1957 *value1 = dvals[0];
1958 *value2 = dvals[1];
1959 *value3 = dvals[2];
1963 ALCcontext_DecRef(Context);
1966 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1968 ALCcontext *Context;
1969 ALsource *Source;
1971 Context = GetContextRef();
1972 if(!Context) return;
1974 if((Source=LookupSource(Context, source)) == NULL)
1975 alSetError(Context, AL_INVALID_NAME);
1976 else if(!values)
1977 alSetError(Context, AL_INVALID_VALUE);
1978 else if(!(DoubleValsByProp(param) > 0))
1979 alSetError(Context, AL_INVALID_ENUM);
1980 else
1981 GetSourcedv(Source, Context, param, values);
1983 ALCcontext_DecRef(Context);
1987 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1989 ALCcontext *Context;
1990 ALsource *Source;
1992 Context = GetContextRef();
1993 if(!Context) return;
1995 if((Source=LookupSource(Context, source)) == NULL)
1996 alSetError(Context, AL_INVALID_NAME);
1997 else if(!value)
1998 alSetError(Context, AL_INVALID_VALUE);
1999 else if(!(IntValsByProp(param) == 1))
2000 alSetError(Context, AL_INVALID_ENUM);
2001 else
2002 GetSourceiv(Source, Context, param, value);
2004 ALCcontext_DecRef(Context);
2008 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2010 ALCcontext *Context;
2011 ALsource *Source;
2013 Context = GetContextRef();
2014 if(!Context) return;
2016 if((Source=LookupSource(Context, source)) == NULL)
2017 alSetError(Context, AL_INVALID_NAME);
2018 else if(!(value1 && value2 && value3))
2019 alSetError(Context, AL_INVALID_VALUE);
2020 else if(!(IntValsByProp(param) == 3))
2021 alSetError(Context, AL_INVALID_ENUM);
2022 else
2024 ALint ivals[3];
2025 if(GetSourceiv(Source, Context, param, ivals))
2027 *value1 = ivals[0];
2028 *value2 = ivals[1];
2029 *value3 = ivals[2];
2033 ALCcontext_DecRef(Context);
2037 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2039 ALCcontext *Context;
2040 ALsource *Source;
2042 Context = GetContextRef();
2043 if(!Context) return;
2045 if((Source=LookupSource(Context, source)) == NULL)
2046 alSetError(Context, AL_INVALID_NAME);
2047 else if(!values)
2048 alSetError(Context, AL_INVALID_VALUE);
2049 else if(!(IntValsByProp(param) > 0))
2050 alSetError(Context, AL_INVALID_ENUM);
2051 else
2052 GetSourceiv(Source, Context, param, values);
2054 ALCcontext_DecRef(Context);
2058 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2060 ALCcontext *Context;
2061 ALsource *Source;
2063 Context = GetContextRef();
2064 if(!Context) return;
2066 if((Source=LookupSource(Context, source)) == NULL)
2067 alSetError(Context, AL_INVALID_NAME);
2068 else if(!value)
2069 alSetError(Context, AL_INVALID_VALUE);
2070 else if(!(Int64ValsByProp(param) == 1))
2071 alSetError(Context, AL_INVALID_ENUM);
2072 else
2073 GetSourcei64v(Source, Context, param, value);
2075 ALCcontext_DecRef(Context);
2078 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2080 ALCcontext *Context;
2081 ALsource *Source;
2083 Context = GetContextRef();
2084 if(!Context) return;
2086 if((Source=LookupSource(Context, source)) == NULL)
2087 alSetError(Context, AL_INVALID_NAME);
2088 else if(!(value1 && value2 && value3))
2089 alSetError(Context, AL_INVALID_VALUE);
2090 else if(!(Int64ValsByProp(param) == 3))
2091 alSetError(Context, AL_INVALID_ENUM);
2092 else
2094 ALint64 i64vals[3];
2095 if(GetSourcei64v(Source, Context, param, i64vals))
2097 *value1 = i64vals[0];
2098 *value2 = i64vals[1];
2099 *value3 = i64vals[2];
2103 ALCcontext_DecRef(Context);
2106 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2108 ALCcontext *Context;
2109 ALsource *Source;
2111 Context = GetContextRef();
2112 if(!Context) return;
2114 if((Source=LookupSource(Context, source)) == NULL)
2115 alSetError(Context, AL_INVALID_NAME);
2116 else if(!values)
2117 alSetError(Context, AL_INVALID_VALUE);
2118 else if(!(Int64ValsByProp(param) > 0))
2119 alSetError(Context, AL_INVALID_ENUM);
2120 else
2121 GetSourcei64v(Source, Context, param, values);
2123 ALCcontext_DecRef(Context);
2127 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2129 alSourcePlayv(1, &source);
2131 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2133 ALCcontext *context;
2134 ALsource *source;
2135 ALsizei i;
2137 context = GetContextRef();
2138 if(!context) return;
2140 if(!(n >= 0))
2141 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2142 for(i = 0;i < n;i++)
2144 if(!LookupSource(context, sources[i]))
2145 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2148 LockContext(context);
2149 while(n > context->MaxVoices-context->VoiceCount)
2151 ALvoice *temp = NULL;
2152 ALsizei newcount;
2154 newcount = context->MaxVoices << 1;
2155 if(newcount > 0)
2156 temp = realloc(context->Voices, newcount * sizeof(context->Voices[0]));
2157 if(!temp)
2159 UnlockContext(context);
2160 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2162 memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0]));
2164 context->Voices = temp;
2165 context->MaxVoices = newcount;
2168 for(i = 0;i < n;i++)
2170 source = LookupSource(context, sources[i]);
2171 if(context->DeferUpdates) source->new_state = AL_PLAYING;
2172 else SetSourceState(source, context, AL_PLAYING);
2174 UnlockContext(context);
2176 done:
2177 ALCcontext_DecRef(context);
2180 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2182 alSourcePausev(1, &source);
2184 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2186 ALCcontext *context;
2187 ALsource *source;
2188 ALsizei i;
2190 context = GetContextRef();
2191 if(!context) return;
2193 if(!(n >= 0))
2194 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2195 for(i = 0;i < n;i++)
2197 if(!LookupSource(context, sources[i]))
2198 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2201 LockContext(context);
2202 for(i = 0;i < n;i++)
2204 source = LookupSource(context, sources[i]);
2205 if(context->DeferUpdates) source->new_state = AL_PAUSED;
2206 else SetSourceState(source, context, AL_PAUSED);
2208 UnlockContext(context);
2210 done:
2211 ALCcontext_DecRef(context);
2214 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2216 alSourceStopv(1, &source);
2218 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2220 ALCcontext *context;
2221 ALsource *source;
2222 ALsizei i;
2224 context = GetContextRef();
2225 if(!context) return;
2227 if(!(n >= 0))
2228 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2229 for(i = 0;i < n;i++)
2231 if(!LookupSource(context, sources[i]))
2232 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2235 LockContext(context);
2236 for(i = 0;i < n;i++)
2238 source = LookupSource(context, sources[i]);
2239 source->new_state = AL_NONE;
2240 SetSourceState(source, context, AL_STOPPED);
2242 UnlockContext(context);
2244 done:
2245 ALCcontext_DecRef(context);
2248 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2250 alSourceRewindv(1, &source);
2252 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2254 ALCcontext *context;
2255 ALsource *source;
2256 ALsizei i;
2258 context = GetContextRef();
2259 if(!context) return;
2261 if(!(n >= 0))
2262 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2263 for(i = 0;i < n;i++)
2265 if(!LookupSource(context, sources[i]))
2266 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2269 LockContext(context);
2270 for(i = 0;i < n;i++)
2272 source = LookupSource(context, sources[i]);
2273 source->new_state = AL_NONE;
2274 SetSourceState(source, context, AL_INITIAL);
2276 UnlockContext(context);
2278 done:
2279 ALCcontext_DecRef(context);
2283 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2285 ALCdevice *device;
2286 ALCcontext *context;
2287 ALsource *source;
2288 ALsizei i;
2289 ALbufferlistitem *BufferListStart;
2290 ALbufferlistitem *BufferList;
2291 ALbuffer *BufferFmt = NULL;
2293 if(nb == 0)
2294 return;
2296 context = GetContextRef();
2297 if(!context) return;
2299 device = context->Device;
2301 if(!(nb >= 0))
2302 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2303 if((source=LookupSource(context, src)) == NULL)
2304 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2306 WriteLock(&source->queue_lock);
2307 if(source->SourceType == AL_STATIC)
2309 WriteUnlock(&source->queue_lock);
2310 /* Can't queue on a Static Source */
2311 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2314 /* Check for a valid Buffer, for its frequency and format */
2315 BufferList = ATOMIC_LOAD(&source->queue);
2316 while(BufferList)
2318 if(BufferList->buffer)
2320 BufferFmt = BufferList->buffer;
2321 break;
2323 BufferList = BufferList->next;
2326 BufferListStart = NULL;
2327 BufferList = NULL;
2328 for(i = 0;i < nb;i++)
2330 ALbuffer *buffer = NULL;
2331 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2333 WriteUnlock(&source->queue_lock);
2334 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2337 if(!BufferListStart)
2339 BufferListStart = malloc(sizeof(ALbufferlistitem));
2340 BufferList = BufferListStart;
2342 else
2344 BufferList->next = malloc(sizeof(ALbufferlistitem));
2345 BufferList = BufferList->next;
2347 BufferList->buffer = buffer;
2348 BufferList->next = NULL;
2349 if(!buffer) continue;
2351 /* Hold a read lock on each buffer being queued while checking all
2352 * provided buffers. This is done so other threads don't see an extra
2353 * reference on some buffers if this operation ends up failing. */
2354 ReadLock(&buffer->lock);
2355 IncrementRef(&buffer->ref);
2357 if(BufferFmt == NULL)
2359 BufferFmt = buffer;
2361 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2362 source->SampleSize = BytesFromFmt(buffer->FmtType);
2364 else if(BufferFmt->Frequency != buffer->Frequency ||
2365 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2366 BufferFmt->OriginalType != buffer->OriginalType)
2368 WriteUnlock(&source->queue_lock);
2369 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2371 buffer_error:
2372 /* A buffer failed (invalid ID or format), so unlock and release
2373 * each buffer we had. */
2374 while(BufferListStart)
2376 ALbufferlistitem *next = BufferListStart->next;
2377 if((buffer=BufferListStart->buffer) != NULL)
2379 DecrementRef(&buffer->ref);
2380 ReadUnlock(&buffer->lock);
2382 free(BufferListStart);
2383 BufferListStart = next;
2385 goto done;
2388 /* All buffers good, unlock them now. */
2389 BufferList = BufferListStart;
2390 while(BufferList != NULL)
2392 ALbuffer *buffer = BufferList->buffer;
2393 if(buffer) ReadUnlock(&buffer->lock);
2394 BufferList = BufferList->next;
2397 /* Source is now streaming */
2398 source->SourceType = AL_STREAMING;
2400 BufferList = NULL;
2401 if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
2403 /* Queue head is not NULL, append to the end of the queue */
2404 while(BufferList->next != NULL)
2405 BufferList = BufferList->next;
2406 BufferList->next = BufferListStart;
2408 /* If the current buffer was at the end (NULL), put it at the start of the newly queued
2409 * buffers.
2411 BufferList = NULL;
2412 ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
2413 WriteUnlock(&source->queue_lock);
2415 done:
2416 ALCcontext_DecRef(context);
2419 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2421 ALCcontext *context;
2422 ALsource *source;
2423 ALbufferlistitem *OldHead;
2424 ALbufferlistitem *OldTail;
2425 ALbufferlistitem *Current;
2426 ALsizei i = 0;
2428 if(nb == 0)
2429 return;
2431 context = GetContextRef();
2432 if(!context) return;
2434 if(!(nb >= 0))
2435 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2437 if((source=LookupSource(context, src)) == NULL)
2438 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2440 WriteLock(&source->queue_lock);
2441 /* Find the new buffer queue head */
2442 OldTail = ATOMIC_LOAD(&source->queue);
2443 Current = ATOMIC_LOAD(&source->current_buffer);
2444 if(OldTail != Current)
2446 for(i = 1;i < nb;i++)
2448 ALbufferlistitem *next = OldTail->next;
2449 if(!next || next == Current) break;
2450 OldTail = next;
2453 if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
2455 WriteUnlock(&source->queue_lock);
2456 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2457 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2460 /* Swap it, and cut the new head from the old. */
2461 OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, OldTail->next);
2462 if(OldTail->next)
2464 ALCdevice *device = context->Device;
2465 uint count;
2467 /* Once the active mix (if any) is done, it's safe to cut the old tail
2468 * from the new head.
2470 if(((count=ReadRef(&device->MixCount))&1) != 0)
2472 while(count == ReadRef(&device->MixCount))
2473 althrd_yield();
2475 OldTail->next = NULL;
2477 WriteUnlock(&source->queue_lock);
2479 while(OldHead != NULL)
2481 ALbufferlistitem *next = OldHead->next;
2482 ALbuffer *buffer = OldHead->buffer;
2484 if(!buffer)
2485 *(buffers++) = 0;
2486 else
2488 *(buffers++) = buffer->id;
2489 DecrementRef(&buffer->ref);
2492 free(OldHead);
2493 OldHead = next;
2496 done:
2497 ALCcontext_DecRef(context);
2501 static ALvoid InitSourceParams(ALsource *Source)
2503 ALuint i;
2505 RWLockInit(&Source->queue_lock);
2507 Source->InnerAngle = 360.0f;
2508 Source->OuterAngle = 360.0f;
2509 Source->Pitch = 1.0f;
2510 aluVectorSet(&Source->Position, 0.0f, 0.0f, 0.0f, 1.0f);
2511 aluVectorSet(&Source->Velocity, 0.0f, 0.0f, 0.0f, 0.0f);
2512 aluVectorSet(&Source->Direction, 0.0f, 0.0f, 0.0f, 0.0f);
2513 Source->Orientation[0][0] = 0.0f;
2514 Source->Orientation[0][1] = 0.0f;
2515 Source->Orientation[0][2] = -1.0f;
2516 Source->Orientation[1][0] = 0.0f;
2517 Source->Orientation[1][1] = 1.0f;
2518 Source->Orientation[1][2] = 0.0f;
2519 Source->RefDistance = 1.0f;
2520 Source->MaxDistance = FLT_MAX;
2521 Source->RollOffFactor = 1.0f;
2522 Source->Looping = AL_FALSE;
2523 Source->Gain = 1.0f;
2524 Source->MinGain = 0.0f;
2525 Source->MaxGain = 1.0f;
2526 Source->OuterGain = 0.0f;
2527 Source->OuterGainHF = 1.0f;
2529 Source->DryGainHFAuto = AL_TRUE;
2530 Source->WetGainAuto = AL_TRUE;
2531 Source->WetGainHFAuto = AL_TRUE;
2532 Source->AirAbsorptionFactor = 0.0f;
2533 Source->RoomRolloffFactor = 0.0f;
2534 Source->DopplerFactor = 1.0f;
2535 Source->DirectChannels = AL_FALSE;
2537 Source->StereoPan[0] = DEG2RAD( 30.0f);
2538 Source->StereoPan[1] = DEG2RAD(-30.0f);
2540 Source->Radius = 0.0f;
2542 Source->DistanceModel = DefaultDistanceModel;
2544 Source->state = AL_INITIAL;
2545 Source->new_state = AL_NONE;
2546 Source->SourceType = AL_UNDETERMINED;
2547 Source->OffsetType = AL_NONE;
2548 Source->Offset = 0.0;
2550 ATOMIC_INIT(&Source->queue, NULL);
2551 ATOMIC_INIT(&Source->current_buffer, NULL);
2553 Source->Direct.Gain = 1.0f;
2554 Source->Direct.GainHF = 1.0f;
2555 Source->Direct.HFReference = LOWPASSFREQREF;
2556 Source->Direct.GainLF = 1.0f;
2557 Source->Direct.LFReference = HIGHPASSFREQREF;
2558 for(i = 0;i < MAX_SENDS;i++)
2560 Source->Send[i].Gain = 1.0f;
2561 Source->Send[i].GainHF = 1.0f;
2562 Source->Send[i].HFReference = LOWPASSFREQREF;
2563 Source->Send[i].GainLF = 1.0f;
2564 Source->Send[i].LFReference = HIGHPASSFREQREF;
2567 ATOMIC_INIT(&Source->NeedsUpdate, AL_TRUE);
2571 /* SetSourceState
2573 * Sets the source's new play state given its current state.
2575 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2577 WriteLock(&Source->queue_lock);
2578 if(state == AL_PLAYING)
2580 ALCdevice *device = Context->Device;
2581 ALbufferlistitem *BufferList;
2582 ALboolean discontinuity;
2583 ALvoice *voice = NULL;
2584 ALsizei i;
2586 /* Check that there is a queue containing at least one valid, non zero
2587 * length Buffer. */
2588 BufferList = ATOMIC_LOAD(&Source->queue);
2589 while(BufferList)
2591 ALbuffer *buffer;
2592 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2593 break;
2594 BufferList = BufferList->next;
2597 if(Source->state != AL_PAUSED)
2599 Source->state = AL_PLAYING;
2600 Source->position = 0;
2601 Source->position_fraction = 0;
2602 ATOMIC_STORE(&Source->current_buffer, BufferList);
2603 discontinuity = AL_TRUE;
2605 else
2607 Source->state = AL_PLAYING;
2608 discontinuity = AL_FALSE;
2611 // Check if an Offset has been set
2612 if(Source->OffsetType != AL_NONE)
2614 ApplyOffset(Source);
2615 /* discontinuity = AL_TRUE;??? */
2618 /* If there's nothing to play, or device is disconnected, go right to
2619 * stopped */
2620 if(!BufferList || !device->Connected)
2621 goto do_stop;
2623 /* Make sure this source isn't already active, while looking for an
2624 * unused active source slot to put it in. */
2625 for(i = 0;i < Context->VoiceCount;i++)
2627 ALsource *old = Source;
2628 if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL))
2630 if(voice == NULL)
2632 voice = &Context->Voices[i];
2633 voice->Source = Source;
2635 break;
2637 old = NULL;
2638 if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source))
2639 voice = &Context->Voices[i];
2641 if(voice == NULL)
2643 voice = &Context->Voices[Context->VoiceCount++];
2644 voice->Source = Source;
2647 /* Clear previous samples if playback is discontinuous. */
2648 if(discontinuity)
2649 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
2651 voice->Moving = AL_FALSE;
2652 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
2654 ALsizei j;
2655 for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
2656 voice->Direct.Hrtf[i].State.History[j] = 0.0f;
2657 for(j = 0;j < HRIR_LENGTH;j++)
2659 voice->Direct.Hrtf[i].State.Values[j][0] = 0.0f;
2660 voice->Direct.Hrtf[i].State.Values[j][1] = 0.0f;
2664 if(BufferList->buffer->FmtChannels == FmtMono)
2665 voice->Update = CalcSourceParams;
2666 else
2667 voice->Update = CalcNonAttnSourceParams;
2669 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
2671 else if(state == AL_PAUSED)
2673 if(Source->state == AL_PLAYING)
2674 Source->state = AL_PAUSED;
2676 else if(state == AL_STOPPED)
2678 do_stop:
2679 if(Source->state != AL_INITIAL)
2681 Source->state = AL_STOPPED;
2682 ATOMIC_STORE(&Source->current_buffer, NULL);
2684 Source->OffsetType = AL_NONE;
2685 Source->Offset = 0.0;
2687 else if(state == AL_INITIAL)
2689 if(Source->state != AL_INITIAL)
2691 Source->state = AL_INITIAL;
2692 Source->position = 0;
2693 Source->position_fraction = 0;
2694 ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue));
2696 Source->OffsetType = AL_NONE;
2697 Source->Offset = 0.0;
2699 WriteUnlock(&Source->queue_lock);
2702 /* GetSourceSampleOffset
2704 * Gets the current read offset for the given Source, in 32.32 fixed-point
2705 * samples. The offset is relative to the start of the queue (not the start of
2706 * the current buffer).
2708 ALint64 GetSourceSampleOffset(ALsource *Source)
2710 const ALbufferlistitem *BufferList;
2711 const ALbufferlistitem *Current;
2712 ALuint64 readPos;
2714 ReadLock(&Source->queue_lock);
2715 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2717 ReadUnlock(&Source->queue_lock);
2718 return 0;
2721 /* NOTE: This is the offset into the *current* buffer, so add the length of
2722 * any played buffers */
2723 readPos = (ALuint64)Source->position << 32;
2724 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2725 BufferList = ATOMIC_LOAD(&Source->queue);
2726 Current = ATOMIC_LOAD(&Source->current_buffer);
2727 while(BufferList && BufferList != Current)
2729 if(BufferList->buffer)
2730 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2731 BufferList = BufferList->next;
2734 ReadUnlock(&Source->queue_lock);
2735 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
2738 /* GetSourceSecOffset
2740 * Gets the current read offset for the given Source, in seconds. The offset is
2741 * relative to the start of the queue (not the start of the current buffer).
2743 static ALdouble GetSourceSecOffset(ALsource *Source)
2745 const ALbufferlistitem *BufferList;
2746 const ALbufferlistitem *Current;
2747 const ALbuffer *Buffer = NULL;
2748 ALuint64 readPos;
2750 ReadLock(&Source->queue_lock);
2751 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2753 ReadUnlock(&Source->queue_lock);
2754 return 0.0;
2757 /* NOTE: This is the offset into the *current* buffer, so add the length of
2758 * any played buffers */
2759 readPos = (ALuint64)Source->position << FRACTIONBITS;
2760 readPos |= (ALuint64)Source->position_fraction;
2761 BufferList = ATOMIC_LOAD(&Source->queue);
2762 Current = ATOMIC_LOAD(&Source->current_buffer);
2763 while(BufferList && BufferList != Current)
2765 const ALbuffer *buffer = BufferList->buffer;
2766 if(buffer != NULL)
2768 if(!Buffer) Buffer = buffer;
2769 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
2771 BufferList = BufferList->next;
2774 while(BufferList && !Buffer)
2776 Buffer = BufferList->buffer;
2777 BufferList = BufferList->next;
2779 assert(Buffer != NULL);
2781 ReadUnlock(&Source->queue_lock);
2782 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2785 /* GetSourceOffset
2787 * Gets the current read offset for the given Source, in the appropriate format
2788 * (Bytes, Samples or Seconds). The offset is relative to the start of the
2789 * queue (not the start of the current buffer).
2791 static ALdouble GetSourceOffset(ALsource *Source, ALenum name)
2793 const ALbufferlistitem *BufferList;
2794 const ALbufferlistitem *Current;
2795 const ALbuffer *Buffer = NULL;
2796 ALboolean readFin = AL_FALSE;
2797 ALuint readPos, readPosFrac;
2798 ALuint totalBufferLen;
2799 ALdouble offset = 0.0;
2801 ReadLock(&Source->queue_lock);
2802 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2804 ReadUnlock(&Source->queue_lock);
2805 return 0.0;
2808 /* NOTE: This is the offset into the *current* buffer, so add the length of
2809 * any played buffers */
2810 totalBufferLen = 0;
2811 readPos = Source->position;
2812 readPosFrac = Source->position_fraction;
2813 BufferList = ATOMIC_LOAD(&Source->queue);
2814 Current = ATOMIC_LOAD(&Source->current_buffer);
2815 while(BufferList != NULL)
2817 const ALbuffer *buffer;
2818 readFin = readFin || (BufferList == Current);
2819 if((buffer=BufferList->buffer) != NULL)
2821 if(!Buffer) Buffer = buffer;
2822 totalBufferLen += buffer->SampleLen;
2823 if(!readFin) readPos += buffer->SampleLen;
2825 BufferList = BufferList->next;
2827 assert(Buffer != NULL);
2829 if(Source->Looping)
2830 readPos %= totalBufferLen;
2831 else
2833 /* Wrap back to 0 */
2834 if(readPos >= totalBufferLen)
2835 readPos = readPosFrac = 0;
2838 switch(name)
2840 case AL_SEC_OFFSET:
2841 offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
2842 break;
2844 case AL_SAMPLE_OFFSET:
2845 offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
2846 break;
2848 case AL_BYTE_OFFSET:
2849 if(Buffer->OriginalType == UserFmtIMA4)
2851 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2852 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2853 ALuint FrameBlockSize = Buffer->OriginalAlign;
2855 /* Round down to nearest ADPCM block */
2856 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2858 else if(Buffer->OriginalType == UserFmtMSADPCM)
2860 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2861 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2862 ALuint FrameBlockSize = Buffer->OriginalAlign;
2864 /* Round down to nearest ADPCM block */
2865 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2867 else
2869 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2870 offset = (ALdouble)(readPos * FrameSize);
2872 break;
2875 ReadUnlock(&Source->queue_lock);
2876 return offset;
2880 /* ApplyOffset
2882 * Apply the stored playback offset to the Source. This function will update
2883 * the number of buffers "played" given the stored offset.
2885 ALboolean ApplyOffset(ALsource *Source)
2887 ALbufferlistitem *BufferList;
2888 const ALbuffer *Buffer;
2889 ALuint bufferLen, totalBufferLen;
2890 ALuint offset=0, frac=0;
2892 /* Get sample frame offset */
2893 if(!GetSampleOffset(Source, &offset, &frac))
2894 return AL_FALSE;
2896 totalBufferLen = 0;
2897 BufferList = ATOMIC_LOAD(&Source->queue);
2898 while(BufferList && totalBufferLen <= offset)
2900 Buffer = BufferList->buffer;
2901 bufferLen = Buffer ? Buffer->SampleLen : 0;
2903 if(bufferLen > offset-totalBufferLen)
2905 /* Offset is in this buffer */
2906 ATOMIC_STORE(&Source->current_buffer, BufferList);
2908 Source->position = offset - totalBufferLen;
2909 Source->position_fraction = frac;
2910 return AL_TRUE;
2913 totalBufferLen += bufferLen;
2915 BufferList = BufferList->next;
2918 /* Offset is out of range of the queue */
2919 return AL_FALSE;
2923 /* GetSampleOffset
2925 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
2926 * or Second offset supplied by the application). This takes into account the
2927 * fact that the buffer format may have been modifed since.
2929 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
2931 const ALbuffer *Buffer = NULL;
2932 const ALbufferlistitem *BufferList;
2933 ALdouble dbloff, dblfrac;
2935 /* Find the first valid Buffer in the Queue */
2936 BufferList = ATOMIC_LOAD(&Source->queue);
2937 while(BufferList)
2939 if(BufferList->buffer)
2941 Buffer = BufferList->buffer;
2942 break;
2944 BufferList = BufferList->next;
2946 if(!Buffer)
2948 Source->OffsetType = AL_NONE;
2949 Source->Offset = 0.0;
2950 return AL_FALSE;
2953 switch(Source->OffsetType)
2955 case AL_BYTE_OFFSET:
2956 /* Determine the ByteOffset (and ensure it is block aligned) */
2957 *offset = (ALuint)Source->Offset;
2958 if(Buffer->OriginalType == UserFmtIMA4)
2960 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2961 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2962 *offset *= Buffer->OriginalAlign;
2964 else if(Buffer->OriginalType == UserFmtMSADPCM)
2966 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2967 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2968 *offset *= Buffer->OriginalAlign;
2970 else
2971 *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2972 *frac = 0;
2973 break;
2975 case AL_SAMPLE_OFFSET:
2976 dblfrac = modf(Source->Offset, &dbloff);
2977 *offset = (ALuint)mind(dbloff, UINT_MAX);
2978 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
2979 break;
2981 case AL_SEC_OFFSET:
2982 dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
2983 *offset = (ALuint)mind(dbloff, UINT_MAX);
2984 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
2985 break;
2987 Source->OffsetType = AL_NONE;
2988 Source->Offset = 0.0;
2990 return AL_TRUE;
2994 /* ReleaseALSources
2996 * Destroys all sources in the source map.
2998 ALvoid ReleaseALSources(ALCcontext *Context)
3000 ALbufferlistitem *item;
3001 ALsizei pos;
3002 ALuint j;
3003 for(pos = 0;pos < Context->SourceMap.size;pos++)
3005 ALsource *temp = Context->SourceMap.array[pos].value;
3006 Context->SourceMap.array[pos].value = NULL;
3008 item = ATOMIC_EXCHANGE(ALbufferlistitem*, &temp->queue, NULL);
3009 while(item != NULL)
3011 ALbufferlistitem *next = item->next;
3012 if(item->buffer != NULL)
3013 DecrementRef(&item->buffer->ref);
3014 free(item);
3015 item = next;
3018 for(j = 0;j < MAX_SENDS;++j)
3020 if(temp->Send[j].Slot)
3021 DecrementRef(&temp->Send[j].Slot->ref);
3022 temp->Send[j].Slot = NULL;
3025 FreeThunkEntry(temp->id);
3026 memset(temp, 0, sizeof(*temp));
3027 al_free(temp);