Reorder some cmake checks
[openal-soft.git] / OpenAL32 / alSource.c
blob0d4548829d3781a28419f69df4499ad23a6de884
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"
42 extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
43 extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
45 static ALvoid InitSourceParams(ALsource *Source);
46 static ALint64 GetSourceSampleOffset(ALsource *Source);
47 static ALdouble GetSourceSecOffset(ALsource *Source);
48 static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
49 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac);
51 typedef enum SourceProp {
52 srcPitch = AL_PITCH,
53 srcGain = AL_GAIN,
54 srcMinGain = AL_MIN_GAIN,
55 srcMaxGain = AL_MAX_GAIN,
56 srcMaxDistance = AL_MAX_DISTANCE,
57 srcRolloffFactor = AL_ROLLOFF_FACTOR,
58 srcDopplerFactor = AL_DOPPLER_FACTOR,
59 srcConeOuterGain = AL_CONE_OUTER_GAIN,
60 srcSecOffset = AL_SEC_OFFSET,
61 srcSampleOffset = AL_SAMPLE_OFFSET,
62 srcByteOffset = AL_BYTE_OFFSET,
63 srcConeInnerAngle = AL_CONE_INNER_ANGLE,
64 srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
65 srcRefDistance = AL_REFERENCE_DISTANCE,
67 srcPosition = AL_POSITION,
68 srcVelocity = AL_VELOCITY,
69 srcDirection = AL_DIRECTION,
71 srcSourceRelative = AL_SOURCE_RELATIVE,
72 srcLooping = AL_LOOPING,
73 srcBuffer = AL_BUFFER,
74 srcSourceState = AL_SOURCE_STATE,
75 srcBuffersQueued = AL_BUFFERS_QUEUED,
76 srcBuffersProcessed = AL_BUFFERS_PROCESSED,
77 srcSourceType = AL_SOURCE_TYPE,
79 /* ALC_EXT_EFX */
80 srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
81 srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
82 srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
83 srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
84 srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
85 srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
86 srcDirectFilter = AL_DIRECT_FILTER,
87 srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
89 /* AL_SOFT_direct_channels */
90 srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
92 /* AL_EXT_source_distance_model */
93 srcDistanceModel = AL_DISTANCE_MODEL,
95 srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
96 srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
97 srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
99 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
100 srcSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
101 srcByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
103 /* AL_SOFT_source_latency */
104 srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
105 srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
107 /* AL_EXT_BFORMAT */
108 srcOrientation = AL_ORIENTATION,
109 } SourceProp;
111 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
112 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
113 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
115 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
116 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
117 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
119 static ALint FloatValsByProp(ALenum prop)
121 if(prop != (ALenum)((SourceProp)prop))
122 return 0;
123 switch((SourceProp)prop)
125 case AL_PITCH:
126 case AL_GAIN:
127 case AL_MIN_GAIN:
128 case AL_MAX_GAIN:
129 case AL_MAX_DISTANCE:
130 case AL_ROLLOFF_FACTOR:
131 case AL_DOPPLER_FACTOR:
132 case AL_CONE_OUTER_GAIN:
133 case AL_SEC_OFFSET:
134 case AL_SAMPLE_OFFSET:
135 case AL_BYTE_OFFSET:
136 case AL_CONE_INNER_ANGLE:
137 case AL_CONE_OUTER_ANGLE:
138 case AL_REFERENCE_DISTANCE:
139 case AL_CONE_OUTER_GAINHF:
140 case AL_AIR_ABSORPTION_FACTOR:
141 case AL_ROOM_ROLLOFF_FACTOR:
142 case AL_DIRECT_FILTER_GAINHF_AUTO:
143 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
144 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
145 case AL_DIRECT_CHANNELS_SOFT:
146 case AL_DISTANCE_MODEL:
147 case AL_SOURCE_RELATIVE:
148 case AL_LOOPING:
149 case AL_SOURCE_STATE:
150 case AL_BUFFERS_QUEUED:
151 case AL_BUFFERS_PROCESSED:
152 case AL_SOURCE_TYPE:
153 case AL_BYTE_LENGTH_SOFT:
154 case AL_SAMPLE_LENGTH_SOFT:
155 case AL_SEC_LENGTH_SOFT:
156 return 1;
158 case AL_SAMPLE_RW_OFFSETS_SOFT:
159 case AL_BYTE_RW_OFFSETS_SOFT:
160 return 2;
162 case AL_POSITION:
163 case AL_VELOCITY:
164 case AL_DIRECTION:
165 return 3;
167 case AL_ORIENTATION:
168 return 6;
170 case AL_SEC_OFFSET_LATENCY_SOFT:
171 break; /* Double only */
173 case AL_BUFFER:
174 case AL_DIRECT_FILTER:
175 case AL_AUXILIARY_SEND_FILTER:
176 break; /* i/i64 only */
177 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
178 break; /* i64 only */
180 return 0;
182 static ALint DoubleValsByProp(ALenum prop)
184 if(prop != (ALenum)((SourceProp)prop))
185 return 0;
186 switch((SourceProp)prop)
188 case AL_PITCH:
189 case AL_GAIN:
190 case AL_MIN_GAIN:
191 case AL_MAX_GAIN:
192 case AL_MAX_DISTANCE:
193 case AL_ROLLOFF_FACTOR:
194 case AL_DOPPLER_FACTOR:
195 case AL_CONE_OUTER_GAIN:
196 case AL_SEC_OFFSET:
197 case AL_SAMPLE_OFFSET:
198 case AL_BYTE_OFFSET:
199 case AL_CONE_INNER_ANGLE:
200 case AL_CONE_OUTER_ANGLE:
201 case AL_REFERENCE_DISTANCE:
202 case AL_CONE_OUTER_GAINHF:
203 case AL_AIR_ABSORPTION_FACTOR:
204 case AL_ROOM_ROLLOFF_FACTOR:
205 case AL_DIRECT_FILTER_GAINHF_AUTO:
206 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
207 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
208 case AL_DIRECT_CHANNELS_SOFT:
209 case AL_DISTANCE_MODEL:
210 case AL_SOURCE_RELATIVE:
211 case AL_LOOPING:
212 case AL_SOURCE_STATE:
213 case AL_BUFFERS_QUEUED:
214 case AL_BUFFERS_PROCESSED:
215 case AL_SOURCE_TYPE:
216 case AL_BYTE_LENGTH_SOFT:
217 case AL_SAMPLE_LENGTH_SOFT:
218 case AL_SEC_LENGTH_SOFT:
219 return 1;
221 case AL_SAMPLE_RW_OFFSETS_SOFT:
222 case AL_BYTE_RW_OFFSETS_SOFT:
223 case AL_SEC_OFFSET_LATENCY_SOFT:
224 return 2;
226 case AL_POSITION:
227 case AL_VELOCITY:
228 case AL_DIRECTION:
229 return 3;
231 case AL_ORIENTATION:
232 return 6;
234 case AL_BUFFER:
235 case AL_DIRECT_FILTER:
236 case AL_AUXILIARY_SEND_FILTER:
237 break; /* i/i64 only */
238 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
239 break; /* i64 only */
241 return 0;
244 static ALint IntValsByProp(ALenum prop)
246 if(prop != (ALenum)((SourceProp)prop))
247 return 0;
248 switch((SourceProp)prop)
250 case AL_PITCH:
251 case AL_GAIN:
252 case AL_MIN_GAIN:
253 case AL_MAX_GAIN:
254 case AL_MAX_DISTANCE:
255 case AL_ROLLOFF_FACTOR:
256 case AL_DOPPLER_FACTOR:
257 case AL_CONE_OUTER_GAIN:
258 case AL_SEC_OFFSET:
259 case AL_SAMPLE_OFFSET:
260 case AL_BYTE_OFFSET:
261 case AL_CONE_INNER_ANGLE:
262 case AL_CONE_OUTER_ANGLE:
263 case AL_REFERENCE_DISTANCE:
264 case AL_CONE_OUTER_GAINHF:
265 case AL_AIR_ABSORPTION_FACTOR:
266 case AL_ROOM_ROLLOFF_FACTOR:
267 case AL_DIRECT_FILTER_GAINHF_AUTO:
268 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
269 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
270 case AL_DIRECT_CHANNELS_SOFT:
271 case AL_DISTANCE_MODEL:
272 case AL_SOURCE_RELATIVE:
273 case AL_LOOPING:
274 case AL_BUFFER:
275 case AL_SOURCE_STATE:
276 case AL_BUFFERS_QUEUED:
277 case AL_BUFFERS_PROCESSED:
278 case AL_SOURCE_TYPE:
279 case AL_DIRECT_FILTER:
280 case AL_BYTE_LENGTH_SOFT:
281 case AL_SAMPLE_LENGTH_SOFT:
282 case AL_SEC_LENGTH_SOFT:
283 return 1;
285 case AL_SAMPLE_RW_OFFSETS_SOFT:
286 case AL_BYTE_RW_OFFSETS_SOFT:
287 return 2;
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 */
303 return 0;
305 static ALint Int64ValsByProp(ALenum prop)
307 if(prop != (ALenum)((SourceProp)prop))
308 return 0;
309 switch((SourceProp)prop)
311 case AL_PITCH:
312 case AL_GAIN:
313 case AL_MIN_GAIN:
314 case AL_MAX_GAIN:
315 case AL_MAX_DISTANCE:
316 case AL_ROLLOFF_FACTOR:
317 case AL_DOPPLER_FACTOR:
318 case AL_CONE_OUTER_GAIN:
319 case AL_SEC_OFFSET:
320 case AL_SAMPLE_OFFSET:
321 case AL_BYTE_OFFSET:
322 case AL_CONE_INNER_ANGLE:
323 case AL_CONE_OUTER_ANGLE:
324 case AL_REFERENCE_DISTANCE:
325 case AL_CONE_OUTER_GAINHF:
326 case AL_AIR_ABSORPTION_FACTOR:
327 case AL_ROOM_ROLLOFF_FACTOR:
328 case AL_DIRECT_FILTER_GAINHF_AUTO:
329 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
330 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
331 case AL_DIRECT_CHANNELS_SOFT:
332 case AL_DISTANCE_MODEL:
333 case AL_SOURCE_RELATIVE:
334 case AL_LOOPING:
335 case AL_BUFFER:
336 case AL_SOURCE_STATE:
337 case AL_BUFFERS_QUEUED:
338 case AL_BUFFERS_PROCESSED:
339 case AL_SOURCE_TYPE:
340 case AL_DIRECT_FILTER:
341 case AL_BYTE_LENGTH_SOFT:
342 case AL_SAMPLE_LENGTH_SOFT:
343 case AL_SEC_LENGTH_SOFT:
344 return 1;
346 case AL_SAMPLE_RW_OFFSETS_SOFT:
347 case AL_BYTE_RW_OFFSETS_SOFT:
348 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
349 return 2;
351 case AL_POSITION:
352 case AL_VELOCITY:
353 case AL_DIRECTION:
354 case AL_AUXILIARY_SEND_FILTER:
355 return 3;
357 case AL_ORIENTATION:
358 return 6;
360 case AL_SEC_OFFSET_LATENCY_SOFT:
361 break; /* Double only */
363 return 0;
367 #define CHECKVAL(x) do { \
368 if(!(x)) \
369 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
370 } while(0)
372 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
374 ALint ival;
376 switch(prop)
378 case AL_BYTE_RW_OFFSETS_SOFT:
379 case AL_SAMPLE_RW_OFFSETS_SOFT:
380 case AL_BYTE_LENGTH_SOFT:
381 case AL_SAMPLE_LENGTH_SOFT:
382 case AL_SEC_LENGTH_SOFT:
383 case AL_SEC_OFFSET_LATENCY_SOFT:
384 /* Query only */
385 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
387 case AL_PITCH:
388 CHECKVAL(*values >= 0.0f);
390 Source->Pitch = *values;
391 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
392 return AL_TRUE;
394 case AL_CONE_INNER_ANGLE:
395 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
397 Source->InnerAngle = *values;
398 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
399 return AL_TRUE;
401 case AL_CONE_OUTER_ANGLE:
402 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
404 Source->OuterAngle = *values;
405 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
406 return AL_TRUE;
408 case AL_GAIN:
409 CHECKVAL(*values >= 0.0f);
411 Source->Gain = *values;
412 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
413 return AL_TRUE;
415 case AL_MAX_DISTANCE:
416 CHECKVAL(*values >= 0.0f);
418 Source->MaxDistance = *values;
419 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
420 return AL_TRUE;
422 case AL_ROLLOFF_FACTOR:
423 CHECKVAL(*values >= 0.0f);
425 Source->RollOffFactor = *values;
426 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
427 return AL_TRUE;
429 case AL_REFERENCE_DISTANCE:
430 CHECKVAL(*values >= 0.0f);
432 Source->RefDistance = *values;
433 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
434 return AL_TRUE;
436 case AL_MIN_GAIN:
437 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
439 Source->MinGain = *values;
440 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
441 return AL_TRUE;
443 case AL_MAX_GAIN:
444 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
446 Source->MaxGain = *values;
447 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
448 return AL_TRUE;
450 case AL_CONE_OUTER_GAIN:
451 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
453 Source->OuterGain = *values;
454 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
455 return AL_TRUE;
457 case AL_CONE_OUTER_GAINHF:
458 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
460 Source->OuterGainHF = *values;
461 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
462 return AL_TRUE;
464 case AL_AIR_ABSORPTION_FACTOR:
465 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
467 Source->AirAbsorptionFactor = *values;
468 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
469 return AL_TRUE;
471 case AL_ROOM_ROLLOFF_FACTOR:
472 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
474 Source->RoomRolloffFactor = *values;
475 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
476 return AL_TRUE;
478 case AL_DOPPLER_FACTOR:
479 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
481 Source->DopplerFactor = *values;
482 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
483 return AL_TRUE;
485 case AL_SEC_OFFSET:
486 case AL_SAMPLE_OFFSET:
487 case AL_BYTE_OFFSET:
488 CHECKVAL(*values >= 0.0f);
490 LockContext(Context);
491 Source->OffsetType = prop;
492 Source->Offset = *values;
494 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
495 !Context->DeferUpdates)
497 WriteLock(&Source->queue_lock);
498 if(ApplyOffset(Source) == AL_FALSE)
500 WriteUnlock(&Source->queue_lock);
501 UnlockContext(Context);
502 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
504 WriteUnlock(&Source->queue_lock);
506 UnlockContext(Context);
507 return AL_TRUE;
510 case AL_POSITION:
511 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
513 LockContext(Context);
514 aluVectorSet(&Source->Position, values[0], values[1], values[2], 1.0f);
515 UnlockContext(Context);
516 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
517 return AL_TRUE;
519 case AL_VELOCITY:
520 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
522 LockContext(Context);
523 aluVectorSet(&Source->Velocity, values[0], values[1], values[2], 0.0f);
524 UnlockContext(Context);
525 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
526 return AL_TRUE;
528 case AL_DIRECTION:
529 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
531 LockContext(Context);
532 aluVectorSet(&Source->Direction, values[0], values[1], values[2], 0.0f);
533 UnlockContext(Context);
534 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
535 return AL_TRUE;
537 case AL_ORIENTATION:
538 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
539 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
541 LockContext(Context);
542 Source->Orientation[0][0] = values[0];
543 Source->Orientation[0][1] = values[1];
544 Source->Orientation[0][2] = values[2];
545 Source->Orientation[1][0] = values[3];
546 Source->Orientation[1][1] = values[4];
547 Source->Orientation[1][2] = values[5];
548 UnlockContext(Context);
549 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
550 return AL_TRUE;
553 case AL_SOURCE_RELATIVE:
554 case AL_LOOPING:
555 case AL_SOURCE_STATE:
556 case AL_SOURCE_TYPE:
557 case AL_DISTANCE_MODEL:
558 case AL_DIRECT_FILTER_GAINHF_AUTO:
559 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
560 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
561 case AL_DIRECT_CHANNELS_SOFT:
562 ival = (ALint)values[0];
563 return SetSourceiv(Source, Context, prop, &ival);
565 case AL_BUFFERS_QUEUED:
566 case AL_BUFFERS_PROCESSED:
567 ival = (ALint)((ALuint)values[0]);
568 return SetSourceiv(Source, Context, prop, &ival);
570 case AL_BUFFER:
571 case AL_DIRECT_FILTER:
572 case AL_AUXILIARY_SEND_FILTER:
573 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
574 break;
577 ERR("Unexpected property: 0x%04x\n", prop);
578 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
581 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
583 ALCdevice *device = Context->Device;
584 ALbuffer *buffer = NULL;
585 ALfilter *filter = NULL;
586 ALeffectslot *slot = NULL;
587 ALbufferlistitem *oldlist;
588 ALbufferlistitem *newlist;
589 ALfloat fvals[6];
591 switch(prop)
593 case AL_SOURCE_STATE:
594 case AL_SOURCE_TYPE:
595 case AL_BUFFERS_QUEUED:
596 case AL_BUFFERS_PROCESSED:
597 case AL_SAMPLE_RW_OFFSETS_SOFT:
598 case AL_BYTE_RW_OFFSETS_SOFT:
599 case AL_BYTE_LENGTH_SOFT:
600 case AL_SAMPLE_LENGTH_SOFT:
601 case AL_SEC_LENGTH_SOFT:
602 /* Query only */
603 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
605 case AL_SOURCE_RELATIVE:
606 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
608 Source->HeadRelative = (ALboolean)*values;
609 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
610 return AL_TRUE;
612 case AL_LOOPING:
613 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
615 Source->Looping = (ALboolean)*values;
616 return AL_TRUE;
618 case AL_BUFFER:
619 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
621 WriteLock(&Source->queue_lock);
622 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
624 WriteUnlock(&Source->queue_lock);
625 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
628 if(buffer != NULL)
630 /* Add the selected buffer to a one-item queue */
631 newlist = malloc(sizeof(ALbufferlistitem));
632 newlist->buffer = buffer;
633 newlist->next = NULL;
634 newlist->prev = NULL;
635 IncrementRef(&buffer->ref);
637 /* Source is now Static */
638 Source->SourceType = AL_STATIC;
640 ReadLock(&buffer->lock);
641 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
642 Source->SampleSize = BytesFromFmt(buffer->FmtType);
643 ReadUnlock(&buffer->lock);
645 else
647 /* Source is now Undetermined */
648 Source->SourceType = AL_UNDETERMINED;
649 newlist = NULL;
651 oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist);
652 ATOMIC_STORE(&Source->current_buffer, newlist);
653 WriteUnlock(&Source->queue_lock);
655 /* Delete all elements in the previous queue */
656 while(oldlist != NULL)
658 ALbufferlistitem *temp = oldlist;
659 oldlist = temp->next;
661 if(temp->buffer)
662 DecrementRef(&temp->buffer->ref);
663 free(temp);
665 return AL_TRUE;
667 case AL_SEC_OFFSET:
668 case AL_SAMPLE_OFFSET:
669 case AL_BYTE_OFFSET:
670 CHECKVAL(*values >= 0);
672 LockContext(Context);
673 Source->OffsetType = prop;
674 Source->Offset = *values;
676 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
677 !Context->DeferUpdates)
679 WriteLock(&Source->queue_lock);
680 if(ApplyOffset(Source) == AL_FALSE)
682 WriteUnlock(&Source->queue_lock);
683 UnlockContext(Context);
684 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
686 WriteUnlock(&Source->queue_lock);
688 UnlockContext(Context);
689 return AL_TRUE;
691 case AL_DIRECT_FILTER:
692 CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
694 LockContext(Context);
695 if(!filter)
697 Source->Direct.Gain = 1.0f;
698 Source->Direct.GainHF = 1.0f;
699 Source->Direct.HFReference = LOWPASSFREQREF;
700 Source->Direct.GainLF = 1.0f;
701 Source->Direct.LFReference = HIGHPASSFREQREF;
703 else
705 Source->Direct.Gain = filter->Gain;
706 Source->Direct.GainHF = filter->GainHF;
707 Source->Direct.HFReference = filter->HFReference;
708 Source->Direct.GainLF = filter->GainLF;
709 Source->Direct.LFReference = filter->LFReference;
711 UnlockContext(Context);
712 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
713 return AL_TRUE;
715 case AL_DIRECT_FILTER_GAINHF_AUTO:
716 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
718 Source->DryGainHFAuto = *values;
719 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
720 return AL_TRUE;
722 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
723 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
725 Source->WetGainAuto = *values;
726 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
727 return AL_TRUE;
729 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
730 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
732 Source->WetGainHFAuto = *values;
733 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
734 return AL_TRUE;
736 case AL_DIRECT_CHANNELS_SOFT:
737 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
739 Source->DirectChannels = *values;
740 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
741 return AL_TRUE;
743 case AL_DISTANCE_MODEL:
744 CHECKVAL(*values == AL_NONE ||
745 *values == AL_INVERSE_DISTANCE ||
746 *values == AL_INVERSE_DISTANCE_CLAMPED ||
747 *values == AL_LINEAR_DISTANCE ||
748 *values == AL_LINEAR_DISTANCE_CLAMPED ||
749 *values == AL_EXPONENT_DISTANCE ||
750 *values == AL_EXPONENT_DISTANCE_CLAMPED);
752 Source->DistanceModel = *values;
753 if(Context->SourceDistanceModel)
754 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
755 return AL_TRUE;
758 case AL_AUXILIARY_SEND_FILTER:
759 LockContext(Context);
760 if(!((ALuint)values[1] < device->NumAuxSends &&
761 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
762 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
764 UnlockContext(Context);
765 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
768 /* Add refcount on the new slot, and release the previous slot */
769 if(slot) IncrementRef(&slot->ref);
770 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
771 if(slot) DecrementRef(&slot->ref);
773 if(!filter)
775 /* Disable filter */
776 Source->Send[values[1]].Gain = 1.0f;
777 Source->Send[values[1]].GainHF = 1.0f;
778 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
779 Source->Send[values[1]].GainLF = 1.0f;
780 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
782 else
784 Source->Send[values[1]].Gain = filter->Gain;
785 Source->Send[values[1]].GainHF = filter->GainHF;
786 Source->Send[values[1]].HFReference = filter->HFReference;
787 Source->Send[values[1]].GainLF = filter->GainLF;
788 Source->Send[values[1]].LFReference = filter->LFReference;
790 UnlockContext(Context);
791 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
792 return AL_TRUE;
795 /* 1x float */
796 case AL_CONE_INNER_ANGLE:
797 case AL_CONE_OUTER_ANGLE:
798 case AL_PITCH:
799 case AL_GAIN:
800 case AL_MIN_GAIN:
801 case AL_MAX_GAIN:
802 case AL_REFERENCE_DISTANCE:
803 case AL_ROLLOFF_FACTOR:
804 case AL_CONE_OUTER_GAIN:
805 case AL_MAX_DISTANCE:
806 case AL_DOPPLER_FACTOR:
807 case AL_CONE_OUTER_GAINHF:
808 case AL_AIR_ABSORPTION_FACTOR:
809 case AL_ROOM_ROLLOFF_FACTOR:
810 fvals[0] = (ALfloat)*values;
811 return SetSourcefv(Source, Context, (int)prop, fvals);
813 /* 3x float */
814 case AL_POSITION:
815 case AL_VELOCITY:
816 case AL_DIRECTION:
817 fvals[0] = (ALfloat)values[0];
818 fvals[1] = (ALfloat)values[1];
819 fvals[2] = (ALfloat)values[2];
820 return SetSourcefv(Source, Context, (int)prop, fvals);
822 /* 6x float */
823 case AL_ORIENTATION:
824 fvals[0] = (ALfloat)values[0];
825 fvals[1] = (ALfloat)values[1];
826 fvals[2] = (ALfloat)values[2];
827 fvals[3] = (ALfloat)values[3];
828 fvals[4] = (ALfloat)values[4];
829 fvals[5] = (ALfloat)values[5];
830 return SetSourcefv(Source, Context, (int)prop, fvals);
832 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
833 case AL_SEC_OFFSET_LATENCY_SOFT:
834 break;
837 ERR("Unexpected property: 0x%04x\n", prop);
838 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
841 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
843 ALfloat fvals[6];
844 ALint ivals[3];
846 switch(prop)
848 case AL_SOURCE_TYPE:
849 case AL_BUFFERS_QUEUED:
850 case AL_BUFFERS_PROCESSED:
851 case AL_SOURCE_STATE:
852 case AL_SAMPLE_RW_OFFSETS_SOFT:
853 case AL_BYTE_RW_OFFSETS_SOFT:
854 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
855 case AL_BYTE_LENGTH_SOFT:
856 case AL_SAMPLE_LENGTH_SOFT:
857 case AL_SEC_LENGTH_SOFT:
858 /* Query only */
859 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
862 /* 1x int */
863 case AL_SOURCE_RELATIVE:
864 case AL_LOOPING:
865 case AL_SEC_OFFSET:
866 case AL_SAMPLE_OFFSET:
867 case AL_BYTE_OFFSET:
868 case AL_DIRECT_FILTER_GAINHF_AUTO:
869 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
870 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
871 case AL_DIRECT_CHANNELS_SOFT:
872 case AL_DISTANCE_MODEL:
873 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
875 ivals[0] = (ALint)*values;
876 return SetSourceiv(Source, Context, (int)prop, ivals);
878 /* 1x uint */
879 case AL_BUFFER:
880 case AL_DIRECT_FILTER:
881 CHECKVAL(*values <= UINT_MAX && *values >= 0);
883 ivals[0] = (ALuint)*values;
884 return SetSourceiv(Source, Context, (int)prop, ivals);
886 /* 3x uint */
887 case AL_AUXILIARY_SEND_FILTER:
888 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
889 values[1] <= UINT_MAX && values[1] >= 0 &&
890 values[2] <= UINT_MAX && values[2] >= 0);
892 ivals[0] = (ALuint)values[0];
893 ivals[1] = (ALuint)values[1];
894 ivals[2] = (ALuint)values[2];
895 return SetSourceiv(Source, Context, (int)prop, ivals);
897 /* 1x float */
898 case AL_CONE_INNER_ANGLE:
899 case AL_CONE_OUTER_ANGLE:
900 case AL_PITCH:
901 case AL_GAIN:
902 case AL_MIN_GAIN:
903 case AL_MAX_GAIN:
904 case AL_REFERENCE_DISTANCE:
905 case AL_ROLLOFF_FACTOR:
906 case AL_CONE_OUTER_GAIN:
907 case AL_MAX_DISTANCE:
908 case AL_DOPPLER_FACTOR:
909 case AL_CONE_OUTER_GAINHF:
910 case AL_AIR_ABSORPTION_FACTOR:
911 case AL_ROOM_ROLLOFF_FACTOR:
912 fvals[0] = (ALfloat)*values;
913 return SetSourcefv(Source, Context, (int)prop, fvals);
915 /* 3x float */
916 case AL_POSITION:
917 case AL_VELOCITY:
918 case AL_DIRECTION:
919 fvals[0] = (ALfloat)values[0];
920 fvals[1] = (ALfloat)values[1];
921 fvals[2] = (ALfloat)values[2];
922 return SetSourcefv(Source, Context, (int)prop, fvals);
924 /* 6x float */
925 case AL_ORIENTATION:
926 fvals[0] = (ALfloat)values[0];
927 fvals[1] = (ALfloat)values[1];
928 fvals[2] = (ALfloat)values[2];
929 fvals[3] = (ALfloat)values[3];
930 fvals[4] = (ALfloat)values[4];
931 fvals[5] = (ALfloat)values[5];
932 return SetSourcefv(Source, Context, (int)prop, fvals);
934 case AL_SEC_OFFSET_LATENCY_SOFT:
935 break;
938 ERR("Unexpected property: 0x%04x\n", prop);
939 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
942 #undef CHECKVAL
945 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
947 ALCdevice *device = Context->Device;
948 ALbufferlistitem *BufferList;
949 ALdouble offsets[2];
950 ALdouble updateLen;
951 ALint ivals[3];
952 ALboolean err;
954 switch(prop)
956 case AL_GAIN:
957 *values = Source->Gain;
958 return AL_TRUE;
960 case AL_PITCH:
961 *values = Source->Pitch;
962 return AL_TRUE;
964 case AL_MAX_DISTANCE:
965 *values = Source->MaxDistance;
966 return AL_TRUE;
968 case AL_ROLLOFF_FACTOR:
969 *values = Source->RollOffFactor;
970 return AL_TRUE;
972 case AL_REFERENCE_DISTANCE:
973 *values = Source->RefDistance;
974 return AL_TRUE;
976 case AL_CONE_INNER_ANGLE:
977 *values = Source->InnerAngle;
978 return AL_TRUE;
980 case AL_CONE_OUTER_ANGLE:
981 *values = Source->OuterAngle;
982 return AL_TRUE;
984 case AL_MIN_GAIN:
985 *values = Source->MinGain;
986 return AL_TRUE;
988 case AL_MAX_GAIN:
989 *values = Source->MaxGain;
990 return AL_TRUE;
992 case AL_CONE_OUTER_GAIN:
993 *values = Source->OuterGain;
994 return AL_TRUE;
996 case AL_SEC_OFFSET:
997 case AL_SAMPLE_OFFSET:
998 case AL_BYTE_OFFSET:
999 LockContext(Context);
1000 GetSourceOffsets(Source, prop, offsets, 0.0);
1001 UnlockContext(Context);
1002 *values = offsets[0];
1003 return AL_TRUE;
1005 case AL_CONE_OUTER_GAINHF:
1006 *values = Source->OuterGainHF;
1007 return AL_TRUE;
1009 case AL_AIR_ABSORPTION_FACTOR:
1010 *values = Source->AirAbsorptionFactor;
1011 return AL_TRUE;
1013 case AL_ROOM_ROLLOFF_FACTOR:
1014 *values = Source->RoomRolloffFactor;
1015 return AL_TRUE;
1017 case AL_DOPPLER_FACTOR:
1018 *values = Source->DopplerFactor;
1019 return AL_TRUE;
1021 case AL_SEC_LENGTH_SOFT:
1022 ReadLock(&Source->queue_lock);
1023 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1024 *values = 0;
1025 else
1027 ALint length = 0;
1028 ALsizei freq = 1;
1029 do {
1030 ALbuffer *buffer = BufferList->buffer;
1031 if(buffer && buffer->SampleLen > 0)
1033 freq = buffer->Frequency;
1034 length += buffer->SampleLen;
1036 } while((BufferList=BufferList->next) != NULL);
1037 *values = (ALdouble)length / (ALdouble)freq;
1039 ReadUnlock(&Source->queue_lock);
1040 return AL_TRUE;
1042 case AL_SAMPLE_RW_OFFSETS_SOFT:
1043 case AL_BYTE_RW_OFFSETS_SOFT:
1044 LockContext(Context);
1045 updateLen = (ALdouble)device->UpdateSize / device->Frequency;
1046 GetSourceOffsets(Source, prop, values, updateLen);
1047 UnlockContext(Context);
1048 return AL_TRUE;
1050 case AL_SEC_OFFSET_LATENCY_SOFT:
1051 LockContext(Context);
1052 values[0] = GetSourceSecOffset(Source);
1053 values[1] = (ALdouble)(V0(device->Backend,getLatency)()) /
1054 1000000000.0;
1055 UnlockContext(Context);
1056 return AL_TRUE;
1058 case AL_POSITION:
1059 LockContext(Context);
1060 values[0] = Source->Position.v[0];
1061 values[1] = Source->Position.v[1];
1062 values[2] = Source->Position.v[2];
1063 UnlockContext(Context);
1064 return AL_TRUE;
1066 case AL_VELOCITY:
1067 LockContext(Context);
1068 values[0] = Source->Velocity.v[0];
1069 values[1] = Source->Velocity.v[1];
1070 values[2] = Source->Velocity.v[2];
1071 UnlockContext(Context);
1072 return AL_TRUE;
1074 case AL_DIRECTION:
1075 LockContext(Context);
1076 values[0] = Source->Direction.v[0];
1077 values[1] = Source->Direction.v[1];
1078 values[2] = Source->Direction.v[2];
1079 UnlockContext(Context);
1080 return AL_TRUE;
1082 case AL_ORIENTATION:
1083 LockContext(Context);
1084 values[0] = Source->Orientation[0][0];
1085 values[1] = Source->Orientation[0][1];
1086 values[2] = Source->Orientation[0][2];
1087 values[3] = Source->Orientation[1][0];
1088 values[4] = Source->Orientation[1][1];
1089 values[5] = Source->Orientation[1][2];
1090 UnlockContext(Context);
1091 return AL_TRUE;
1093 /* 1x int */
1094 case AL_SOURCE_RELATIVE:
1095 case AL_LOOPING:
1096 case AL_SOURCE_STATE:
1097 case AL_BUFFERS_QUEUED:
1098 case AL_BUFFERS_PROCESSED:
1099 case AL_SOURCE_TYPE:
1100 case AL_DIRECT_FILTER_GAINHF_AUTO:
1101 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1102 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1103 case AL_DIRECT_CHANNELS_SOFT:
1104 case AL_BYTE_LENGTH_SOFT:
1105 case AL_SAMPLE_LENGTH_SOFT:
1106 case AL_DISTANCE_MODEL:
1107 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1108 *values = (ALdouble)ivals[0];
1109 return err;
1111 case AL_BUFFER:
1112 case AL_DIRECT_FILTER:
1113 case AL_AUXILIARY_SEND_FILTER:
1114 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1115 break;
1118 ERR("Unexpected property: 0x%04x\n", prop);
1119 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1122 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1124 ALbufferlistitem *BufferList;
1125 ALdouble dvals[6];
1126 ALboolean err;
1128 switch(prop)
1130 case AL_SOURCE_RELATIVE:
1131 *values = Source->HeadRelative;
1132 return AL_TRUE;
1134 case AL_LOOPING:
1135 *values = Source->Looping;
1136 return AL_TRUE;
1138 case AL_BUFFER:
1139 ReadLock(&Source->queue_lock);
1140 BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) :
1141 ATOMIC_LOAD(&Source->current_buffer);
1142 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1143 ReadUnlock(&Source->queue_lock);
1144 return AL_TRUE;
1146 case AL_SOURCE_STATE:
1147 *values = Source->state;
1148 return AL_TRUE;
1150 case AL_BYTE_LENGTH_SOFT:
1151 ReadLock(&Source->queue_lock);
1152 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1153 *values = 0;
1154 else
1156 ALint length = 0;
1157 do {
1158 ALbuffer *buffer = BufferList->buffer;
1159 if(buffer && buffer->SampleLen > 0)
1161 ALuint byte_align, sample_align;
1162 if(buffer->OriginalType == UserFmtIMA4)
1164 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1165 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1166 sample_align = buffer->OriginalAlign;
1168 else if(buffer->OriginalType == UserFmtMSADPCM)
1170 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1171 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1172 sample_align = buffer->OriginalAlign;
1174 else
1176 ALsizei align = buffer->OriginalAlign;
1177 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1178 sample_align = buffer->OriginalAlign;
1181 length += buffer->SampleLen / sample_align * byte_align;
1183 } while((BufferList=BufferList->next) != NULL);
1184 *values = length;
1186 ReadUnlock(&Source->queue_lock);
1187 return AL_TRUE;
1189 case AL_SAMPLE_LENGTH_SOFT:
1190 ReadLock(&Source->queue_lock);
1191 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1192 *values = 0;
1193 else
1195 ALint length = 0;
1196 do {
1197 ALbuffer *buffer = BufferList->buffer;
1198 if(buffer) length += buffer->SampleLen;
1199 } while((BufferList=BufferList->next) != NULL);
1200 *values = length;
1202 ReadUnlock(&Source->queue_lock);
1203 return AL_TRUE;
1205 case AL_BUFFERS_QUEUED:
1206 ReadLock(&Source->queue_lock);
1207 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1208 *values = 0;
1209 else
1211 ALsizei count = 0;
1212 do {
1213 ++count;
1214 } while((BufferList=BufferList->next) != NULL);
1215 *values = count;
1217 ReadUnlock(&Source->queue_lock);
1218 return AL_TRUE;
1220 case AL_BUFFERS_PROCESSED:
1221 ReadLock(&Source->queue_lock);
1222 if(Source->Looping || Source->SourceType != AL_STREAMING)
1224 /* Buffers on a looping source are in a perpetual state of
1225 * PENDING, so don't report any as PROCESSED */
1226 *values = 0;
1228 else
1230 const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue);
1231 const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer);
1232 ALsizei played = 0;
1233 while(BufferList && BufferList != Current)
1235 played++;
1236 BufferList = BufferList->next;
1238 *values = played;
1240 ReadUnlock(&Source->queue_lock);
1241 return AL_TRUE;
1243 case AL_SOURCE_TYPE:
1244 *values = Source->SourceType;
1245 return AL_TRUE;
1247 case AL_DIRECT_FILTER_GAINHF_AUTO:
1248 *values = Source->DryGainHFAuto;
1249 return AL_TRUE;
1251 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1252 *values = Source->WetGainAuto;
1253 return AL_TRUE;
1255 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1256 *values = Source->WetGainHFAuto;
1257 return AL_TRUE;
1259 case AL_DIRECT_CHANNELS_SOFT:
1260 *values = Source->DirectChannels;
1261 return AL_TRUE;
1263 case AL_DISTANCE_MODEL:
1264 *values = Source->DistanceModel;
1265 return AL_TRUE;
1267 /* 1x float/double */
1268 case AL_CONE_INNER_ANGLE:
1269 case AL_CONE_OUTER_ANGLE:
1270 case AL_PITCH:
1271 case AL_GAIN:
1272 case AL_MIN_GAIN:
1273 case AL_MAX_GAIN:
1274 case AL_REFERENCE_DISTANCE:
1275 case AL_ROLLOFF_FACTOR:
1276 case AL_CONE_OUTER_GAIN:
1277 case AL_MAX_DISTANCE:
1278 case AL_SEC_OFFSET:
1279 case AL_SAMPLE_OFFSET:
1280 case AL_BYTE_OFFSET:
1281 case AL_DOPPLER_FACTOR:
1282 case AL_AIR_ABSORPTION_FACTOR:
1283 case AL_ROOM_ROLLOFF_FACTOR:
1284 case AL_CONE_OUTER_GAINHF:
1285 case AL_SEC_LENGTH_SOFT:
1286 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1287 *values = (ALint)dvals[0];
1288 return err;
1290 /* 2x float/double */
1291 case AL_SAMPLE_RW_OFFSETS_SOFT:
1292 case AL_BYTE_RW_OFFSETS_SOFT:
1293 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1295 values[0] = (ALint)dvals[0];
1296 values[1] = (ALint)dvals[1];
1298 return err;
1300 /* 3x float/double */
1301 case AL_POSITION:
1302 case AL_VELOCITY:
1303 case AL_DIRECTION:
1304 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1306 values[0] = (ALint)dvals[0];
1307 values[1] = (ALint)dvals[1];
1308 values[2] = (ALint)dvals[2];
1310 return err;
1312 /* 6x float/double */
1313 case AL_ORIENTATION:
1314 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1316 values[0] = (ALint)dvals[0];
1317 values[1] = (ALint)dvals[1];
1318 values[2] = (ALint)dvals[2];
1319 values[3] = (ALint)dvals[3];
1320 values[4] = (ALint)dvals[4];
1321 values[5] = (ALint)dvals[5];
1323 return err;
1325 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1326 break; /* i64 only */
1327 case AL_SEC_OFFSET_LATENCY_SOFT:
1328 break; /* Double only */
1330 case AL_DIRECT_FILTER:
1331 case AL_AUXILIARY_SEND_FILTER:
1332 break; /* ??? */
1335 ERR("Unexpected property: 0x%04x\n", prop);
1336 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1339 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1341 ALCdevice *device = Context->Device;
1342 ALdouble dvals[6];
1343 ALint ivals[3];
1344 ALboolean err;
1346 switch(prop)
1348 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1349 LockContext(Context);
1350 values[0] = GetSourceSampleOffset(Source);
1351 values[1] = V0(device->Backend,getLatency)();
1352 UnlockContext(Context);
1353 return AL_TRUE;
1355 /* 1x float/double */
1356 case AL_CONE_INNER_ANGLE:
1357 case AL_CONE_OUTER_ANGLE:
1358 case AL_PITCH:
1359 case AL_GAIN:
1360 case AL_MIN_GAIN:
1361 case AL_MAX_GAIN:
1362 case AL_REFERENCE_DISTANCE:
1363 case AL_ROLLOFF_FACTOR:
1364 case AL_CONE_OUTER_GAIN:
1365 case AL_MAX_DISTANCE:
1366 case AL_SEC_OFFSET:
1367 case AL_SAMPLE_OFFSET:
1368 case AL_BYTE_OFFSET:
1369 case AL_DOPPLER_FACTOR:
1370 case AL_AIR_ABSORPTION_FACTOR:
1371 case AL_ROOM_ROLLOFF_FACTOR:
1372 case AL_CONE_OUTER_GAINHF:
1373 case AL_SEC_LENGTH_SOFT:
1374 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1375 *values = (ALint64)dvals[0];
1376 return err;
1378 /* 2x float/double */
1379 case AL_SAMPLE_RW_OFFSETS_SOFT:
1380 case AL_BYTE_RW_OFFSETS_SOFT:
1381 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1383 values[0] = (ALint64)dvals[0];
1384 values[1] = (ALint64)dvals[1];
1386 return err;
1388 /* 3x float/double */
1389 case AL_POSITION:
1390 case AL_VELOCITY:
1391 case AL_DIRECTION:
1392 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1394 values[0] = (ALint64)dvals[0];
1395 values[1] = (ALint64)dvals[1];
1396 values[2] = (ALint64)dvals[2];
1398 return err;
1400 /* 6x float/double */
1401 case AL_ORIENTATION:
1402 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1404 values[0] = (ALint64)dvals[0];
1405 values[1] = (ALint64)dvals[1];
1406 values[2] = (ALint64)dvals[2];
1407 values[3] = (ALint64)dvals[3];
1408 values[4] = (ALint64)dvals[4];
1409 values[5] = (ALint64)dvals[5];
1411 return err;
1413 /* 1x int */
1414 case AL_SOURCE_RELATIVE:
1415 case AL_LOOPING:
1416 case AL_SOURCE_STATE:
1417 case AL_BUFFERS_QUEUED:
1418 case AL_BUFFERS_PROCESSED:
1419 case AL_BYTE_LENGTH_SOFT:
1420 case AL_SAMPLE_LENGTH_SOFT:
1421 case AL_SOURCE_TYPE:
1422 case AL_DIRECT_FILTER_GAINHF_AUTO:
1423 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1424 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1425 case AL_DIRECT_CHANNELS_SOFT:
1426 case AL_DISTANCE_MODEL:
1427 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1428 *values = ivals[0];
1429 return err;
1431 /* 1x uint */
1432 case AL_BUFFER:
1433 case AL_DIRECT_FILTER:
1434 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1435 *values = (ALuint)ivals[0];
1436 return err;
1438 /* 3x uint */
1439 case AL_AUXILIARY_SEND_FILTER:
1440 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1442 values[0] = (ALuint)ivals[0];
1443 values[1] = (ALuint)ivals[1];
1444 values[2] = (ALuint)ivals[2];
1446 return err;
1448 case AL_SEC_OFFSET_LATENCY_SOFT:
1449 break; /* Double only */
1452 ERR("Unexpected property: 0x%04x\n", prop);
1453 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1457 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1459 ALCcontext *context;
1460 ALsizei cur = 0;
1461 ALenum err;
1463 context = GetContextRef();
1464 if(!context) return;
1466 if(!(n >= 0))
1467 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1468 for(cur = 0;cur < n;cur++)
1470 ALsource *source = al_calloc(16, sizeof(ALsource));
1471 if(!source)
1473 alDeleteSources(cur, sources);
1474 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1476 InitSourceParams(source);
1478 err = NewThunkEntry(&source->id);
1479 if(err == AL_NO_ERROR)
1480 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1481 if(err != AL_NO_ERROR)
1483 FreeThunkEntry(source->id);
1484 memset(source, 0, sizeof(ALsource));
1485 al_free(source);
1487 alDeleteSources(cur, sources);
1488 SET_ERROR_AND_GOTO(context, err, done);
1491 sources[cur] = source->id;
1494 done:
1495 ALCcontext_DecRef(context);
1499 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1501 ALCcontext *context;
1502 ALbufferlistitem *BufferList;
1503 ALsource *Source;
1504 ALsizei i, j;
1506 context = GetContextRef();
1507 if(!context) return;
1509 if(!(n >= 0))
1510 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1512 /* Check that all Sources are valid */
1513 for(i = 0;i < n;i++)
1515 if(LookupSource(context, sources[i]) == NULL)
1516 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1518 for(i = 0;i < n;i++)
1520 ALvoice *voice, *voice_end;
1522 if((Source=RemoveSource(context, sources[i])) == NULL)
1523 continue;
1524 FreeThunkEntry(Source->id);
1526 LockContext(context);
1527 voice = context->Voices;
1528 voice_end = voice + context->VoiceCount;
1529 while(voice != voice_end)
1531 ALsource *old = Source;
1532 if(COMPARE_EXCHANGE(&voice->Source, &old, NULL))
1533 break;
1534 voice++;
1536 UnlockContext(context);
1538 BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, NULL);
1539 while(BufferList != NULL)
1541 ALbufferlistitem *next = BufferList->next;
1542 if(BufferList->buffer != NULL)
1543 DecrementRef(&BufferList->buffer->ref);
1544 free(BufferList);
1545 BufferList = next;
1548 for(j = 0;j < MAX_SENDS;++j)
1550 if(Source->Send[j].Slot)
1551 DecrementRef(&Source->Send[j].Slot->ref);
1552 Source->Send[j].Slot = NULL;
1555 memset(Source, 0, sizeof(*Source));
1556 al_free(Source);
1559 done:
1560 ALCcontext_DecRef(context);
1564 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1566 ALCcontext *context;
1567 ALboolean ret;
1569 context = GetContextRef();
1570 if(!context) return AL_FALSE;
1572 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1574 ALCcontext_DecRef(context);
1576 return ret;
1580 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1582 ALCcontext *Context;
1583 ALsource *Source;
1585 Context = GetContextRef();
1586 if(!Context) return;
1588 if((Source=LookupSource(Context, source)) == NULL)
1589 alSetError(Context, AL_INVALID_NAME);
1590 else if(!(FloatValsByProp(param) == 1))
1591 alSetError(Context, AL_INVALID_ENUM);
1592 else
1593 SetSourcefv(Source, Context, param, &value);
1595 ALCcontext_DecRef(Context);
1598 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1600 ALCcontext *Context;
1601 ALsource *Source;
1603 Context = GetContextRef();
1604 if(!Context) return;
1606 if((Source=LookupSource(Context, source)) == NULL)
1607 alSetError(Context, AL_INVALID_NAME);
1608 else if(!(FloatValsByProp(param) == 3))
1609 alSetError(Context, AL_INVALID_ENUM);
1610 else
1612 ALfloat fvals[3] = { value1, value2, value3 };
1613 SetSourcefv(Source, Context, param, fvals);
1616 ALCcontext_DecRef(Context);
1619 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1621 ALCcontext *Context;
1622 ALsource *Source;
1624 Context = GetContextRef();
1625 if(!Context) return;
1627 if((Source=LookupSource(Context, source)) == NULL)
1628 alSetError(Context, AL_INVALID_NAME);
1629 else if(!values)
1630 alSetError(Context, AL_INVALID_VALUE);
1631 else if(!(FloatValsByProp(param) > 0))
1632 alSetError(Context, AL_INVALID_ENUM);
1633 else
1634 SetSourcefv(Source, Context, param, values);
1636 ALCcontext_DecRef(Context);
1640 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1642 ALCcontext *Context;
1643 ALsource *Source;
1645 Context = GetContextRef();
1646 if(!Context) return;
1648 if((Source=LookupSource(Context, source)) == NULL)
1649 alSetError(Context, AL_INVALID_NAME);
1650 else if(!(DoubleValsByProp(param) == 1))
1651 alSetError(Context, AL_INVALID_ENUM);
1652 else
1654 ALfloat fval = (ALfloat)value;
1655 SetSourcefv(Source, Context, param, &fval);
1658 ALCcontext_DecRef(Context);
1661 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1663 ALCcontext *Context;
1664 ALsource *Source;
1666 Context = GetContextRef();
1667 if(!Context) return;
1669 if((Source=LookupSource(Context, source)) == NULL)
1670 alSetError(Context, AL_INVALID_NAME);
1671 else if(!(DoubleValsByProp(param) == 3))
1672 alSetError(Context, AL_INVALID_ENUM);
1673 else
1675 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1676 SetSourcefv(Source, Context, param, fvals);
1679 ALCcontext_DecRef(Context);
1682 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1684 ALCcontext *Context;
1685 ALsource *Source;
1686 ALint count;
1688 Context = GetContextRef();
1689 if(!Context) return;
1691 if((Source=LookupSource(Context, source)) == NULL)
1692 alSetError(Context, AL_INVALID_NAME);
1693 else if(!values)
1694 alSetError(Context, AL_INVALID_VALUE);
1695 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1696 alSetError(Context, AL_INVALID_ENUM);
1697 else
1699 ALfloat fvals[6];
1700 ALint i;
1702 for(i = 0;i < count;i++)
1703 fvals[i] = (ALfloat)values[i];
1704 SetSourcefv(Source, Context, param, fvals);
1707 ALCcontext_DecRef(Context);
1711 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1713 ALCcontext *Context;
1714 ALsource *Source;
1716 Context = GetContextRef();
1717 if(!Context) return;
1719 if((Source=LookupSource(Context, source)) == NULL)
1720 alSetError(Context, AL_INVALID_NAME);
1721 else if(!(IntValsByProp(param) == 1))
1722 alSetError(Context, AL_INVALID_ENUM);
1723 else
1724 SetSourceiv(Source, Context, param, &value);
1726 ALCcontext_DecRef(Context);
1729 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1731 ALCcontext *Context;
1732 ALsource *Source;
1734 Context = GetContextRef();
1735 if(!Context) return;
1737 if((Source=LookupSource(Context, source)) == NULL)
1738 alSetError(Context, AL_INVALID_NAME);
1739 else if(!(IntValsByProp(param) == 3))
1740 alSetError(Context, AL_INVALID_ENUM);
1741 else
1743 ALint ivals[3] = { value1, value2, value3 };
1744 SetSourceiv(Source, Context, param, ivals);
1747 ALCcontext_DecRef(Context);
1750 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1752 ALCcontext *Context;
1753 ALsource *Source;
1755 Context = GetContextRef();
1756 if(!Context) return;
1758 if((Source=LookupSource(Context, source)) == NULL)
1759 alSetError(Context, AL_INVALID_NAME);
1760 else if(!values)
1761 alSetError(Context, AL_INVALID_VALUE);
1762 else if(!(IntValsByProp(param) > 0))
1763 alSetError(Context, AL_INVALID_ENUM);
1764 else
1765 SetSourceiv(Source, Context, param, values);
1767 ALCcontext_DecRef(Context);
1771 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1773 ALCcontext *Context;
1774 ALsource *Source;
1776 Context = GetContextRef();
1777 if(!Context) return;
1779 if((Source=LookupSource(Context, source)) == NULL)
1780 alSetError(Context, AL_INVALID_NAME);
1781 else if(!(Int64ValsByProp(param) == 1))
1782 alSetError(Context, AL_INVALID_ENUM);
1783 else
1784 SetSourcei64v(Source, Context, param, &value);
1786 ALCcontext_DecRef(Context);
1789 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1791 ALCcontext *Context;
1792 ALsource *Source;
1794 Context = GetContextRef();
1795 if(!Context) return;
1797 if((Source=LookupSource(Context, source)) == NULL)
1798 alSetError(Context, AL_INVALID_NAME);
1799 else if(!(Int64ValsByProp(param) == 3))
1800 alSetError(Context, AL_INVALID_ENUM);
1801 else
1803 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1804 SetSourcei64v(Source, Context, param, i64vals);
1807 ALCcontext_DecRef(Context);
1810 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1812 ALCcontext *Context;
1813 ALsource *Source;
1815 Context = GetContextRef();
1816 if(!Context) return;
1818 if((Source=LookupSource(Context, source)) == NULL)
1819 alSetError(Context, AL_INVALID_NAME);
1820 else if(!values)
1821 alSetError(Context, AL_INVALID_VALUE);
1822 else if(!(Int64ValsByProp(param) > 0))
1823 alSetError(Context, AL_INVALID_ENUM);
1824 else
1825 SetSourcei64v(Source, Context, param, values);
1827 ALCcontext_DecRef(Context);
1831 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1833 ALCcontext *Context;
1834 ALsource *Source;
1836 Context = GetContextRef();
1837 if(!Context) return;
1839 if((Source=LookupSource(Context, source)) == NULL)
1840 alSetError(Context, AL_INVALID_NAME);
1841 else if(!value)
1842 alSetError(Context, AL_INVALID_VALUE);
1843 else if(!(FloatValsByProp(param) == 1))
1844 alSetError(Context, AL_INVALID_ENUM);
1845 else
1847 ALdouble dval;
1848 if(GetSourcedv(Source, Context, param, &dval))
1849 *value = (ALfloat)dval;
1852 ALCcontext_DecRef(Context);
1856 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1858 ALCcontext *Context;
1859 ALsource *Source;
1861 Context = GetContextRef();
1862 if(!Context) return;
1864 if((Source=LookupSource(Context, source)) == NULL)
1865 alSetError(Context, AL_INVALID_NAME);
1866 else if(!(value1 && value2 && value3))
1867 alSetError(Context, AL_INVALID_VALUE);
1868 else if(!(FloatValsByProp(param) == 3))
1869 alSetError(Context, AL_INVALID_ENUM);
1870 else
1872 ALdouble dvals[3];
1873 if(GetSourcedv(Source, Context, param, dvals))
1875 *value1 = (ALfloat)dvals[0];
1876 *value2 = (ALfloat)dvals[1];
1877 *value3 = (ALfloat)dvals[2];
1881 ALCcontext_DecRef(Context);
1885 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1887 ALCcontext *Context;
1888 ALsource *Source;
1889 ALint count;
1891 Context = GetContextRef();
1892 if(!Context) return;
1894 if((Source=LookupSource(Context, source)) == NULL)
1895 alSetError(Context, AL_INVALID_NAME);
1896 else if(!values)
1897 alSetError(Context, AL_INVALID_VALUE);
1898 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
1899 alSetError(Context, AL_INVALID_ENUM);
1900 else
1902 ALdouble dvals[6];
1903 if(GetSourcedv(Source, Context, param, dvals))
1905 ALint i;
1906 for(i = 0;i < count;i++)
1907 values[i] = (ALfloat)dvals[i];
1911 ALCcontext_DecRef(Context);
1915 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1917 ALCcontext *Context;
1918 ALsource *Source;
1920 Context = GetContextRef();
1921 if(!Context) return;
1923 if((Source=LookupSource(Context, source)) == NULL)
1924 alSetError(Context, AL_INVALID_NAME);
1925 else if(!value)
1926 alSetError(Context, AL_INVALID_VALUE);
1927 else if(!(DoubleValsByProp(param) == 1))
1928 alSetError(Context, AL_INVALID_ENUM);
1929 else
1930 GetSourcedv(Source, Context, param, value);
1932 ALCcontext_DecRef(Context);
1935 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1937 ALCcontext *Context;
1938 ALsource *Source;
1940 Context = GetContextRef();
1941 if(!Context) return;
1943 if((Source=LookupSource(Context, source)) == NULL)
1944 alSetError(Context, AL_INVALID_NAME);
1945 else if(!(value1 && value2 && value3))
1946 alSetError(Context, AL_INVALID_VALUE);
1947 else if(!(DoubleValsByProp(param) == 3))
1948 alSetError(Context, AL_INVALID_ENUM);
1949 else
1951 ALdouble dvals[3];
1952 if(GetSourcedv(Source, Context, param, dvals))
1954 *value1 = dvals[0];
1955 *value2 = dvals[1];
1956 *value3 = dvals[2];
1960 ALCcontext_DecRef(Context);
1963 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1965 ALCcontext *Context;
1966 ALsource *Source;
1968 Context = GetContextRef();
1969 if(!Context) return;
1971 if((Source=LookupSource(Context, source)) == NULL)
1972 alSetError(Context, AL_INVALID_NAME);
1973 else if(!values)
1974 alSetError(Context, AL_INVALID_VALUE);
1975 else if(!(DoubleValsByProp(param) > 0))
1976 alSetError(Context, AL_INVALID_ENUM);
1977 else
1978 GetSourcedv(Source, Context, param, values);
1980 ALCcontext_DecRef(Context);
1984 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1986 ALCcontext *Context;
1987 ALsource *Source;
1989 Context = GetContextRef();
1990 if(!Context) return;
1992 if((Source=LookupSource(Context, source)) == NULL)
1993 alSetError(Context, AL_INVALID_NAME);
1994 else if(!value)
1995 alSetError(Context, AL_INVALID_VALUE);
1996 else if(!(IntValsByProp(param) == 1))
1997 alSetError(Context, AL_INVALID_ENUM);
1998 else
1999 GetSourceiv(Source, Context, param, value);
2001 ALCcontext_DecRef(Context);
2005 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2007 ALCcontext *Context;
2008 ALsource *Source;
2010 Context = GetContextRef();
2011 if(!Context) return;
2013 if((Source=LookupSource(Context, source)) == NULL)
2014 alSetError(Context, AL_INVALID_NAME);
2015 else if(!(value1 && value2 && value3))
2016 alSetError(Context, AL_INVALID_VALUE);
2017 else if(!(IntValsByProp(param) == 3))
2018 alSetError(Context, AL_INVALID_ENUM);
2019 else
2021 ALint ivals[3];
2022 if(GetSourceiv(Source, Context, param, ivals))
2024 *value1 = ivals[0];
2025 *value2 = ivals[1];
2026 *value3 = ivals[2];
2030 ALCcontext_DecRef(Context);
2034 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2036 ALCcontext *Context;
2037 ALsource *Source;
2039 Context = GetContextRef();
2040 if(!Context) return;
2042 if((Source=LookupSource(Context, source)) == NULL)
2043 alSetError(Context, AL_INVALID_NAME);
2044 else if(!values)
2045 alSetError(Context, AL_INVALID_VALUE);
2046 else if(!(IntValsByProp(param) > 0))
2047 alSetError(Context, AL_INVALID_ENUM);
2048 else
2049 GetSourceiv(Source, Context, param, values);
2051 ALCcontext_DecRef(Context);
2055 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2057 ALCcontext *Context;
2058 ALsource *Source;
2060 Context = GetContextRef();
2061 if(!Context) return;
2063 if((Source=LookupSource(Context, source)) == NULL)
2064 alSetError(Context, AL_INVALID_NAME);
2065 else if(!value)
2066 alSetError(Context, AL_INVALID_VALUE);
2067 else if(!(Int64ValsByProp(param) == 1))
2068 alSetError(Context, AL_INVALID_ENUM);
2069 else
2070 GetSourcei64v(Source, Context, param, value);
2072 ALCcontext_DecRef(Context);
2075 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2077 ALCcontext *Context;
2078 ALsource *Source;
2080 Context = GetContextRef();
2081 if(!Context) return;
2083 if((Source=LookupSource(Context, source)) == NULL)
2084 alSetError(Context, AL_INVALID_NAME);
2085 else if(!(value1 && value2 && value3))
2086 alSetError(Context, AL_INVALID_VALUE);
2087 else if(!(Int64ValsByProp(param) == 3))
2088 alSetError(Context, AL_INVALID_ENUM);
2089 else
2091 ALint64 i64vals[3];
2092 if(GetSourcei64v(Source, Context, param, i64vals))
2094 *value1 = i64vals[0];
2095 *value2 = i64vals[1];
2096 *value3 = i64vals[2];
2100 ALCcontext_DecRef(Context);
2103 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2105 ALCcontext *Context;
2106 ALsource *Source;
2108 Context = GetContextRef();
2109 if(!Context) return;
2111 if((Source=LookupSource(Context, source)) == NULL)
2112 alSetError(Context, AL_INVALID_NAME);
2113 else if(!values)
2114 alSetError(Context, AL_INVALID_VALUE);
2115 else if(!(Int64ValsByProp(param) > 0))
2116 alSetError(Context, AL_INVALID_ENUM);
2117 else
2118 GetSourcei64v(Source, Context, param, values);
2120 ALCcontext_DecRef(Context);
2124 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2126 alSourcePlayv(1, &source);
2128 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2130 ALCcontext *context;
2131 ALsource *source;
2132 ALsizei i;
2134 context = GetContextRef();
2135 if(!context) return;
2137 if(!(n >= 0))
2138 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2139 for(i = 0;i < n;i++)
2141 if(!LookupSource(context, sources[i]))
2142 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2145 LockContext(context);
2146 while(n > context->MaxVoices-context->VoiceCount)
2148 ALvoice *temp = NULL;
2149 ALsizei newcount;
2151 newcount = context->MaxVoices << 1;
2152 if(newcount > 0)
2153 temp = realloc(context->Voices, newcount * sizeof(context->Voices[0]));
2154 if(!temp)
2156 UnlockContext(context);
2157 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2159 memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0]));
2161 context->Voices = temp;
2162 context->MaxVoices = newcount;
2165 for(i = 0;i < n;i++)
2167 source = LookupSource(context, sources[i]);
2168 if(context->DeferUpdates) source->new_state = AL_PLAYING;
2169 else SetSourceState(source, context, AL_PLAYING);
2171 UnlockContext(context);
2173 done:
2174 ALCcontext_DecRef(context);
2177 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2179 alSourcePausev(1, &source);
2181 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2183 ALCcontext *context;
2184 ALsource *source;
2185 ALsizei i;
2187 context = GetContextRef();
2188 if(!context) return;
2190 if(!(n >= 0))
2191 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2192 for(i = 0;i < n;i++)
2194 if(!LookupSource(context, sources[i]))
2195 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2198 LockContext(context);
2199 for(i = 0;i < n;i++)
2201 source = LookupSource(context, sources[i]);
2202 if(context->DeferUpdates) source->new_state = AL_PAUSED;
2203 else SetSourceState(source, context, AL_PAUSED);
2205 UnlockContext(context);
2207 done:
2208 ALCcontext_DecRef(context);
2211 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2213 alSourceStopv(1, &source);
2215 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2217 ALCcontext *context;
2218 ALsource *source;
2219 ALsizei i;
2221 context = GetContextRef();
2222 if(!context) return;
2224 if(!(n >= 0))
2225 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2226 for(i = 0;i < n;i++)
2228 if(!LookupSource(context, sources[i]))
2229 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2232 LockContext(context);
2233 for(i = 0;i < n;i++)
2235 source = LookupSource(context, sources[i]);
2236 source->new_state = AL_NONE;
2237 SetSourceState(source, context, AL_STOPPED);
2239 UnlockContext(context);
2241 done:
2242 ALCcontext_DecRef(context);
2245 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2247 alSourceRewindv(1, &source);
2249 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2251 ALCcontext *context;
2252 ALsource *source;
2253 ALsizei i;
2255 context = GetContextRef();
2256 if(!context) return;
2258 if(!(n >= 0))
2259 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2260 for(i = 0;i < n;i++)
2262 if(!LookupSource(context, sources[i]))
2263 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2266 LockContext(context);
2267 for(i = 0;i < n;i++)
2269 source = LookupSource(context, sources[i]);
2270 source->new_state = AL_NONE;
2271 SetSourceState(source, context, AL_INITIAL);
2273 UnlockContext(context);
2275 done:
2276 ALCcontext_DecRef(context);
2280 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2282 ALCdevice *device;
2283 ALCcontext *context;
2284 ALsource *source;
2285 ALsizei i;
2286 ALbufferlistitem *BufferListStart;
2287 ALbufferlistitem *BufferList;
2288 ALbuffer *BufferFmt = NULL;
2290 if(nb == 0)
2291 return;
2293 context = GetContextRef();
2294 if(!context) return;
2296 device = context->Device;
2298 if(!(nb >= 0))
2299 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2300 if((source=LookupSource(context, src)) == NULL)
2301 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2303 WriteLock(&source->queue_lock);
2304 if(source->SourceType == AL_STATIC)
2306 WriteUnlock(&source->queue_lock);
2307 /* Can't queue on a Static Source */
2308 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2311 /* Check for a valid Buffer, for its frequency and format */
2312 BufferList = ATOMIC_LOAD(&source->queue);
2313 while(BufferList)
2315 if(BufferList->buffer)
2317 BufferFmt = BufferList->buffer;
2318 break;
2320 BufferList = BufferList->next;
2323 BufferListStart = NULL;
2324 BufferList = NULL;
2325 for(i = 0;i < nb;i++)
2327 ALbuffer *buffer = NULL;
2328 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2330 WriteUnlock(&source->queue_lock);
2331 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2334 if(!BufferListStart)
2336 BufferListStart = malloc(sizeof(ALbufferlistitem));
2337 BufferListStart->buffer = buffer;
2338 BufferListStart->next = NULL;
2339 BufferListStart->prev = NULL;
2340 BufferList = BufferListStart;
2342 else
2344 BufferList->next = malloc(sizeof(ALbufferlistitem));
2345 BufferList->next->buffer = buffer;
2346 BufferList->next->next = NULL;
2347 BufferList->next->prev = BufferList;
2348 BufferList = BufferList->next;
2350 if(!buffer) continue;
2352 /* Hold a read lock on each buffer being queued while checking all
2353 * provided buffers. This is done so other threads don't see an extra
2354 * reference on some buffers if this operation ends up failing. */
2355 ReadLock(&buffer->lock);
2356 IncrementRef(&buffer->ref);
2358 if(BufferFmt == NULL)
2360 BufferFmt = buffer;
2362 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2363 source->SampleSize = BytesFromFmt(buffer->FmtType);
2365 else if(BufferFmt->Frequency != buffer->Frequency ||
2366 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2367 BufferFmt->OriginalType != buffer->OriginalType)
2369 WriteUnlock(&source->queue_lock);
2370 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2372 buffer_error:
2373 /* A buffer failed (invalid ID or format), so unlock and release
2374 * each buffer we had. */
2375 while(BufferList != NULL)
2377 ALbufferlistitem *prev = BufferList->prev;
2378 if((buffer=BufferList->buffer) != NULL)
2380 DecrementRef(&buffer->ref);
2381 ReadUnlock(&buffer->lock);
2383 free(BufferList);
2384 BufferList = prev;
2386 goto done;
2389 /* All buffers good, unlock them now. */
2390 while(BufferList != NULL)
2392 ALbuffer *buffer = BufferList->buffer;
2393 if(buffer) ReadUnlock(&buffer->lock);
2394 BufferList = BufferList->prev;
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;
2407 BufferListStart->prev = BufferList;
2408 BufferList->next = BufferListStart;
2410 BufferList = NULL;
2411 ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
2412 WriteUnlock(&source->queue_lock);
2414 done:
2415 ALCcontext_DecRef(context);
2418 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2420 ALCcontext *context;
2421 ALsource *source;
2422 ALbufferlistitem *NewHead;
2423 ALbufferlistitem *OldHead;
2424 ALbufferlistitem *Current;
2425 ALsizei i;
2427 if(nb == 0)
2428 return;
2430 context = GetContextRef();
2431 if(!context) return;
2433 if(!(nb >= 0))
2434 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2436 if((source=LookupSource(context, src)) == NULL)
2437 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2439 WriteLock(&source->queue_lock);
2440 /* Find the new buffer queue head */
2441 NewHead = ATOMIC_LOAD(&source->queue);
2442 Current = ATOMIC_LOAD(&source->current_buffer);
2443 for(i = 0;i < nb && NewHead;i++)
2445 if(NewHead == Current)
2446 break;
2447 NewHead = NewHead->next;
2449 if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
2451 WriteUnlock(&source->queue_lock);
2452 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2453 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2456 /* Swap it, and cut the new head from the old. */
2457 OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NewHead);
2458 if(NewHead)
2460 ALCdevice *device = context->Device;
2461 ALbufferlistitem *OldTail = NewHead->prev;
2462 uint count;
2464 /* Cut the new head's link back to the old body. The mixer is robust
2465 * enough to handle the link back going away. Once the active mix (if
2466 * any) is complete, it's safe to finish cutting the old tail from the
2467 * new head. */
2468 NewHead->prev = NULL;
2469 if(((count=ReadRef(&device->MixCount))&1) != 0)
2471 while(count == ReadRef(&device->MixCount))
2472 althrd_yield();
2474 OldTail->next = NULL;
2476 WriteUnlock(&source->queue_lock);
2478 while(OldHead != NULL)
2480 ALbufferlistitem *next = OldHead->next;
2481 ALbuffer *buffer = OldHead->buffer;
2483 if(!buffer)
2484 *(buffers++) = 0;
2485 else
2487 *(buffers++) = buffer->id;
2488 DecrementRef(&buffer->ref);
2491 free(OldHead);
2492 OldHead = next;
2495 done:
2496 ALCcontext_DecRef(context);
2500 static ALvoid InitSourceParams(ALsource *Source)
2502 ALuint i;
2504 RWLockInit(&Source->queue_lock);
2506 Source->InnerAngle = 360.0f;
2507 Source->OuterAngle = 360.0f;
2508 Source->Pitch = 1.0f;
2509 aluVectorSet(&Source->Position, 0.0f, 0.0f, 0.0f, 1.0f);
2510 aluVectorSet(&Source->Velocity, 0.0f, 0.0f, 0.0f, 0.0f);
2511 aluVectorSet(&Source->Direction, 0.0f, 0.0f, 0.0f, 0.0f);
2512 Source->Orientation[0][0] = 0.0f;
2513 Source->Orientation[0][1] = 0.0f;
2514 Source->Orientation[0][2] = -1.0f;
2515 Source->Orientation[1][0] = 0.0f;
2516 Source->Orientation[1][1] = 1.0f;
2517 Source->Orientation[1][2] = 0.0f;
2518 Source->RefDistance = 1.0f;
2519 Source->MaxDistance = FLT_MAX;
2520 Source->RollOffFactor = 1.0f;
2521 Source->Looping = AL_FALSE;
2522 Source->Gain = 1.0f;
2523 Source->MinGain = 0.0f;
2524 Source->MaxGain = 1.0f;
2525 Source->OuterGain = 0.0f;
2526 Source->OuterGainHF = 1.0f;
2528 Source->DryGainHFAuto = AL_TRUE;
2529 Source->WetGainAuto = AL_TRUE;
2530 Source->WetGainHFAuto = AL_TRUE;
2531 Source->AirAbsorptionFactor = 0.0f;
2532 Source->RoomRolloffFactor = 0.0f;
2533 Source->DopplerFactor = 1.0f;
2534 Source->DirectChannels = AL_FALSE;
2536 Source->Radius = 0.0f;
2538 Source->DistanceModel = DefaultDistanceModel;
2540 Source->state = AL_INITIAL;
2541 Source->new_state = AL_NONE;
2542 Source->SourceType = AL_UNDETERMINED;
2543 Source->Offset = -1.0;
2545 ATOMIC_INIT(&Source->queue, NULL);
2546 ATOMIC_INIT(&Source->current_buffer, NULL);
2548 Source->Direct.Gain = 1.0f;
2549 Source->Direct.GainHF = 1.0f;
2550 Source->Direct.HFReference = LOWPASSFREQREF;
2551 Source->Direct.GainLF = 1.0f;
2552 Source->Direct.LFReference = HIGHPASSFREQREF;
2553 for(i = 0;i < MAX_SENDS;i++)
2555 Source->Send[i].Gain = 1.0f;
2556 Source->Send[i].GainHF = 1.0f;
2557 Source->Send[i].HFReference = LOWPASSFREQREF;
2558 Source->Send[i].GainLF = 1.0f;
2559 Source->Send[i].LFReference = HIGHPASSFREQREF;
2562 ATOMIC_INIT(&Source->NeedsUpdate, AL_TRUE);
2566 /* SetSourceState
2568 * Sets the source's new play state given its current state.
2570 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2572 WriteLock(&Source->queue_lock);
2573 if(state == AL_PLAYING)
2575 ALCdevice *device = Context->Device;
2576 ALbufferlistitem *BufferList;
2577 ALboolean discontinuity;
2578 ALvoice *voice = NULL;
2579 ALsizei i;
2581 /* Check that there is a queue containing at least one valid, non zero
2582 * length Buffer. */
2583 BufferList = ATOMIC_LOAD(&Source->queue);
2584 while(BufferList)
2586 ALbuffer *buffer;
2587 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2588 break;
2589 BufferList = BufferList->next;
2592 if(Source->state != AL_PAUSED)
2594 Source->state = AL_PLAYING;
2595 Source->position = 0;
2596 Source->position_fraction = 0;
2597 ATOMIC_STORE(&Source->current_buffer, BufferList);
2598 discontinuity = AL_TRUE;
2600 else
2602 Source->state = AL_PLAYING;
2603 discontinuity = AL_FALSE;
2606 // Check if an Offset has been set
2607 if(Source->Offset >= 0.0)
2609 ApplyOffset(Source);
2610 /* discontinuity = AL_TRUE;??? */
2613 /* If there's nothing to play, or device is disconnected, go right to
2614 * stopped */
2615 if(!BufferList || !device->Connected)
2616 goto do_stop;
2618 /* Make sure this source isn't already active, while looking for an
2619 * unused active source slot to put it in. */
2620 for(i = 0;i < Context->VoiceCount;i++)
2622 ALsource *old = Source;
2623 if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL))
2625 if(voice == NULL)
2627 voice = &Context->Voices[i];
2628 voice->Source = Source;
2630 break;
2632 old = NULL;
2633 if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source))
2634 voice = &Context->Voices[i];
2636 if(voice == NULL)
2638 voice = &Context->Voices[Context->VoiceCount++];
2639 voice->Source = Source;
2642 /* Clear previous samples if playback is discontinuous. */
2643 if(discontinuity)
2644 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
2646 voice->Direct.Moving = AL_FALSE;
2647 voice->Direct.Counter = 0;
2648 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
2650 ALsizei j;
2651 for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
2652 voice->Direct.Hrtf[i].State.History[j] = 0.0f;
2653 for(j = 0;j < HRIR_LENGTH;j++)
2655 voice->Direct.Hrtf[i].State.Values[j][0] = 0.0f;
2656 voice->Direct.Hrtf[i].State.Values[j][1] = 0.0f;
2659 for(i = 0;i < (ALsizei)device->NumAuxSends;i++)
2661 voice->Send[i].Moving = AL_FALSE;
2662 voice->Send[i].Counter = 0;
2665 if(BufferList->buffer->FmtChannels == FmtMono)
2666 voice->Update = CalcSourceParams;
2667 else
2668 voice->Update = CalcNonAttnSourceParams;
2670 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
2672 else if(state == AL_PAUSED)
2674 if(Source->state == AL_PLAYING)
2675 Source->state = AL_PAUSED;
2677 else if(state == AL_STOPPED)
2679 do_stop:
2680 if(Source->state != AL_INITIAL)
2682 Source->state = AL_STOPPED;
2683 ATOMIC_STORE(&Source->current_buffer, NULL);
2685 Source->Offset = -1.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->Offset = -1.0;
2698 WriteUnlock(&Source->queue_lock);
2701 /* GetSourceSampleOffset
2703 * Gets the current read offset for the given Source, in 32.32 fixed-point
2704 * samples. The offset is relative to the start of the queue (not the start of
2705 * the current buffer).
2707 ALint64 GetSourceSampleOffset(ALsource *Source)
2709 const ALbufferlistitem *BufferList;
2710 const ALbufferlistitem *Current;
2711 ALuint64 readPos;
2713 ReadLock(&Source->queue_lock);
2714 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2716 ReadUnlock(&Source->queue_lock);
2717 return 0;
2720 /* NOTE: This is the offset into the *current* buffer, so add the length of
2721 * any played buffers */
2722 readPos = (ALuint64)Source->position << 32;
2723 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2724 BufferList = ATOMIC_LOAD(&Source->queue);
2725 Current = ATOMIC_LOAD(&Source->current_buffer);
2726 while(BufferList && BufferList != Current)
2728 if(BufferList->buffer)
2729 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2730 BufferList = BufferList->next;
2733 ReadUnlock(&Source->queue_lock);
2734 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
2737 /* GetSourceSecOffset
2739 * Gets the current read offset for the given Source, in seconds. The offset is
2740 * relative to the start of the queue (not the start of the current buffer).
2742 static ALdouble GetSourceSecOffset(ALsource *Source)
2744 const ALbufferlistitem *BufferList;
2745 const ALbufferlistitem *Current;
2746 const ALbuffer *Buffer = NULL;
2747 ALuint64 readPos;
2749 ReadLock(&Source->queue_lock);
2750 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2752 ReadUnlock(&Source->queue_lock);
2753 return 0.0;
2756 /* NOTE: This is the offset into the *current* buffer, so add the length of
2757 * any played buffers */
2758 readPos = (ALuint64)Source->position << FRACTIONBITS;
2759 readPos |= (ALuint64)Source->position_fraction;
2760 BufferList = ATOMIC_LOAD(&Source->queue);
2761 Current = ATOMIC_LOAD(&Source->current_buffer);
2762 while(BufferList && BufferList != Current)
2764 const ALbuffer *buffer = BufferList->buffer;
2765 if(buffer != NULL)
2767 if(!Buffer) Buffer = buffer;
2768 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
2770 BufferList = BufferList->next;
2773 while(BufferList && !Buffer)
2775 Buffer = BufferList->buffer;
2776 BufferList = BufferList->next;
2778 assert(Buffer != NULL);
2780 ReadUnlock(&Source->queue_lock);
2781 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2784 /* GetSourceOffsets
2786 * Gets the current read and write offsets for the given Source, in the
2787 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2788 * the start of the queue (not the start of the current buffer).
2790 static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2792 const ALbufferlistitem *BufferList;
2793 const ALbufferlistitem *Current;
2794 const ALbuffer *Buffer = NULL;
2795 ALboolean readFin = AL_FALSE;
2796 ALuint readPos, readPosFrac, writePos;
2797 ALuint totalBufferLen;
2799 ReadLock(&Source->queue_lock);
2800 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2802 offset[0] = 0.0;
2803 offset[1] = 0.0;
2804 ReadUnlock(&Source->queue_lock);
2805 return;
2808 if(updateLen > 0.0 && updateLen < 0.015)
2809 updateLen = 0.015;
2811 /* NOTE: This is the offset into the *current* buffer, so add the length of
2812 * any played buffers */
2813 totalBufferLen = 0;
2814 readPos = Source->position;
2815 readPosFrac = Source->position_fraction;
2816 BufferList = ATOMIC_LOAD(&Source->queue);
2817 Current = ATOMIC_LOAD(&Source->current_buffer);
2818 while(BufferList != NULL)
2820 const ALbuffer *buffer;
2821 readFin = readFin || (BufferList == Current);
2822 if((buffer=BufferList->buffer) != NULL)
2824 if(!Buffer) Buffer = buffer;
2825 totalBufferLen += buffer->SampleLen;
2826 if(!readFin) readPos += buffer->SampleLen;
2828 BufferList = BufferList->next;
2830 assert(Buffer != NULL);
2832 if(Source->state == AL_PLAYING)
2833 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency + 0.5f);
2834 else
2835 writePos = readPos;
2837 if(Source->Looping)
2839 readPos %= totalBufferLen;
2840 writePos %= totalBufferLen;
2842 else
2844 /* Wrap positions back to 0 */
2845 if(readPos >= totalBufferLen)
2846 readPos = readPosFrac = 0;
2847 if(writePos >= totalBufferLen)
2848 writePos = 0;
2851 switch(name)
2853 case AL_SEC_OFFSET:
2854 offset[0] = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
2855 offset[1] = (ALdouble)writePos/Buffer->Frequency;
2856 break;
2858 case AL_SAMPLE_OFFSET:
2859 case AL_SAMPLE_RW_OFFSETS_SOFT:
2860 offset[0] = readPos + (ALdouble)readPosFrac/FRACTIONONE;
2861 offset[1] = (ALdouble)writePos;
2862 break;
2864 case AL_BYTE_OFFSET:
2865 case AL_BYTE_RW_OFFSETS_SOFT:
2866 if(Buffer->OriginalType == UserFmtIMA4)
2868 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2869 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2870 ALuint FrameBlockSize = Buffer->OriginalAlign;
2872 /* Round down to nearest ADPCM block */
2873 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2874 if(Source->state != AL_PLAYING)
2875 offset[1] = offset[0];
2876 else
2878 /* Round up to nearest ADPCM block */
2879 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2880 FrameBlockSize * BlockSize);
2883 else if(Buffer->OriginalType == UserFmtMSADPCM)
2885 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2886 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2887 ALuint FrameBlockSize = Buffer->OriginalAlign;
2889 /* Round down to nearest ADPCM block */
2890 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2891 if(Source->state != AL_PLAYING)
2892 offset[1] = offset[0];
2893 else
2895 /* Round up to nearest ADPCM block */
2896 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2897 FrameBlockSize * BlockSize);
2900 else
2902 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2903 offset[0] = (ALdouble)(readPos * FrameSize);
2904 offset[1] = (ALdouble)(writePos * FrameSize);
2906 break;
2909 ReadUnlock(&Source->queue_lock);
2913 /* ApplyOffset
2915 * Apply the stored playback offset to the Source. This function will update
2916 * the number of buffers "played" given the stored offset.
2918 ALboolean ApplyOffset(ALsource *Source)
2920 ALbufferlistitem *BufferList;
2921 const ALbuffer *Buffer;
2922 ALuint bufferLen, totalBufferLen;
2923 ALuint offset=0, frac=0;
2925 /* Get sample frame offset */
2926 if(!GetSampleOffset(Source, &offset, &frac))
2927 return AL_FALSE;
2929 totalBufferLen = 0;
2930 BufferList = ATOMIC_LOAD(&Source->queue);
2931 while(BufferList && totalBufferLen <= offset)
2933 Buffer = BufferList->buffer;
2934 bufferLen = Buffer ? Buffer->SampleLen : 0;
2936 if(bufferLen > offset-totalBufferLen)
2938 /* Offset is in this buffer */
2939 ATOMIC_STORE(&Source->current_buffer, BufferList);
2941 Source->position = offset - totalBufferLen;
2942 Source->position_fraction = frac;
2943 return AL_TRUE;
2946 totalBufferLen += bufferLen;
2948 BufferList = BufferList->next;
2951 /* Offset is out of range of the queue */
2952 return AL_FALSE;
2956 /* GetSampleOffset
2958 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
2959 * or Second offset supplied by the application). This takes into account the
2960 * fact that the buffer format may have been modifed since.
2962 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
2964 const ALbuffer *Buffer = NULL;
2965 const ALbufferlistitem *BufferList;
2966 ALdouble dbloff, dblfrac;
2968 /* Find the first valid Buffer in the Queue */
2969 BufferList = ATOMIC_LOAD(&Source->queue);
2970 while(BufferList)
2972 if(BufferList->buffer)
2974 Buffer = BufferList->buffer;
2975 break;
2977 BufferList = BufferList->next;
2979 if(!Buffer)
2981 Source->Offset = -1.0;
2982 return AL_FALSE;
2985 switch(Source->OffsetType)
2987 case AL_BYTE_OFFSET:
2988 /* Determine the ByteOffset (and ensure it is block aligned) */
2989 *offset = (ALuint)Source->Offset;
2990 if(Buffer->OriginalType == UserFmtIMA4)
2992 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2993 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2994 *offset *= Buffer->OriginalAlign;
2996 else if(Buffer->OriginalType == UserFmtMSADPCM)
2998 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2999 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3000 *offset *= Buffer->OriginalAlign;
3002 else
3003 *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3004 *frac = 0;
3005 break;
3007 case AL_SAMPLE_OFFSET:
3008 dblfrac = modf(Source->Offset, &dbloff);
3009 *offset = (ALuint)mind(dbloff, UINT_MAX);
3010 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3011 break;
3013 case AL_SEC_OFFSET:
3014 dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
3015 *offset = (ALuint)mind(dbloff, UINT_MAX);
3016 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3017 break;
3019 Source->Offset = -1.0;
3021 return AL_TRUE;
3025 /* ReleaseALSources
3027 * Destroys all sources in the source map.
3029 ALvoid ReleaseALSources(ALCcontext *Context)
3031 ALbufferlistitem *item;
3032 ALsizei pos;
3033 ALuint j;
3034 for(pos = 0;pos < Context->SourceMap.size;pos++)
3036 ALsource *temp = Context->SourceMap.array[pos].value;
3037 Context->SourceMap.array[pos].value = NULL;
3039 item = ATOMIC_EXCHANGE(ALbufferlistitem*, &temp->queue, NULL);
3040 while(item != NULL)
3042 ALbufferlistitem *next = item->next;
3043 if(item->buffer != NULL)
3044 DecrementRef(&item->buffer->ref);
3045 free(item);
3046 item = next;
3049 for(j = 0;j < MAX_SENDS;++j)
3051 if(temp->Send[j].Slot)
3052 DecrementRef(&temp->Send[j].Slot->ref);
3053 temp->Send[j].Slot = NULL;
3056 FreeThunkEntry(temp->id);
3057 memset(temp, 0, sizeof(*temp));
3058 al_free(temp);