Apply the main reverb gain with the panning
[openal-soft.git] / OpenAL32 / alSource.c
blobd31a03770ac024eebc2c0e9c34278a78efec09c3
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <math.h>
26 #include <float.h>
28 #include "AL/al.h"
29 #include "AL/alc.h"
30 #include "alMain.h"
31 #include "alError.h"
32 #include "alSource.h"
33 #include "alBuffer.h"
34 #include "alThunk.h"
35 #include "alAuxEffectSlot.h"
37 #include "backends/base.h"
39 #include "threads.h"
42 extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
43 extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
45 static ALvoid InitSourceParams(ALsource *Source);
46 static ALint64 GetSourceSampleOffset(ALsource *Source);
47 static ALdouble GetSourceSecOffset(ALsource *Source);
48 static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
49 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac);
51 typedef enum SourceProp {
52 srcPitch = AL_PITCH,
53 srcGain = AL_GAIN,
54 srcMinGain = AL_MIN_GAIN,
55 srcMaxGain = AL_MAX_GAIN,
56 srcMaxDistance = AL_MAX_DISTANCE,
57 srcRolloffFactor = AL_ROLLOFF_FACTOR,
58 srcDopplerFactor = AL_DOPPLER_FACTOR,
59 srcConeOuterGain = AL_CONE_OUTER_GAIN,
60 srcSecOffset = AL_SEC_OFFSET,
61 srcSampleOffset = AL_SAMPLE_OFFSET,
62 srcByteOffset = AL_BYTE_OFFSET,
63 srcConeInnerAngle = AL_CONE_INNER_ANGLE,
64 srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
65 srcRefDistance = AL_REFERENCE_DISTANCE,
67 srcPosition = AL_POSITION,
68 srcVelocity = AL_VELOCITY,
69 srcDirection = AL_DIRECTION,
71 srcSourceRelative = AL_SOURCE_RELATIVE,
72 srcLooping = AL_LOOPING,
73 srcBuffer = AL_BUFFER,
74 srcSourceState = AL_SOURCE_STATE,
75 srcBuffersQueued = AL_BUFFERS_QUEUED,
76 srcBuffersProcessed = AL_BUFFERS_PROCESSED,
77 srcSourceType = AL_SOURCE_TYPE,
79 /* ALC_EXT_EFX */
80 srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
81 srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
82 srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
83 srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
84 srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
85 srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
86 srcDirectFilter = AL_DIRECT_FILTER,
87 srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
89 /* AL_SOFT_direct_channels */
90 srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
92 /* AL_EXT_source_distance_model */
93 srcDistanceModel = AL_DISTANCE_MODEL,
95 srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
96 srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
97 srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
99 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
100 srcSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
101 srcByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
103 /* AL_SOFT_source_latency */
104 srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
105 srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
107 /* AL_EXT_BFORMAT */
108 srcOrientation = AL_ORIENTATION,
109 } SourceProp;
111 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
112 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
113 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
115 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
116 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
117 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
119 static ALint FloatValsByProp(ALenum prop)
121 if(prop != (ALenum)((SourceProp)prop))
122 return 0;
123 switch((SourceProp)prop)
125 case AL_PITCH:
126 case AL_GAIN:
127 case AL_MIN_GAIN:
128 case AL_MAX_GAIN:
129 case AL_MAX_DISTANCE:
130 case AL_ROLLOFF_FACTOR:
131 case AL_DOPPLER_FACTOR:
132 case AL_CONE_OUTER_GAIN:
133 case AL_SEC_OFFSET:
134 case AL_SAMPLE_OFFSET:
135 case AL_BYTE_OFFSET:
136 case AL_CONE_INNER_ANGLE:
137 case AL_CONE_OUTER_ANGLE:
138 case AL_REFERENCE_DISTANCE:
139 case AL_CONE_OUTER_GAINHF:
140 case AL_AIR_ABSORPTION_FACTOR:
141 case AL_ROOM_ROLLOFF_FACTOR:
142 case AL_DIRECT_FILTER_GAINHF_AUTO:
143 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
144 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
145 case AL_DIRECT_CHANNELS_SOFT:
146 case AL_DISTANCE_MODEL:
147 case AL_SOURCE_RELATIVE:
148 case AL_LOOPING:
149 case AL_SOURCE_STATE:
150 case AL_BUFFERS_QUEUED:
151 case AL_BUFFERS_PROCESSED:
152 case AL_SOURCE_TYPE:
153 case AL_BYTE_LENGTH_SOFT:
154 case AL_SAMPLE_LENGTH_SOFT:
155 case AL_SEC_LENGTH_SOFT:
156 return 1;
158 case AL_SAMPLE_RW_OFFSETS_SOFT:
159 case AL_BYTE_RW_OFFSETS_SOFT:
160 return 2;
162 case AL_POSITION:
163 case AL_VELOCITY:
164 case AL_DIRECTION:
165 return 3;
167 case AL_ORIENTATION:
168 return 6;
170 case AL_SEC_OFFSET_LATENCY_SOFT:
171 break; /* Double only */
173 case AL_BUFFER:
174 case AL_DIRECT_FILTER:
175 case AL_AUXILIARY_SEND_FILTER:
176 break; /* i/i64 only */
177 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
178 break; /* i64 only */
180 return 0;
182 static ALint DoubleValsByProp(ALenum prop)
184 if(prop != (ALenum)((SourceProp)prop))
185 return 0;
186 switch((SourceProp)prop)
188 case AL_PITCH:
189 case AL_GAIN:
190 case AL_MIN_GAIN:
191 case AL_MAX_GAIN:
192 case AL_MAX_DISTANCE:
193 case AL_ROLLOFF_FACTOR:
194 case AL_DOPPLER_FACTOR:
195 case AL_CONE_OUTER_GAIN:
196 case AL_SEC_OFFSET:
197 case AL_SAMPLE_OFFSET:
198 case AL_BYTE_OFFSET:
199 case AL_CONE_INNER_ANGLE:
200 case AL_CONE_OUTER_ANGLE:
201 case AL_REFERENCE_DISTANCE:
202 case AL_CONE_OUTER_GAINHF:
203 case AL_AIR_ABSORPTION_FACTOR:
204 case AL_ROOM_ROLLOFF_FACTOR:
205 case AL_DIRECT_FILTER_GAINHF_AUTO:
206 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
207 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
208 case AL_DIRECT_CHANNELS_SOFT:
209 case AL_DISTANCE_MODEL:
210 case AL_SOURCE_RELATIVE:
211 case AL_LOOPING:
212 case AL_SOURCE_STATE:
213 case AL_BUFFERS_QUEUED:
214 case AL_BUFFERS_PROCESSED:
215 case AL_SOURCE_TYPE:
216 case AL_BYTE_LENGTH_SOFT:
217 case AL_SAMPLE_LENGTH_SOFT:
218 case AL_SEC_LENGTH_SOFT:
219 return 1;
221 case AL_SAMPLE_RW_OFFSETS_SOFT:
222 case AL_BYTE_RW_OFFSETS_SOFT:
223 case AL_SEC_OFFSET_LATENCY_SOFT:
224 return 2;
226 case AL_POSITION:
227 case AL_VELOCITY:
228 case AL_DIRECTION:
229 return 3;
231 case AL_ORIENTATION:
232 return 6;
234 case AL_BUFFER:
235 case AL_DIRECT_FILTER:
236 case AL_AUXILIARY_SEND_FILTER:
237 break; /* i/i64 only */
238 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
239 break; /* i64 only */
241 return 0;
244 static ALint IntValsByProp(ALenum prop)
246 if(prop != (ALenum)((SourceProp)prop))
247 return 0;
248 switch((SourceProp)prop)
250 case AL_PITCH:
251 case AL_GAIN:
252 case AL_MIN_GAIN:
253 case AL_MAX_GAIN:
254 case AL_MAX_DISTANCE:
255 case AL_ROLLOFF_FACTOR:
256 case AL_DOPPLER_FACTOR:
257 case AL_CONE_OUTER_GAIN:
258 case AL_SEC_OFFSET:
259 case AL_SAMPLE_OFFSET:
260 case AL_BYTE_OFFSET:
261 case AL_CONE_INNER_ANGLE:
262 case AL_CONE_OUTER_ANGLE:
263 case AL_REFERENCE_DISTANCE:
264 case AL_CONE_OUTER_GAINHF:
265 case AL_AIR_ABSORPTION_FACTOR:
266 case AL_ROOM_ROLLOFF_FACTOR:
267 case AL_DIRECT_FILTER_GAINHF_AUTO:
268 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
269 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
270 case AL_DIRECT_CHANNELS_SOFT:
271 case AL_DISTANCE_MODEL:
272 case AL_SOURCE_RELATIVE:
273 case AL_LOOPING:
274 case AL_BUFFER:
275 case AL_SOURCE_STATE:
276 case AL_BUFFERS_QUEUED:
277 case AL_BUFFERS_PROCESSED:
278 case AL_SOURCE_TYPE:
279 case AL_DIRECT_FILTER:
280 case AL_BYTE_LENGTH_SOFT:
281 case AL_SAMPLE_LENGTH_SOFT:
282 case AL_SEC_LENGTH_SOFT:
283 return 1;
285 case AL_SAMPLE_RW_OFFSETS_SOFT:
286 case AL_BYTE_RW_OFFSETS_SOFT:
287 return 2;
289 case AL_POSITION:
290 case AL_VELOCITY:
291 case AL_DIRECTION:
292 case AL_AUXILIARY_SEND_FILTER:
293 return 3;
295 case AL_ORIENTATION:
296 return 6;
298 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
299 break; /* i64 only */
300 case AL_SEC_OFFSET_LATENCY_SOFT:
301 break; /* Double only */
303 return 0;
305 static ALint Int64ValsByProp(ALenum prop)
307 if(prop != (ALenum)((SourceProp)prop))
308 return 0;
309 switch((SourceProp)prop)
311 case AL_PITCH:
312 case AL_GAIN:
313 case AL_MIN_GAIN:
314 case AL_MAX_GAIN:
315 case AL_MAX_DISTANCE:
316 case AL_ROLLOFF_FACTOR:
317 case AL_DOPPLER_FACTOR:
318 case AL_CONE_OUTER_GAIN:
319 case AL_SEC_OFFSET:
320 case AL_SAMPLE_OFFSET:
321 case AL_BYTE_OFFSET:
322 case AL_CONE_INNER_ANGLE:
323 case AL_CONE_OUTER_ANGLE:
324 case AL_REFERENCE_DISTANCE:
325 case AL_CONE_OUTER_GAINHF:
326 case AL_AIR_ABSORPTION_FACTOR:
327 case AL_ROOM_ROLLOFF_FACTOR:
328 case AL_DIRECT_FILTER_GAINHF_AUTO:
329 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
330 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
331 case AL_DIRECT_CHANNELS_SOFT:
332 case AL_DISTANCE_MODEL:
333 case AL_SOURCE_RELATIVE:
334 case AL_LOOPING:
335 case AL_BUFFER:
336 case AL_SOURCE_STATE:
337 case AL_BUFFERS_QUEUED:
338 case AL_BUFFERS_PROCESSED:
339 case AL_SOURCE_TYPE:
340 case AL_DIRECT_FILTER:
341 case AL_BYTE_LENGTH_SOFT:
342 case AL_SAMPLE_LENGTH_SOFT:
343 case AL_SEC_LENGTH_SOFT:
344 return 1;
346 case AL_SAMPLE_RW_OFFSETS_SOFT:
347 case AL_BYTE_RW_OFFSETS_SOFT:
348 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
349 return 2;
351 case AL_POSITION:
352 case AL_VELOCITY:
353 case AL_DIRECTION:
354 case AL_AUXILIARY_SEND_FILTER:
355 return 3;
357 case AL_ORIENTATION:
358 return 6;
360 case AL_SEC_OFFSET_LATENCY_SOFT:
361 break; /* Double only */
363 return 0;
367 #define CHECKVAL(x) do { \
368 if(!(x)) \
369 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
370 } while(0)
372 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
374 ALint ival;
376 switch(prop)
378 case AL_BYTE_RW_OFFSETS_SOFT:
379 case AL_SAMPLE_RW_OFFSETS_SOFT:
380 case AL_BYTE_LENGTH_SOFT:
381 case AL_SAMPLE_LENGTH_SOFT:
382 case AL_SEC_LENGTH_SOFT:
383 case AL_SEC_OFFSET_LATENCY_SOFT:
384 /* Query only */
385 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
387 case AL_PITCH:
388 CHECKVAL(*values >= 0.0f);
390 Source->Pitch = *values;
391 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
392 return AL_TRUE;
394 case AL_CONE_INNER_ANGLE:
395 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
397 Source->InnerAngle = *values;
398 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
399 return AL_TRUE;
401 case AL_CONE_OUTER_ANGLE:
402 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
404 Source->OuterAngle = *values;
405 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
406 return AL_TRUE;
408 case AL_GAIN:
409 CHECKVAL(*values >= 0.0f);
411 Source->Gain = *values;
412 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
413 return AL_TRUE;
415 case AL_MAX_DISTANCE:
416 CHECKVAL(*values >= 0.0f);
418 Source->MaxDistance = *values;
419 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
420 return AL_TRUE;
422 case AL_ROLLOFF_FACTOR:
423 CHECKVAL(*values >= 0.0f);
425 Source->RollOffFactor = *values;
426 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
427 return AL_TRUE;
429 case AL_REFERENCE_DISTANCE:
430 CHECKVAL(*values >= 0.0f);
432 Source->RefDistance = *values;
433 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
434 return AL_TRUE;
436 case AL_MIN_GAIN:
437 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
439 Source->MinGain = *values;
440 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
441 return AL_TRUE;
443 case AL_MAX_GAIN:
444 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
446 Source->MaxGain = *values;
447 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
448 return AL_TRUE;
450 case AL_CONE_OUTER_GAIN:
451 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
453 Source->OuterGain = *values;
454 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
455 return AL_TRUE;
457 case AL_CONE_OUTER_GAINHF:
458 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
460 Source->OuterGainHF = *values;
461 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
462 return AL_TRUE;
464 case AL_AIR_ABSORPTION_FACTOR:
465 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
467 Source->AirAbsorptionFactor = *values;
468 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
469 return AL_TRUE;
471 case AL_ROOM_ROLLOFF_FACTOR:
472 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
474 Source->RoomRolloffFactor = *values;
475 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
476 return AL_TRUE;
478 case AL_DOPPLER_FACTOR:
479 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
481 Source->DopplerFactor = *values;
482 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
483 return AL_TRUE;
485 case AL_SEC_OFFSET:
486 case AL_SAMPLE_OFFSET:
487 case AL_BYTE_OFFSET:
488 CHECKVAL(*values >= 0.0f);
490 LockContext(Context);
491 Source->OffsetType = prop;
492 Source->Offset = *values;
494 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
495 !Context->DeferUpdates)
497 WriteLock(&Source->queue_lock);
498 if(ApplyOffset(Source) == AL_FALSE)
500 WriteUnlock(&Source->queue_lock);
501 UnlockContext(Context);
502 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
504 WriteUnlock(&Source->queue_lock);
506 UnlockContext(Context);
507 return AL_TRUE;
510 case AL_POSITION:
511 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
513 LockContext(Context);
514 aluVectorSet(&Source->Position, values[0], values[1], values[2], 1.0f);
515 UnlockContext(Context);
516 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
517 return AL_TRUE;
519 case AL_VELOCITY:
520 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
522 LockContext(Context);
523 aluVectorSet(&Source->Velocity, values[0], values[1], values[2], 0.0f);
524 UnlockContext(Context);
525 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
526 return AL_TRUE;
528 case AL_DIRECTION:
529 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
531 LockContext(Context);
532 aluVectorSet(&Source->Direction, values[0], values[1], values[2], 0.0f);
533 UnlockContext(Context);
534 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
535 return AL_TRUE;
537 case AL_ORIENTATION:
538 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
539 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
541 LockContext(Context);
542 Source->Orientation[0][0] = values[0];
543 Source->Orientation[0][1] = values[1];
544 Source->Orientation[0][2] = values[2];
545 Source->Orientation[1][0] = values[3];
546 Source->Orientation[1][1] = values[4];
547 Source->Orientation[1][2] = values[5];
548 UnlockContext(Context);
549 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
550 return AL_TRUE;
553 case AL_SOURCE_RELATIVE:
554 case AL_LOOPING:
555 case AL_SOURCE_STATE:
556 case AL_SOURCE_TYPE:
557 case AL_DISTANCE_MODEL:
558 case AL_DIRECT_FILTER_GAINHF_AUTO:
559 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
560 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
561 case AL_DIRECT_CHANNELS_SOFT:
562 ival = (ALint)values[0];
563 return SetSourceiv(Source, Context, prop, &ival);
565 case AL_BUFFERS_QUEUED:
566 case AL_BUFFERS_PROCESSED:
567 ival = (ALint)((ALuint)values[0]);
568 return SetSourceiv(Source, Context, prop, &ival);
570 case AL_BUFFER:
571 case AL_DIRECT_FILTER:
572 case AL_AUXILIARY_SEND_FILTER:
573 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
574 break;
577 ERR("Unexpected property: 0x%04x\n", prop);
578 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
581 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
583 ALCdevice *device = Context->Device;
584 ALbuffer *buffer = NULL;
585 ALfilter *filter = NULL;
586 ALeffectslot *slot = NULL;
587 ALbufferlistitem *oldlist;
588 ALbufferlistitem *newlist;
589 ALfloat fvals[6];
591 switch(prop)
593 case AL_SOURCE_STATE:
594 case AL_SOURCE_TYPE:
595 case AL_BUFFERS_QUEUED:
596 case AL_BUFFERS_PROCESSED:
597 case AL_SAMPLE_RW_OFFSETS_SOFT:
598 case AL_BYTE_RW_OFFSETS_SOFT:
599 case AL_BYTE_LENGTH_SOFT:
600 case AL_SAMPLE_LENGTH_SOFT:
601 case AL_SEC_LENGTH_SOFT:
602 /* Query only */
603 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
605 case AL_SOURCE_RELATIVE:
606 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
608 Source->HeadRelative = (ALboolean)*values;
609 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
610 return AL_TRUE;
612 case AL_LOOPING:
613 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
615 Source->Looping = (ALboolean)*values;
616 return AL_TRUE;
618 case AL_BUFFER:
619 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
621 WriteLock(&Source->queue_lock);
622 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
624 WriteUnlock(&Source->queue_lock);
625 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
628 if(buffer != NULL)
630 /* Add the selected buffer to a one-item queue */
631 newlist = malloc(sizeof(ALbufferlistitem));
632 newlist->buffer = buffer;
633 newlist->next = NULL;
634 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 WriteLock(&Source->queue_lock);
679 if(ApplyOffset(Source) == AL_FALSE)
681 WriteUnlock(&Source->queue_lock);
682 UnlockContext(Context);
683 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
685 WriteUnlock(&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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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 BufferList = BufferListStart;
2338 else
2340 BufferList->next = malloc(sizeof(ALbufferlistitem));
2341 BufferList = BufferList->next;
2343 BufferList->buffer = buffer;
2344 BufferList->next = NULL;
2345 if(!buffer) continue;
2347 /* Hold a read lock on each buffer being queued while checking all
2348 * provided buffers. This is done so other threads don't see an extra
2349 * reference on some buffers if this operation ends up failing. */
2350 ReadLock(&buffer->lock);
2351 IncrementRef(&buffer->ref);
2353 if(BufferFmt == NULL)
2355 BufferFmt = buffer;
2357 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2358 source->SampleSize = BytesFromFmt(buffer->FmtType);
2360 else if(BufferFmt->Frequency != buffer->Frequency ||
2361 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2362 BufferFmt->OriginalType != buffer->OriginalType)
2364 WriteUnlock(&source->queue_lock);
2365 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2367 buffer_error:
2368 /* A buffer failed (invalid ID or format), so unlock and release
2369 * each buffer we had. */
2370 while(BufferListStart)
2372 ALbufferlistitem *next = BufferListStart->next;
2373 if((buffer=BufferListStart->buffer) != NULL)
2375 DecrementRef(&buffer->ref);
2376 ReadUnlock(&buffer->lock);
2378 free(BufferListStart);
2379 BufferListStart = next;
2381 goto done;
2384 /* All buffers good, unlock them now. */
2385 BufferList = BufferListStart;
2386 while(BufferList != NULL)
2388 ALbuffer *buffer = BufferList->buffer;
2389 if(buffer) ReadUnlock(&buffer->lock);
2390 BufferList = BufferList->next;
2393 /* Source is now streaming */
2394 source->SourceType = AL_STREAMING;
2396 BufferList = NULL;
2397 if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
2399 /* Queue head is not NULL, append to the end of the queue */
2400 while(BufferList->next != NULL)
2401 BufferList = BufferList->next;
2402 BufferList->next = BufferListStart;
2404 /* If the current buffer was at the end (NULL), put it at the start of the newly queued
2405 * buffers.
2407 BufferList = NULL;
2408 ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
2409 WriteUnlock(&source->queue_lock);
2411 done:
2412 ALCcontext_DecRef(context);
2415 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2417 ALCcontext *context;
2418 ALsource *source;
2419 ALbufferlistitem *OldHead;
2420 ALbufferlistitem *OldTail;
2421 ALbufferlistitem *Current;
2422 ALsizei i = 0;
2424 if(nb == 0)
2425 return;
2427 context = GetContextRef();
2428 if(!context) return;
2430 if(!(nb >= 0))
2431 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2433 if((source=LookupSource(context, src)) == NULL)
2434 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2436 WriteLock(&source->queue_lock);
2437 /* Find the new buffer queue head */
2438 OldTail = ATOMIC_LOAD(&source->queue);
2439 Current = ATOMIC_LOAD(&source->current_buffer);
2440 if(OldTail != Current)
2442 for(i = 1;i < nb;i++)
2444 ALbufferlistitem *next = OldTail->next;
2445 if(!next || next == Current) break;
2446 OldTail = next;
2449 if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
2451 WriteUnlock(&source->queue_lock);
2452 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2453 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2456 /* Swap it, and cut the new head from the old. */
2457 OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, OldTail->next);
2458 if(OldTail->next)
2460 ALCdevice *device = context->Device;
2461 uint count;
2463 /* Once the active mix (if any) is done, it's safe to cut the old tail
2464 * from the new head.
2466 if(((count=ReadRef(&device->MixCount))&1) != 0)
2468 while(count == ReadRef(&device->MixCount))
2469 althrd_yield();
2471 OldTail->next = NULL;
2473 WriteUnlock(&source->queue_lock);
2475 while(OldHead != NULL)
2477 ALbufferlistitem *next = OldHead->next;
2478 ALbuffer *buffer = OldHead->buffer;
2480 if(!buffer)
2481 *(buffers++) = 0;
2482 else
2484 *(buffers++) = buffer->id;
2485 DecrementRef(&buffer->ref);
2488 free(OldHead);
2489 OldHead = next;
2492 done:
2493 ALCcontext_DecRef(context);
2497 static ALvoid InitSourceParams(ALsource *Source)
2499 ALuint i;
2501 RWLockInit(&Source->queue_lock);
2503 Source->InnerAngle = 360.0f;
2504 Source->OuterAngle = 360.0f;
2505 Source->Pitch = 1.0f;
2506 aluVectorSet(&Source->Position, 0.0f, 0.0f, 0.0f, 1.0f);
2507 aluVectorSet(&Source->Velocity, 0.0f, 0.0f, 0.0f, 0.0f);
2508 aluVectorSet(&Source->Direction, 0.0f, 0.0f, 0.0f, 0.0f);
2509 Source->Orientation[0][0] = 0.0f;
2510 Source->Orientation[0][1] = 0.0f;
2511 Source->Orientation[0][2] = -1.0f;
2512 Source->Orientation[1][0] = 0.0f;
2513 Source->Orientation[1][1] = 1.0f;
2514 Source->Orientation[1][2] = 0.0f;
2515 Source->RefDistance = 1.0f;
2516 Source->MaxDistance = FLT_MAX;
2517 Source->RollOffFactor = 1.0f;
2518 Source->Looping = AL_FALSE;
2519 Source->Gain = 1.0f;
2520 Source->MinGain = 0.0f;
2521 Source->MaxGain = 1.0f;
2522 Source->OuterGain = 0.0f;
2523 Source->OuterGainHF = 1.0f;
2525 Source->DryGainHFAuto = AL_TRUE;
2526 Source->WetGainAuto = AL_TRUE;
2527 Source->WetGainHFAuto = AL_TRUE;
2528 Source->AirAbsorptionFactor = 0.0f;
2529 Source->RoomRolloffFactor = 0.0f;
2530 Source->DopplerFactor = 1.0f;
2531 Source->DirectChannels = AL_FALSE;
2533 Source->Radius = 0.0f;
2535 Source->DistanceModel = DefaultDistanceModel;
2537 Source->state = AL_INITIAL;
2538 Source->new_state = AL_NONE;
2539 Source->SourceType = AL_UNDETERMINED;
2540 Source->Offset = -1.0;
2542 ATOMIC_INIT(&Source->queue, NULL);
2543 ATOMIC_INIT(&Source->current_buffer, NULL);
2545 Source->Direct.Gain = 1.0f;
2546 Source->Direct.GainHF = 1.0f;
2547 Source->Direct.HFReference = LOWPASSFREQREF;
2548 Source->Direct.GainLF = 1.0f;
2549 Source->Direct.LFReference = HIGHPASSFREQREF;
2550 for(i = 0;i < MAX_SENDS;i++)
2552 Source->Send[i].Gain = 1.0f;
2553 Source->Send[i].GainHF = 1.0f;
2554 Source->Send[i].HFReference = LOWPASSFREQREF;
2555 Source->Send[i].GainLF = 1.0f;
2556 Source->Send[i].LFReference = HIGHPASSFREQREF;
2559 ATOMIC_INIT(&Source->NeedsUpdate, AL_TRUE);
2563 /* SetSourceState
2565 * Sets the source's new play state given its current state.
2567 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2569 WriteLock(&Source->queue_lock);
2570 if(state == AL_PLAYING)
2572 ALCdevice *device = Context->Device;
2573 ALbufferlistitem *BufferList;
2574 ALboolean discontinuity;
2575 ALvoice *voice = NULL;
2576 ALsizei i;
2578 /* Check that there is a queue containing at least one valid, non zero
2579 * length Buffer. */
2580 BufferList = ATOMIC_LOAD(&Source->queue);
2581 while(BufferList)
2583 ALbuffer *buffer;
2584 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2585 break;
2586 BufferList = BufferList->next;
2589 if(Source->state != AL_PAUSED)
2591 Source->state = AL_PLAYING;
2592 Source->position = 0;
2593 Source->position_fraction = 0;
2594 ATOMIC_STORE(&Source->current_buffer, BufferList);
2595 discontinuity = AL_TRUE;
2597 else
2599 Source->state = AL_PLAYING;
2600 discontinuity = AL_FALSE;
2603 // Check if an Offset has been set
2604 if(Source->Offset >= 0.0)
2606 ApplyOffset(Source);
2607 /* discontinuity = AL_TRUE;??? */
2610 /* If there's nothing to play, or device is disconnected, go right to
2611 * stopped */
2612 if(!BufferList || !device->Connected)
2613 goto do_stop;
2615 /* Make sure this source isn't already active, while looking for an
2616 * unused active source slot to put it in. */
2617 for(i = 0;i < Context->VoiceCount;i++)
2619 ALsource *old = Source;
2620 if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL))
2622 if(voice == NULL)
2624 voice = &Context->Voices[i];
2625 voice->Source = Source;
2627 break;
2629 old = NULL;
2630 if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source))
2631 voice = &Context->Voices[i];
2633 if(voice == NULL)
2635 voice = &Context->Voices[Context->VoiceCount++];
2636 voice->Source = Source;
2639 /* Clear previous samples if playback is discontinuous. */
2640 if(discontinuity)
2641 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
2643 voice->Direct.Moving = AL_FALSE;
2644 voice->Direct.Counter = 0;
2645 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
2647 ALsizei j;
2648 for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
2649 voice->Direct.Hrtf[i].State.History[j] = 0.0f;
2650 for(j = 0;j < HRIR_LENGTH;j++)
2652 voice->Direct.Hrtf[i].State.Values[j][0] = 0.0f;
2653 voice->Direct.Hrtf[i].State.Values[j][1] = 0.0f;
2656 for(i = 0;i < (ALsizei)device->NumAuxSends;i++)
2658 voice->Send[i].Moving = AL_FALSE;
2659 voice->Send[i].Counter = 0;
2662 if(BufferList->buffer->FmtChannels == FmtMono)
2663 voice->Update = CalcSourceParams;
2664 else
2665 voice->Update = CalcNonAttnSourceParams;
2667 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
2669 else if(state == AL_PAUSED)
2671 if(Source->state == AL_PLAYING)
2672 Source->state = AL_PAUSED;
2674 else if(state == AL_STOPPED)
2676 do_stop:
2677 if(Source->state != AL_INITIAL)
2679 Source->state = AL_STOPPED;
2680 ATOMIC_STORE(&Source->current_buffer, NULL);
2682 Source->Offset = -1.0;
2684 else if(state == AL_INITIAL)
2686 if(Source->state != AL_INITIAL)
2688 Source->state = AL_INITIAL;
2689 Source->position = 0;
2690 Source->position_fraction = 0;
2691 ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue));
2693 Source->Offset = -1.0;
2695 WriteUnlock(&Source->queue_lock);
2698 /* GetSourceSampleOffset
2700 * Gets the current read offset for the given Source, in 32.32 fixed-point
2701 * samples. The offset is relative to the start of the queue (not the start of
2702 * the current buffer).
2704 ALint64 GetSourceSampleOffset(ALsource *Source)
2706 const ALbufferlistitem *BufferList;
2707 const ALbufferlistitem *Current;
2708 ALuint64 readPos;
2710 ReadLock(&Source->queue_lock);
2711 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2713 ReadUnlock(&Source->queue_lock);
2714 return 0;
2717 /* NOTE: This is the offset into the *current* buffer, so add the length of
2718 * any played buffers */
2719 readPos = (ALuint64)Source->position << 32;
2720 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2721 BufferList = ATOMIC_LOAD(&Source->queue);
2722 Current = ATOMIC_LOAD(&Source->current_buffer);
2723 while(BufferList && BufferList != Current)
2725 if(BufferList->buffer)
2726 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2727 BufferList = BufferList->next;
2730 ReadUnlock(&Source->queue_lock);
2731 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
2734 /* GetSourceSecOffset
2736 * Gets the current read offset for the given Source, in seconds. The offset is
2737 * relative to the start of the queue (not the start of the current buffer).
2739 static ALdouble GetSourceSecOffset(ALsource *Source)
2741 const ALbufferlistitem *BufferList;
2742 const ALbufferlistitem *Current;
2743 const ALbuffer *Buffer = NULL;
2744 ALuint64 readPos;
2746 ReadLock(&Source->queue_lock);
2747 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2749 ReadUnlock(&Source->queue_lock);
2750 return 0.0;
2753 /* NOTE: This is the offset into the *current* buffer, so add the length of
2754 * any played buffers */
2755 readPos = (ALuint64)Source->position << FRACTIONBITS;
2756 readPos |= (ALuint64)Source->position_fraction;
2757 BufferList = ATOMIC_LOAD(&Source->queue);
2758 Current = ATOMIC_LOAD(&Source->current_buffer);
2759 while(BufferList && BufferList != Current)
2761 const ALbuffer *buffer = BufferList->buffer;
2762 if(buffer != NULL)
2764 if(!Buffer) Buffer = buffer;
2765 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
2767 BufferList = BufferList->next;
2770 while(BufferList && !Buffer)
2772 Buffer = BufferList->buffer;
2773 BufferList = BufferList->next;
2775 assert(Buffer != NULL);
2777 ReadUnlock(&Source->queue_lock);
2778 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2781 /* GetSourceOffsets
2783 * Gets the current read and write offsets for the given Source, in the
2784 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2785 * the start of the queue (not the start of the current buffer).
2787 static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2789 const ALbufferlistitem *BufferList;
2790 const ALbufferlistitem *Current;
2791 const ALbuffer *Buffer = NULL;
2792 ALboolean readFin = AL_FALSE;
2793 ALuint readPos, readPosFrac, writePos;
2794 ALuint totalBufferLen;
2796 ReadLock(&Source->queue_lock);
2797 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2799 offset[0] = 0.0;
2800 offset[1] = 0.0;
2801 ReadUnlock(&Source->queue_lock);
2802 return;
2805 if(updateLen > 0.0 && updateLen < 0.015)
2806 updateLen = 0.015;
2808 /* NOTE: This is the offset into the *current* buffer, so add the length of
2809 * any played buffers */
2810 totalBufferLen = 0;
2811 readPos = Source->position;
2812 readPosFrac = Source->position_fraction;
2813 BufferList = ATOMIC_LOAD(&Source->queue);
2814 Current = ATOMIC_LOAD(&Source->current_buffer);
2815 while(BufferList != NULL)
2817 const ALbuffer *buffer;
2818 readFin = readFin || (BufferList == Current);
2819 if((buffer=BufferList->buffer) != NULL)
2821 if(!Buffer) Buffer = buffer;
2822 totalBufferLen += buffer->SampleLen;
2823 if(!readFin) readPos += buffer->SampleLen;
2825 BufferList = BufferList->next;
2827 assert(Buffer != NULL);
2829 if(Source->state == AL_PLAYING)
2830 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency + 0.5f);
2831 else
2832 writePos = readPos;
2834 if(Source->Looping)
2836 readPos %= totalBufferLen;
2837 writePos %= totalBufferLen;
2839 else
2841 /* Wrap positions back to 0 */
2842 if(readPos >= totalBufferLen)
2843 readPos = readPosFrac = 0;
2844 if(writePos >= totalBufferLen)
2845 writePos = 0;
2848 switch(name)
2850 case AL_SEC_OFFSET:
2851 offset[0] = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
2852 offset[1] = (ALdouble)writePos/Buffer->Frequency;
2853 break;
2855 case AL_SAMPLE_OFFSET:
2856 case AL_SAMPLE_RW_OFFSETS_SOFT:
2857 offset[0] = readPos + (ALdouble)readPosFrac/FRACTIONONE;
2858 offset[1] = (ALdouble)writePos;
2859 break;
2861 case AL_BYTE_OFFSET:
2862 case AL_BYTE_RW_OFFSETS_SOFT:
2863 if(Buffer->OriginalType == UserFmtIMA4)
2865 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2866 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2867 ALuint FrameBlockSize = Buffer->OriginalAlign;
2869 /* Round down to nearest ADPCM block */
2870 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2871 if(Source->state != AL_PLAYING)
2872 offset[1] = offset[0];
2873 else
2875 /* Round up to nearest ADPCM block */
2876 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2877 FrameBlockSize * BlockSize);
2880 else if(Buffer->OriginalType == UserFmtMSADPCM)
2882 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2883 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2884 ALuint FrameBlockSize = Buffer->OriginalAlign;
2886 /* Round down to nearest ADPCM block */
2887 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2888 if(Source->state != AL_PLAYING)
2889 offset[1] = offset[0];
2890 else
2892 /* Round up to nearest ADPCM block */
2893 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2894 FrameBlockSize * BlockSize);
2897 else
2899 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2900 offset[0] = (ALdouble)(readPos * FrameSize);
2901 offset[1] = (ALdouble)(writePos * FrameSize);
2903 break;
2906 ReadUnlock(&Source->queue_lock);
2910 /* ApplyOffset
2912 * Apply the stored playback offset to the Source. This function will update
2913 * the number of buffers "played" given the stored offset.
2915 ALboolean ApplyOffset(ALsource *Source)
2917 ALbufferlistitem *BufferList;
2918 const ALbuffer *Buffer;
2919 ALuint bufferLen, totalBufferLen;
2920 ALuint offset=0, frac=0;
2922 /* Get sample frame offset */
2923 if(!GetSampleOffset(Source, &offset, &frac))
2924 return AL_FALSE;
2926 totalBufferLen = 0;
2927 BufferList = ATOMIC_LOAD(&Source->queue);
2928 while(BufferList && totalBufferLen <= offset)
2930 Buffer = BufferList->buffer;
2931 bufferLen = Buffer ? Buffer->SampleLen : 0;
2933 if(bufferLen > offset-totalBufferLen)
2935 /* Offset is in this buffer */
2936 ATOMIC_STORE(&Source->current_buffer, BufferList);
2938 Source->position = offset - totalBufferLen;
2939 Source->position_fraction = frac;
2940 return AL_TRUE;
2943 totalBufferLen += bufferLen;
2945 BufferList = BufferList->next;
2948 /* Offset is out of range of the queue */
2949 return AL_FALSE;
2953 /* GetSampleOffset
2955 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
2956 * or Second offset supplied by the application). This takes into account the
2957 * fact that the buffer format may have been modifed since.
2959 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
2961 const ALbuffer *Buffer = NULL;
2962 const ALbufferlistitem *BufferList;
2963 ALdouble dbloff, dblfrac;
2965 /* Find the first valid Buffer in the Queue */
2966 BufferList = ATOMIC_LOAD(&Source->queue);
2967 while(BufferList)
2969 if(BufferList->buffer)
2971 Buffer = BufferList->buffer;
2972 break;
2974 BufferList = BufferList->next;
2976 if(!Buffer)
2978 Source->Offset = -1.0;
2979 return AL_FALSE;
2982 switch(Source->OffsetType)
2984 case AL_BYTE_OFFSET:
2985 /* Determine the ByteOffset (and ensure it is block aligned) */
2986 *offset = (ALuint)Source->Offset;
2987 if(Buffer->OriginalType == UserFmtIMA4)
2989 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2990 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2991 *offset *= Buffer->OriginalAlign;
2993 else if(Buffer->OriginalType == UserFmtMSADPCM)
2995 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2996 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2997 *offset *= Buffer->OriginalAlign;
2999 else
3000 *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3001 *frac = 0;
3002 break;
3004 case AL_SAMPLE_OFFSET:
3005 dblfrac = modf(Source->Offset, &dbloff);
3006 *offset = (ALuint)mind(dbloff, UINT_MAX);
3007 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3008 break;
3010 case AL_SEC_OFFSET:
3011 dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
3012 *offset = (ALuint)mind(dbloff, UINT_MAX);
3013 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3014 break;
3016 Source->Offset = -1.0;
3018 return AL_TRUE;
3022 /* ReleaseALSources
3024 * Destroys all sources in the source map.
3026 ALvoid ReleaseALSources(ALCcontext *Context)
3028 ALbufferlistitem *item;
3029 ALsizei pos;
3030 ALuint j;
3031 for(pos = 0;pos < Context->SourceMap.size;pos++)
3033 ALsource *temp = Context->SourceMap.array[pos].value;
3034 Context->SourceMap.array[pos].value = NULL;
3036 item = ATOMIC_EXCHANGE(ALbufferlistitem*, &temp->queue, NULL);
3037 while(item != NULL)
3039 ALbufferlistitem *next = item->next;
3040 if(item->buffer != NULL)
3041 DecrementRef(&item->buffer->ref);
3042 free(item);
3043 item = next;
3046 for(j = 0;j < MAX_SENDS;++j)
3048 if(temp->Send[j].Slot)
3049 DecrementRef(&temp->Send[j].Slot->ref);
3050 temp->Send[j].Slot = NULL;
3053 FreeThunkEntry(temp->id);
3054 memset(temp, 0, sizeof(*temp));
3055 al_free(temp);