Move the resampler stuff to mixer.c where it's used
[openal-soft.git] / OpenAL32 / alSource.c
blob7ab17c74a47df6dfe1c5164779f2ed18db7bba35
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 <math.h>
25 #include <float.h>
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alMain.h"
30 #include "alError.h"
31 #include "alSource.h"
32 #include "alBuffer.h"
33 #include "alThunk.h"
34 #include "alAuxEffectSlot.h"
36 #include "backends/base.h"
38 #include "threads.h"
41 extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
42 extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
44 static ALvoid InitSourceParams(ALsource *Source);
45 static ALint64 GetSourceSampleOffset(ALsource *Source);
46 static ALdouble GetSourceSecOffset(ALsource *Source);
47 static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
48 static ALint GetSampleOffset(ALsource *Source);
50 typedef enum SourceProp {
51 srcPitch = AL_PITCH,
52 srcGain = AL_GAIN,
53 srcMinGain = AL_MIN_GAIN,
54 srcMaxGain = AL_MAX_GAIN,
55 srcMaxDistance = AL_MAX_DISTANCE,
56 srcRolloffFactor = AL_ROLLOFF_FACTOR,
57 srcDopplerFactor = AL_DOPPLER_FACTOR,
58 srcConeOuterGain = AL_CONE_OUTER_GAIN,
59 srcSecOffset = AL_SEC_OFFSET,
60 srcSampleOffset = AL_SAMPLE_OFFSET,
61 srcByteOffset = AL_BYTE_OFFSET,
62 srcConeInnerAngle = AL_CONE_INNER_ANGLE,
63 srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
64 srcRefDistance = AL_REFERENCE_DISTANCE,
66 srcPosition = AL_POSITION,
67 srcVelocity = AL_VELOCITY,
68 srcDirection = AL_DIRECTION,
70 srcSourceRelative = AL_SOURCE_RELATIVE,
71 srcLooping = AL_LOOPING,
72 srcBuffer = AL_BUFFER,
73 srcSourceState = AL_SOURCE_STATE,
74 srcBuffersQueued = AL_BUFFERS_QUEUED,
75 srcBuffersProcessed = AL_BUFFERS_PROCESSED,
76 srcSourceType = AL_SOURCE_TYPE,
78 /* ALC_EXT_EFX */
79 srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
80 srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
81 srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
82 srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
83 srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
84 srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
85 srcDirectFilter = AL_DIRECT_FILTER,
86 srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
88 /* AL_SOFT_direct_channels */
89 srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
91 /* AL_EXT_source_distance_model */
92 srcDistanceModel = AL_DISTANCE_MODEL,
94 srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
95 srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
96 srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
98 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
99 srcSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
100 srcByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
102 /* AL_SOFT_source_latency */
103 srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
104 srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
106 /* AL_EXT_BFORMAT */
107 srcOrientation = AL_ORIENTATION,
108 } SourceProp;
110 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
111 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
112 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
114 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
115 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
116 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
118 static ALint FloatValsByProp(ALenum prop)
120 if(prop != (ALenum)((SourceProp)prop))
121 return 0;
122 switch((SourceProp)prop)
124 case AL_PITCH:
125 case AL_GAIN:
126 case AL_MIN_GAIN:
127 case AL_MAX_GAIN:
128 case AL_MAX_DISTANCE:
129 case AL_ROLLOFF_FACTOR:
130 case AL_DOPPLER_FACTOR:
131 case AL_CONE_OUTER_GAIN:
132 case AL_SEC_OFFSET:
133 case AL_SAMPLE_OFFSET:
134 case AL_BYTE_OFFSET:
135 case AL_CONE_INNER_ANGLE:
136 case AL_CONE_OUTER_ANGLE:
137 case AL_REFERENCE_DISTANCE:
138 case AL_CONE_OUTER_GAINHF:
139 case AL_AIR_ABSORPTION_FACTOR:
140 case AL_ROOM_ROLLOFF_FACTOR:
141 case AL_DIRECT_FILTER_GAINHF_AUTO:
142 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
143 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
144 case AL_DIRECT_CHANNELS_SOFT:
145 case AL_DISTANCE_MODEL:
146 case AL_SOURCE_RELATIVE:
147 case AL_LOOPING:
148 case AL_SOURCE_STATE:
149 case AL_BUFFERS_QUEUED:
150 case AL_BUFFERS_PROCESSED:
151 case AL_SOURCE_TYPE:
152 case AL_BYTE_LENGTH_SOFT:
153 case AL_SAMPLE_LENGTH_SOFT:
154 case AL_SEC_LENGTH_SOFT:
155 return 1;
157 case AL_SAMPLE_RW_OFFSETS_SOFT:
158 case AL_BYTE_RW_OFFSETS_SOFT:
159 return 2;
161 case AL_POSITION:
162 case AL_VELOCITY:
163 case AL_DIRECTION:
164 return 3;
166 case AL_ORIENTATION:
167 return 6;
169 case AL_SEC_OFFSET_LATENCY_SOFT:
170 break; /* Double only */
172 case AL_BUFFER:
173 case AL_DIRECT_FILTER:
174 case AL_AUXILIARY_SEND_FILTER:
175 break; /* i/i64 only */
176 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
177 break; /* i64 only */
179 return 0;
181 static ALint DoubleValsByProp(ALenum prop)
183 if(prop != (ALenum)((SourceProp)prop))
184 return 0;
185 switch((SourceProp)prop)
187 case AL_PITCH:
188 case AL_GAIN:
189 case AL_MIN_GAIN:
190 case AL_MAX_GAIN:
191 case AL_MAX_DISTANCE:
192 case AL_ROLLOFF_FACTOR:
193 case AL_DOPPLER_FACTOR:
194 case AL_CONE_OUTER_GAIN:
195 case AL_SEC_OFFSET:
196 case AL_SAMPLE_OFFSET:
197 case AL_BYTE_OFFSET:
198 case AL_CONE_INNER_ANGLE:
199 case AL_CONE_OUTER_ANGLE:
200 case AL_REFERENCE_DISTANCE:
201 case AL_CONE_OUTER_GAINHF:
202 case AL_AIR_ABSORPTION_FACTOR:
203 case AL_ROOM_ROLLOFF_FACTOR:
204 case AL_DIRECT_FILTER_GAINHF_AUTO:
205 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
206 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
207 case AL_DIRECT_CHANNELS_SOFT:
208 case AL_DISTANCE_MODEL:
209 case AL_SOURCE_RELATIVE:
210 case AL_LOOPING:
211 case AL_SOURCE_STATE:
212 case AL_BUFFERS_QUEUED:
213 case AL_BUFFERS_PROCESSED:
214 case AL_SOURCE_TYPE:
215 case AL_BYTE_LENGTH_SOFT:
216 case AL_SAMPLE_LENGTH_SOFT:
217 case AL_SEC_LENGTH_SOFT:
218 return 1;
220 case AL_SAMPLE_RW_OFFSETS_SOFT:
221 case AL_BYTE_RW_OFFSETS_SOFT:
222 case AL_SEC_OFFSET_LATENCY_SOFT:
223 return 2;
225 case AL_POSITION:
226 case AL_VELOCITY:
227 case AL_DIRECTION:
228 return 3;
230 case AL_ORIENTATION:
231 return 6;
233 case AL_BUFFER:
234 case AL_DIRECT_FILTER:
235 case AL_AUXILIARY_SEND_FILTER:
236 break; /* i/i64 only */
237 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
238 break; /* i64 only */
240 return 0;
243 static ALint IntValsByProp(ALenum prop)
245 if(prop != (ALenum)((SourceProp)prop))
246 return 0;
247 switch((SourceProp)prop)
249 case AL_PITCH:
250 case AL_GAIN:
251 case AL_MIN_GAIN:
252 case AL_MAX_GAIN:
253 case AL_MAX_DISTANCE:
254 case AL_ROLLOFF_FACTOR:
255 case AL_DOPPLER_FACTOR:
256 case AL_CONE_OUTER_GAIN:
257 case AL_SEC_OFFSET:
258 case AL_SAMPLE_OFFSET:
259 case AL_BYTE_OFFSET:
260 case AL_CONE_INNER_ANGLE:
261 case AL_CONE_OUTER_ANGLE:
262 case AL_REFERENCE_DISTANCE:
263 case AL_CONE_OUTER_GAINHF:
264 case AL_AIR_ABSORPTION_FACTOR:
265 case AL_ROOM_ROLLOFF_FACTOR:
266 case AL_DIRECT_FILTER_GAINHF_AUTO:
267 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
268 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
269 case AL_DIRECT_CHANNELS_SOFT:
270 case AL_DISTANCE_MODEL:
271 case AL_SOURCE_RELATIVE:
272 case AL_LOOPING:
273 case AL_BUFFER:
274 case AL_SOURCE_STATE:
275 case AL_BUFFERS_QUEUED:
276 case AL_BUFFERS_PROCESSED:
277 case AL_SOURCE_TYPE:
278 case AL_DIRECT_FILTER:
279 case AL_BYTE_LENGTH_SOFT:
280 case AL_SAMPLE_LENGTH_SOFT:
281 case AL_SEC_LENGTH_SOFT:
282 return 1;
284 case AL_SAMPLE_RW_OFFSETS_SOFT:
285 case AL_BYTE_RW_OFFSETS_SOFT:
286 return 2;
288 case AL_POSITION:
289 case AL_VELOCITY:
290 case AL_DIRECTION:
291 case AL_AUXILIARY_SEND_FILTER:
292 return 3;
294 case AL_ORIENTATION:
295 return 6;
297 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
298 break; /* i64 only */
299 case AL_SEC_OFFSET_LATENCY_SOFT:
300 break; /* Double only */
302 return 0;
304 static ALint Int64ValsByProp(ALenum prop)
306 if(prop != (ALenum)((SourceProp)prop))
307 return 0;
308 switch((SourceProp)prop)
310 case AL_PITCH:
311 case AL_GAIN:
312 case AL_MIN_GAIN:
313 case AL_MAX_GAIN:
314 case AL_MAX_DISTANCE:
315 case AL_ROLLOFF_FACTOR:
316 case AL_DOPPLER_FACTOR:
317 case AL_CONE_OUTER_GAIN:
318 case AL_SEC_OFFSET:
319 case AL_SAMPLE_OFFSET:
320 case AL_BYTE_OFFSET:
321 case AL_CONE_INNER_ANGLE:
322 case AL_CONE_OUTER_ANGLE:
323 case AL_REFERENCE_DISTANCE:
324 case AL_CONE_OUTER_GAINHF:
325 case AL_AIR_ABSORPTION_FACTOR:
326 case AL_ROOM_ROLLOFF_FACTOR:
327 case AL_DIRECT_FILTER_GAINHF_AUTO:
328 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
329 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
330 case AL_DIRECT_CHANNELS_SOFT:
331 case AL_DISTANCE_MODEL:
332 case AL_SOURCE_RELATIVE:
333 case AL_LOOPING:
334 case AL_BUFFER:
335 case AL_SOURCE_STATE:
336 case AL_BUFFERS_QUEUED:
337 case AL_BUFFERS_PROCESSED:
338 case AL_SOURCE_TYPE:
339 case AL_DIRECT_FILTER:
340 case AL_BYTE_LENGTH_SOFT:
341 case AL_SAMPLE_LENGTH_SOFT:
342 case AL_SEC_LENGTH_SOFT:
343 return 1;
345 case AL_SAMPLE_RW_OFFSETS_SOFT:
346 case AL_BYTE_RW_OFFSETS_SOFT:
347 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
348 return 2;
350 case AL_POSITION:
351 case AL_VELOCITY:
352 case AL_DIRECTION:
353 case AL_AUXILIARY_SEND_FILTER:
354 return 3;
356 case AL_ORIENTATION:
357 return 6;
359 case AL_SEC_OFFSET_LATENCY_SOFT:
360 break; /* Double only */
362 return 0;
366 #define CHECKVAL(x) do { \
367 if(!(x)) \
368 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
369 } while(0)
371 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
373 ALint ival;
375 switch(prop)
377 case AL_BYTE_RW_OFFSETS_SOFT:
378 case AL_SAMPLE_RW_OFFSETS_SOFT:
379 case AL_BYTE_LENGTH_SOFT:
380 case AL_SAMPLE_LENGTH_SOFT:
381 case AL_SEC_LENGTH_SOFT:
382 case AL_SEC_OFFSET_LATENCY_SOFT:
383 /* Query only */
384 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
386 case AL_PITCH:
387 CHECKVAL(*values >= 0.0f);
389 Source->Pitch = *values;
390 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
391 return AL_TRUE;
393 case AL_CONE_INNER_ANGLE:
394 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
396 Source->InnerAngle = *values;
397 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
398 return AL_TRUE;
400 case AL_CONE_OUTER_ANGLE:
401 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
403 Source->OuterAngle = *values;
404 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
405 return AL_TRUE;
407 case AL_GAIN:
408 CHECKVAL(*values >= 0.0f);
410 Source->Gain = *values;
411 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
412 return AL_TRUE;
414 case AL_MAX_DISTANCE:
415 CHECKVAL(*values >= 0.0f);
417 Source->MaxDistance = *values;
418 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
419 return AL_TRUE;
421 case AL_ROLLOFF_FACTOR:
422 CHECKVAL(*values >= 0.0f);
424 Source->RollOffFactor = *values;
425 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
426 return AL_TRUE;
428 case AL_REFERENCE_DISTANCE:
429 CHECKVAL(*values >= 0.0f);
431 Source->RefDistance = *values;
432 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
433 return AL_TRUE;
435 case AL_MIN_GAIN:
436 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
438 Source->MinGain = *values;
439 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
440 return AL_TRUE;
442 case AL_MAX_GAIN:
443 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
445 Source->MaxGain = *values;
446 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
447 return AL_TRUE;
449 case AL_CONE_OUTER_GAIN:
450 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
452 Source->OuterGain = *values;
453 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
454 return AL_TRUE;
456 case AL_CONE_OUTER_GAINHF:
457 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
459 Source->OuterGainHF = *values;
460 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
461 return AL_TRUE;
463 case AL_AIR_ABSORPTION_FACTOR:
464 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
466 Source->AirAbsorptionFactor = *values;
467 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
468 return AL_TRUE;
470 case AL_ROOM_ROLLOFF_FACTOR:
471 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
473 Source->RoomRolloffFactor = *values;
474 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
475 return AL_TRUE;
477 case AL_DOPPLER_FACTOR:
478 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
480 Source->DopplerFactor = *values;
481 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
482 return AL_TRUE;
484 case AL_SEC_OFFSET:
485 case AL_SAMPLE_OFFSET:
486 case AL_BYTE_OFFSET:
487 CHECKVAL(*values >= 0.0f);
489 LockContext(Context);
490 Source->OffsetType = prop;
491 Source->Offset = *values;
493 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
494 !Context->DeferUpdates)
496 ReadLock(&Source->queue_lock);
497 if(ApplyOffset(Source) == AL_FALSE)
499 ReadUnlock(&Source->queue_lock);
500 UnlockContext(Context);
501 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
503 ReadUnlock(&Source->queue_lock);
505 UnlockContext(Context);
506 return AL_TRUE;
509 case AL_POSITION:
510 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
512 LockContext(Context);
513 aluVectorSet(&Source->Position, values[0], values[1], values[2], 1.0f);
514 UnlockContext(Context);
515 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
516 return AL_TRUE;
518 case AL_VELOCITY:
519 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
521 LockContext(Context);
522 aluVectorSet(&Source->Velocity, values[0], values[1], values[2], 0.0f);
523 UnlockContext(Context);
524 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
525 return AL_TRUE;
527 case AL_DIRECTION:
528 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
530 LockContext(Context);
531 aluVectorSet(&Source->Direction, values[0], values[1], values[2], 0.0f);
532 UnlockContext(Context);
533 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
534 return AL_TRUE;
536 case AL_ORIENTATION:
537 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
538 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
540 LockContext(Context);
541 Source->Orientation[0][0] = values[0];
542 Source->Orientation[0][1] = values[1];
543 Source->Orientation[0][2] = values[2];
544 Source->Orientation[1][0] = values[3];
545 Source->Orientation[1][1] = values[4];
546 Source->Orientation[1][2] = values[5];
547 UnlockContext(Context);
548 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
549 return AL_TRUE;
552 case AL_SOURCE_RELATIVE:
553 case AL_LOOPING:
554 case AL_SOURCE_STATE:
555 case AL_SOURCE_TYPE:
556 case AL_DISTANCE_MODEL:
557 case AL_DIRECT_FILTER_GAINHF_AUTO:
558 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
559 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
560 case AL_DIRECT_CHANNELS_SOFT:
561 ival = (ALint)values[0];
562 return SetSourceiv(Source, Context, prop, &ival);
564 case AL_BUFFERS_QUEUED:
565 case AL_BUFFERS_PROCESSED:
566 ival = (ALint)((ALuint)values[0]);
567 return SetSourceiv(Source, Context, prop, &ival);
569 case AL_BUFFER:
570 case AL_DIRECT_FILTER:
571 case AL_AUXILIARY_SEND_FILTER:
572 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
573 break;
576 ERR("Unexpected property: 0x%04x\n", prop);
577 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
580 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
582 ALCdevice *device = Context->Device;
583 ALbuffer *buffer = NULL;
584 ALfilter *filter = NULL;
585 ALeffectslot *slot = NULL;
586 ALbufferlistitem *oldlist;
587 ALbufferlistitem *newlist;
588 ALfloat fvals[6];
590 switch(prop)
592 case AL_SOURCE_STATE:
593 case AL_SOURCE_TYPE:
594 case AL_BUFFERS_QUEUED:
595 case AL_BUFFERS_PROCESSED:
596 case AL_SAMPLE_RW_OFFSETS_SOFT:
597 case AL_BYTE_RW_OFFSETS_SOFT:
598 case AL_BYTE_LENGTH_SOFT:
599 case AL_SAMPLE_LENGTH_SOFT:
600 case AL_SEC_LENGTH_SOFT:
601 /* Query only */
602 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
604 case AL_SOURCE_RELATIVE:
605 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
607 Source->HeadRelative = (ALboolean)*values;
608 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
609 return AL_TRUE;
611 case AL_LOOPING:
612 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
614 Source->Looping = (ALboolean)*values;
615 return AL_TRUE;
617 case AL_BUFFER:
618 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
620 WriteLock(&Source->queue_lock);
621 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
623 WriteUnlock(&Source->queue_lock);
624 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
627 if(buffer != NULL)
629 /* Add the selected buffer to a one-item queue */
630 newlist = malloc(sizeof(ALbufferlistitem));
631 newlist->buffer = buffer;
632 newlist->next = NULL;
633 newlist->prev = NULL;
634 IncrementRef(&buffer->ref);
636 /* Source is now Static */
637 Source->SourceType = AL_STATIC;
639 ReadLock(&buffer->lock);
640 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
641 Source->SampleSize = BytesFromFmt(buffer->FmtType);
642 ReadUnlock(&buffer->lock);
644 else
646 /* Source is now Undetermined */
647 Source->SourceType = AL_UNDETERMINED;
648 newlist = NULL;
650 oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist);
651 ATOMIC_STORE(&Source->current_buffer, newlist);
652 WriteUnlock(&Source->queue_lock);
654 /* Delete all elements in the previous queue */
655 while(oldlist != NULL)
657 ALbufferlistitem *temp = oldlist;
658 oldlist = temp->next;
660 if(temp->buffer)
661 DecrementRef(&temp->buffer->ref);
662 free(temp);
664 return AL_TRUE;
666 case AL_SEC_OFFSET:
667 case AL_SAMPLE_OFFSET:
668 case AL_BYTE_OFFSET:
669 CHECKVAL(*values >= 0);
671 LockContext(Context);
672 Source->OffsetType = prop;
673 Source->Offset = *values;
675 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
676 !Context->DeferUpdates)
678 ReadLock(&Source->queue_lock);
679 if(ApplyOffset(Source) == AL_FALSE)
681 ReadUnlock(&Source->queue_lock);
682 UnlockContext(Context);
683 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
685 ReadUnlock(&Source->queue_lock);
687 UnlockContext(Context);
688 return AL_TRUE;
690 case AL_DIRECT_FILTER:
691 CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
693 LockContext(Context);
694 if(!filter)
696 Source->Direct.Gain = 1.0f;
697 Source->Direct.GainHF = 1.0f;
698 Source->Direct.HFReference = LOWPASSFREQREF;
699 Source->Direct.GainLF = 1.0f;
700 Source->Direct.LFReference = HIGHPASSFREQREF;
702 else
704 Source->Direct.Gain = filter->Gain;
705 Source->Direct.GainHF = filter->GainHF;
706 Source->Direct.HFReference = filter->HFReference;
707 Source->Direct.GainLF = filter->GainLF;
708 Source->Direct.LFReference = filter->LFReference;
710 UnlockContext(Context);
711 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
712 return AL_TRUE;
714 case AL_DIRECT_FILTER_GAINHF_AUTO:
715 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
717 Source->DryGainHFAuto = *values;
718 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
719 return AL_TRUE;
721 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
722 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
724 Source->WetGainAuto = *values;
725 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
726 return AL_TRUE;
728 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
729 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
731 Source->WetGainHFAuto = *values;
732 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
733 return AL_TRUE;
735 case AL_DIRECT_CHANNELS_SOFT:
736 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
738 Source->DirectChannels = *values;
739 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
740 return AL_TRUE;
742 case AL_DISTANCE_MODEL:
743 CHECKVAL(*values == AL_NONE ||
744 *values == AL_INVERSE_DISTANCE ||
745 *values == AL_INVERSE_DISTANCE_CLAMPED ||
746 *values == AL_LINEAR_DISTANCE ||
747 *values == AL_LINEAR_DISTANCE_CLAMPED ||
748 *values == AL_EXPONENT_DISTANCE ||
749 *values == AL_EXPONENT_DISTANCE_CLAMPED);
751 Source->DistanceModel = *values;
752 if(Context->SourceDistanceModel)
753 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
754 return AL_TRUE;
757 case AL_AUXILIARY_SEND_FILTER:
758 LockContext(Context);
759 if(!((ALuint)values[1] < device->NumAuxSends &&
760 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
761 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
763 UnlockContext(Context);
764 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
767 /* Add refcount on the new slot, and release the previous slot */
768 if(slot) IncrementRef(&slot->ref);
769 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
770 if(slot) DecrementRef(&slot->ref);
772 if(!filter)
774 /* Disable filter */
775 Source->Send[values[1]].Gain = 1.0f;
776 Source->Send[values[1]].GainHF = 1.0f;
777 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
778 Source->Send[values[1]].GainLF = 1.0f;
779 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
781 else
783 Source->Send[values[1]].Gain = filter->Gain;
784 Source->Send[values[1]].GainHF = filter->GainHF;
785 Source->Send[values[1]].HFReference = filter->HFReference;
786 Source->Send[values[1]].GainLF = filter->GainLF;
787 Source->Send[values[1]].LFReference = filter->LFReference;
789 UnlockContext(Context);
790 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
791 return AL_TRUE;
794 /* 1x float */
795 case AL_CONE_INNER_ANGLE:
796 case AL_CONE_OUTER_ANGLE:
797 case AL_PITCH:
798 case AL_GAIN:
799 case AL_MIN_GAIN:
800 case AL_MAX_GAIN:
801 case AL_REFERENCE_DISTANCE:
802 case AL_ROLLOFF_FACTOR:
803 case AL_CONE_OUTER_GAIN:
804 case AL_MAX_DISTANCE:
805 case AL_DOPPLER_FACTOR:
806 case AL_CONE_OUTER_GAINHF:
807 case AL_AIR_ABSORPTION_FACTOR:
808 case AL_ROOM_ROLLOFF_FACTOR:
809 fvals[0] = (ALfloat)*values;
810 return SetSourcefv(Source, Context, (int)prop, fvals);
812 /* 3x float */
813 case AL_POSITION:
814 case AL_VELOCITY:
815 case AL_DIRECTION:
816 fvals[0] = (ALfloat)values[0];
817 fvals[1] = (ALfloat)values[1];
818 fvals[2] = (ALfloat)values[2];
819 return SetSourcefv(Source, Context, (int)prop, fvals);
821 /* 6x float */
822 case AL_ORIENTATION:
823 fvals[0] = (ALfloat)values[0];
824 fvals[1] = (ALfloat)values[1];
825 fvals[2] = (ALfloat)values[2];
826 fvals[3] = (ALfloat)values[3];
827 fvals[4] = (ALfloat)values[4];
828 fvals[5] = (ALfloat)values[5];
829 return SetSourcefv(Source, Context, (int)prop, fvals);
831 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
832 case AL_SEC_OFFSET_LATENCY_SOFT:
833 break;
836 ERR("Unexpected property: 0x%04x\n", prop);
837 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
840 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
842 ALfloat fvals[6];
843 ALint ivals[3];
845 switch(prop)
847 case AL_SOURCE_TYPE:
848 case AL_BUFFERS_QUEUED:
849 case AL_BUFFERS_PROCESSED:
850 case AL_SOURCE_STATE:
851 case AL_SAMPLE_RW_OFFSETS_SOFT:
852 case AL_BYTE_RW_OFFSETS_SOFT:
853 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
854 case AL_BYTE_LENGTH_SOFT:
855 case AL_SAMPLE_LENGTH_SOFT:
856 case AL_SEC_LENGTH_SOFT:
857 /* Query only */
858 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
861 /* 1x int */
862 case AL_SOURCE_RELATIVE:
863 case AL_LOOPING:
864 case AL_SEC_OFFSET:
865 case AL_SAMPLE_OFFSET:
866 case AL_BYTE_OFFSET:
867 case AL_DIRECT_FILTER_GAINHF_AUTO:
868 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
869 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
870 case AL_DIRECT_CHANNELS_SOFT:
871 case AL_DISTANCE_MODEL:
872 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
874 ivals[0] = (ALint)*values;
875 return SetSourceiv(Source, Context, (int)prop, ivals);
877 /* 1x uint */
878 case AL_BUFFER:
879 case AL_DIRECT_FILTER:
880 CHECKVAL(*values <= UINT_MAX && *values >= 0);
882 ivals[0] = (ALuint)*values;
883 return SetSourceiv(Source, Context, (int)prop, ivals);
885 /* 3x uint */
886 case AL_AUXILIARY_SEND_FILTER:
887 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
888 values[1] <= UINT_MAX && values[1] >= 0 &&
889 values[2] <= UINT_MAX && values[2] >= 0);
891 ivals[0] = (ALuint)values[0];
892 ivals[1] = (ALuint)values[1];
893 ivals[2] = (ALuint)values[2];
894 return SetSourceiv(Source, Context, (int)prop, ivals);
896 /* 1x float */
897 case AL_CONE_INNER_ANGLE:
898 case AL_CONE_OUTER_ANGLE:
899 case AL_PITCH:
900 case AL_GAIN:
901 case AL_MIN_GAIN:
902 case AL_MAX_GAIN:
903 case AL_REFERENCE_DISTANCE:
904 case AL_ROLLOFF_FACTOR:
905 case AL_CONE_OUTER_GAIN:
906 case AL_MAX_DISTANCE:
907 case AL_DOPPLER_FACTOR:
908 case AL_CONE_OUTER_GAINHF:
909 case AL_AIR_ABSORPTION_FACTOR:
910 case AL_ROOM_ROLLOFF_FACTOR:
911 fvals[0] = (ALfloat)*values;
912 return SetSourcefv(Source, Context, (int)prop, fvals);
914 /* 3x float */
915 case AL_POSITION:
916 case AL_VELOCITY:
917 case AL_DIRECTION:
918 fvals[0] = (ALfloat)values[0];
919 fvals[1] = (ALfloat)values[1];
920 fvals[2] = (ALfloat)values[2];
921 return SetSourcefv(Source, Context, (int)prop, fvals);
923 /* 6x float */
924 case AL_ORIENTATION:
925 fvals[0] = (ALfloat)values[0];
926 fvals[1] = (ALfloat)values[1];
927 fvals[2] = (ALfloat)values[2];
928 fvals[3] = (ALfloat)values[3];
929 fvals[4] = (ALfloat)values[4];
930 fvals[5] = (ALfloat)values[5];
931 return SetSourcefv(Source, Context, (int)prop, fvals);
933 case AL_SEC_OFFSET_LATENCY_SOFT:
934 break;
937 ERR("Unexpected property: 0x%04x\n", prop);
938 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
941 #undef CHECKVAL
944 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
946 ALCdevice *device = Context->Device;
947 ALbufferlistitem *BufferList;
948 ALdouble offsets[2];
949 ALdouble updateLen;
950 ALint ivals[3];
951 ALboolean err;
953 switch(prop)
955 case AL_GAIN:
956 *values = Source->Gain;
957 return AL_TRUE;
959 case AL_PITCH:
960 *values = Source->Pitch;
961 return AL_TRUE;
963 case AL_MAX_DISTANCE:
964 *values = Source->MaxDistance;
965 return AL_TRUE;
967 case AL_ROLLOFF_FACTOR:
968 *values = Source->RollOffFactor;
969 return AL_TRUE;
971 case AL_REFERENCE_DISTANCE:
972 *values = Source->RefDistance;
973 return AL_TRUE;
975 case AL_CONE_INNER_ANGLE:
976 *values = Source->InnerAngle;
977 return AL_TRUE;
979 case AL_CONE_OUTER_ANGLE:
980 *values = Source->OuterAngle;
981 return AL_TRUE;
983 case AL_MIN_GAIN:
984 *values = Source->MinGain;
985 return AL_TRUE;
987 case AL_MAX_GAIN:
988 *values = Source->MaxGain;
989 return AL_TRUE;
991 case AL_CONE_OUTER_GAIN:
992 *values = Source->OuterGain;
993 return AL_TRUE;
995 case AL_SEC_OFFSET:
996 case AL_SAMPLE_OFFSET:
997 case AL_BYTE_OFFSET:
998 LockContext(Context);
999 GetSourceOffsets(Source, prop, offsets, 0.0);
1000 UnlockContext(Context);
1001 *values = offsets[0];
1002 return AL_TRUE;
1004 case AL_CONE_OUTER_GAINHF:
1005 *values = Source->OuterGainHF;
1006 return AL_TRUE;
1008 case AL_AIR_ABSORPTION_FACTOR:
1009 *values = Source->AirAbsorptionFactor;
1010 return AL_TRUE;
1012 case AL_ROOM_ROLLOFF_FACTOR:
1013 *values = Source->RoomRolloffFactor;
1014 return AL_TRUE;
1016 case AL_DOPPLER_FACTOR:
1017 *values = Source->DopplerFactor;
1018 return AL_TRUE;
1020 case AL_SEC_LENGTH_SOFT:
1021 ReadLock(&Source->queue_lock);
1022 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1023 *values = 0;
1024 else
1026 ALint length = 0;
1027 ALsizei freq = 1;
1028 do {
1029 ALbuffer *buffer = BufferList->buffer;
1030 if(buffer && buffer->SampleLen > 0)
1032 freq = buffer->Frequency;
1033 length += buffer->SampleLen;
1035 } while((BufferList=BufferList->next) != NULL);
1036 *values = (ALdouble)length / (ALdouble)freq;
1038 ReadUnlock(&Source->queue_lock);
1039 return AL_TRUE;
1041 case AL_SAMPLE_RW_OFFSETS_SOFT:
1042 case AL_BYTE_RW_OFFSETS_SOFT:
1043 LockContext(Context);
1044 updateLen = (ALdouble)device->UpdateSize / device->Frequency;
1045 GetSourceOffsets(Source, prop, values, updateLen);
1046 UnlockContext(Context);
1047 return AL_TRUE;
1049 case AL_SEC_OFFSET_LATENCY_SOFT:
1050 LockContext(Context);
1051 values[0] = GetSourceSecOffset(Source);
1052 values[1] = (ALdouble)(V0(device->Backend,getLatency)()) /
1053 1000000000.0;
1054 UnlockContext(Context);
1055 return AL_TRUE;
1057 case AL_POSITION:
1058 LockContext(Context);
1059 values[0] = Source->Position.v[0];
1060 values[1] = Source->Position.v[1];
1061 values[2] = Source->Position.v[2];
1062 UnlockContext(Context);
1063 return AL_TRUE;
1065 case AL_VELOCITY:
1066 LockContext(Context);
1067 values[0] = Source->Velocity.v[0];
1068 values[1] = Source->Velocity.v[1];
1069 values[2] = Source->Velocity.v[2];
1070 UnlockContext(Context);
1071 return AL_TRUE;
1073 case AL_DIRECTION:
1074 LockContext(Context);
1075 values[0] = Source->Direction.v[0];
1076 values[1] = Source->Direction.v[1];
1077 values[2] = Source->Direction.v[2];
1078 UnlockContext(Context);
1079 return AL_TRUE;
1081 case AL_ORIENTATION:
1082 LockContext(Context);
1083 values[0] = Source->Orientation[0][0];
1084 values[1] = Source->Orientation[0][1];
1085 values[2] = Source->Orientation[0][2];
1086 values[3] = Source->Orientation[1][0];
1087 values[4] = Source->Orientation[1][1];
1088 values[5] = Source->Orientation[1][2];
1089 UnlockContext(Context);
1090 return AL_TRUE;
1092 /* 1x int */
1093 case AL_SOURCE_RELATIVE:
1094 case AL_LOOPING:
1095 case AL_SOURCE_STATE:
1096 case AL_BUFFERS_QUEUED:
1097 case AL_BUFFERS_PROCESSED:
1098 case AL_SOURCE_TYPE:
1099 case AL_DIRECT_FILTER_GAINHF_AUTO:
1100 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1101 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1102 case AL_DIRECT_CHANNELS_SOFT:
1103 case AL_BYTE_LENGTH_SOFT:
1104 case AL_SAMPLE_LENGTH_SOFT:
1105 case AL_DISTANCE_MODEL:
1106 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1107 *values = (ALdouble)ivals[0];
1108 return err;
1110 case AL_BUFFER:
1111 case AL_DIRECT_FILTER:
1112 case AL_AUXILIARY_SEND_FILTER:
1113 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1114 break;
1117 ERR("Unexpected property: 0x%04x\n", prop);
1118 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1121 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1123 ALbufferlistitem *BufferList;
1124 ALdouble dvals[6];
1125 ALboolean err;
1127 switch(prop)
1129 case AL_SOURCE_RELATIVE:
1130 *values = Source->HeadRelative;
1131 return AL_TRUE;
1133 case AL_LOOPING:
1134 *values = Source->Looping;
1135 return AL_TRUE;
1137 case AL_BUFFER:
1138 ReadLock(&Source->queue_lock);
1139 BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) :
1140 ATOMIC_LOAD(&Source->current_buffer);
1141 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1142 ReadUnlock(&Source->queue_lock);
1143 return AL_TRUE;
1145 case AL_SOURCE_STATE:
1146 *values = Source->state;
1147 return AL_TRUE;
1149 case AL_BYTE_LENGTH_SOFT:
1150 ReadLock(&Source->queue_lock);
1151 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1152 *values = 0;
1153 else
1155 ALint length = 0;
1156 do {
1157 ALbuffer *buffer = BufferList->buffer;
1158 if(buffer && buffer->SampleLen > 0)
1160 ALuint byte_align, sample_align;
1161 if(buffer->OriginalType == UserFmtIMA4)
1163 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1164 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1165 sample_align = buffer->OriginalAlign;
1167 else if(buffer->OriginalType == UserFmtMSADPCM)
1169 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1170 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1171 sample_align = buffer->OriginalAlign;
1173 else
1175 ALsizei align = buffer->OriginalAlign;
1176 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1177 sample_align = buffer->OriginalAlign;
1180 length += buffer->SampleLen / sample_align * byte_align;
1182 } while((BufferList=BufferList->next) != NULL);
1183 *values = length;
1185 ReadUnlock(&Source->queue_lock);
1186 return AL_TRUE;
1188 case AL_SAMPLE_LENGTH_SOFT:
1189 ReadLock(&Source->queue_lock);
1190 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1191 *values = 0;
1192 else
1194 ALint length = 0;
1195 do {
1196 ALbuffer *buffer = BufferList->buffer;
1197 if(buffer) length += buffer->SampleLen;
1198 } while((BufferList=BufferList->next) != NULL);
1199 *values = length;
1201 ReadUnlock(&Source->queue_lock);
1202 return AL_TRUE;
1204 case AL_BUFFERS_QUEUED:
1205 ReadLock(&Source->queue_lock);
1206 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1207 *values = 0;
1208 else
1210 ALsizei count = 0;
1211 do {
1212 ++count;
1213 } while((BufferList=BufferList->next) != NULL);
1214 *values = count;
1216 ReadUnlock(&Source->queue_lock);
1217 return AL_TRUE;
1219 case AL_BUFFERS_PROCESSED:
1220 ReadLock(&Source->queue_lock);
1221 if(Source->Looping || Source->SourceType != AL_STREAMING)
1223 /* Buffers on a looping source are in a perpetual state of
1224 * PENDING, so don't report any as PROCESSED */
1225 *values = 0;
1227 else
1229 const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue);
1230 const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer);
1231 ALsizei played = 0;
1232 while(BufferList && BufferList != Current)
1234 played++;
1235 BufferList = BufferList->next;
1237 *values = played;
1239 ReadUnlock(&Source->queue_lock);
1240 return AL_TRUE;
1242 case AL_SOURCE_TYPE:
1243 *values = Source->SourceType;
1244 return AL_TRUE;
1246 case AL_DIRECT_FILTER_GAINHF_AUTO:
1247 *values = Source->DryGainHFAuto;
1248 return AL_TRUE;
1250 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1251 *values = Source->WetGainAuto;
1252 return AL_TRUE;
1254 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1255 *values = Source->WetGainHFAuto;
1256 return AL_TRUE;
1258 case AL_DIRECT_CHANNELS_SOFT:
1259 *values = Source->DirectChannels;
1260 return AL_TRUE;
1262 case AL_DISTANCE_MODEL:
1263 *values = Source->DistanceModel;
1264 return AL_TRUE;
1266 /* 1x float/double */
1267 case AL_CONE_INNER_ANGLE:
1268 case AL_CONE_OUTER_ANGLE:
1269 case AL_PITCH:
1270 case AL_GAIN:
1271 case AL_MIN_GAIN:
1272 case AL_MAX_GAIN:
1273 case AL_REFERENCE_DISTANCE:
1274 case AL_ROLLOFF_FACTOR:
1275 case AL_CONE_OUTER_GAIN:
1276 case AL_MAX_DISTANCE:
1277 case AL_SEC_OFFSET:
1278 case AL_SAMPLE_OFFSET:
1279 case AL_BYTE_OFFSET:
1280 case AL_DOPPLER_FACTOR:
1281 case AL_AIR_ABSORPTION_FACTOR:
1282 case AL_ROOM_ROLLOFF_FACTOR:
1283 case AL_CONE_OUTER_GAINHF:
1284 case AL_SEC_LENGTH_SOFT:
1285 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1286 *values = (ALint)dvals[0];
1287 return err;
1289 /* 2x float/double */
1290 case AL_SAMPLE_RW_OFFSETS_SOFT:
1291 case AL_BYTE_RW_OFFSETS_SOFT:
1292 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1294 values[0] = (ALint)dvals[0];
1295 values[1] = (ALint)dvals[1];
1297 return err;
1299 /* 3x float/double */
1300 case AL_POSITION:
1301 case AL_VELOCITY:
1302 case AL_DIRECTION:
1303 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1305 values[0] = (ALint)dvals[0];
1306 values[1] = (ALint)dvals[1];
1307 values[2] = (ALint)dvals[2];
1309 return err;
1311 /* 6x float/double */
1312 case AL_ORIENTATION:
1313 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1315 values[0] = (ALint)dvals[0];
1316 values[1] = (ALint)dvals[1];
1317 values[2] = (ALint)dvals[2];
1318 values[3] = (ALint)dvals[3];
1319 values[4] = (ALint)dvals[4];
1320 values[5] = (ALint)dvals[5];
1322 return err;
1324 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1325 break; /* i64 only */
1326 case AL_SEC_OFFSET_LATENCY_SOFT:
1327 break; /* Double only */
1329 case AL_DIRECT_FILTER:
1330 case AL_AUXILIARY_SEND_FILTER:
1331 break; /* ??? */
1334 ERR("Unexpected property: 0x%04x\n", prop);
1335 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1338 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1340 ALCdevice *device = Context->Device;
1341 ALdouble dvals[6];
1342 ALint ivals[3];
1343 ALboolean err;
1345 switch(prop)
1347 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1348 LockContext(Context);
1349 values[0] = GetSourceSampleOffset(Source);
1350 values[1] = V0(device->Backend,getLatency)();
1351 UnlockContext(Context);
1352 return AL_TRUE;
1354 /* 1x float/double */
1355 case AL_CONE_INNER_ANGLE:
1356 case AL_CONE_OUTER_ANGLE:
1357 case AL_PITCH:
1358 case AL_GAIN:
1359 case AL_MIN_GAIN:
1360 case AL_MAX_GAIN:
1361 case AL_REFERENCE_DISTANCE:
1362 case AL_ROLLOFF_FACTOR:
1363 case AL_CONE_OUTER_GAIN:
1364 case AL_MAX_DISTANCE:
1365 case AL_SEC_OFFSET:
1366 case AL_SAMPLE_OFFSET:
1367 case AL_BYTE_OFFSET:
1368 case AL_DOPPLER_FACTOR:
1369 case AL_AIR_ABSORPTION_FACTOR:
1370 case AL_ROOM_ROLLOFF_FACTOR:
1371 case AL_CONE_OUTER_GAINHF:
1372 case AL_SEC_LENGTH_SOFT:
1373 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1374 *values = (ALint64)dvals[0];
1375 return err;
1377 /* 2x float/double */
1378 case AL_SAMPLE_RW_OFFSETS_SOFT:
1379 case AL_BYTE_RW_OFFSETS_SOFT:
1380 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1382 values[0] = (ALint64)dvals[0];
1383 values[1] = (ALint64)dvals[1];
1385 return err;
1387 /* 3x float/double */
1388 case AL_POSITION:
1389 case AL_VELOCITY:
1390 case AL_DIRECTION:
1391 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1393 values[0] = (ALint64)dvals[0];
1394 values[1] = (ALint64)dvals[1];
1395 values[2] = (ALint64)dvals[2];
1397 return err;
1399 /* 6x float/double */
1400 case AL_ORIENTATION:
1401 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1403 values[0] = (ALint64)dvals[0];
1404 values[1] = (ALint64)dvals[1];
1405 values[2] = (ALint64)dvals[2];
1406 values[3] = (ALint64)dvals[3];
1407 values[4] = (ALint64)dvals[4];
1408 values[5] = (ALint64)dvals[5];
1410 return err;
1412 /* 1x int */
1413 case AL_SOURCE_RELATIVE:
1414 case AL_LOOPING:
1415 case AL_SOURCE_STATE:
1416 case AL_BUFFERS_QUEUED:
1417 case AL_BUFFERS_PROCESSED:
1418 case AL_BYTE_LENGTH_SOFT:
1419 case AL_SAMPLE_LENGTH_SOFT:
1420 case AL_SOURCE_TYPE:
1421 case AL_DIRECT_FILTER_GAINHF_AUTO:
1422 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1423 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1424 case AL_DIRECT_CHANNELS_SOFT:
1425 case AL_DISTANCE_MODEL:
1426 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1427 *values = ivals[0];
1428 return err;
1430 /* 1x uint */
1431 case AL_BUFFER:
1432 case AL_DIRECT_FILTER:
1433 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1434 *values = (ALuint)ivals[0];
1435 return err;
1437 /* 3x uint */
1438 case AL_AUXILIARY_SEND_FILTER:
1439 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1441 values[0] = (ALuint)ivals[0];
1442 values[1] = (ALuint)ivals[1];
1443 values[2] = (ALuint)ivals[2];
1445 return err;
1447 case AL_SEC_OFFSET_LATENCY_SOFT:
1448 break; /* Double only */
1451 ERR("Unexpected property: 0x%04x\n", prop);
1452 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1456 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1458 ALCcontext *context;
1459 ALsizei cur = 0;
1460 ALenum err;
1462 context = GetContextRef();
1463 if(!context) return;
1465 if(!(n >= 0))
1466 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1467 for(cur = 0;cur < n;cur++)
1469 ALsource *source = al_calloc(16, sizeof(ALsource));
1470 if(!source)
1472 alDeleteSources(cur, sources);
1473 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1475 InitSourceParams(source);
1477 err = NewThunkEntry(&source->id);
1478 if(err == AL_NO_ERROR)
1479 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1480 if(err != AL_NO_ERROR)
1482 FreeThunkEntry(source->id);
1483 memset(source, 0, sizeof(ALsource));
1484 al_free(source);
1486 alDeleteSources(cur, sources);
1487 SET_ERROR_AND_GOTO(context, err, done);
1490 sources[cur] = source->id;
1493 done:
1494 ALCcontext_DecRef(context);
1498 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1500 ALCcontext *context;
1501 ALbufferlistitem *BufferList;
1502 ALsource *Source;
1503 ALsizei i, j;
1505 context = GetContextRef();
1506 if(!context) return;
1508 if(!(n >= 0))
1509 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1511 /* Check that all Sources are valid */
1512 for(i = 0;i < n;i++)
1514 if(LookupSource(context, sources[i]) == NULL)
1515 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1517 for(i = 0;i < n;i++)
1519 ALvoice *voice, *voice_end;
1521 if((Source=RemoveSource(context, sources[i])) == NULL)
1522 continue;
1523 FreeThunkEntry(Source->id);
1525 LockContext(context);
1526 voice = context->Voices;
1527 voice_end = voice + context->VoiceCount;
1528 while(voice != voice_end)
1530 ALsource *old = Source;
1531 if(COMPARE_EXCHANGE(&voice->Source, &old, NULL))
1532 break;
1533 voice++;
1535 UnlockContext(context);
1537 BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, NULL);
1538 while(BufferList != NULL)
1540 ALbufferlistitem *next = BufferList->next;
1541 if(BufferList->buffer != NULL)
1542 DecrementRef(&BufferList->buffer->ref);
1543 free(BufferList);
1544 BufferList = next;
1547 for(j = 0;j < MAX_SENDS;++j)
1549 if(Source->Send[j].Slot)
1550 DecrementRef(&Source->Send[j].Slot->ref);
1551 Source->Send[j].Slot = NULL;
1554 memset(Source, 0, sizeof(*Source));
1555 al_free(Source);
1558 done:
1559 ALCcontext_DecRef(context);
1563 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1565 ALCcontext *context;
1566 ALboolean ret;
1568 context = GetContextRef();
1569 if(!context) return AL_FALSE;
1571 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1573 ALCcontext_DecRef(context);
1575 return ret;
1579 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1581 ALCcontext *Context;
1582 ALsource *Source;
1584 Context = GetContextRef();
1585 if(!Context) return;
1587 if((Source=LookupSource(Context, source)) == NULL)
1588 alSetError(Context, AL_INVALID_NAME);
1589 else if(!(FloatValsByProp(param) == 1))
1590 alSetError(Context, AL_INVALID_ENUM);
1591 else
1592 SetSourcefv(Source, Context, param, &value);
1594 ALCcontext_DecRef(Context);
1597 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1599 ALCcontext *Context;
1600 ALsource *Source;
1602 Context = GetContextRef();
1603 if(!Context) return;
1605 if((Source=LookupSource(Context, source)) == NULL)
1606 alSetError(Context, AL_INVALID_NAME);
1607 else if(!(FloatValsByProp(param) == 3))
1608 alSetError(Context, AL_INVALID_ENUM);
1609 else
1611 ALfloat fvals[3] = { value1, value2, value3 };
1612 SetSourcefv(Source, Context, param, fvals);
1615 ALCcontext_DecRef(Context);
1618 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1620 ALCcontext *Context;
1621 ALsource *Source;
1623 Context = GetContextRef();
1624 if(!Context) return;
1626 if((Source=LookupSource(Context, source)) == NULL)
1627 alSetError(Context, AL_INVALID_NAME);
1628 else if(!values)
1629 alSetError(Context, AL_INVALID_VALUE);
1630 else if(!(FloatValsByProp(param) > 0))
1631 alSetError(Context, AL_INVALID_ENUM);
1632 else
1633 SetSourcefv(Source, Context, param, values);
1635 ALCcontext_DecRef(Context);
1639 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1641 ALCcontext *Context;
1642 ALsource *Source;
1644 Context = GetContextRef();
1645 if(!Context) return;
1647 if((Source=LookupSource(Context, source)) == NULL)
1648 alSetError(Context, AL_INVALID_NAME);
1649 else if(!(DoubleValsByProp(param) == 1))
1650 alSetError(Context, AL_INVALID_ENUM);
1651 else
1653 ALfloat fval = (ALfloat)value;
1654 SetSourcefv(Source, Context, param, &fval);
1657 ALCcontext_DecRef(Context);
1660 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1662 ALCcontext *Context;
1663 ALsource *Source;
1665 Context = GetContextRef();
1666 if(!Context) return;
1668 if((Source=LookupSource(Context, source)) == NULL)
1669 alSetError(Context, AL_INVALID_NAME);
1670 else if(!(DoubleValsByProp(param) == 3))
1671 alSetError(Context, AL_INVALID_ENUM);
1672 else
1674 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1675 SetSourcefv(Source, Context, param, fvals);
1678 ALCcontext_DecRef(Context);
1681 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1683 ALCcontext *Context;
1684 ALsource *Source;
1685 ALint count;
1687 Context = GetContextRef();
1688 if(!Context) return;
1690 if((Source=LookupSource(Context, source)) == NULL)
1691 alSetError(Context, AL_INVALID_NAME);
1692 else if(!values)
1693 alSetError(Context, AL_INVALID_VALUE);
1694 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1695 alSetError(Context, AL_INVALID_ENUM);
1696 else
1698 ALfloat fvals[6];
1699 ALint i;
1701 for(i = 0;i < count;i++)
1702 fvals[i] = (ALfloat)values[i];
1703 SetSourcefv(Source, Context, param, fvals);
1706 ALCcontext_DecRef(Context);
1710 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1712 ALCcontext *Context;
1713 ALsource *Source;
1715 Context = GetContextRef();
1716 if(!Context) return;
1718 if((Source=LookupSource(Context, source)) == NULL)
1719 alSetError(Context, AL_INVALID_NAME);
1720 else if(!(IntValsByProp(param) == 1))
1721 alSetError(Context, AL_INVALID_ENUM);
1722 else
1723 SetSourceiv(Source, Context, param, &value);
1725 ALCcontext_DecRef(Context);
1728 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1730 ALCcontext *Context;
1731 ALsource *Source;
1733 Context = GetContextRef();
1734 if(!Context) return;
1736 if((Source=LookupSource(Context, source)) == NULL)
1737 alSetError(Context, AL_INVALID_NAME);
1738 else if(!(IntValsByProp(param) == 3))
1739 alSetError(Context, AL_INVALID_ENUM);
1740 else
1742 ALint ivals[3] = { value1, value2, value3 };
1743 SetSourceiv(Source, Context, param, ivals);
1746 ALCcontext_DecRef(Context);
1749 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1751 ALCcontext *Context;
1752 ALsource *Source;
1754 Context = GetContextRef();
1755 if(!Context) return;
1757 if((Source=LookupSource(Context, source)) == NULL)
1758 alSetError(Context, AL_INVALID_NAME);
1759 else if(!values)
1760 alSetError(Context, AL_INVALID_VALUE);
1761 else if(!(IntValsByProp(param) > 0))
1762 alSetError(Context, AL_INVALID_ENUM);
1763 else
1764 SetSourceiv(Source, Context, param, values);
1766 ALCcontext_DecRef(Context);
1770 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1772 ALCcontext *Context;
1773 ALsource *Source;
1775 Context = GetContextRef();
1776 if(!Context) return;
1778 if((Source=LookupSource(Context, source)) == NULL)
1779 alSetError(Context, AL_INVALID_NAME);
1780 else if(!(Int64ValsByProp(param) == 1))
1781 alSetError(Context, AL_INVALID_ENUM);
1782 else
1783 SetSourcei64v(Source, Context, param, &value);
1785 ALCcontext_DecRef(Context);
1788 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1790 ALCcontext *Context;
1791 ALsource *Source;
1793 Context = GetContextRef();
1794 if(!Context) return;
1796 if((Source=LookupSource(Context, source)) == NULL)
1797 alSetError(Context, AL_INVALID_NAME);
1798 else if(!(Int64ValsByProp(param) == 3))
1799 alSetError(Context, AL_INVALID_ENUM);
1800 else
1802 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1803 SetSourcei64v(Source, Context, param, i64vals);
1806 ALCcontext_DecRef(Context);
1809 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1811 ALCcontext *Context;
1812 ALsource *Source;
1814 Context = GetContextRef();
1815 if(!Context) return;
1817 if((Source=LookupSource(Context, source)) == NULL)
1818 alSetError(Context, AL_INVALID_NAME);
1819 else if(!values)
1820 alSetError(Context, AL_INVALID_VALUE);
1821 else if(!(Int64ValsByProp(param) > 0))
1822 alSetError(Context, AL_INVALID_ENUM);
1823 else
1824 SetSourcei64v(Source, Context, param, values);
1826 ALCcontext_DecRef(Context);
1830 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1832 ALCcontext *Context;
1833 ALsource *Source;
1835 Context = GetContextRef();
1836 if(!Context) return;
1838 if((Source=LookupSource(Context, source)) == NULL)
1839 alSetError(Context, AL_INVALID_NAME);
1840 else if(!value)
1841 alSetError(Context, AL_INVALID_VALUE);
1842 else if(!(FloatValsByProp(param) == 1))
1843 alSetError(Context, AL_INVALID_ENUM);
1844 else
1846 ALdouble dval;
1847 if(GetSourcedv(Source, Context, param, &dval))
1848 *value = (ALfloat)dval;
1851 ALCcontext_DecRef(Context);
1855 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1857 ALCcontext *Context;
1858 ALsource *Source;
1860 Context = GetContextRef();
1861 if(!Context) return;
1863 if((Source=LookupSource(Context, source)) == NULL)
1864 alSetError(Context, AL_INVALID_NAME);
1865 else if(!(value1 && value2 && value3))
1866 alSetError(Context, AL_INVALID_VALUE);
1867 else if(!(FloatValsByProp(param) == 3))
1868 alSetError(Context, AL_INVALID_ENUM);
1869 else
1871 ALdouble dvals[3];
1872 if(GetSourcedv(Source, Context, param, dvals))
1874 *value1 = (ALfloat)dvals[0];
1875 *value2 = (ALfloat)dvals[1];
1876 *value3 = (ALfloat)dvals[2];
1880 ALCcontext_DecRef(Context);
1884 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1886 ALCcontext *Context;
1887 ALsource *Source;
1888 ALint count;
1890 Context = GetContextRef();
1891 if(!Context) return;
1893 if((Source=LookupSource(Context, source)) == NULL)
1894 alSetError(Context, AL_INVALID_NAME);
1895 else if(!values)
1896 alSetError(Context, AL_INVALID_VALUE);
1897 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
1898 alSetError(Context, AL_INVALID_ENUM);
1899 else
1901 ALdouble dvals[6];
1902 if(GetSourcedv(Source, Context, param, dvals))
1904 ALint i;
1905 for(i = 0;i < count;i++)
1906 values[i] = (ALfloat)dvals[i];
1910 ALCcontext_DecRef(Context);
1914 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1916 ALCcontext *Context;
1917 ALsource *Source;
1919 Context = GetContextRef();
1920 if(!Context) return;
1922 if((Source=LookupSource(Context, source)) == NULL)
1923 alSetError(Context, AL_INVALID_NAME);
1924 else if(!value)
1925 alSetError(Context, AL_INVALID_VALUE);
1926 else if(!(DoubleValsByProp(param) == 1))
1927 alSetError(Context, AL_INVALID_ENUM);
1928 else
1929 GetSourcedv(Source, Context, param, value);
1931 ALCcontext_DecRef(Context);
1934 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1936 ALCcontext *Context;
1937 ALsource *Source;
1939 Context = GetContextRef();
1940 if(!Context) return;
1942 if((Source=LookupSource(Context, source)) == NULL)
1943 alSetError(Context, AL_INVALID_NAME);
1944 else if(!(value1 && value2 && value3))
1945 alSetError(Context, AL_INVALID_VALUE);
1946 else if(!(DoubleValsByProp(param) == 3))
1947 alSetError(Context, AL_INVALID_ENUM);
1948 else
1950 ALdouble dvals[3];
1951 if(GetSourcedv(Source, Context, param, dvals))
1953 *value1 = dvals[0];
1954 *value2 = dvals[1];
1955 *value3 = dvals[2];
1959 ALCcontext_DecRef(Context);
1962 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1964 ALCcontext *Context;
1965 ALsource *Source;
1967 Context = GetContextRef();
1968 if(!Context) return;
1970 if((Source=LookupSource(Context, source)) == NULL)
1971 alSetError(Context, AL_INVALID_NAME);
1972 else if(!values)
1973 alSetError(Context, AL_INVALID_VALUE);
1974 else if(!(DoubleValsByProp(param) > 0))
1975 alSetError(Context, AL_INVALID_ENUM);
1976 else
1977 GetSourcedv(Source, Context, param, values);
1979 ALCcontext_DecRef(Context);
1983 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1985 ALCcontext *Context;
1986 ALsource *Source;
1988 Context = GetContextRef();
1989 if(!Context) return;
1991 if((Source=LookupSource(Context, source)) == NULL)
1992 alSetError(Context, AL_INVALID_NAME);
1993 else if(!value)
1994 alSetError(Context, AL_INVALID_VALUE);
1995 else if(!(IntValsByProp(param) == 1))
1996 alSetError(Context, AL_INVALID_ENUM);
1997 else
1998 GetSourceiv(Source, Context, param, value);
2000 ALCcontext_DecRef(Context);
2004 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2006 ALCcontext *Context;
2007 ALsource *Source;
2009 Context = GetContextRef();
2010 if(!Context) return;
2012 if((Source=LookupSource(Context, source)) == NULL)
2013 alSetError(Context, AL_INVALID_NAME);
2014 else if(!(value1 && value2 && value3))
2015 alSetError(Context, AL_INVALID_VALUE);
2016 else if(!(IntValsByProp(param) == 3))
2017 alSetError(Context, AL_INVALID_ENUM);
2018 else
2020 ALint ivals[3];
2021 if(GetSourceiv(Source, Context, param, ivals))
2023 *value1 = ivals[0];
2024 *value2 = ivals[1];
2025 *value3 = ivals[2];
2029 ALCcontext_DecRef(Context);
2033 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2035 ALCcontext *Context;
2036 ALsource *Source;
2038 Context = GetContextRef();
2039 if(!Context) return;
2041 if((Source=LookupSource(Context, source)) == NULL)
2042 alSetError(Context, AL_INVALID_NAME);
2043 else if(!values)
2044 alSetError(Context, AL_INVALID_VALUE);
2045 else if(!(IntValsByProp(param) > 0))
2046 alSetError(Context, AL_INVALID_ENUM);
2047 else
2048 GetSourceiv(Source, Context, param, values);
2050 ALCcontext_DecRef(Context);
2054 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2056 ALCcontext *Context;
2057 ALsource *Source;
2059 Context = GetContextRef();
2060 if(!Context) return;
2062 if((Source=LookupSource(Context, source)) == NULL)
2063 alSetError(Context, AL_INVALID_NAME);
2064 else if(!value)
2065 alSetError(Context, AL_INVALID_VALUE);
2066 else if(!(Int64ValsByProp(param) == 1))
2067 alSetError(Context, AL_INVALID_ENUM);
2068 else
2069 GetSourcei64v(Source, Context, param, value);
2071 ALCcontext_DecRef(Context);
2074 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2076 ALCcontext *Context;
2077 ALsource *Source;
2079 Context = GetContextRef();
2080 if(!Context) return;
2082 if((Source=LookupSource(Context, source)) == NULL)
2083 alSetError(Context, AL_INVALID_NAME);
2084 else if(!(value1 && value2 && value3))
2085 alSetError(Context, AL_INVALID_VALUE);
2086 else if(!(Int64ValsByProp(param) == 3))
2087 alSetError(Context, AL_INVALID_ENUM);
2088 else
2090 ALint64 i64vals[3];
2091 if(GetSourcei64v(Source, Context, param, i64vals))
2093 *value1 = i64vals[0];
2094 *value2 = i64vals[1];
2095 *value3 = i64vals[2];
2099 ALCcontext_DecRef(Context);
2102 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2104 ALCcontext *Context;
2105 ALsource *Source;
2107 Context = GetContextRef();
2108 if(!Context) return;
2110 if((Source=LookupSource(Context, source)) == NULL)
2111 alSetError(Context, AL_INVALID_NAME);
2112 else if(!values)
2113 alSetError(Context, AL_INVALID_VALUE);
2114 else if(!(Int64ValsByProp(param) > 0))
2115 alSetError(Context, AL_INVALID_ENUM);
2116 else
2117 GetSourcei64v(Source, Context, param, values);
2119 ALCcontext_DecRef(Context);
2123 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2125 alSourcePlayv(1, &source);
2127 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2129 ALCcontext *context;
2130 ALsource *source;
2131 ALsizei i;
2133 context = GetContextRef();
2134 if(!context) return;
2136 if(!(n >= 0))
2137 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2138 for(i = 0;i < n;i++)
2140 if(!LookupSource(context, sources[i]))
2141 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2144 LockContext(context);
2145 while(n > context->MaxVoices-context->VoiceCount)
2147 ALvoice *temp = NULL;
2148 ALsizei newcount;
2150 newcount = context->MaxVoices << 1;
2151 if(newcount > 0)
2152 temp = realloc(context->Voices, newcount * sizeof(context->Voices[0]));
2153 if(!temp)
2155 UnlockContext(context);
2156 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2158 memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0]));
2160 context->Voices = temp;
2161 context->MaxVoices = newcount;
2164 for(i = 0;i < n;i++)
2166 source = LookupSource(context, sources[i]);
2167 if(context->DeferUpdates) source->new_state = AL_PLAYING;
2168 else SetSourceState(source, context, AL_PLAYING);
2170 UnlockContext(context);
2172 done:
2173 ALCcontext_DecRef(context);
2176 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2178 alSourcePausev(1, &source);
2180 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2182 ALCcontext *context;
2183 ALsource *source;
2184 ALsizei i;
2186 context = GetContextRef();
2187 if(!context) return;
2189 if(!(n >= 0))
2190 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2191 for(i = 0;i < n;i++)
2193 if(!LookupSource(context, sources[i]))
2194 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2197 LockContext(context);
2198 for(i = 0;i < n;i++)
2200 source = LookupSource(context, sources[i]);
2201 if(context->DeferUpdates) source->new_state = AL_PAUSED;
2202 else SetSourceState(source, context, AL_PAUSED);
2204 UnlockContext(context);
2206 done:
2207 ALCcontext_DecRef(context);
2210 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2212 alSourceStopv(1, &source);
2214 AL_API ALvoid AL_APIENTRY alSourceStopv(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 source->new_state = AL_NONE;
2236 SetSourceState(source, context, AL_STOPPED);
2238 UnlockContext(context);
2240 done:
2241 ALCcontext_DecRef(context);
2244 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2246 alSourceRewindv(1, &source);
2248 AL_API ALvoid AL_APIENTRY alSourceRewindv(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_INITIAL);
2272 UnlockContext(context);
2274 done:
2275 ALCcontext_DecRef(context);
2279 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2281 ALCdevice *device;
2282 ALCcontext *context;
2283 ALsource *source;
2284 ALsizei i;
2285 ALbufferlistitem *BufferListStart;
2286 ALbufferlistitem *BufferList;
2287 ALbuffer *BufferFmt = NULL;
2289 if(nb == 0)
2290 return;
2292 context = GetContextRef();
2293 if(!context) return;
2295 device = context->Device;
2297 if(!(nb >= 0))
2298 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2299 if((source=LookupSource(context, src)) == NULL)
2300 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2302 WriteLock(&source->queue_lock);
2303 if(source->SourceType == AL_STATIC)
2305 WriteUnlock(&source->queue_lock);
2306 /* Can't queue on a Static Source */
2307 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2310 /* Check for a valid Buffer, for its frequency and format */
2311 BufferList = ATOMIC_LOAD(&source->queue);
2312 while(BufferList)
2314 if(BufferList->buffer)
2316 BufferFmt = BufferList->buffer;
2317 break;
2319 BufferList = BufferList->next;
2322 BufferListStart = NULL;
2323 BufferList = NULL;
2324 for(i = 0;i < nb;i++)
2326 ALbuffer *buffer = NULL;
2327 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2329 WriteUnlock(&source->queue_lock);
2330 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2333 if(!BufferListStart)
2335 BufferListStart = malloc(sizeof(ALbufferlistitem));
2336 BufferListStart->buffer = buffer;
2337 BufferListStart->next = NULL;
2338 BufferListStart->prev = NULL;
2339 BufferList = BufferListStart;
2341 else
2343 BufferList->next = malloc(sizeof(ALbufferlistitem));
2344 BufferList->next->buffer = buffer;
2345 BufferList->next->next = NULL;
2346 BufferList->next->prev = BufferList;
2347 BufferList = BufferList->next;
2349 if(!buffer) continue;
2351 /* Hold a read lock on each buffer being queued while checking all
2352 * provided buffers. This is done so other threads don't see an extra
2353 * reference on some buffers if this operation ends up failing. */
2354 ReadLock(&buffer->lock);
2355 IncrementRef(&buffer->ref);
2357 if(BufferFmt == NULL)
2359 BufferFmt = buffer;
2361 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2362 source->SampleSize = BytesFromFmt(buffer->FmtType);
2364 else if(BufferFmt->Frequency != buffer->Frequency ||
2365 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2366 BufferFmt->OriginalType != buffer->OriginalType)
2368 WriteUnlock(&source->queue_lock);
2369 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2371 buffer_error:
2372 /* A buffer failed (invalid ID or format), so unlock and release
2373 * each buffer we had. */
2374 while(BufferList != NULL)
2376 ALbufferlistitem *prev = BufferList->prev;
2377 if((buffer=BufferList->buffer) != NULL)
2379 DecrementRef(&buffer->ref);
2380 ReadUnlock(&buffer->lock);
2382 free(BufferList);
2383 BufferList = prev;
2385 goto done;
2388 /* All buffers good, unlock them now. */
2389 while(BufferList != NULL)
2391 ALbuffer *buffer = BufferList->buffer;
2392 if(buffer) ReadUnlock(&buffer->lock);
2393 BufferList = BufferList->prev;
2396 /* Source is now streaming */
2397 source->SourceType = AL_STREAMING;
2399 BufferList = NULL;
2400 if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
2402 /* Queue head is not NULL, append to the end of the queue */
2403 while(BufferList->next != NULL)
2404 BufferList = BufferList->next;
2406 BufferListStart->prev = BufferList;
2407 BufferList->next = BufferListStart;
2409 BufferList = NULL;
2410 ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
2411 WriteUnlock(&source->queue_lock);
2413 done:
2414 ALCcontext_DecRef(context);
2417 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2419 ALCcontext *context;
2420 ALsource *source;
2421 ALbufferlistitem *NewHead;
2422 ALbufferlistitem *OldHead;
2423 ALbufferlistitem *Current;
2424 ALsizei i;
2426 if(nb == 0)
2427 return;
2429 context = GetContextRef();
2430 if(!context) return;
2432 if(!(nb >= 0))
2433 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2435 if((source=LookupSource(context, src)) == NULL)
2436 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2438 WriteLock(&source->queue_lock);
2439 /* Find the new buffer queue head */
2440 NewHead = ATOMIC_LOAD(&source->queue);
2441 Current = ATOMIC_LOAD(&source->current_buffer);
2442 for(i = 0;i < nb && NewHead;i++)
2444 if(NewHead == Current)
2445 break;
2446 NewHead = NewHead->next;
2448 if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
2450 WriteUnlock(&source->queue_lock);
2451 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2452 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2455 /* Swap it, and cut the new head from the old. */
2456 OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NewHead);
2457 if(NewHead)
2459 ALCdevice *device = context->Device;
2460 ALbufferlistitem *OldTail = NewHead->prev;
2461 uint count;
2463 /* Cut the new head's link back to the old body. The mixer is robust
2464 * enough to handle the link back going away. Once the active mix (if
2465 * any) is complete, it's safe to finish cutting the old tail from the
2466 * new head. */
2467 NewHead->prev = NULL;
2468 if(((count=ReadRef(&device->MixCount))&1) != 0)
2470 while(count == ReadRef(&device->MixCount))
2471 althrd_yield();
2473 OldTail->next = NULL;
2475 WriteUnlock(&source->queue_lock);
2477 while(OldHead != NULL)
2479 ALbufferlistitem *next = OldHead->next;
2480 ALbuffer *buffer = OldHead->buffer;
2482 if(!buffer)
2483 *(buffers++) = 0;
2484 else
2486 *(buffers++) = buffer->id;
2487 DecrementRef(&buffer->ref);
2490 free(OldHead);
2491 OldHead = next;
2494 done:
2495 ALCcontext_DecRef(context);
2499 static ALvoid InitSourceParams(ALsource *Source)
2501 ALuint i;
2503 RWLockInit(&Source->queue_lock);
2505 Source->InnerAngle = 360.0f;
2506 Source->OuterAngle = 360.0f;
2507 Source->Pitch = 1.0f;
2508 aluVectorSet(&Source->Position, 0.0f, 0.0f, 0.0f, 1.0f);
2509 aluVectorSet(&Source->Velocity, 0.0f, 0.0f, 0.0f, 0.0f);
2510 aluVectorSet(&Source->Direction, 0.0f, 0.0f, 0.0f, 0.0f);
2511 Source->Orientation[0][0] = 0.0f;
2512 Source->Orientation[0][1] = 0.0f;
2513 Source->Orientation[0][2] = -1.0f;
2514 Source->Orientation[1][0] = 0.0f;
2515 Source->Orientation[1][1] = 1.0f;
2516 Source->Orientation[1][2] = 0.0f;
2517 Source->RefDistance = 1.0f;
2518 Source->MaxDistance = FLT_MAX;
2519 Source->RollOffFactor = 1.0f;
2520 Source->Looping = AL_FALSE;
2521 Source->Gain = 1.0f;
2522 Source->MinGain = 0.0f;
2523 Source->MaxGain = 1.0f;
2524 Source->OuterGain = 0.0f;
2525 Source->OuterGainHF = 1.0f;
2527 Source->DryGainHFAuto = AL_TRUE;
2528 Source->WetGainAuto = AL_TRUE;
2529 Source->WetGainHFAuto = AL_TRUE;
2530 Source->AirAbsorptionFactor = 0.0f;
2531 Source->RoomRolloffFactor = 0.0f;
2532 Source->DopplerFactor = 1.0f;
2533 Source->DirectChannels = AL_FALSE;
2535 Source->Radius = 0.0f;
2537 Source->DistanceModel = DefaultDistanceModel;
2539 Source->state = AL_INITIAL;
2540 Source->new_state = AL_NONE;
2541 Source->SourceType = AL_UNDETERMINED;
2542 Source->Offset = -1.0;
2544 ATOMIC_INIT(&Source->queue, NULL);
2545 ATOMIC_INIT(&Source->current_buffer, NULL);
2547 Source->Direct.Gain = 1.0f;
2548 Source->Direct.GainHF = 1.0f;
2549 Source->Direct.HFReference = LOWPASSFREQREF;
2550 Source->Direct.GainLF = 1.0f;
2551 Source->Direct.LFReference = HIGHPASSFREQREF;
2552 for(i = 0;i < MAX_SENDS;i++)
2554 Source->Send[i].Gain = 1.0f;
2555 Source->Send[i].GainHF = 1.0f;
2556 Source->Send[i].HFReference = LOWPASSFREQREF;
2557 Source->Send[i].GainLF = 1.0f;
2558 Source->Send[i].LFReference = HIGHPASSFREQREF;
2561 ATOMIC_INIT(&Source->NeedsUpdate, AL_TRUE);
2565 /* SetSourceState
2567 * Sets the source's new play state given its current state.
2569 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2571 ReadLock(&Source->queue_lock);
2572 if(state == AL_PLAYING)
2574 ALCdevice *device = Context->Device;
2575 ALbufferlistitem *BufferList;
2576 ALvoice *voice = NULL;
2577 ALsizei i;
2579 /* Check that there is a queue containing at least one valid, non zero
2580 * length Buffer. */
2581 BufferList = ATOMIC_LOAD(&Source->queue);
2582 while(BufferList)
2584 ALbuffer *buffer;
2585 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2586 break;
2587 BufferList = BufferList->next;
2590 if(Source->state != AL_PAUSED)
2592 Source->state = AL_PLAYING;
2593 Source->position = 0;
2594 Source->position_fraction = 0;
2595 ATOMIC_STORE(&Source->current_buffer, BufferList);
2597 else
2598 Source->state = AL_PLAYING;
2600 // Check if an Offset has been set
2601 if(Source->Offset >= 0.0)
2602 ApplyOffset(Source);
2604 /* If there's nothing to play, or device is disconnected, go right to
2605 * stopped */
2606 if(!BufferList || !device->Connected)
2607 goto do_stop;
2609 /* Make sure this source isn't already active, while looking for an
2610 * unused active source slot to put it in. */
2611 for(i = 0;i < Context->VoiceCount;i++)
2613 ALsource *old = Source;
2614 if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL))
2616 if(voice == NULL)
2618 voice = &Context->Voices[i];
2619 voice->Source = Source;
2621 break;
2623 old = NULL;
2624 if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source))
2625 voice = &Context->Voices[i];
2627 if(voice == NULL)
2629 voice = &Context->Voices[Context->VoiceCount++];
2630 voice->Source = Source;
2633 voice->Direct.Moving = AL_FALSE;
2634 voice->Direct.Counter = 0;
2635 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
2637 ALsizei j;
2638 for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
2639 voice->Direct.Hrtf[i].State.History[j] = 0.0f;
2640 for(j = 0;j < HRIR_LENGTH;j++)
2642 voice->Direct.Hrtf[i].State.Values[j][0] = 0.0f;
2643 voice->Direct.Hrtf[i].State.Values[j][1] = 0.0f;
2646 for(i = 0;i < (ALsizei)device->NumAuxSends;i++)
2648 voice->Send[i].Moving = AL_FALSE;
2649 voice->Send[i].Counter = 0;
2652 if(BufferList->buffer->FmtChannels == FmtMono)
2653 voice->Update = CalcSourceParams;
2654 else
2655 voice->Update = CalcNonAttnSourceParams;
2657 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
2659 else if(state == AL_PAUSED)
2661 if(Source->state == AL_PLAYING)
2662 Source->state = AL_PAUSED;
2664 else if(state == AL_STOPPED)
2666 do_stop:
2667 if(Source->state != AL_INITIAL)
2669 Source->state = AL_STOPPED;
2670 ATOMIC_STORE(&Source->current_buffer, NULL);
2672 Source->Offset = -1.0;
2674 else if(state == AL_INITIAL)
2676 if(Source->state != AL_INITIAL)
2678 Source->state = AL_INITIAL;
2679 Source->position = 0;
2680 Source->position_fraction = 0;
2681 ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue));
2683 Source->Offset = -1.0;
2685 ReadUnlock(&Source->queue_lock);
2688 /* GetSourceSampleOffset
2690 * Gets the current read offset for the given Source, in 32.32 fixed-point
2691 * samples. The offset is relative to the start of the queue (not the start of
2692 * the current buffer).
2694 ALint64 GetSourceSampleOffset(ALsource *Source)
2696 const ALbufferlistitem *BufferList;
2697 const ALbufferlistitem *Current;
2698 ALuint64 readPos;
2700 ReadLock(&Source->queue_lock);
2701 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2703 ReadUnlock(&Source->queue_lock);
2704 return 0;
2707 /* NOTE: This is the offset into the *current* buffer, so add the length of
2708 * any played buffers */
2709 readPos = (ALuint64)Source->position << 32;
2710 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2711 BufferList = ATOMIC_LOAD(&Source->queue);
2712 Current = ATOMIC_LOAD(&Source->current_buffer);
2713 while(BufferList && BufferList != Current)
2715 if(BufferList->buffer)
2716 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2717 BufferList = BufferList->next;
2720 ReadUnlock(&Source->queue_lock);
2721 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
2724 /* GetSourceSecOffset
2726 * Gets the current read offset for the given Source, in seconds. The offset is
2727 * relative to the start of the queue (not the start of the current buffer).
2729 static ALdouble GetSourceSecOffset(ALsource *Source)
2731 const ALbufferlistitem *BufferList;
2732 const ALbufferlistitem *Current;
2733 const ALbuffer *Buffer = NULL;
2734 ALuint64 readPos;
2736 ReadLock(&Source->queue_lock);
2737 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2739 ReadUnlock(&Source->queue_lock);
2740 return 0.0;
2743 /* NOTE: This is the offset into the *current* buffer, so add the length of
2744 * any played buffers */
2745 readPos = (ALuint64)Source->position << FRACTIONBITS;
2746 readPos |= (ALuint64)Source->position_fraction;
2747 BufferList = ATOMIC_LOAD(&Source->queue);
2748 Current = ATOMIC_LOAD(&Source->current_buffer);
2749 while(BufferList && BufferList != Current)
2751 const ALbuffer *buffer = BufferList->buffer;
2752 if(buffer != NULL)
2754 if(!Buffer) Buffer = buffer;
2755 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
2757 BufferList = BufferList->next;
2760 while(BufferList && !Buffer)
2762 Buffer = BufferList->buffer;
2763 BufferList = BufferList->next;
2765 assert(Buffer != NULL);
2767 ReadUnlock(&Source->queue_lock);
2768 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2771 /* GetSourceOffsets
2773 * Gets the current read and write offsets for the given Source, in the
2774 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2775 * the start of the queue (not the start of the current buffer).
2777 static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2779 const ALbufferlistitem *BufferList;
2780 const ALbufferlistitem *Current;
2781 const ALbuffer *Buffer = NULL;
2782 ALboolean readFin = AL_FALSE;
2783 ALuint readPos, writePos;
2784 ALuint totalBufferLen;
2786 ReadLock(&Source->queue_lock);
2787 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2789 offset[0] = 0.0;
2790 offset[1] = 0.0;
2791 ReadUnlock(&Source->queue_lock);
2792 return;
2795 if(updateLen > 0.0 && updateLen < 0.015)
2796 updateLen = 0.015;
2798 /* NOTE: This is the offset into the *current* buffer, so add the length of
2799 * any played buffers */
2800 totalBufferLen = 0;
2801 readPos = Source->position;
2802 BufferList = ATOMIC_LOAD(&Source->queue);
2803 Current = ATOMIC_LOAD(&Source->current_buffer);
2804 while(BufferList != NULL)
2806 const ALbuffer *buffer;
2807 readFin = readFin || (BufferList == Current);
2808 if((buffer=BufferList->buffer) != NULL)
2810 if(!Buffer) Buffer = buffer;
2811 totalBufferLen += buffer->SampleLen;
2812 if(!readFin) readPos += buffer->SampleLen;
2814 BufferList = BufferList->next;
2816 assert(Buffer != NULL);
2818 if(Source->state == AL_PLAYING)
2819 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
2820 else
2821 writePos = readPos;
2823 if(Source->Looping)
2825 readPos %= totalBufferLen;
2826 writePos %= totalBufferLen;
2828 else
2830 /* Wrap positions back to 0 */
2831 if(readPos >= totalBufferLen)
2832 readPos = 0;
2833 if(writePos >= totalBufferLen)
2834 writePos = 0;
2837 switch(name)
2839 case AL_SEC_OFFSET:
2840 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2841 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2842 break;
2844 case AL_SAMPLE_OFFSET:
2845 case AL_SAMPLE_RW_OFFSETS_SOFT:
2846 offset[0] = (ALdouble)readPos;
2847 offset[1] = (ALdouble)writePos;
2848 break;
2850 case AL_BYTE_OFFSET:
2851 case AL_BYTE_RW_OFFSETS_SOFT:
2852 if(Buffer->OriginalType == UserFmtIMA4)
2854 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2855 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2856 ALuint FrameBlockSize = Buffer->OriginalAlign;
2858 /* Round down to nearest ADPCM block */
2859 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2860 if(Source->state != AL_PLAYING)
2861 offset[1] = offset[0];
2862 else
2864 /* Round up to nearest ADPCM block */
2865 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2866 FrameBlockSize * BlockSize);
2869 else if(Buffer->OriginalType == UserFmtMSADPCM)
2871 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2872 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2873 ALuint FrameBlockSize = Buffer->OriginalAlign;
2875 /* Round down to nearest ADPCM block */
2876 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2877 if(Source->state != AL_PLAYING)
2878 offset[1] = offset[0];
2879 else
2881 /* Round up to nearest ADPCM block */
2882 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2883 FrameBlockSize * BlockSize);
2886 else
2888 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2889 offset[0] = (ALdouble)(readPos * FrameSize);
2890 offset[1] = (ALdouble)(writePos * FrameSize);
2892 break;
2895 ReadUnlock(&Source->queue_lock);
2899 /* ApplyOffset
2901 * Apply the stored playback offset to the Source. This function will update
2902 * the number of buffers "played" given the stored offset.
2904 ALboolean ApplyOffset(ALsource *Source)
2906 ALbufferlistitem *BufferList;
2907 const ALbuffer *Buffer;
2908 ALint bufferLen, totalBufferLen;
2909 ALint offset;
2911 /* Get sample frame offset */
2912 offset = GetSampleOffset(Source);
2913 if(offset == -1)
2914 return AL_FALSE;
2916 totalBufferLen = 0;
2917 BufferList = ATOMIC_LOAD(&Source->queue);
2918 while(BufferList && totalBufferLen <= offset)
2920 Buffer = BufferList->buffer;
2921 bufferLen = Buffer ? Buffer->SampleLen : 0;
2923 if(bufferLen > offset-totalBufferLen)
2925 /* Offset is in this buffer */
2926 ATOMIC_STORE(&Source->current_buffer, BufferList);
2928 Source->position = offset - totalBufferLen;
2929 Source->position_fraction = 0;
2930 return AL_TRUE;
2933 totalBufferLen += bufferLen;
2935 BufferList = BufferList->next;
2938 /* Offset is out of range of the queue */
2939 return AL_FALSE;
2943 /* GetSampleOffset
2945 * Returns the sample offset into the Source's queue (from the Sample, Byte or
2946 * Second offset supplied by the application). This takes into account the fact
2947 * that the buffer format may have been modifed since.
2949 static ALint GetSampleOffset(ALsource *Source)
2951 const ALbuffer *Buffer = NULL;
2952 const ALbufferlistitem *BufferList;
2953 ALint Offset = -1;
2955 /* Find the first valid Buffer in the Queue */
2956 BufferList = ATOMIC_LOAD(&Source->queue);
2957 while(BufferList)
2959 if(BufferList->buffer)
2961 Buffer = BufferList->buffer;
2962 break;
2964 BufferList = BufferList->next;
2967 if(!Buffer)
2969 Source->Offset = -1.0;
2970 return -1;
2973 switch(Source->OffsetType)
2975 case AL_BYTE_OFFSET:
2976 /* Determine the ByteOffset (and ensure it is block aligned) */
2977 Offset = (ALint)Source->Offset;
2978 if(Buffer->OriginalType == UserFmtIMA4)
2980 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2981 Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2982 Offset *= Buffer->OriginalAlign;
2984 else if(Buffer->OriginalType == UserFmtMSADPCM)
2986 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2987 Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2988 Offset *= Buffer->OriginalAlign;
2990 else
2991 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2992 break;
2994 case AL_SAMPLE_OFFSET:
2995 Offset = (ALint)Source->Offset;
2996 break;
2998 case AL_SEC_OFFSET:
2999 Offset = (ALint)(Source->Offset * Buffer->Frequency);
3000 break;
3002 Source->Offset = -1.0;
3004 return Offset;
3008 /* ReleaseALSources
3010 * Destroys all sources in the source map.
3012 ALvoid ReleaseALSources(ALCcontext *Context)
3014 ALbufferlistitem *item;
3015 ALsizei pos;
3016 ALuint j;
3017 for(pos = 0;pos < Context->SourceMap.size;pos++)
3019 ALsource *temp = Context->SourceMap.array[pos].value;
3020 Context->SourceMap.array[pos].value = NULL;
3022 item = ATOMIC_EXCHANGE(ALbufferlistitem*, &temp->queue, NULL);
3023 while(item != NULL)
3025 ALbufferlistitem *next = item->next;
3026 if(item->buffer != NULL)
3027 DecrementRef(&item->buffer->ref);
3028 free(item);
3029 item = next;
3032 for(j = 0;j < MAX_SENDS;++j)
3034 if(temp->Send[j].Slot)
3035 DecrementRef(&temp->Send[j].Slot->ref);
3036 temp->Send[j].Slot = NULL;
3039 FreeThunkEntry(temp->id);
3040 memset(temp, 0, sizeof(*temp));
3041 al_free(temp);