Remove unneeded ChannelMaps for BFormat formats
[openal-soft.git] / OpenAL32 / alSource.c
blob03eae0803c05517bc3279e89f30b1b8bd988f8c0
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 ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
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_buffer_sub_data / AL_SOFT_buffer_samples */
101 srcSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
102 srcByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
104 /* AL_SOFT_source_latency */
105 srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
106 srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
108 /* AL_EXT_STEREO_ANGLES */
109 srcAngles = AL_STEREO_ANGLES,
111 /* AL_EXT_BFORMAT */
112 srcOrientation = AL_ORIENTATION,
113 } SourceProp;
115 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
116 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
117 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
119 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
120 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
121 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
123 static ALint FloatValsByProp(ALenum prop)
125 if(prop != (ALenum)((SourceProp)prop))
126 return 0;
127 switch((SourceProp)prop)
129 case AL_PITCH:
130 case AL_GAIN:
131 case AL_MIN_GAIN:
132 case AL_MAX_GAIN:
133 case AL_MAX_DISTANCE:
134 case AL_ROLLOFF_FACTOR:
135 case AL_DOPPLER_FACTOR:
136 case AL_CONE_OUTER_GAIN:
137 case AL_SEC_OFFSET:
138 case AL_SAMPLE_OFFSET:
139 case AL_BYTE_OFFSET:
140 case AL_CONE_INNER_ANGLE:
141 case AL_CONE_OUTER_ANGLE:
142 case AL_REFERENCE_DISTANCE:
143 case AL_CONE_OUTER_GAINHF:
144 case AL_AIR_ABSORPTION_FACTOR:
145 case AL_ROOM_ROLLOFF_FACTOR:
146 case AL_DIRECT_FILTER_GAINHF_AUTO:
147 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
148 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
149 case AL_DIRECT_CHANNELS_SOFT:
150 case AL_DISTANCE_MODEL:
151 case AL_SOURCE_RELATIVE:
152 case AL_LOOPING:
153 case AL_SOURCE_STATE:
154 case AL_BUFFERS_QUEUED:
155 case AL_BUFFERS_PROCESSED:
156 case AL_SOURCE_TYPE:
157 case AL_BYTE_LENGTH_SOFT:
158 case AL_SAMPLE_LENGTH_SOFT:
159 case AL_SEC_LENGTH_SOFT:
160 return 1;
162 case AL_SAMPLE_RW_OFFSETS_SOFT:
163 case AL_BYTE_RW_OFFSETS_SOFT:
164 case AL_STEREO_ANGLES:
165 return 2;
167 case AL_POSITION:
168 case AL_VELOCITY:
169 case AL_DIRECTION:
170 return 3;
172 case AL_ORIENTATION:
173 return 6;
175 case AL_SEC_OFFSET_LATENCY_SOFT:
176 break; /* Double only */
178 case AL_BUFFER:
179 case AL_DIRECT_FILTER:
180 case AL_AUXILIARY_SEND_FILTER:
181 break; /* i/i64 only */
182 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
183 break; /* i64 only */
185 return 0;
187 static ALint DoubleValsByProp(ALenum prop)
189 if(prop != (ALenum)((SourceProp)prop))
190 return 0;
191 switch((SourceProp)prop)
193 case AL_PITCH:
194 case AL_GAIN:
195 case AL_MIN_GAIN:
196 case AL_MAX_GAIN:
197 case AL_MAX_DISTANCE:
198 case AL_ROLLOFF_FACTOR:
199 case AL_DOPPLER_FACTOR:
200 case AL_CONE_OUTER_GAIN:
201 case AL_SEC_OFFSET:
202 case AL_SAMPLE_OFFSET:
203 case AL_BYTE_OFFSET:
204 case AL_CONE_INNER_ANGLE:
205 case AL_CONE_OUTER_ANGLE:
206 case AL_REFERENCE_DISTANCE:
207 case AL_CONE_OUTER_GAINHF:
208 case AL_AIR_ABSORPTION_FACTOR:
209 case AL_ROOM_ROLLOFF_FACTOR:
210 case AL_DIRECT_FILTER_GAINHF_AUTO:
211 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
212 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
213 case AL_DIRECT_CHANNELS_SOFT:
214 case AL_DISTANCE_MODEL:
215 case AL_SOURCE_RELATIVE:
216 case AL_LOOPING:
217 case AL_SOURCE_STATE:
218 case AL_BUFFERS_QUEUED:
219 case AL_BUFFERS_PROCESSED:
220 case AL_SOURCE_TYPE:
221 case AL_BYTE_LENGTH_SOFT:
222 case AL_SAMPLE_LENGTH_SOFT:
223 case AL_SEC_LENGTH_SOFT:
224 return 1;
226 case AL_SAMPLE_RW_OFFSETS_SOFT:
227 case AL_BYTE_RW_OFFSETS_SOFT:
228 case AL_SEC_OFFSET_LATENCY_SOFT:
229 case AL_STEREO_ANGLES:
230 return 2;
232 case AL_POSITION:
233 case AL_VELOCITY:
234 case AL_DIRECTION:
235 return 3;
237 case AL_ORIENTATION:
238 return 6;
240 case AL_BUFFER:
241 case AL_DIRECT_FILTER:
242 case AL_AUXILIARY_SEND_FILTER:
243 break; /* i/i64 only */
244 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
245 break; /* i64 only */
247 return 0;
250 static ALint IntValsByProp(ALenum prop)
252 if(prop != (ALenum)((SourceProp)prop))
253 return 0;
254 switch((SourceProp)prop)
256 case AL_PITCH:
257 case AL_GAIN:
258 case AL_MIN_GAIN:
259 case AL_MAX_GAIN:
260 case AL_MAX_DISTANCE:
261 case AL_ROLLOFF_FACTOR:
262 case AL_DOPPLER_FACTOR:
263 case AL_CONE_OUTER_GAIN:
264 case AL_SEC_OFFSET:
265 case AL_SAMPLE_OFFSET:
266 case AL_BYTE_OFFSET:
267 case AL_CONE_INNER_ANGLE:
268 case AL_CONE_OUTER_ANGLE:
269 case AL_REFERENCE_DISTANCE:
270 case AL_CONE_OUTER_GAINHF:
271 case AL_AIR_ABSORPTION_FACTOR:
272 case AL_ROOM_ROLLOFF_FACTOR:
273 case AL_DIRECT_FILTER_GAINHF_AUTO:
274 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
275 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
276 case AL_DIRECT_CHANNELS_SOFT:
277 case AL_DISTANCE_MODEL:
278 case AL_SOURCE_RELATIVE:
279 case AL_LOOPING:
280 case AL_BUFFER:
281 case AL_SOURCE_STATE:
282 case AL_BUFFERS_QUEUED:
283 case AL_BUFFERS_PROCESSED:
284 case AL_SOURCE_TYPE:
285 case AL_DIRECT_FILTER:
286 case AL_BYTE_LENGTH_SOFT:
287 case AL_SAMPLE_LENGTH_SOFT:
288 case AL_SEC_LENGTH_SOFT:
289 return 1;
291 case AL_SAMPLE_RW_OFFSETS_SOFT:
292 case AL_BYTE_RW_OFFSETS_SOFT:
293 return 2;
295 case AL_POSITION:
296 case AL_VELOCITY:
297 case AL_DIRECTION:
298 case AL_AUXILIARY_SEND_FILTER:
299 return 3;
301 case AL_ORIENTATION:
302 return 6;
304 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
305 break; /* i64 only */
306 case AL_SEC_OFFSET_LATENCY_SOFT:
307 break; /* Double only */
308 case AL_STEREO_ANGLES:
309 break; /* Float/double only */
311 return 0;
313 static ALint Int64ValsByProp(ALenum prop)
315 if(prop != (ALenum)((SourceProp)prop))
316 return 0;
317 switch((SourceProp)prop)
319 case AL_PITCH:
320 case AL_GAIN:
321 case AL_MIN_GAIN:
322 case AL_MAX_GAIN:
323 case AL_MAX_DISTANCE:
324 case AL_ROLLOFF_FACTOR:
325 case AL_DOPPLER_FACTOR:
326 case AL_CONE_OUTER_GAIN:
327 case AL_SEC_OFFSET:
328 case AL_SAMPLE_OFFSET:
329 case AL_BYTE_OFFSET:
330 case AL_CONE_INNER_ANGLE:
331 case AL_CONE_OUTER_ANGLE:
332 case AL_REFERENCE_DISTANCE:
333 case AL_CONE_OUTER_GAINHF:
334 case AL_AIR_ABSORPTION_FACTOR:
335 case AL_ROOM_ROLLOFF_FACTOR:
336 case AL_DIRECT_FILTER_GAINHF_AUTO:
337 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
338 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
339 case AL_DIRECT_CHANNELS_SOFT:
340 case AL_DISTANCE_MODEL:
341 case AL_SOURCE_RELATIVE:
342 case AL_LOOPING:
343 case AL_BUFFER:
344 case AL_SOURCE_STATE:
345 case AL_BUFFERS_QUEUED:
346 case AL_BUFFERS_PROCESSED:
347 case AL_SOURCE_TYPE:
348 case AL_DIRECT_FILTER:
349 case AL_BYTE_LENGTH_SOFT:
350 case AL_SAMPLE_LENGTH_SOFT:
351 case AL_SEC_LENGTH_SOFT:
352 return 1;
354 case AL_SAMPLE_RW_OFFSETS_SOFT:
355 case AL_BYTE_RW_OFFSETS_SOFT:
356 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
357 return 2;
359 case AL_POSITION:
360 case AL_VELOCITY:
361 case AL_DIRECTION:
362 case AL_AUXILIARY_SEND_FILTER:
363 return 3;
365 case AL_ORIENTATION:
366 return 6;
368 case AL_SEC_OFFSET_LATENCY_SOFT:
369 break; /* Double only */
370 case AL_STEREO_ANGLES:
371 break; /* Float/double only */
373 return 0;
377 #define CHECKVAL(x) do { \
378 if(!(x)) \
379 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
380 } while(0)
382 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
384 ALint ival;
386 switch(prop)
388 case AL_BYTE_RW_OFFSETS_SOFT:
389 case AL_SAMPLE_RW_OFFSETS_SOFT:
390 case AL_BYTE_LENGTH_SOFT:
391 case AL_SAMPLE_LENGTH_SOFT:
392 case AL_SEC_LENGTH_SOFT:
393 case AL_SEC_OFFSET_LATENCY_SOFT:
394 /* Query only */
395 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
397 case AL_PITCH:
398 CHECKVAL(*values >= 0.0f);
400 Source->Pitch = *values;
401 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
402 return AL_TRUE;
404 case AL_CONE_INNER_ANGLE:
405 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
407 Source->InnerAngle = *values;
408 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
409 return AL_TRUE;
411 case AL_CONE_OUTER_ANGLE:
412 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
414 Source->OuterAngle = *values;
415 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
416 return AL_TRUE;
418 case AL_GAIN:
419 CHECKVAL(*values >= 0.0f);
421 Source->Gain = *values;
422 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
423 return AL_TRUE;
425 case AL_MAX_DISTANCE:
426 CHECKVAL(*values >= 0.0f);
428 Source->MaxDistance = *values;
429 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
430 return AL_TRUE;
432 case AL_ROLLOFF_FACTOR:
433 CHECKVAL(*values >= 0.0f);
435 Source->RollOffFactor = *values;
436 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
437 return AL_TRUE;
439 case AL_REFERENCE_DISTANCE:
440 CHECKVAL(*values >= 0.0f);
442 Source->RefDistance = *values;
443 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
444 return AL_TRUE;
446 case AL_MIN_GAIN:
447 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
449 Source->MinGain = *values;
450 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
451 return AL_TRUE;
453 case AL_MAX_GAIN:
454 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
456 Source->MaxGain = *values;
457 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
458 return AL_TRUE;
460 case AL_CONE_OUTER_GAIN:
461 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
463 Source->OuterGain = *values;
464 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
465 return AL_TRUE;
467 case AL_CONE_OUTER_GAINHF:
468 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
470 Source->OuterGainHF = *values;
471 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
472 return AL_TRUE;
474 case AL_AIR_ABSORPTION_FACTOR:
475 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
477 Source->AirAbsorptionFactor = *values;
478 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
479 return AL_TRUE;
481 case AL_ROOM_ROLLOFF_FACTOR:
482 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
484 Source->RoomRolloffFactor = *values;
485 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
486 return AL_TRUE;
488 case AL_DOPPLER_FACTOR:
489 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
491 Source->DopplerFactor = *values;
492 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
493 return AL_TRUE;
495 case AL_SEC_OFFSET:
496 case AL_SAMPLE_OFFSET:
497 case AL_BYTE_OFFSET:
498 CHECKVAL(*values >= 0.0f);
500 LockContext(Context);
501 Source->OffsetType = prop;
502 Source->Offset = *values;
504 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
505 !Context->DeferUpdates)
507 WriteLock(&Source->queue_lock);
508 if(ApplyOffset(Source) == AL_FALSE)
510 WriteUnlock(&Source->queue_lock);
511 UnlockContext(Context);
512 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
514 WriteUnlock(&Source->queue_lock);
516 UnlockContext(Context);
517 return AL_TRUE;
520 case AL_STEREO_ANGLES:
521 CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
523 LockContext(Context);
524 Source->StereoPan[0] = values[0];
525 Source->StereoPan[1] = values[1];
526 UnlockContext(Context);
527 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
528 return AL_TRUE;
531 case AL_POSITION:
532 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
534 LockContext(Context);
535 aluVectorSet(&Source->Position, values[0], values[1], values[2], 1.0f);
536 UnlockContext(Context);
537 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
538 return AL_TRUE;
540 case AL_VELOCITY:
541 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
543 LockContext(Context);
544 aluVectorSet(&Source->Velocity, values[0], values[1], values[2], 0.0f);
545 UnlockContext(Context);
546 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
547 return AL_TRUE;
549 case AL_DIRECTION:
550 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
552 LockContext(Context);
553 aluVectorSet(&Source->Direction, values[0], values[1], values[2], 0.0f);
554 UnlockContext(Context);
555 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
556 return AL_TRUE;
558 case AL_ORIENTATION:
559 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
560 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
562 LockContext(Context);
563 Source->Orientation[0][0] = values[0];
564 Source->Orientation[0][1] = values[1];
565 Source->Orientation[0][2] = values[2];
566 Source->Orientation[1][0] = values[3];
567 Source->Orientation[1][1] = values[4];
568 Source->Orientation[1][2] = values[5];
569 UnlockContext(Context);
570 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
571 return AL_TRUE;
574 case AL_SOURCE_RELATIVE:
575 case AL_LOOPING:
576 case AL_SOURCE_STATE:
577 case AL_SOURCE_TYPE:
578 case AL_DISTANCE_MODEL:
579 case AL_DIRECT_FILTER_GAINHF_AUTO:
580 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
581 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
582 case AL_DIRECT_CHANNELS_SOFT:
583 ival = (ALint)values[0];
584 return SetSourceiv(Source, Context, prop, &ival);
586 case AL_BUFFERS_QUEUED:
587 case AL_BUFFERS_PROCESSED:
588 ival = (ALint)((ALuint)values[0]);
589 return SetSourceiv(Source, Context, prop, &ival);
591 case AL_BUFFER:
592 case AL_DIRECT_FILTER:
593 case AL_AUXILIARY_SEND_FILTER:
594 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
595 break;
598 ERR("Unexpected property: 0x%04x\n", prop);
599 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
602 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
604 ALCdevice *device = Context->Device;
605 ALbuffer *buffer = NULL;
606 ALfilter *filter = NULL;
607 ALeffectslot *slot = NULL;
608 ALbufferlistitem *oldlist;
609 ALbufferlistitem *newlist;
610 ALfloat fvals[6];
612 switch(prop)
614 case AL_SOURCE_STATE:
615 case AL_SOURCE_TYPE:
616 case AL_BUFFERS_QUEUED:
617 case AL_BUFFERS_PROCESSED:
618 case AL_SAMPLE_RW_OFFSETS_SOFT:
619 case AL_BYTE_RW_OFFSETS_SOFT:
620 case AL_BYTE_LENGTH_SOFT:
621 case AL_SAMPLE_LENGTH_SOFT:
622 case AL_SEC_LENGTH_SOFT:
623 /* Query only */
624 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
626 case AL_SOURCE_RELATIVE:
627 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
629 Source->HeadRelative = (ALboolean)*values;
630 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
631 return AL_TRUE;
633 case AL_LOOPING:
634 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
636 Source->Looping = (ALboolean)*values;
637 return AL_TRUE;
639 case AL_BUFFER:
640 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
642 WriteLock(&Source->queue_lock);
643 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
645 WriteUnlock(&Source->queue_lock);
646 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
649 if(buffer != NULL)
651 /* Add the selected buffer to a one-item queue */
652 newlist = malloc(sizeof(ALbufferlistitem));
653 newlist->buffer = buffer;
654 newlist->next = NULL;
655 IncrementRef(&buffer->ref);
657 /* Source is now Static */
658 Source->SourceType = AL_STATIC;
660 ReadLock(&buffer->lock);
661 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
662 Source->SampleSize = BytesFromFmt(buffer->FmtType);
663 ReadUnlock(&buffer->lock);
665 else
667 /* Source is now Undetermined */
668 Source->SourceType = AL_UNDETERMINED;
669 newlist = NULL;
671 oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist);
672 ATOMIC_STORE(&Source->current_buffer, newlist);
673 WriteUnlock(&Source->queue_lock);
675 /* Delete all elements in the previous queue */
676 while(oldlist != NULL)
678 ALbufferlistitem *temp = oldlist;
679 oldlist = temp->next;
681 if(temp->buffer)
682 DecrementRef(&temp->buffer->ref);
683 free(temp);
685 return AL_TRUE;
687 case AL_SEC_OFFSET:
688 case AL_SAMPLE_OFFSET:
689 case AL_BYTE_OFFSET:
690 CHECKVAL(*values >= 0);
692 LockContext(Context);
693 Source->OffsetType = prop;
694 Source->Offset = *values;
696 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
697 !Context->DeferUpdates)
699 WriteLock(&Source->queue_lock);
700 if(ApplyOffset(Source) == AL_FALSE)
702 WriteUnlock(&Source->queue_lock);
703 UnlockContext(Context);
704 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
706 WriteUnlock(&Source->queue_lock);
708 UnlockContext(Context);
709 return AL_TRUE;
711 case AL_DIRECT_FILTER:
712 CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
714 LockContext(Context);
715 if(!filter)
717 Source->Direct.Gain = 1.0f;
718 Source->Direct.GainHF = 1.0f;
719 Source->Direct.HFReference = LOWPASSFREQREF;
720 Source->Direct.GainLF = 1.0f;
721 Source->Direct.LFReference = HIGHPASSFREQREF;
723 else
725 Source->Direct.Gain = filter->Gain;
726 Source->Direct.GainHF = filter->GainHF;
727 Source->Direct.HFReference = filter->HFReference;
728 Source->Direct.GainLF = filter->GainLF;
729 Source->Direct.LFReference = filter->LFReference;
731 UnlockContext(Context);
732 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
733 return AL_TRUE;
735 case AL_DIRECT_FILTER_GAINHF_AUTO:
736 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
738 Source->DryGainHFAuto = *values;
739 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
740 return AL_TRUE;
742 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
743 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
745 Source->WetGainAuto = *values;
746 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
747 return AL_TRUE;
749 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
750 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
752 Source->WetGainHFAuto = *values;
753 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
754 return AL_TRUE;
756 case AL_DIRECT_CHANNELS_SOFT:
757 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
759 Source->DirectChannels = *values;
760 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
761 return AL_TRUE;
763 case AL_DISTANCE_MODEL:
764 CHECKVAL(*values == AL_NONE ||
765 *values == AL_INVERSE_DISTANCE ||
766 *values == AL_INVERSE_DISTANCE_CLAMPED ||
767 *values == AL_LINEAR_DISTANCE ||
768 *values == AL_LINEAR_DISTANCE_CLAMPED ||
769 *values == AL_EXPONENT_DISTANCE ||
770 *values == AL_EXPONENT_DISTANCE_CLAMPED);
772 Source->DistanceModel = *values;
773 if(Context->SourceDistanceModel)
774 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
775 return AL_TRUE;
778 case AL_AUXILIARY_SEND_FILTER:
779 LockContext(Context);
780 if(!((ALuint)values[1] < device->NumAuxSends &&
781 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
782 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
784 UnlockContext(Context);
785 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
788 /* Add refcount on the new slot, and release the previous slot */
789 if(slot) IncrementRef(&slot->ref);
790 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
791 if(slot) DecrementRef(&slot->ref);
793 if(!filter)
795 /* Disable filter */
796 Source->Send[values[1]].Gain = 1.0f;
797 Source->Send[values[1]].GainHF = 1.0f;
798 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
799 Source->Send[values[1]].GainLF = 1.0f;
800 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
802 else
804 Source->Send[values[1]].Gain = filter->Gain;
805 Source->Send[values[1]].GainHF = filter->GainHF;
806 Source->Send[values[1]].HFReference = filter->HFReference;
807 Source->Send[values[1]].GainLF = filter->GainLF;
808 Source->Send[values[1]].LFReference = filter->LFReference;
810 UnlockContext(Context);
811 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
812 return AL_TRUE;
815 /* 1x float */
816 case AL_CONE_INNER_ANGLE:
817 case AL_CONE_OUTER_ANGLE:
818 case AL_PITCH:
819 case AL_GAIN:
820 case AL_MIN_GAIN:
821 case AL_MAX_GAIN:
822 case AL_REFERENCE_DISTANCE:
823 case AL_ROLLOFF_FACTOR:
824 case AL_CONE_OUTER_GAIN:
825 case AL_MAX_DISTANCE:
826 case AL_DOPPLER_FACTOR:
827 case AL_CONE_OUTER_GAINHF:
828 case AL_AIR_ABSORPTION_FACTOR:
829 case AL_ROOM_ROLLOFF_FACTOR:
830 fvals[0] = (ALfloat)*values;
831 return SetSourcefv(Source, Context, (int)prop, fvals);
833 /* 3x float */
834 case AL_POSITION:
835 case AL_VELOCITY:
836 case AL_DIRECTION:
837 fvals[0] = (ALfloat)values[0];
838 fvals[1] = (ALfloat)values[1];
839 fvals[2] = (ALfloat)values[2];
840 return SetSourcefv(Source, Context, (int)prop, fvals);
842 /* 6x float */
843 case AL_ORIENTATION:
844 fvals[0] = (ALfloat)values[0];
845 fvals[1] = (ALfloat)values[1];
846 fvals[2] = (ALfloat)values[2];
847 fvals[3] = (ALfloat)values[3];
848 fvals[4] = (ALfloat)values[4];
849 fvals[5] = (ALfloat)values[5];
850 return SetSourcefv(Source, Context, (int)prop, fvals);
852 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
853 case AL_SEC_OFFSET_LATENCY_SOFT:
854 case AL_STEREO_ANGLES:
855 break;
858 ERR("Unexpected property: 0x%04x\n", prop);
859 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
862 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
864 ALfloat fvals[6];
865 ALint ivals[3];
867 switch(prop)
869 case AL_SOURCE_TYPE:
870 case AL_BUFFERS_QUEUED:
871 case AL_BUFFERS_PROCESSED:
872 case AL_SOURCE_STATE:
873 case AL_SAMPLE_RW_OFFSETS_SOFT:
874 case AL_BYTE_RW_OFFSETS_SOFT:
875 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
876 case AL_BYTE_LENGTH_SOFT:
877 case AL_SAMPLE_LENGTH_SOFT:
878 case AL_SEC_LENGTH_SOFT:
879 /* Query only */
880 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
883 /* 1x int */
884 case AL_SOURCE_RELATIVE:
885 case AL_LOOPING:
886 case AL_SEC_OFFSET:
887 case AL_SAMPLE_OFFSET:
888 case AL_BYTE_OFFSET:
889 case AL_DIRECT_FILTER_GAINHF_AUTO:
890 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
891 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
892 case AL_DIRECT_CHANNELS_SOFT:
893 case AL_DISTANCE_MODEL:
894 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
896 ivals[0] = (ALint)*values;
897 return SetSourceiv(Source, Context, (int)prop, ivals);
899 /* 1x uint */
900 case AL_BUFFER:
901 case AL_DIRECT_FILTER:
902 CHECKVAL(*values <= UINT_MAX && *values >= 0);
904 ivals[0] = (ALuint)*values;
905 return SetSourceiv(Source, Context, (int)prop, ivals);
907 /* 3x uint */
908 case AL_AUXILIARY_SEND_FILTER:
909 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
910 values[1] <= UINT_MAX && values[1] >= 0 &&
911 values[2] <= UINT_MAX && values[2] >= 0);
913 ivals[0] = (ALuint)values[0];
914 ivals[1] = (ALuint)values[1];
915 ivals[2] = (ALuint)values[2];
916 return SetSourceiv(Source, Context, (int)prop, ivals);
918 /* 1x float */
919 case AL_CONE_INNER_ANGLE:
920 case AL_CONE_OUTER_ANGLE:
921 case AL_PITCH:
922 case AL_GAIN:
923 case AL_MIN_GAIN:
924 case AL_MAX_GAIN:
925 case AL_REFERENCE_DISTANCE:
926 case AL_ROLLOFF_FACTOR:
927 case AL_CONE_OUTER_GAIN:
928 case AL_MAX_DISTANCE:
929 case AL_DOPPLER_FACTOR:
930 case AL_CONE_OUTER_GAINHF:
931 case AL_AIR_ABSORPTION_FACTOR:
932 case AL_ROOM_ROLLOFF_FACTOR:
933 fvals[0] = (ALfloat)*values;
934 return SetSourcefv(Source, Context, (int)prop, fvals);
936 /* 3x float */
937 case AL_POSITION:
938 case AL_VELOCITY:
939 case AL_DIRECTION:
940 fvals[0] = (ALfloat)values[0];
941 fvals[1] = (ALfloat)values[1];
942 fvals[2] = (ALfloat)values[2];
943 return SetSourcefv(Source, Context, (int)prop, fvals);
945 /* 6x float */
946 case AL_ORIENTATION:
947 fvals[0] = (ALfloat)values[0];
948 fvals[1] = (ALfloat)values[1];
949 fvals[2] = (ALfloat)values[2];
950 fvals[3] = (ALfloat)values[3];
951 fvals[4] = (ALfloat)values[4];
952 fvals[5] = (ALfloat)values[5];
953 return SetSourcefv(Source, Context, (int)prop, fvals);
955 case AL_SEC_OFFSET_LATENCY_SOFT:
956 case AL_STEREO_ANGLES:
957 break;
960 ERR("Unexpected property: 0x%04x\n", prop);
961 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
964 #undef CHECKVAL
967 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
969 ALCdevice *device = Context->Device;
970 ALbufferlistitem *BufferList;
971 ALdouble offsets[2];
972 ALdouble updateLen;
973 ALint ivals[3];
974 ALboolean err;
976 switch(prop)
978 case AL_GAIN:
979 *values = Source->Gain;
980 return AL_TRUE;
982 case AL_PITCH:
983 *values = Source->Pitch;
984 return AL_TRUE;
986 case AL_MAX_DISTANCE:
987 *values = Source->MaxDistance;
988 return AL_TRUE;
990 case AL_ROLLOFF_FACTOR:
991 *values = Source->RollOffFactor;
992 return AL_TRUE;
994 case AL_REFERENCE_DISTANCE:
995 *values = Source->RefDistance;
996 return AL_TRUE;
998 case AL_CONE_INNER_ANGLE:
999 *values = Source->InnerAngle;
1000 return AL_TRUE;
1002 case AL_CONE_OUTER_ANGLE:
1003 *values = Source->OuterAngle;
1004 return AL_TRUE;
1006 case AL_MIN_GAIN:
1007 *values = Source->MinGain;
1008 return AL_TRUE;
1010 case AL_MAX_GAIN:
1011 *values = Source->MaxGain;
1012 return AL_TRUE;
1014 case AL_CONE_OUTER_GAIN:
1015 *values = Source->OuterGain;
1016 return AL_TRUE;
1018 case AL_SEC_OFFSET:
1019 case AL_SAMPLE_OFFSET:
1020 case AL_BYTE_OFFSET:
1021 LockContext(Context);
1022 GetSourceOffsets(Source, prop, offsets, 0.0);
1023 UnlockContext(Context);
1024 *values = offsets[0];
1025 return AL_TRUE;
1027 case AL_CONE_OUTER_GAINHF:
1028 *values = Source->OuterGainHF;
1029 return AL_TRUE;
1031 case AL_AIR_ABSORPTION_FACTOR:
1032 *values = Source->AirAbsorptionFactor;
1033 return AL_TRUE;
1035 case AL_ROOM_ROLLOFF_FACTOR:
1036 *values = Source->RoomRolloffFactor;
1037 return AL_TRUE;
1039 case AL_DOPPLER_FACTOR:
1040 *values = Source->DopplerFactor;
1041 return AL_TRUE;
1043 case AL_SEC_LENGTH_SOFT:
1044 ReadLock(&Source->queue_lock);
1045 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1046 *values = 0;
1047 else
1049 ALint length = 0;
1050 ALsizei freq = 1;
1051 do {
1052 ALbuffer *buffer = BufferList->buffer;
1053 if(buffer && buffer->SampleLen > 0)
1055 freq = buffer->Frequency;
1056 length += buffer->SampleLen;
1058 } while((BufferList=BufferList->next) != NULL);
1059 *values = (ALdouble)length / (ALdouble)freq;
1061 ReadUnlock(&Source->queue_lock);
1062 return AL_TRUE;
1064 case AL_SAMPLE_RW_OFFSETS_SOFT:
1065 case AL_BYTE_RW_OFFSETS_SOFT:
1066 LockContext(Context);
1067 updateLen = (ALdouble)device->UpdateSize / device->Frequency;
1068 GetSourceOffsets(Source, prop, values, updateLen);
1069 UnlockContext(Context);
1070 return AL_TRUE;
1072 case AL_SEC_OFFSET_LATENCY_SOFT:
1073 LockContext(Context);
1074 values[0] = GetSourceSecOffset(Source);
1075 values[1] = (ALdouble)(V0(device->Backend,getLatency)()) /
1076 1000000000.0;
1077 UnlockContext(Context);
1078 return AL_TRUE;
1080 case AL_STEREO_ANGLES:
1081 LockContext(Context);
1082 values[0] = Source->StereoPan[0];
1083 values[1] = Source->StereoPan[1];
1084 UnlockContext(Context);
1085 return AL_TRUE;
1087 case AL_POSITION:
1088 LockContext(Context);
1089 values[0] = Source->Position.v[0];
1090 values[1] = Source->Position.v[1];
1091 values[2] = Source->Position.v[2];
1092 UnlockContext(Context);
1093 return AL_TRUE;
1095 case AL_VELOCITY:
1096 LockContext(Context);
1097 values[0] = Source->Velocity.v[0];
1098 values[1] = Source->Velocity.v[1];
1099 values[2] = Source->Velocity.v[2];
1100 UnlockContext(Context);
1101 return AL_TRUE;
1103 case AL_DIRECTION:
1104 LockContext(Context);
1105 values[0] = Source->Direction.v[0];
1106 values[1] = Source->Direction.v[1];
1107 values[2] = Source->Direction.v[2];
1108 UnlockContext(Context);
1109 return AL_TRUE;
1111 case AL_ORIENTATION:
1112 LockContext(Context);
1113 values[0] = Source->Orientation[0][0];
1114 values[1] = Source->Orientation[0][1];
1115 values[2] = Source->Orientation[0][2];
1116 values[3] = Source->Orientation[1][0];
1117 values[4] = Source->Orientation[1][1];
1118 values[5] = Source->Orientation[1][2];
1119 UnlockContext(Context);
1120 return AL_TRUE;
1122 /* 1x int */
1123 case AL_SOURCE_RELATIVE:
1124 case AL_LOOPING:
1125 case AL_SOURCE_STATE:
1126 case AL_BUFFERS_QUEUED:
1127 case AL_BUFFERS_PROCESSED:
1128 case AL_SOURCE_TYPE:
1129 case AL_DIRECT_FILTER_GAINHF_AUTO:
1130 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1131 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1132 case AL_DIRECT_CHANNELS_SOFT:
1133 case AL_BYTE_LENGTH_SOFT:
1134 case AL_SAMPLE_LENGTH_SOFT:
1135 case AL_DISTANCE_MODEL:
1136 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1137 *values = (ALdouble)ivals[0];
1138 return err;
1140 case AL_BUFFER:
1141 case AL_DIRECT_FILTER:
1142 case AL_AUXILIARY_SEND_FILTER:
1143 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1144 break;
1147 ERR("Unexpected property: 0x%04x\n", prop);
1148 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1151 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1153 ALbufferlistitem *BufferList;
1154 ALdouble dvals[6];
1155 ALboolean err;
1157 switch(prop)
1159 case AL_SOURCE_RELATIVE:
1160 *values = Source->HeadRelative;
1161 return AL_TRUE;
1163 case AL_LOOPING:
1164 *values = Source->Looping;
1165 return AL_TRUE;
1167 case AL_BUFFER:
1168 ReadLock(&Source->queue_lock);
1169 BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) :
1170 ATOMIC_LOAD(&Source->current_buffer);
1171 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1172 ReadUnlock(&Source->queue_lock);
1173 return AL_TRUE;
1175 case AL_SOURCE_STATE:
1176 *values = Source->state;
1177 return AL_TRUE;
1179 case AL_BYTE_LENGTH_SOFT:
1180 ReadLock(&Source->queue_lock);
1181 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1182 *values = 0;
1183 else
1185 ALint length = 0;
1186 do {
1187 ALbuffer *buffer = BufferList->buffer;
1188 if(buffer && buffer->SampleLen > 0)
1190 ALuint byte_align, sample_align;
1191 if(buffer->OriginalType == UserFmtIMA4)
1193 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1194 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1195 sample_align = buffer->OriginalAlign;
1197 else if(buffer->OriginalType == UserFmtMSADPCM)
1199 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1200 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1201 sample_align = buffer->OriginalAlign;
1203 else
1205 ALsizei align = buffer->OriginalAlign;
1206 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1207 sample_align = buffer->OriginalAlign;
1210 length += buffer->SampleLen / sample_align * byte_align;
1212 } while((BufferList=BufferList->next) != NULL);
1213 *values = length;
1215 ReadUnlock(&Source->queue_lock);
1216 return AL_TRUE;
1218 case AL_SAMPLE_LENGTH_SOFT:
1219 ReadLock(&Source->queue_lock);
1220 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1221 *values = 0;
1222 else
1224 ALint length = 0;
1225 do {
1226 ALbuffer *buffer = BufferList->buffer;
1227 if(buffer) length += buffer->SampleLen;
1228 } while((BufferList=BufferList->next) != NULL);
1229 *values = length;
1231 ReadUnlock(&Source->queue_lock);
1232 return AL_TRUE;
1234 case AL_BUFFERS_QUEUED:
1235 ReadLock(&Source->queue_lock);
1236 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1237 *values = 0;
1238 else
1240 ALsizei count = 0;
1241 do {
1242 ++count;
1243 } while((BufferList=BufferList->next) != NULL);
1244 *values = count;
1246 ReadUnlock(&Source->queue_lock);
1247 return AL_TRUE;
1249 case AL_BUFFERS_PROCESSED:
1250 ReadLock(&Source->queue_lock);
1251 if(Source->Looping || Source->SourceType != AL_STREAMING)
1253 /* Buffers on a looping source are in a perpetual state of
1254 * PENDING, so don't report any as PROCESSED */
1255 *values = 0;
1257 else
1259 const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue);
1260 const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer);
1261 ALsizei played = 0;
1262 while(BufferList && BufferList != Current)
1264 played++;
1265 BufferList = BufferList->next;
1267 *values = played;
1269 ReadUnlock(&Source->queue_lock);
1270 return AL_TRUE;
1272 case AL_SOURCE_TYPE:
1273 *values = Source->SourceType;
1274 return AL_TRUE;
1276 case AL_DIRECT_FILTER_GAINHF_AUTO:
1277 *values = Source->DryGainHFAuto;
1278 return AL_TRUE;
1280 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1281 *values = Source->WetGainAuto;
1282 return AL_TRUE;
1284 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1285 *values = Source->WetGainHFAuto;
1286 return AL_TRUE;
1288 case AL_DIRECT_CHANNELS_SOFT:
1289 *values = Source->DirectChannels;
1290 return AL_TRUE;
1292 case AL_DISTANCE_MODEL:
1293 *values = Source->DistanceModel;
1294 return AL_TRUE;
1296 /* 1x float/double */
1297 case AL_CONE_INNER_ANGLE:
1298 case AL_CONE_OUTER_ANGLE:
1299 case AL_PITCH:
1300 case AL_GAIN:
1301 case AL_MIN_GAIN:
1302 case AL_MAX_GAIN:
1303 case AL_REFERENCE_DISTANCE:
1304 case AL_ROLLOFF_FACTOR:
1305 case AL_CONE_OUTER_GAIN:
1306 case AL_MAX_DISTANCE:
1307 case AL_SEC_OFFSET:
1308 case AL_SAMPLE_OFFSET:
1309 case AL_BYTE_OFFSET:
1310 case AL_DOPPLER_FACTOR:
1311 case AL_AIR_ABSORPTION_FACTOR:
1312 case AL_ROOM_ROLLOFF_FACTOR:
1313 case AL_CONE_OUTER_GAINHF:
1314 case AL_SEC_LENGTH_SOFT:
1315 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1316 *values = (ALint)dvals[0];
1317 return err;
1319 /* 2x float/double */
1320 case AL_SAMPLE_RW_OFFSETS_SOFT:
1321 case AL_BYTE_RW_OFFSETS_SOFT:
1322 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1324 values[0] = (ALint)dvals[0];
1325 values[1] = (ALint)dvals[1];
1327 return err;
1329 /* 3x float/double */
1330 case AL_POSITION:
1331 case AL_VELOCITY:
1332 case AL_DIRECTION:
1333 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1335 values[0] = (ALint)dvals[0];
1336 values[1] = (ALint)dvals[1];
1337 values[2] = (ALint)dvals[2];
1339 return err;
1341 /* 6x float/double */
1342 case AL_ORIENTATION:
1343 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1345 values[0] = (ALint)dvals[0];
1346 values[1] = (ALint)dvals[1];
1347 values[2] = (ALint)dvals[2];
1348 values[3] = (ALint)dvals[3];
1349 values[4] = (ALint)dvals[4];
1350 values[5] = (ALint)dvals[5];
1352 return err;
1354 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1355 break; /* i64 only */
1356 case AL_SEC_OFFSET_LATENCY_SOFT:
1357 break; /* Double only */
1358 case AL_STEREO_ANGLES:
1359 break; /* Float/double only */
1361 case AL_DIRECT_FILTER:
1362 case AL_AUXILIARY_SEND_FILTER:
1363 break; /* ??? */
1366 ERR("Unexpected property: 0x%04x\n", prop);
1367 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1370 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1372 ALCdevice *device = Context->Device;
1373 ALdouble dvals[6];
1374 ALint ivals[3];
1375 ALboolean err;
1377 switch(prop)
1379 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1380 LockContext(Context);
1381 values[0] = GetSourceSampleOffset(Source);
1382 values[1] = V0(device->Backend,getLatency)();
1383 UnlockContext(Context);
1384 return AL_TRUE;
1386 /* 1x float/double */
1387 case AL_CONE_INNER_ANGLE:
1388 case AL_CONE_OUTER_ANGLE:
1389 case AL_PITCH:
1390 case AL_GAIN:
1391 case AL_MIN_GAIN:
1392 case AL_MAX_GAIN:
1393 case AL_REFERENCE_DISTANCE:
1394 case AL_ROLLOFF_FACTOR:
1395 case AL_CONE_OUTER_GAIN:
1396 case AL_MAX_DISTANCE:
1397 case AL_SEC_OFFSET:
1398 case AL_SAMPLE_OFFSET:
1399 case AL_BYTE_OFFSET:
1400 case AL_DOPPLER_FACTOR:
1401 case AL_AIR_ABSORPTION_FACTOR:
1402 case AL_ROOM_ROLLOFF_FACTOR:
1403 case AL_CONE_OUTER_GAINHF:
1404 case AL_SEC_LENGTH_SOFT:
1405 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1406 *values = (ALint64)dvals[0];
1407 return err;
1409 /* 2x float/double */
1410 case AL_SAMPLE_RW_OFFSETS_SOFT:
1411 case AL_BYTE_RW_OFFSETS_SOFT:
1412 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1414 values[0] = (ALint64)dvals[0];
1415 values[1] = (ALint64)dvals[1];
1417 return err;
1419 /* 3x float/double */
1420 case AL_POSITION:
1421 case AL_VELOCITY:
1422 case AL_DIRECTION:
1423 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1425 values[0] = (ALint64)dvals[0];
1426 values[1] = (ALint64)dvals[1];
1427 values[2] = (ALint64)dvals[2];
1429 return err;
1431 /* 6x float/double */
1432 case AL_ORIENTATION:
1433 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1435 values[0] = (ALint64)dvals[0];
1436 values[1] = (ALint64)dvals[1];
1437 values[2] = (ALint64)dvals[2];
1438 values[3] = (ALint64)dvals[3];
1439 values[4] = (ALint64)dvals[4];
1440 values[5] = (ALint64)dvals[5];
1442 return err;
1444 /* 1x int */
1445 case AL_SOURCE_RELATIVE:
1446 case AL_LOOPING:
1447 case AL_SOURCE_STATE:
1448 case AL_BUFFERS_QUEUED:
1449 case AL_BUFFERS_PROCESSED:
1450 case AL_BYTE_LENGTH_SOFT:
1451 case AL_SAMPLE_LENGTH_SOFT:
1452 case AL_SOURCE_TYPE:
1453 case AL_DIRECT_FILTER_GAINHF_AUTO:
1454 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1455 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1456 case AL_DIRECT_CHANNELS_SOFT:
1457 case AL_DISTANCE_MODEL:
1458 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1459 *values = ivals[0];
1460 return err;
1462 /* 1x uint */
1463 case AL_BUFFER:
1464 case AL_DIRECT_FILTER:
1465 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1466 *values = (ALuint)ivals[0];
1467 return err;
1469 /* 3x uint */
1470 case AL_AUXILIARY_SEND_FILTER:
1471 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1473 values[0] = (ALuint)ivals[0];
1474 values[1] = (ALuint)ivals[1];
1475 values[2] = (ALuint)ivals[2];
1477 return err;
1479 case AL_SEC_OFFSET_LATENCY_SOFT:
1480 break; /* Double only */
1481 case AL_STEREO_ANGLES:
1482 break; /* Float/double only */
1485 ERR("Unexpected property: 0x%04x\n", prop);
1486 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1490 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1492 ALCcontext *context;
1493 ALsizei cur = 0;
1494 ALenum err;
1496 context = GetContextRef();
1497 if(!context) return;
1499 if(!(n >= 0))
1500 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1501 for(cur = 0;cur < n;cur++)
1503 ALsource *source = al_calloc(16, sizeof(ALsource));
1504 if(!source)
1506 alDeleteSources(cur, sources);
1507 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1509 InitSourceParams(source);
1511 err = NewThunkEntry(&source->id);
1512 if(err == AL_NO_ERROR)
1513 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1514 if(err != AL_NO_ERROR)
1516 FreeThunkEntry(source->id);
1517 memset(source, 0, sizeof(ALsource));
1518 al_free(source);
1520 alDeleteSources(cur, sources);
1521 SET_ERROR_AND_GOTO(context, err, done);
1524 sources[cur] = source->id;
1527 done:
1528 ALCcontext_DecRef(context);
1532 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1534 ALCcontext *context;
1535 ALbufferlistitem *BufferList;
1536 ALsource *Source;
1537 ALsizei i, j;
1539 context = GetContextRef();
1540 if(!context) return;
1542 if(!(n >= 0))
1543 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1545 /* Check that all Sources are valid */
1546 for(i = 0;i < n;i++)
1548 if(LookupSource(context, sources[i]) == NULL)
1549 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1551 for(i = 0;i < n;i++)
1553 ALvoice *voice, *voice_end;
1555 if((Source=RemoveSource(context, sources[i])) == NULL)
1556 continue;
1557 FreeThunkEntry(Source->id);
1559 LockContext(context);
1560 voice = context->Voices;
1561 voice_end = voice + context->VoiceCount;
1562 while(voice != voice_end)
1564 ALsource *old = Source;
1565 if(COMPARE_EXCHANGE(&voice->Source, &old, NULL))
1566 break;
1567 voice++;
1569 UnlockContext(context);
1571 BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, NULL);
1572 while(BufferList != NULL)
1574 ALbufferlistitem *next = BufferList->next;
1575 if(BufferList->buffer != NULL)
1576 DecrementRef(&BufferList->buffer->ref);
1577 free(BufferList);
1578 BufferList = next;
1581 for(j = 0;j < MAX_SENDS;++j)
1583 if(Source->Send[j].Slot)
1584 DecrementRef(&Source->Send[j].Slot->ref);
1585 Source->Send[j].Slot = NULL;
1588 memset(Source, 0, sizeof(*Source));
1589 al_free(Source);
1592 done:
1593 ALCcontext_DecRef(context);
1597 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1599 ALCcontext *context;
1600 ALboolean ret;
1602 context = GetContextRef();
1603 if(!context) return AL_FALSE;
1605 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1607 ALCcontext_DecRef(context);
1609 return ret;
1613 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1615 ALCcontext *Context;
1616 ALsource *Source;
1618 Context = GetContextRef();
1619 if(!Context) return;
1621 if((Source=LookupSource(Context, source)) == NULL)
1622 alSetError(Context, AL_INVALID_NAME);
1623 else if(!(FloatValsByProp(param) == 1))
1624 alSetError(Context, AL_INVALID_ENUM);
1625 else
1626 SetSourcefv(Source, Context, param, &value);
1628 ALCcontext_DecRef(Context);
1631 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1633 ALCcontext *Context;
1634 ALsource *Source;
1636 Context = GetContextRef();
1637 if(!Context) return;
1639 if((Source=LookupSource(Context, source)) == NULL)
1640 alSetError(Context, AL_INVALID_NAME);
1641 else if(!(FloatValsByProp(param) == 3))
1642 alSetError(Context, AL_INVALID_ENUM);
1643 else
1645 ALfloat fvals[3] = { value1, value2, value3 };
1646 SetSourcefv(Source, Context, param, fvals);
1649 ALCcontext_DecRef(Context);
1652 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1654 ALCcontext *Context;
1655 ALsource *Source;
1657 Context = GetContextRef();
1658 if(!Context) return;
1660 if((Source=LookupSource(Context, source)) == NULL)
1661 alSetError(Context, AL_INVALID_NAME);
1662 else if(!values)
1663 alSetError(Context, AL_INVALID_VALUE);
1664 else if(!(FloatValsByProp(param) > 0))
1665 alSetError(Context, AL_INVALID_ENUM);
1666 else
1667 SetSourcefv(Source, Context, param, values);
1669 ALCcontext_DecRef(Context);
1673 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1675 ALCcontext *Context;
1676 ALsource *Source;
1678 Context = GetContextRef();
1679 if(!Context) return;
1681 if((Source=LookupSource(Context, source)) == NULL)
1682 alSetError(Context, AL_INVALID_NAME);
1683 else if(!(DoubleValsByProp(param) == 1))
1684 alSetError(Context, AL_INVALID_ENUM);
1685 else
1687 ALfloat fval = (ALfloat)value;
1688 SetSourcefv(Source, Context, param, &fval);
1691 ALCcontext_DecRef(Context);
1694 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1696 ALCcontext *Context;
1697 ALsource *Source;
1699 Context = GetContextRef();
1700 if(!Context) return;
1702 if((Source=LookupSource(Context, source)) == NULL)
1703 alSetError(Context, AL_INVALID_NAME);
1704 else if(!(DoubleValsByProp(param) == 3))
1705 alSetError(Context, AL_INVALID_ENUM);
1706 else
1708 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1709 SetSourcefv(Source, Context, param, fvals);
1712 ALCcontext_DecRef(Context);
1715 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1717 ALCcontext *Context;
1718 ALsource *Source;
1719 ALint count;
1721 Context = GetContextRef();
1722 if(!Context) return;
1724 if((Source=LookupSource(Context, source)) == NULL)
1725 alSetError(Context, AL_INVALID_NAME);
1726 else if(!values)
1727 alSetError(Context, AL_INVALID_VALUE);
1728 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1729 alSetError(Context, AL_INVALID_ENUM);
1730 else
1732 ALfloat fvals[6];
1733 ALint i;
1735 for(i = 0;i < count;i++)
1736 fvals[i] = (ALfloat)values[i];
1737 SetSourcefv(Source, Context, param, fvals);
1740 ALCcontext_DecRef(Context);
1744 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1746 ALCcontext *Context;
1747 ALsource *Source;
1749 Context = GetContextRef();
1750 if(!Context) return;
1752 if((Source=LookupSource(Context, source)) == NULL)
1753 alSetError(Context, AL_INVALID_NAME);
1754 else if(!(IntValsByProp(param) == 1))
1755 alSetError(Context, AL_INVALID_ENUM);
1756 else
1757 SetSourceiv(Source, Context, param, &value);
1759 ALCcontext_DecRef(Context);
1762 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1764 ALCcontext *Context;
1765 ALsource *Source;
1767 Context = GetContextRef();
1768 if(!Context) return;
1770 if((Source=LookupSource(Context, source)) == NULL)
1771 alSetError(Context, AL_INVALID_NAME);
1772 else if(!(IntValsByProp(param) == 3))
1773 alSetError(Context, AL_INVALID_ENUM);
1774 else
1776 ALint ivals[3] = { value1, value2, value3 };
1777 SetSourceiv(Source, Context, param, ivals);
1780 ALCcontext_DecRef(Context);
1783 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1785 ALCcontext *Context;
1786 ALsource *Source;
1788 Context = GetContextRef();
1789 if(!Context) return;
1791 if((Source=LookupSource(Context, source)) == NULL)
1792 alSetError(Context, AL_INVALID_NAME);
1793 else if(!values)
1794 alSetError(Context, AL_INVALID_VALUE);
1795 else if(!(IntValsByProp(param) > 0))
1796 alSetError(Context, AL_INVALID_ENUM);
1797 else
1798 SetSourceiv(Source, Context, param, values);
1800 ALCcontext_DecRef(Context);
1804 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1806 ALCcontext *Context;
1807 ALsource *Source;
1809 Context = GetContextRef();
1810 if(!Context) return;
1812 if((Source=LookupSource(Context, source)) == NULL)
1813 alSetError(Context, AL_INVALID_NAME);
1814 else if(!(Int64ValsByProp(param) == 1))
1815 alSetError(Context, AL_INVALID_ENUM);
1816 else
1817 SetSourcei64v(Source, Context, param, &value);
1819 ALCcontext_DecRef(Context);
1822 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1824 ALCcontext *Context;
1825 ALsource *Source;
1827 Context = GetContextRef();
1828 if(!Context) return;
1830 if((Source=LookupSource(Context, source)) == NULL)
1831 alSetError(Context, AL_INVALID_NAME);
1832 else if(!(Int64ValsByProp(param) == 3))
1833 alSetError(Context, AL_INVALID_ENUM);
1834 else
1836 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1837 SetSourcei64v(Source, Context, param, i64vals);
1840 ALCcontext_DecRef(Context);
1843 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1845 ALCcontext *Context;
1846 ALsource *Source;
1848 Context = GetContextRef();
1849 if(!Context) return;
1851 if((Source=LookupSource(Context, source)) == NULL)
1852 alSetError(Context, AL_INVALID_NAME);
1853 else if(!values)
1854 alSetError(Context, AL_INVALID_VALUE);
1855 else if(!(Int64ValsByProp(param) > 0))
1856 alSetError(Context, AL_INVALID_ENUM);
1857 else
1858 SetSourcei64v(Source, Context, param, values);
1860 ALCcontext_DecRef(Context);
1864 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1866 ALCcontext *Context;
1867 ALsource *Source;
1869 Context = GetContextRef();
1870 if(!Context) return;
1872 if((Source=LookupSource(Context, source)) == NULL)
1873 alSetError(Context, AL_INVALID_NAME);
1874 else if(!value)
1875 alSetError(Context, AL_INVALID_VALUE);
1876 else if(!(FloatValsByProp(param) == 1))
1877 alSetError(Context, AL_INVALID_ENUM);
1878 else
1880 ALdouble dval;
1881 if(GetSourcedv(Source, Context, param, &dval))
1882 *value = (ALfloat)dval;
1885 ALCcontext_DecRef(Context);
1889 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1891 ALCcontext *Context;
1892 ALsource *Source;
1894 Context = GetContextRef();
1895 if(!Context) return;
1897 if((Source=LookupSource(Context, source)) == NULL)
1898 alSetError(Context, AL_INVALID_NAME);
1899 else if(!(value1 && value2 && value3))
1900 alSetError(Context, AL_INVALID_VALUE);
1901 else if(!(FloatValsByProp(param) == 3))
1902 alSetError(Context, AL_INVALID_ENUM);
1903 else
1905 ALdouble dvals[3];
1906 if(GetSourcedv(Source, Context, param, dvals))
1908 *value1 = (ALfloat)dvals[0];
1909 *value2 = (ALfloat)dvals[1];
1910 *value3 = (ALfloat)dvals[2];
1914 ALCcontext_DecRef(Context);
1918 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1920 ALCcontext *Context;
1921 ALsource *Source;
1922 ALint count;
1924 Context = GetContextRef();
1925 if(!Context) return;
1927 if((Source=LookupSource(Context, source)) == NULL)
1928 alSetError(Context, AL_INVALID_NAME);
1929 else if(!values)
1930 alSetError(Context, AL_INVALID_VALUE);
1931 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
1932 alSetError(Context, AL_INVALID_ENUM);
1933 else
1935 ALdouble dvals[6];
1936 if(GetSourcedv(Source, Context, param, dvals))
1938 ALint i;
1939 for(i = 0;i < count;i++)
1940 values[i] = (ALfloat)dvals[i];
1944 ALCcontext_DecRef(Context);
1948 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1950 ALCcontext *Context;
1951 ALsource *Source;
1953 Context = GetContextRef();
1954 if(!Context) return;
1956 if((Source=LookupSource(Context, source)) == NULL)
1957 alSetError(Context, AL_INVALID_NAME);
1958 else if(!value)
1959 alSetError(Context, AL_INVALID_VALUE);
1960 else if(!(DoubleValsByProp(param) == 1))
1961 alSetError(Context, AL_INVALID_ENUM);
1962 else
1963 GetSourcedv(Source, Context, param, value);
1965 ALCcontext_DecRef(Context);
1968 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1970 ALCcontext *Context;
1971 ALsource *Source;
1973 Context = GetContextRef();
1974 if(!Context) return;
1976 if((Source=LookupSource(Context, source)) == NULL)
1977 alSetError(Context, AL_INVALID_NAME);
1978 else if(!(value1 && value2 && value3))
1979 alSetError(Context, AL_INVALID_VALUE);
1980 else if(!(DoubleValsByProp(param) == 3))
1981 alSetError(Context, AL_INVALID_ENUM);
1982 else
1984 ALdouble dvals[3];
1985 if(GetSourcedv(Source, Context, param, dvals))
1987 *value1 = dvals[0];
1988 *value2 = dvals[1];
1989 *value3 = dvals[2];
1993 ALCcontext_DecRef(Context);
1996 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1998 ALCcontext *Context;
1999 ALsource *Source;
2001 Context = GetContextRef();
2002 if(!Context) return;
2004 if((Source=LookupSource(Context, source)) == NULL)
2005 alSetError(Context, AL_INVALID_NAME);
2006 else if(!values)
2007 alSetError(Context, AL_INVALID_VALUE);
2008 else if(!(DoubleValsByProp(param) > 0))
2009 alSetError(Context, AL_INVALID_ENUM);
2010 else
2011 GetSourcedv(Source, Context, param, values);
2013 ALCcontext_DecRef(Context);
2017 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2019 ALCcontext *Context;
2020 ALsource *Source;
2022 Context = GetContextRef();
2023 if(!Context) return;
2025 if((Source=LookupSource(Context, source)) == NULL)
2026 alSetError(Context, AL_INVALID_NAME);
2027 else if(!value)
2028 alSetError(Context, AL_INVALID_VALUE);
2029 else if(!(IntValsByProp(param) == 1))
2030 alSetError(Context, AL_INVALID_ENUM);
2031 else
2032 GetSourceiv(Source, Context, param, value);
2034 ALCcontext_DecRef(Context);
2038 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2040 ALCcontext *Context;
2041 ALsource *Source;
2043 Context = GetContextRef();
2044 if(!Context) return;
2046 if((Source=LookupSource(Context, source)) == NULL)
2047 alSetError(Context, AL_INVALID_NAME);
2048 else if(!(value1 && value2 && value3))
2049 alSetError(Context, AL_INVALID_VALUE);
2050 else if(!(IntValsByProp(param) == 3))
2051 alSetError(Context, AL_INVALID_ENUM);
2052 else
2054 ALint ivals[3];
2055 if(GetSourceiv(Source, Context, param, ivals))
2057 *value1 = ivals[0];
2058 *value2 = ivals[1];
2059 *value3 = ivals[2];
2063 ALCcontext_DecRef(Context);
2067 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2069 ALCcontext *Context;
2070 ALsource *Source;
2072 Context = GetContextRef();
2073 if(!Context) return;
2075 if((Source=LookupSource(Context, source)) == NULL)
2076 alSetError(Context, AL_INVALID_NAME);
2077 else if(!values)
2078 alSetError(Context, AL_INVALID_VALUE);
2079 else if(!(IntValsByProp(param) > 0))
2080 alSetError(Context, AL_INVALID_ENUM);
2081 else
2082 GetSourceiv(Source, Context, param, values);
2084 ALCcontext_DecRef(Context);
2088 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2090 ALCcontext *Context;
2091 ALsource *Source;
2093 Context = GetContextRef();
2094 if(!Context) return;
2096 if((Source=LookupSource(Context, source)) == NULL)
2097 alSetError(Context, AL_INVALID_NAME);
2098 else if(!value)
2099 alSetError(Context, AL_INVALID_VALUE);
2100 else if(!(Int64ValsByProp(param) == 1))
2101 alSetError(Context, AL_INVALID_ENUM);
2102 else
2103 GetSourcei64v(Source, Context, param, value);
2105 ALCcontext_DecRef(Context);
2108 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2110 ALCcontext *Context;
2111 ALsource *Source;
2113 Context = GetContextRef();
2114 if(!Context) return;
2116 if((Source=LookupSource(Context, source)) == NULL)
2117 alSetError(Context, AL_INVALID_NAME);
2118 else if(!(value1 && value2 && value3))
2119 alSetError(Context, AL_INVALID_VALUE);
2120 else if(!(Int64ValsByProp(param) == 3))
2121 alSetError(Context, AL_INVALID_ENUM);
2122 else
2124 ALint64 i64vals[3];
2125 if(GetSourcei64v(Source, Context, param, i64vals))
2127 *value1 = i64vals[0];
2128 *value2 = i64vals[1];
2129 *value3 = i64vals[2];
2133 ALCcontext_DecRef(Context);
2136 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2138 ALCcontext *Context;
2139 ALsource *Source;
2141 Context = GetContextRef();
2142 if(!Context) return;
2144 if((Source=LookupSource(Context, source)) == NULL)
2145 alSetError(Context, AL_INVALID_NAME);
2146 else if(!values)
2147 alSetError(Context, AL_INVALID_VALUE);
2148 else if(!(Int64ValsByProp(param) > 0))
2149 alSetError(Context, AL_INVALID_ENUM);
2150 else
2151 GetSourcei64v(Source, Context, param, values);
2153 ALCcontext_DecRef(Context);
2157 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2159 alSourcePlayv(1, &source);
2161 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2163 ALCcontext *context;
2164 ALsource *source;
2165 ALsizei i;
2167 context = GetContextRef();
2168 if(!context) return;
2170 if(!(n >= 0))
2171 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2172 for(i = 0;i < n;i++)
2174 if(!LookupSource(context, sources[i]))
2175 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2178 LockContext(context);
2179 while(n > context->MaxVoices-context->VoiceCount)
2181 ALvoice *temp = NULL;
2182 ALsizei newcount;
2184 newcount = context->MaxVoices << 1;
2185 if(newcount > 0)
2186 temp = realloc(context->Voices, newcount * sizeof(context->Voices[0]));
2187 if(!temp)
2189 UnlockContext(context);
2190 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2192 memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0]));
2194 context->Voices = temp;
2195 context->MaxVoices = newcount;
2198 for(i = 0;i < n;i++)
2200 source = LookupSource(context, sources[i]);
2201 if(context->DeferUpdates) source->new_state = AL_PLAYING;
2202 else SetSourceState(source, context, AL_PLAYING);
2204 UnlockContext(context);
2206 done:
2207 ALCcontext_DecRef(context);
2210 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2212 alSourcePausev(1, &source);
2214 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2216 ALCcontext *context;
2217 ALsource *source;
2218 ALsizei i;
2220 context = GetContextRef();
2221 if(!context) return;
2223 if(!(n >= 0))
2224 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2225 for(i = 0;i < n;i++)
2227 if(!LookupSource(context, sources[i]))
2228 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2231 LockContext(context);
2232 for(i = 0;i < n;i++)
2234 source = LookupSource(context, sources[i]);
2235 if(context->DeferUpdates) source->new_state = AL_PAUSED;
2236 else SetSourceState(source, context, AL_PAUSED);
2238 UnlockContext(context);
2240 done:
2241 ALCcontext_DecRef(context);
2244 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2246 alSourceStopv(1, &source);
2248 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2250 ALCcontext *context;
2251 ALsource *source;
2252 ALsizei i;
2254 context = GetContextRef();
2255 if(!context) return;
2257 if(!(n >= 0))
2258 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2259 for(i = 0;i < n;i++)
2261 if(!LookupSource(context, sources[i]))
2262 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2265 LockContext(context);
2266 for(i = 0;i < n;i++)
2268 source = LookupSource(context, sources[i]);
2269 source->new_state = AL_NONE;
2270 SetSourceState(source, context, AL_STOPPED);
2272 UnlockContext(context);
2274 done:
2275 ALCcontext_DecRef(context);
2278 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2280 alSourceRewindv(1, &source);
2282 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2284 ALCcontext *context;
2285 ALsource *source;
2286 ALsizei i;
2288 context = GetContextRef();
2289 if(!context) return;
2291 if(!(n >= 0))
2292 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2293 for(i = 0;i < n;i++)
2295 if(!LookupSource(context, sources[i]))
2296 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2299 LockContext(context);
2300 for(i = 0;i < n;i++)
2302 source = LookupSource(context, sources[i]);
2303 source->new_state = AL_NONE;
2304 SetSourceState(source, context, AL_INITIAL);
2306 UnlockContext(context);
2308 done:
2309 ALCcontext_DecRef(context);
2313 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2315 ALCdevice *device;
2316 ALCcontext *context;
2317 ALsource *source;
2318 ALsizei i;
2319 ALbufferlistitem *BufferListStart;
2320 ALbufferlistitem *BufferList;
2321 ALbuffer *BufferFmt = NULL;
2323 if(nb == 0)
2324 return;
2326 context = GetContextRef();
2327 if(!context) return;
2329 device = context->Device;
2331 if(!(nb >= 0))
2332 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2333 if((source=LookupSource(context, src)) == NULL)
2334 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2336 WriteLock(&source->queue_lock);
2337 if(source->SourceType == AL_STATIC)
2339 WriteUnlock(&source->queue_lock);
2340 /* Can't queue on a Static Source */
2341 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2344 /* Check for a valid Buffer, for its frequency and format */
2345 BufferList = ATOMIC_LOAD(&source->queue);
2346 while(BufferList)
2348 if(BufferList->buffer)
2350 BufferFmt = BufferList->buffer;
2351 break;
2353 BufferList = BufferList->next;
2356 BufferListStart = NULL;
2357 BufferList = NULL;
2358 for(i = 0;i < nb;i++)
2360 ALbuffer *buffer = NULL;
2361 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2363 WriteUnlock(&source->queue_lock);
2364 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2367 if(!BufferListStart)
2369 BufferListStart = malloc(sizeof(ALbufferlistitem));
2370 BufferList = BufferListStart;
2372 else
2374 BufferList->next = malloc(sizeof(ALbufferlistitem));
2375 BufferList = BufferList->next;
2377 BufferList->buffer = buffer;
2378 BufferList->next = NULL;
2379 if(!buffer) continue;
2381 /* Hold a read lock on each buffer being queued while checking all
2382 * provided buffers. This is done so other threads don't see an extra
2383 * reference on some buffers if this operation ends up failing. */
2384 ReadLock(&buffer->lock);
2385 IncrementRef(&buffer->ref);
2387 if(BufferFmt == NULL)
2389 BufferFmt = buffer;
2391 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2392 source->SampleSize = BytesFromFmt(buffer->FmtType);
2394 else if(BufferFmt->Frequency != buffer->Frequency ||
2395 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2396 BufferFmt->OriginalType != buffer->OriginalType)
2398 WriteUnlock(&source->queue_lock);
2399 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2401 buffer_error:
2402 /* A buffer failed (invalid ID or format), so unlock and release
2403 * each buffer we had. */
2404 while(BufferListStart)
2406 ALbufferlistitem *next = BufferListStart->next;
2407 if((buffer=BufferListStart->buffer) != NULL)
2409 DecrementRef(&buffer->ref);
2410 ReadUnlock(&buffer->lock);
2412 free(BufferListStart);
2413 BufferListStart = next;
2415 goto done;
2418 /* All buffers good, unlock them now. */
2419 BufferList = BufferListStart;
2420 while(BufferList != NULL)
2422 ALbuffer *buffer = BufferList->buffer;
2423 if(buffer) ReadUnlock(&buffer->lock);
2424 BufferList = BufferList->next;
2427 /* Source is now streaming */
2428 source->SourceType = AL_STREAMING;
2430 BufferList = NULL;
2431 if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
2433 /* Queue head is not NULL, append to the end of the queue */
2434 while(BufferList->next != NULL)
2435 BufferList = BufferList->next;
2436 BufferList->next = BufferListStart;
2438 /* If the current buffer was at the end (NULL), put it at the start of the newly queued
2439 * buffers.
2441 BufferList = NULL;
2442 ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
2443 WriteUnlock(&source->queue_lock);
2445 done:
2446 ALCcontext_DecRef(context);
2449 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2451 ALCcontext *context;
2452 ALsource *source;
2453 ALbufferlistitem *OldHead;
2454 ALbufferlistitem *OldTail;
2455 ALbufferlistitem *Current;
2456 ALsizei i = 0;
2458 if(nb == 0)
2459 return;
2461 context = GetContextRef();
2462 if(!context) return;
2464 if(!(nb >= 0))
2465 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2467 if((source=LookupSource(context, src)) == NULL)
2468 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2470 WriteLock(&source->queue_lock);
2471 /* Find the new buffer queue head */
2472 OldTail = ATOMIC_LOAD(&source->queue);
2473 Current = ATOMIC_LOAD(&source->current_buffer);
2474 if(OldTail != Current)
2476 for(i = 1;i < nb;i++)
2478 ALbufferlistitem *next = OldTail->next;
2479 if(!next || next == Current) break;
2480 OldTail = next;
2483 if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
2485 WriteUnlock(&source->queue_lock);
2486 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2487 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2490 /* Swap it, and cut the new head from the old. */
2491 OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, OldTail->next);
2492 if(OldTail->next)
2494 ALCdevice *device = context->Device;
2495 uint count;
2497 /* Once the active mix (if any) is done, it's safe to cut the old tail
2498 * from the new head.
2500 if(((count=ReadRef(&device->MixCount))&1) != 0)
2502 while(count == ReadRef(&device->MixCount))
2503 althrd_yield();
2505 OldTail->next = NULL;
2507 WriteUnlock(&source->queue_lock);
2509 while(OldHead != NULL)
2511 ALbufferlistitem *next = OldHead->next;
2512 ALbuffer *buffer = OldHead->buffer;
2514 if(!buffer)
2515 *(buffers++) = 0;
2516 else
2518 *(buffers++) = buffer->id;
2519 DecrementRef(&buffer->ref);
2522 free(OldHead);
2523 OldHead = next;
2526 done:
2527 ALCcontext_DecRef(context);
2531 static ALvoid InitSourceParams(ALsource *Source)
2533 ALuint i;
2535 RWLockInit(&Source->queue_lock);
2537 Source->InnerAngle = 360.0f;
2538 Source->OuterAngle = 360.0f;
2539 Source->Pitch = 1.0f;
2540 aluVectorSet(&Source->Position, 0.0f, 0.0f, 0.0f, 1.0f);
2541 aluVectorSet(&Source->Velocity, 0.0f, 0.0f, 0.0f, 0.0f);
2542 aluVectorSet(&Source->Direction, 0.0f, 0.0f, 0.0f, 0.0f);
2543 Source->Orientation[0][0] = 0.0f;
2544 Source->Orientation[0][1] = 0.0f;
2545 Source->Orientation[0][2] = -1.0f;
2546 Source->Orientation[1][0] = 0.0f;
2547 Source->Orientation[1][1] = 1.0f;
2548 Source->Orientation[1][2] = 0.0f;
2549 Source->RefDistance = 1.0f;
2550 Source->MaxDistance = FLT_MAX;
2551 Source->RollOffFactor = 1.0f;
2552 Source->Looping = AL_FALSE;
2553 Source->Gain = 1.0f;
2554 Source->MinGain = 0.0f;
2555 Source->MaxGain = 1.0f;
2556 Source->OuterGain = 0.0f;
2557 Source->OuterGainHF = 1.0f;
2559 Source->DryGainHFAuto = AL_TRUE;
2560 Source->WetGainAuto = AL_TRUE;
2561 Source->WetGainHFAuto = AL_TRUE;
2562 Source->AirAbsorptionFactor = 0.0f;
2563 Source->RoomRolloffFactor = 0.0f;
2564 Source->DopplerFactor = 1.0f;
2565 Source->DirectChannels = AL_FALSE;
2567 Source->StereoPan[0] = DEG2RAD( 30.0f);
2568 Source->StereoPan[1] = DEG2RAD(-30.0f);
2570 Source->Radius = 0.0f;
2572 Source->DistanceModel = DefaultDistanceModel;
2574 Source->state = AL_INITIAL;
2575 Source->new_state = AL_NONE;
2576 Source->SourceType = AL_UNDETERMINED;
2577 Source->Offset = -1.0;
2579 ATOMIC_INIT(&Source->queue, NULL);
2580 ATOMIC_INIT(&Source->current_buffer, NULL);
2582 Source->Direct.Gain = 1.0f;
2583 Source->Direct.GainHF = 1.0f;
2584 Source->Direct.HFReference = LOWPASSFREQREF;
2585 Source->Direct.GainLF = 1.0f;
2586 Source->Direct.LFReference = HIGHPASSFREQREF;
2587 for(i = 0;i < MAX_SENDS;i++)
2589 Source->Send[i].Gain = 1.0f;
2590 Source->Send[i].GainHF = 1.0f;
2591 Source->Send[i].HFReference = LOWPASSFREQREF;
2592 Source->Send[i].GainLF = 1.0f;
2593 Source->Send[i].LFReference = HIGHPASSFREQREF;
2596 ATOMIC_INIT(&Source->NeedsUpdate, AL_TRUE);
2600 /* SetSourceState
2602 * Sets the source's new play state given its current state.
2604 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2606 WriteLock(&Source->queue_lock);
2607 if(state == AL_PLAYING)
2609 ALCdevice *device = Context->Device;
2610 ALbufferlistitem *BufferList;
2611 ALboolean discontinuity;
2612 ALvoice *voice = NULL;
2613 ALsizei i;
2615 /* Check that there is a queue containing at least one valid, non zero
2616 * length Buffer. */
2617 BufferList = ATOMIC_LOAD(&Source->queue);
2618 while(BufferList)
2620 ALbuffer *buffer;
2621 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2622 break;
2623 BufferList = BufferList->next;
2626 if(Source->state != AL_PAUSED)
2628 Source->state = AL_PLAYING;
2629 Source->position = 0;
2630 Source->position_fraction = 0;
2631 ATOMIC_STORE(&Source->current_buffer, BufferList);
2632 discontinuity = AL_TRUE;
2634 else
2636 Source->state = AL_PLAYING;
2637 discontinuity = AL_FALSE;
2640 // Check if an Offset has been set
2641 if(Source->Offset >= 0.0)
2643 ApplyOffset(Source);
2644 /* discontinuity = AL_TRUE;??? */
2647 /* If there's nothing to play, or device is disconnected, go right to
2648 * stopped */
2649 if(!BufferList || !device->Connected)
2650 goto do_stop;
2652 /* Make sure this source isn't already active, while looking for an
2653 * unused active source slot to put it in. */
2654 for(i = 0;i < Context->VoiceCount;i++)
2656 ALsource *old = Source;
2657 if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL))
2659 if(voice == NULL)
2661 voice = &Context->Voices[i];
2662 voice->Source = Source;
2664 break;
2666 old = NULL;
2667 if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source))
2668 voice = &Context->Voices[i];
2670 if(voice == NULL)
2672 voice = &Context->Voices[Context->VoiceCount++];
2673 voice->Source = Source;
2676 /* Clear previous samples if playback is discontinuous. */
2677 if(discontinuity)
2678 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
2680 voice->Moving = AL_FALSE;
2681 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
2683 ALsizei j;
2684 for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
2685 voice->Direct.Hrtf[i].State.History[j] = 0.0f;
2686 for(j = 0;j < HRIR_LENGTH;j++)
2688 voice->Direct.Hrtf[i].State.Values[j][0] = 0.0f;
2689 voice->Direct.Hrtf[i].State.Values[j][1] = 0.0f;
2693 if(BufferList->buffer->FmtChannels == FmtMono)
2694 voice->Update = CalcSourceParams;
2695 else
2696 voice->Update = CalcNonAttnSourceParams;
2698 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
2700 else if(state == AL_PAUSED)
2702 if(Source->state == AL_PLAYING)
2703 Source->state = AL_PAUSED;
2705 else if(state == AL_STOPPED)
2707 do_stop:
2708 if(Source->state != AL_INITIAL)
2710 Source->state = AL_STOPPED;
2711 ATOMIC_STORE(&Source->current_buffer, NULL);
2713 Source->Offset = -1.0;
2715 else if(state == AL_INITIAL)
2717 if(Source->state != AL_INITIAL)
2719 Source->state = AL_INITIAL;
2720 Source->position = 0;
2721 Source->position_fraction = 0;
2722 ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue));
2724 Source->Offset = -1.0;
2726 WriteUnlock(&Source->queue_lock);
2729 /* GetSourceSampleOffset
2731 * Gets the current read offset for the given Source, in 32.32 fixed-point
2732 * samples. The offset is relative to the start of the queue (not the start of
2733 * the current buffer).
2735 ALint64 GetSourceSampleOffset(ALsource *Source)
2737 const ALbufferlistitem *BufferList;
2738 const ALbufferlistitem *Current;
2739 ALuint64 readPos;
2741 ReadLock(&Source->queue_lock);
2742 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2744 ReadUnlock(&Source->queue_lock);
2745 return 0;
2748 /* NOTE: This is the offset into the *current* buffer, so add the length of
2749 * any played buffers */
2750 readPos = (ALuint64)Source->position << 32;
2751 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2752 BufferList = ATOMIC_LOAD(&Source->queue);
2753 Current = ATOMIC_LOAD(&Source->current_buffer);
2754 while(BufferList && BufferList != Current)
2756 if(BufferList->buffer)
2757 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2758 BufferList = BufferList->next;
2761 ReadUnlock(&Source->queue_lock);
2762 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
2765 /* GetSourceSecOffset
2767 * Gets the current read offset for the given Source, in seconds. The offset is
2768 * relative to the start of the queue (not the start of the current buffer).
2770 static ALdouble GetSourceSecOffset(ALsource *Source)
2772 const ALbufferlistitem *BufferList;
2773 const ALbufferlistitem *Current;
2774 const ALbuffer *Buffer = NULL;
2775 ALuint64 readPos;
2777 ReadLock(&Source->queue_lock);
2778 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2780 ReadUnlock(&Source->queue_lock);
2781 return 0.0;
2784 /* NOTE: This is the offset into the *current* buffer, so add the length of
2785 * any played buffers */
2786 readPos = (ALuint64)Source->position << FRACTIONBITS;
2787 readPos |= (ALuint64)Source->position_fraction;
2788 BufferList = ATOMIC_LOAD(&Source->queue);
2789 Current = ATOMIC_LOAD(&Source->current_buffer);
2790 while(BufferList && BufferList != Current)
2792 const ALbuffer *buffer = BufferList->buffer;
2793 if(buffer != NULL)
2795 if(!Buffer) Buffer = buffer;
2796 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
2798 BufferList = BufferList->next;
2801 while(BufferList && !Buffer)
2803 Buffer = BufferList->buffer;
2804 BufferList = BufferList->next;
2806 assert(Buffer != NULL);
2808 ReadUnlock(&Source->queue_lock);
2809 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2812 /* GetSourceOffsets
2814 * Gets the current read and write offsets for the given Source, in the
2815 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2816 * the start of the queue (not the start of the current buffer).
2818 static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2820 const ALbufferlistitem *BufferList;
2821 const ALbufferlistitem *Current;
2822 const ALbuffer *Buffer = NULL;
2823 ALboolean readFin = AL_FALSE;
2824 ALuint readPos, readPosFrac, writePos;
2825 ALuint totalBufferLen;
2827 ReadLock(&Source->queue_lock);
2828 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2830 offset[0] = 0.0;
2831 offset[1] = 0.0;
2832 ReadUnlock(&Source->queue_lock);
2833 return;
2836 if(updateLen > 0.0 && updateLen < 0.015)
2837 updateLen = 0.015;
2839 /* NOTE: This is the offset into the *current* buffer, so add the length of
2840 * any played buffers */
2841 totalBufferLen = 0;
2842 readPos = Source->position;
2843 readPosFrac = Source->position_fraction;
2844 BufferList = ATOMIC_LOAD(&Source->queue);
2845 Current = ATOMIC_LOAD(&Source->current_buffer);
2846 while(BufferList != NULL)
2848 const ALbuffer *buffer;
2849 readFin = readFin || (BufferList == Current);
2850 if((buffer=BufferList->buffer) != NULL)
2852 if(!Buffer) Buffer = buffer;
2853 totalBufferLen += buffer->SampleLen;
2854 if(!readFin) readPos += buffer->SampleLen;
2856 BufferList = BufferList->next;
2858 assert(Buffer != NULL);
2860 if(Source->state == AL_PLAYING)
2861 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency + 0.5f);
2862 else
2863 writePos = readPos;
2865 if(Source->Looping)
2867 readPos %= totalBufferLen;
2868 writePos %= totalBufferLen;
2870 else
2872 /* Wrap positions back to 0 */
2873 if(readPos >= totalBufferLen)
2874 readPos = readPosFrac = 0;
2875 if(writePos >= totalBufferLen)
2876 writePos = 0;
2879 switch(name)
2881 case AL_SEC_OFFSET:
2882 offset[0] = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
2883 offset[1] = (ALdouble)writePos/Buffer->Frequency;
2884 break;
2886 case AL_SAMPLE_OFFSET:
2887 case AL_SAMPLE_RW_OFFSETS_SOFT:
2888 offset[0] = readPos + (ALdouble)readPosFrac/FRACTIONONE;
2889 offset[1] = (ALdouble)writePos;
2890 break;
2892 case AL_BYTE_OFFSET:
2893 case AL_BYTE_RW_OFFSETS_SOFT:
2894 if(Buffer->OriginalType == UserFmtIMA4)
2896 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2897 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2898 ALuint FrameBlockSize = Buffer->OriginalAlign;
2900 /* Round down to nearest ADPCM block */
2901 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2902 if(Source->state != AL_PLAYING)
2903 offset[1] = offset[0];
2904 else
2906 /* Round up to nearest ADPCM block */
2907 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2908 FrameBlockSize * BlockSize);
2911 else if(Buffer->OriginalType == UserFmtMSADPCM)
2913 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2914 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2915 ALuint FrameBlockSize = Buffer->OriginalAlign;
2917 /* Round down to nearest ADPCM block */
2918 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2919 if(Source->state != AL_PLAYING)
2920 offset[1] = offset[0];
2921 else
2923 /* Round up to nearest ADPCM block */
2924 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2925 FrameBlockSize * BlockSize);
2928 else
2930 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2931 offset[0] = (ALdouble)(readPos * FrameSize);
2932 offset[1] = (ALdouble)(writePos * FrameSize);
2934 break;
2937 ReadUnlock(&Source->queue_lock);
2941 /* ApplyOffset
2943 * Apply the stored playback offset to the Source. This function will update
2944 * the number of buffers "played" given the stored offset.
2946 ALboolean ApplyOffset(ALsource *Source)
2948 ALbufferlistitem *BufferList;
2949 const ALbuffer *Buffer;
2950 ALuint bufferLen, totalBufferLen;
2951 ALuint offset=0, frac=0;
2953 /* Get sample frame offset */
2954 if(!GetSampleOffset(Source, &offset, &frac))
2955 return AL_FALSE;
2957 totalBufferLen = 0;
2958 BufferList = ATOMIC_LOAD(&Source->queue);
2959 while(BufferList && totalBufferLen <= offset)
2961 Buffer = BufferList->buffer;
2962 bufferLen = Buffer ? Buffer->SampleLen : 0;
2964 if(bufferLen > offset-totalBufferLen)
2966 /* Offset is in this buffer */
2967 ATOMIC_STORE(&Source->current_buffer, BufferList);
2969 Source->position = offset - totalBufferLen;
2970 Source->position_fraction = frac;
2971 return AL_TRUE;
2974 totalBufferLen += bufferLen;
2976 BufferList = BufferList->next;
2979 /* Offset is out of range of the queue */
2980 return AL_FALSE;
2984 /* GetSampleOffset
2986 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
2987 * or Second offset supplied by the application). This takes into account the
2988 * fact that the buffer format may have been modifed since.
2990 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
2992 const ALbuffer *Buffer = NULL;
2993 const ALbufferlistitem *BufferList;
2994 ALdouble dbloff, dblfrac;
2996 /* Find the first valid Buffer in the Queue */
2997 BufferList = ATOMIC_LOAD(&Source->queue);
2998 while(BufferList)
3000 if(BufferList->buffer)
3002 Buffer = BufferList->buffer;
3003 break;
3005 BufferList = BufferList->next;
3007 if(!Buffer)
3009 Source->Offset = -1.0;
3010 return AL_FALSE;
3013 switch(Source->OffsetType)
3015 case AL_BYTE_OFFSET:
3016 /* Determine the ByteOffset (and ensure it is block aligned) */
3017 *offset = (ALuint)Source->Offset;
3018 if(Buffer->OriginalType == UserFmtIMA4)
3020 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3021 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3022 *offset *= Buffer->OriginalAlign;
3024 else if(Buffer->OriginalType == UserFmtMSADPCM)
3026 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3027 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3028 *offset *= Buffer->OriginalAlign;
3030 else
3031 *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3032 *frac = 0;
3033 break;
3035 case AL_SAMPLE_OFFSET:
3036 dblfrac = modf(Source->Offset, &dbloff);
3037 *offset = (ALuint)mind(dbloff, UINT_MAX);
3038 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3039 break;
3041 case AL_SEC_OFFSET:
3042 dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
3043 *offset = (ALuint)mind(dbloff, UINT_MAX);
3044 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3045 break;
3047 Source->Offset = -1.0;
3049 return AL_TRUE;
3053 /* ReleaseALSources
3055 * Destroys all sources in the source map.
3057 ALvoid ReleaseALSources(ALCcontext *Context)
3059 ALbufferlistitem *item;
3060 ALsizei pos;
3061 ALuint j;
3062 for(pos = 0;pos < Context->SourceMap.size;pos++)
3064 ALsource *temp = Context->SourceMap.array[pos].value;
3065 Context->SourceMap.array[pos].value = NULL;
3067 item = ATOMIC_EXCHANGE(ALbufferlistitem*, &temp->queue, NULL);
3068 while(item != NULL)
3070 ALbufferlistitem *next = item->next;
3071 if(item->buffer != NULL)
3072 DecrementRef(&item->buffer->ref);
3073 free(item);
3074 item = next;
3077 for(j = 0;j < MAX_SENDS;++j)
3079 if(temp->Send[j].Slot)
3080 DecrementRef(&temp->Send[j].Slot->ref);
3081 temp->Send[j].Slot = NULL;
3084 FreeThunkEntry(temp->id);
3085 memset(temp, 0, sizeof(*temp));
3086 al_free(temp);