Don't store the looping state in the voice
[openal-soft.git] / OpenAL32 / alSource.c
blob0e98f2f553968207ca390be8a610a042c41788d1
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <math.h>
26 #include <float.h>
28 #include "AL/al.h"
29 #include "AL/alc.h"
30 #include "alMain.h"
31 #include "alError.h"
32 #include "alSource.h"
33 #include "alBuffer.h"
34 #include "alThunk.h"
35 #include "alAuxEffectSlot.h"
37 #include "backends/base.h"
39 #include "threads.h"
40 #include "almalloc.h"
43 extern inline void LockSourcesRead(ALCcontext *context);
44 extern inline void UnlockSourcesRead(ALCcontext *context);
45 extern inline void LockSourcesWrite(ALCcontext *context);
46 extern inline void UnlockSourcesWrite(ALCcontext *context);
47 extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
48 extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
50 static void InitSourceParams(ALsource *Source);
51 static void DeinitSource(ALsource *source);
52 static void UpdateSourceProps(ALsource *source, ALuint num_sends, ALCcontext *context);
53 static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime);
54 static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime);
55 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device);
56 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac);
58 typedef enum SourceProp {
59 srcPitch = AL_PITCH,
60 srcGain = AL_GAIN,
61 srcMinGain = AL_MIN_GAIN,
62 srcMaxGain = AL_MAX_GAIN,
63 srcMaxDistance = AL_MAX_DISTANCE,
64 srcRolloffFactor = AL_ROLLOFF_FACTOR,
65 srcDopplerFactor = AL_DOPPLER_FACTOR,
66 srcConeOuterGain = AL_CONE_OUTER_GAIN,
67 srcSecOffset = AL_SEC_OFFSET,
68 srcSampleOffset = AL_SAMPLE_OFFSET,
69 srcByteOffset = AL_BYTE_OFFSET,
70 srcConeInnerAngle = AL_CONE_INNER_ANGLE,
71 srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
72 srcRefDistance = AL_REFERENCE_DISTANCE,
74 srcPosition = AL_POSITION,
75 srcVelocity = AL_VELOCITY,
76 srcDirection = AL_DIRECTION,
78 srcSourceRelative = AL_SOURCE_RELATIVE,
79 srcLooping = AL_LOOPING,
80 srcBuffer = AL_BUFFER,
81 srcSourceState = AL_SOURCE_STATE,
82 srcBuffersQueued = AL_BUFFERS_QUEUED,
83 srcBuffersProcessed = AL_BUFFERS_PROCESSED,
84 srcSourceType = AL_SOURCE_TYPE,
86 /* ALC_EXT_EFX */
87 srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
88 srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
89 srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
90 srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
91 srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
92 srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
93 srcDirectFilter = AL_DIRECT_FILTER,
94 srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
96 /* AL_SOFT_direct_channels */
97 srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
99 /* AL_EXT_source_distance_model */
100 srcDistanceModel = AL_DISTANCE_MODEL,
102 srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
103 srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
104 srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
106 /* AL_SOFT_source_latency */
107 srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
108 srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
110 /* AL_EXT_STEREO_ANGLES */
111 srcAngles = AL_STEREO_ANGLES,
113 /* AL_EXT_SOURCE_RADIUS */
114 srcRadius = AL_SOURCE_RADIUS,
116 /* AL_EXT_BFORMAT */
117 srcOrientation = AL_ORIENTATION,
118 } SourceProp;
120 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
121 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
122 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
124 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
125 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
126 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
128 static inline bool SourceShouldUpdate(const ALsource *source, const ALCcontext *context)
130 return (source->state == AL_PLAYING || source->state == AL_PAUSED) &&
131 !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire);
134 static ALint FloatValsByProp(ALenum prop)
136 if(prop != (ALenum)((SourceProp)prop))
137 return 0;
138 switch((SourceProp)prop)
140 case AL_PITCH:
141 case AL_GAIN:
142 case AL_MIN_GAIN:
143 case AL_MAX_GAIN:
144 case AL_MAX_DISTANCE:
145 case AL_ROLLOFF_FACTOR:
146 case AL_DOPPLER_FACTOR:
147 case AL_CONE_OUTER_GAIN:
148 case AL_SEC_OFFSET:
149 case AL_SAMPLE_OFFSET:
150 case AL_BYTE_OFFSET:
151 case AL_CONE_INNER_ANGLE:
152 case AL_CONE_OUTER_ANGLE:
153 case AL_REFERENCE_DISTANCE:
154 case AL_CONE_OUTER_GAINHF:
155 case AL_AIR_ABSORPTION_FACTOR:
156 case AL_ROOM_ROLLOFF_FACTOR:
157 case AL_DIRECT_FILTER_GAINHF_AUTO:
158 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
159 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
160 case AL_DIRECT_CHANNELS_SOFT:
161 case AL_DISTANCE_MODEL:
162 case AL_SOURCE_RELATIVE:
163 case AL_LOOPING:
164 case AL_SOURCE_STATE:
165 case AL_BUFFERS_QUEUED:
166 case AL_BUFFERS_PROCESSED:
167 case AL_SOURCE_TYPE:
168 case AL_BYTE_LENGTH_SOFT:
169 case AL_SAMPLE_LENGTH_SOFT:
170 case AL_SEC_LENGTH_SOFT:
171 case AL_SOURCE_RADIUS:
172 return 1;
174 case AL_STEREO_ANGLES:
175 return 2;
177 case AL_POSITION:
178 case AL_VELOCITY:
179 case AL_DIRECTION:
180 return 3;
182 case AL_ORIENTATION:
183 return 6;
185 case AL_SEC_OFFSET_LATENCY_SOFT:
186 break; /* Double only */
188 case AL_BUFFER:
189 case AL_DIRECT_FILTER:
190 case AL_AUXILIARY_SEND_FILTER:
191 break; /* i/i64 only */
192 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
193 break; /* i64 only */
195 return 0;
197 static ALint DoubleValsByProp(ALenum prop)
199 if(prop != (ALenum)((SourceProp)prop))
200 return 0;
201 switch((SourceProp)prop)
203 case AL_PITCH:
204 case AL_GAIN:
205 case AL_MIN_GAIN:
206 case AL_MAX_GAIN:
207 case AL_MAX_DISTANCE:
208 case AL_ROLLOFF_FACTOR:
209 case AL_DOPPLER_FACTOR:
210 case AL_CONE_OUTER_GAIN:
211 case AL_SEC_OFFSET:
212 case AL_SAMPLE_OFFSET:
213 case AL_BYTE_OFFSET:
214 case AL_CONE_INNER_ANGLE:
215 case AL_CONE_OUTER_ANGLE:
216 case AL_REFERENCE_DISTANCE:
217 case AL_CONE_OUTER_GAINHF:
218 case AL_AIR_ABSORPTION_FACTOR:
219 case AL_ROOM_ROLLOFF_FACTOR:
220 case AL_DIRECT_FILTER_GAINHF_AUTO:
221 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
222 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
223 case AL_DIRECT_CHANNELS_SOFT:
224 case AL_DISTANCE_MODEL:
225 case AL_SOURCE_RELATIVE:
226 case AL_LOOPING:
227 case AL_SOURCE_STATE:
228 case AL_BUFFERS_QUEUED:
229 case AL_BUFFERS_PROCESSED:
230 case AL_SOURCE_TYPE:
231 case AL_BYTE_LENGTH_SOFT:
232 case AL_SAMPLE_LENGTH_SOFT:
233 case AL_SEC_LENGTH_SOFT:
234 case AL_SOURCE_RADIUS:
235 return 1;
237 case AL_SEC_OFFSET_LATENCY_SOFT:
238 case AL_STEREO_ANGLES:
239 return 2;
241 case AL_POSITION:
242 case AL_VELOCITY:
243 case AL_DIRECTION:
244 return 3;
246 case AL_ORIENTATION:
247 return 6;
249 case AL_BUFFER:
250 case AL_DIRECT_FILTER:
251 case AL_AUXILIARY_SEND_FILTER:
252 break; /* i/i64 only */
253 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
254 break; /* i64 only */
256 return 0;
259 static ALint IntValsByProp(ALenum prop)
261 if(prop != (ALenum)((SourceProp)prop))
262 return 0;
263 switch((SourceProp)prop)
265 case AL_PITCH:
266 case AL_GAIN:
267 case AL_MIN_GAIN:
268 case AL_MAX_GAIN:
269 case AL_MAX_DISTANCE:
270 case AL_ROLLOFF_FACTOR:
271 case AL_DOPPLER_FACTOR:
272 case AL_CONE_OUTER_GAIN:
273 case AL_SEC_OFFSET:
274 case AL_SAMPLE_OFFSET:
275 case AL_BYTE_OFFSET:
276 case AL_CONE_INNER_ANGLE:
277 case AL_CONE_OUTER_ANGLE:
278 case AL_REFERENCE_DISTANCE:
279 case AL_CONE_OUTER_GAINHF:
280 case AL_AIR_ABSORPTION_FACTOR:
281 case AL_ROOM_ROLLOFF_FACTOR:
282 case AL_DIRECT_FILTER_GAINHF_AUTO:
283 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
284 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
285 case AL_DIRECT_CHANNELS_SOFT:
286 case AL_DISTANCE_MODEL:
287 case AL_SOURCE_RELATIVE:
288 case AL_LOOPING:
289 case AL_BUFFER:
290 case AL_SOURCE_STATE:
291 case AL_BUFFERS_QUEUED:
292 case AL_BUFFERS_PROCESSED:
293 case AL_SOURCE_TYPE:
294 case AL_DIRECT_FILTER:
295 case AL_BYTE_LENGTH_SOFT:
296 case AL_SAMPLE_LENGTH_SOFT:
297 case AL_SEC_LENGTH_SOFT:
298 case AL_SOURCE_RADIUS:
299 return 1;
301 case AL_POSITION:
302 case AL_VELOCITY:
303 case AL_DIRECTION:
304 case AL_AUXILIARY_SEND_FILTER:
305 return 3;
307 case AL_ORIENTATION:
308 return 6;
310 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
311 break; /* i64 only */
312 case AL_SEC_OFFSET_LATENCY_SOFT:
313 break; /* Double only */
314 case AL_STEREO_ANGLES:
315 break; /* Float/double only */
317 return 0;
319 static ALint Int64ValsByProp(ALenum prop)
321 if(prop != (ALenum)((SourceProp)prop))
322 return 0;
323 switch((SourceProp)prop)
325 case AL_PITCH:
326 case AL_GAIN:
327 case AL_MIN_GAIN:
328 case AL_MAX_GAIN:
329 case AL_MAX_DISTANCE:
330 case AL_ROLLOFF_FACTOR:
331 case AL_DOPPLER_FACTOR:
332 case AL_CONE_OUTER_GAIN:
333 case AL_SEC_OFFSET:
334 case AL_SAMPLE_OFFSET:
335 case AL_BYTE_OFFSET:
336 case AL_CONE_INNER_ANGLE:
337 case AL_CONE_OUTER_ANGLE:
338 case AL_REFERENCE_DISTANCE:
339 case AL_CONE_OUTER_GAINHF:
340 case AL_AIR_ABSORPTION_FACTOR:
341 case AL_ROOM_ROLLOFF_FACTOR:
342 case AL_DIRECT_FILTER_GAINHF_AUTO:
343 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
344 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
345 case AL_DIRECT_CHANNELS_SOFT:
346 case AL_DISTANCE_MODEL:
347 case AL_SOURCE_RELATIVE:
348 case AL_LOOPING:
349 case AL_BUFFER:
350 case AL_SOURCE_STATE:
351 case AL_BUFFERS_QUEUED:
352 case AL_BUFFERS_PROCESSED:
353 case AL_SOURCE_TYPE:
354 case AL_DIRECT_FILTER:
355 case AL_BYTE_LENGTH_SOFT:
356 case AL_SAMPLE_LENGTH_SOFT:
357 case AL_SEC_LENGTH_SOFT:
358 case AL_SOURCE_RADIUS:
359 return 1;
361 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
362 return 2;
364 case AL_POSITION:
365 case AL_VELOCITY:
366 case AL_DIRECTION:
367 case AL_AUXILIARY_SEND_FILTER:
368 return 3;
370 case AL_ORIENTATION:
371 return 6;
373 case AL_SEC_OFFSET_LATENCY_SOFT:
374 break; /* Double only */
375 case AL_STEREO_ANGLES:
376 break; /* Float/double only */
378 return 0;
382 #define CHECKVAL(x) do { \
383 if(!(x)) \
384 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
385 } while(0)
387 #define DO_UPDATEPROPS() do { \
388 if(SourceShouldUpdate(Source, Context)) \
389 UpdateSourceProps(Source, device->NumAuxSends, Context); \
390 } while(0)
392 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
394 ALCdevice *device = Context->Device;
395 ALint ival;
397 switch(prop)
399 case AL_BYTE_LENGTH_SOFT:
400 case AL_SAMPLE_LENGTH_SOFT:
401 case AL_SEC_LENGTH_SOFT:
402 case AL_SEC_OFFSET_LATENCY_SOFT:
403 /* Query only */
404 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
406 case AL_PITCH:
407 CHECKVAL(*values >= 0.0f);
409 Source->Pitch = *values;
410 DO_UPDATEPROPS();
411 return AL_TRUE;
413 case AL_CONE_INNER_ANGLE:
414 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
416 Source->InnerAngle = *values;
417 DO_UPDATEPROPS();
418 return AL_TRUE;
420 case AL_CONE_OUTER_ANGLE:
421 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
423 Source->OuterAngle = *values;
424 DO_UPDATEPROPS();
425 return AL_TRUE;
427 case AL_GAIN:
428 CHECKVAL(*values >= 0.0f);
430 Source->Gain = *values;
431 DO_UPDATEPROPS();
432 return AL_TRUE;
434 case AL_MAX_DISTANCE:
435 CHECKVAL(*values >= 0.0f);
437 Source->MaxDistance = *values;
438 DO_UPDATEPROPS();
439 return AL_TRUE;
441 case AL_ROLLOFF_FACTOR:
442 CHECKVAL(*values >= 0.0f);
444 Source->RollOffFactor = *values;
445 DO_UPDATEPROPS();
446 return AL_TRUE;
448 case AL_REFERENCE_DISTANCE:
449 CHECKVAL(*values >= 0.0f);
451 Source->RefDistance = *values;
452 DO_UPDATEPROPS();
453 return AL_TRUE;
455 case AL_MIN_GAIN:
456 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
458 Source->MinGain = *values;
459 DO_UPDATEPROPS();
460 return AL_TRUE;
462 case AL_MAX_GAIN:
463 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
465 Source->MaxGain = *values;
466 DO_UPDATEPROPS();
467 return AL_TRUE;
469 case AL_CONE_OUTER_GAIN:
470 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
472 Source->OuterGain = *values;
473 DO_UPDATEPROPS();
474 return AL_TRUE;
476 case AL_CONE_OUTER_GAINHF:
477 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
479 Source->OuterGainHF = *values;
480 DO_UPDATEPROPS();
481 return AL_TRUE;
483 case AL_AIR_ABSORPTION_FACTOR:
484 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
486 Source->AirAbsorptionFactor = *values;
487 DO_UPDATEPROPS();
488 return AL_TRUE;
490 case AL_ROOM_ROLLOFF_FACTOR:
491 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
493 Source->RoomRolloffFactor = *values;
494 DO_UPDATEPROPS();
495 return AL_TRUE;
497 case AL_DOPPLER_FACTOR:
498 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
500 Source->DopplerFactor = *values;
501 DO_UPDATEPROPS();
502 return AL_TRUE;
504 case AL_SEC_OFFSET:
505 case AL_SAMPLE_OFFSET:
506 case AL_BYTE_OFFSET:
507 CHECKVAL(*values >= 0.0f);
509 Source->OffsetType = prop;
510 Source->Offset = *values;
512 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
513 !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire))
515 LockContext(Context);
516 WriteLock(&Source->queue_lock);
517 if(ApplyOffset(Source) == AL_FALSE)
519 WriteUnlock(&Source->queue_lock);
520 UnlockContext(Context);
521 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
523 WriteUnlock(&Source->queue_lock);
524 UnlockContext(Context);
526 return AL_TRUE;
528 case AL_SOURCE_RADIUS:
529 CHECKVAL(*values >= 0.0f && isfinite(*values));
531 Source->Radius = *values;
532 DO_UPDATEPROPS();
533 return AL_TRUE;
535 case AL_STEREO_ANGLES:
536 CHECKVAL(isfinite(values[0]) && isfinite(values[1]));
538 Source->StereoPan[0] = values[0];
539 Source->StereoPan[1] = values[1];
540 DO_UPDATEPROPS();
541 return AL_TRUE;
544 case AL_POSITION:
545 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
547 Source->Position[0] = values[0];
548 Source->Position[1] = values[1];
549 Source->Position[2] = values[2];
550 DO_UPDATEPROPS();
551 return AL_TRUE;
553 case AL_VELOCITY:
554 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
556 Source->Velocity[0] = values[0];
557 Source->Velocity[1] = values[1];
558 Source->Velocity[2] = values[2];
559 DO_UPDATEPROPS();
560 return AL_TRUE;
562 case AL_DIRECTION:
563 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
565 Source->Direction[0] = values[0];
566 Source->Direction[1] = values[1];
567 Source->Direction[2] = values[2];
568 DO_UPDATEPROPS();
569 return AL_TRUE;
571 case AL_ORIENTATION:
572 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
573 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
575 Source->Orientation[0][0] = values[0];
576 Source->Orientation[0][1] = values[1];
577 Source->Orientation[0][2] = values[2];
578 Source->Orientation[1][0] = values[3];
579 Source->Orientation[1][1] = values[4];
580 Source->Orientation[1][2] = values[5];
581 DO_UPDATEPROPS();
582 return AL_TRUE;
585 case AL_SOURCE_RELATIVE:
586 case AL_LOOPING:
587 case AL_SOURCE_STATE:
588 case AL_SOURCE_TYPE:
589 case AL_DISTANCE_MODEL:
590 case AL_DIRECT_FILTER_GAINHF_AUTO:
591 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
592 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
593 case AL_DIRECT_CHANNELS_SOFT:
594 ival = (ALint)values[0];
595 return SetSourceiv(Source, Context, prop, &ival);
597 case AL_BUFFERS_QUEUED:
598 case AL_BUFFERS_PROCESSED:
599 ival = (ALint)((ALuint)values[0]);
600 return SetSourceiv(Source, Context, prop, &ival);
602 case AL_BUFFER:
603 case AL_DIRECT_FILTER:
604 case AL_AUXILIARY_SEND_FILTER:
605 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
606 break;
609 ERR("Unexpected property: 0x%04x\n", prop);
610 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
613 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
615 ALCdevice *device = Context->Device;
616 ALbuffer *buffer = NULL;
617 ALfilter *filter = NULL;
618 ALeffectslot *slot = NULL;
619 ALbufferlistitem *oldlist;
620 ALbufferlistitem *newlist;
621 ALfloat fvals[6];
623 switch(prop)
625 case AL_SOURCE_STATE:
626 case AL_SOURCE_TYPE:
627 case AL_BUFFERS_QUEUED:
628 case AL_BUFFERS_PROCESSED:
629 case AL_BYTE_LENGTH_SOFT:
630 case AL_SAMPLE_LENGTH_SOFT:
631 case AL_SEC_LENGTH_SOFT:
632 /* Query only */
633 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
635 case AL_SOURCE_RELATIVE:
636 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
638 Source->HeadRelative = (ALboolean)*values;
639 DO_UPDATEPROPS();
640 return AL_TRUE;
642 case AL_LOOPING:
643 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
645 WriteLock(&Source->queue_lock);
646 ATOMIC_STORE(&Source->looping, *values);
647 WriteUnlock(&Source->queue_lock);
648 return AL_TRUE;
650 case AL_BUFFER:
651 LockBuffersRead(device);
652 if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
654 UnlockBuffersRead(device);
655 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
658 WriteLock(&Source->queue_lock);
659 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
661 WriteUnlock(&Source->queue_lock);
662 UnlockBuffersRead(device);
663 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
666 if(buffer != NULL)
668 /* Add the selected buffer to a one-item queue */
669 newlist = malloc(sizeof(ALbufferlistitem));
670 newlist->buffer = buffer;
671 newlist->next = NULL;
672 IncrementRef(&buffer->ref);
674 /* Source is now Static */
675 Source->SourceType = AL_STATIC;
677 ReadLock(&buffer->lock);
678 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
679 Source->SampleSize = BytesFromFmt(buffer->FmtType);
680 ReadUnlock(&buffer->lock);
682 else
684 /* Source is now Undetermined */
685 Source->SourceType = AL_UNDETERMINED;
686 newlist = NULL;
688 oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist);
689 ATOMIC_STORE(&Source->current_buffer, newlist);
690 WriteUnlock(&Source->queue_lock);
691 UnlockBuffersRead(device);
693 /* Delete all elements in the previous queue */
694 while(oldlist != NULL)
696 ALbufferlistitem *temp = oldlist;
697 oldlist = temp->next;
699 if(temp->buffer)
700 DecrementRef(&temp->buffer->ref);
701 free(temp);
703 return AL_TRUE;
705 case AL_SEC_OFFSET:
706 case AL_SAMPLE_OFFSET:
707 case AL_BYTE_OFFSET:
708 CHECKVAL(*values >= 0);
710 Source->OffsetType = prop;
711 Source->Offset = *values;
713 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
714 !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire))
716 LockContext(Context);
717 WriteLock(&Source->queue_lock);
718 if(ApplyOffset(Source) == AL_FALSE)
720 WriteUnlock(&Source->queue_lock);
721 UnlockContext(Context);
722 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
724 WriteUnlock(&Source->queue_lock);
725 UnlockContext(Context);
727 return AL_TRUE;
729 case AL_DIRECT_FILTER:
730 LockFiltersRead(device);
731 if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
733 UnlockFiltersRead(device);
734 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
737 if(!filter)
739 Source->Direct.Gain = 1.0f;
740 Source->Direct.GainHF = 1.0f;
741 Source->Direct.HFReference = LOWPASSFREQREF;
742 Source->Direct.GainLF = 1.0f;
743 Source->Direct.LFReference = HIGHPASSFREQREF;
745 else
747 Source->Direct.Gain = filter->Gain;
748 Source->Direct.GainHF = filter->GainHF;
749 Source->Direct.HFReference = filter->HFReference;
750 Source->Direct.GainLF = filter->GainLF;
751 Source->Direct.LFReference = filter->LFReference;
753 UnlockFiltersRead(device);
754 DO_UPDATEPROPS();
755 return AL_TRUE;
757 case AL_DIRECT_FILTER_GAINHF_AUTO:
758 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
760 Source->DryGainHFAuto = *values;
761 DO_UPDATEPROPS();
762 return AL_TRUE;
764 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
765 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
767 Source->WetGainAuto = *values;
768 DO_UPDATEPROPS();
769 return AL_TRUE;
771 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
772 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
774 Source->WetGainHFAuto = *values;
775 DO_UPDATEPROPS();
776 return AL_TRUE;
778 case AL_DIRECT_CHANNELS_SOFT:
779 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
781 Source->DirectChannels = *values;
782 DO_UPDATEPROPS();
783 return AL_TRUE;
785 case AL_DISTANCE_MODEL:
786 CHECKVAL(*values == AL_NONE ||
787 *values == AL_INVERSE_DISTANCE ||
788 *values == AL_INVERSE_DISTANCE_CLAMPED ||
789 *values == AL_LINEAR_DISTANCE ||
790 *values == AL_LINEAR_DISTANCE_CLAMPED ||
791 *values == AL_EXPONENT_DISTANCE ||
792 *values == AL_EXPONENT_DISTANCE_CLAMPED);
794 Source->DistanceModel = *values;
795 if(Context->SourceDistanceModel)
796 DO_UPDATEPROPS();
797 return AL_TRUE;
800 case AL_AUXILIARY_SEND_FILTER:
801 LockEffectSlotsRead(Context);
802 LockFiltersRead(device);
803 if(!((ALuint)values[1] < device->NumAuxSends &&
804 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
805 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
807 UnlockFiltersRead(device);
808 UnlockEffectSlotsRead(Context);
809 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
812 if(!filter)
814 /* Disable filter */
815 Source->Send[values[1]].Gain = 1.0f;
816 Source->Send[values[1]].GainHF = 1.0f;
817 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
818 Source->Send[values[1]].GainLF = 1.0f;
819 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
821 else
823 Source->Send[values[1]].Gain = filter->Gain;
824 Source->Send[values[1]].GainHF = filter->GainHF;
825 Source->Send[values[1]].HFReference = filter->HFReference;
826 Source->Send[values[1]].GainLF = filter->GainLF;
827 Source->Send[values[1]].LFReference = filter->LFReference;
829 UnlockFiltersRead(device);
831 if(slot != Source->Send[values[1]].Slot &&
832 (Source->state == AL_PLAYING || Source->state == AL_PAUSED))
834 /* Add refcount on the new slot, and release the previous slot */
835 if(slot) IncrementRef(&slot->ref);
836 if(Source->Send[values[1]].Slot)
837 DecrementRef(&Source->Send[values[1]].Slot->ref);
838 Source->Send[values[1]].Slot = slot;
840 /* We must force an update if the auxiliary slot changed on a
841 * playing source, in case the slot is about to be deleted.
843 UpdateSourceProps(Source, device->NumAuxSends, Context);
845 else
847 if(slot) IncrementRef(&slot->ref);
848 if(Source->Send[values[1]].Slot)
849 DecrementRef(&Source->Send[values[1]].Slot->ref);
850 Source->Send[values[1]].Slot = slot;
851 DO_UPDATEPROPS();
853 UnlockEffectSlotsRead(Context);
855 return AL_TRUE;
858 /* 1x float */
859 case AL_CONE_INNER_ANGLE:
860 case AL_CONE_OUTER_ANGLE:
861 case AL_PITCH:
862 case AL_GAIN:
863 case AL_MIN_GAIN:
864 case AL_MAX_GAIN:
865 case AL_REFERENCE_DISTANCE:
866 case AL_ROLLOFF_FACTOR:
867 case AL_CONE_OUTER_GAIN:
868 case AL_MAX_DISTANCE:
869 case AL_DOPPLER_FACTOR:
870 case AL_CONE_OUTER_GAINHF:
871 case AL_AIR_ABSORPTION_FACTOR:
872 case AL_ROOM_ROLLOFF_FACTOR:
873 case AL_SOURCE_RADIUS:
874 fvals[0] = (ALfloat)*values;
875 return SetSourcefv(Source, Context, (int)prop, fvals);
877 /* 3x float */
878 case AL_POSITION:
879 case AL_VELOCITY:
880 case AL_DIRECTION:
881 fvals[0] = (ALfloat)values[0];
882 fvals[1] = (ALfloat)values[1];
883 fvals[2] = (ALfloat)values[2];
884 return SetSourcefv(Source, Context, (int)prop, fvals);
886 /* 6x float */
887 case AL_ORIENTATION:
888 fvals[0] = (ALfloat)values[0];
889 fvals[1] = (ALfloat)values[1];
890 fvals[2] = (ALfloat)values[2];
891 fvals[3] = (ALfloat)values[3];
892 fvals[4] = (ALfloat)values[4];
893 fvals[5] = (ALfloat)values[5];
894 return SetSourcefv(Source, Context, (int)prop, fvals);
896 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
897 case AL_SEC_OFFSET_LATENCY_SOFT:
898 case AL_STEREO_ANGLES:
899 break;
902 ERR("Unexpected property: 0x%04x\n", prop);
903 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
906 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
908 ALfloat fvals[6];
909 ALint ivals[3];
911 switch(prop)
913 case AL_SOURCE_TYPE:
914 case AL_BUFFERS_QUEUED:
915 case AL_BUFFERS_PROCESSED:
916 case AL_SOURCE_STATE:
917 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
918 case AL_BYTE_LENGTH_SOFT:
919 case AL_SAMPLE_LENGTH_SOFT:
920 case AL_SEC_LENGTH_SOFT:
921 /* Query only */
922 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
925 /* 1x int */
926 case AL_SOURCE_RELATIVE:
927 case AL_LOOPING:
928 case AL_SEC_OFFSET:
929 case AL_SAMPLE_OFFSET:
930 case AL_BYTE_OFFSET:
931 case AL_DIRECT_FILTER_GAINHF_AUTO:
932 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
933 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
934 case AL_DIRECT_CHANNELS_SOFT:
935 case AL_DISTANCE_MODEL:
936 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
938 ivals[0] = (ALint)*values;
939 return SetSourceiv(Source, Context, (int)prop, ivals);
941 /* 1x uint */
942 case AL_BUFFER:
943 case AL_DIRECT_FILTER:
944 CHECKVAL(*values <= UINT_MAX && *values >= 0);
946 ivals[0] = (ALuint)*values;
947 return SetSourceiv(Source, Context, (int)prop, ivals);
949 /* 3x uint */
950 case AL_AUXILIARY_SEND_FILTER:
951 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
952 values[1] <= UINT_MAX && values[1] >= 0 &&
953 values[2] <= UINT_MAX && values[2] >= 0);
955 ivals[0] = (ALuint)values[0];
956 ivals[1] = (ALuint)values[1];
957 ivals[2] = (ALuint)values[2];
958 return SetSourceiv(Source, Context, (int)prop, ivals);
960 /* 1x float */
961 case AL_CONE_INNER_ANGLE:
962 case AL_CONE_OUTER_ANGLE:
963 case AL_PITCH:
964 case AL_GAIN:
965 case AL_MIN_GAIN:
966 case AL_MAX_GAIN:
967 case AL_REFERENCE_DISTANCE:
968 case AL_ROLLOFF_FACTOR:
969 case AL_CONE_OUTER_GAIN:
970 case AL_MAX_DISTANCE:
971 case AL_DOPPLER_FACTOR:
972 case AL_CONE_OUTER_GAINHF:
973 case AL_AIR_ABSORPTION_FACTOR:
974 case AL_ROOM_ROLLOFF_FACTOR:
975 case AL_SOURCE_RADIUS:
976 fvals[0] = (ALfloat)*values;
977 return SetSourcefv(Source, Context, (int)prop, fvals);
979 /* 3x float */
980 case AL_POSITION:
981 case AL_VELOCITY:
982 case AL_DIRECTION:
983 fvals[0] = (ALfloat)values[0];
984 fvals[1] = (ALfloat)values[1];
985 fvals[2] = (ALfloat)values[2];
986 return SetSourcefv(Source, Context, (int)prop, fvals);
988 /* 6x float */
989 case AL_ORIENTATION:
990 fvals[0] = (ALfloat)values[0];
991 fvals[1] = (ALfloat)values[1];
992 fvals[2] = (ALfloat)values[2];
993 fvals[3] = (ALfloat)values[3];
994 fvals[4] = (ALfloat)values[4];
995 fvals[5] = (ALfloat)values[5];
996 return SetSourcefv(Source, Context, (int)prop, fvals);
998 case AL_SEC_OFFSET_LATENCY_SOFT:
999 case AL_STEREO_ANGLES:
1000 break;
1003 ERR("Unexpected property: 0x%04x\n", prop);
1004 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1007 #undef CHECKVAL
1010 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
1012 ALCdevice *device = Context->Device;
1013 ALbufferlistitem *BufferList;
1014 ClockLatency clocktime;
1015 ALuint64 srcclock;
1016 ALint ivals[3];
1017 ALboolean err;
1019 switch(prop)
1021 case AL_GAIN:
1022 *values = Source->Gain;
1023 return AL_TRUE;
1025 case AL_PITCH:
1026 *values = Source->Pitch;
1027 return AL_TRUE;
1029 case AL_MAX_DISTANCE:
1030 *values = Source->MaxDistance;
1031 return AL_TRUE;
1033 case AL_ROLLOFF_FACTOR:
1034 *values = Source->RollOffFactor;
1035 return AL_TRUE;
1037 case AL_REFERENCE_DISTANCE:
1038 *values = Source->RefDistance;
1039 return AL_TRUE;
1041 case AL_CONE_INNER_ANGLE:
1042 *values = Source->InnerAngle;
1043 return AL_TRUE;
1045 case AL_CONE_OUTER_ANGLE:
1046 *values = Source->OuterAngle;
1047 return AL_TRUE;
1049 case AL_MIN_GAIN:
1050 *values = Source->MinGain;
1051 return AL_TRUE;
1053 case AL_MAX_GAIN:
1054 *values = Source->MaxGain;
1055 return AL_TRUE;
1057 case AL_CONE_OUTER_GAIN:
1058 *values = Source->OuterGain;
1059 return AL_TRUE;
1061 case AL_SEC_OFFSET:
1062 case AL_SAMPLE_OFFSET:
1063 case AL_BYTE_OFFSET:
1064 *values = GetSourceOffset(Source, prop, device);
1065 return AL_TRUE;
1067 case AL_CONE_OUTER_GAINHF:
1068 *values = Source->OuterGainHF;
1069 return AL_TRUE;
1071 case AL_AIR_ABSORPTION_FACTOR:
1072 *values = Source->AirAbsorptionFactor;
1073 return AL_TRUE;
1075 case AL_ROOM_ROLLOFF_FACTOR:
1076 *values = Source->RoomRolloffFactor;
1077 return AL_TRUE;
1079 case AL_DOPPLER_FACTOR:
1080 *values = Source->DopplerFactor;
1081 return AL_TRUE;
1083 case AL_SEC_LENGTH_SOFT:
1084 ReadLock(&Source->queue_lock);
1085 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1086 *values = 0;
1087 else
1089 ALint length = 0;
1090 ALsizei freq = 1;
1091 do {
1092 ALbuffer *buffer = BufferList->buffer;
1093 if(buffer && buffer->SampleLen > 0)
1095 freq = buffer->Frequency;
1096 length += buffer->SampleLen;
1098 } while((BufferList=BufferList->next) != NULL);
1099 *values = (ALdouble)length / (ALdouble)freq;
1101 ReadUnlock(&Source->queue_lock);
1102 return AL_TRUE;
1104 case AL_SOURCE_RADIUS:
1105 *values = Source->Radius;
1106 return AL_TRUE;
1108 case AL_STEREO_ANGLES:
1109 values[0] = Source->StereoPan[0];
1110 values[1] = Source->StereoPan[1];
1111 return AL_TRUE;
1113 case AL_SEC_OFFSET_LATENCY_SOFT:
1114 /* Get the source offset with the clock time first. Then get the
1115 * clock time with the device latency. Order is important.
1117 values[0] = GetSourceSecOffset(Source, device, &srcclock);
1118 clocktime = V0(device->Backend,getClockLatency)();
1119 if(srcclock == (ALuint64)clocktime.ClockTime)
1120 values[1] = (ALdouble)clocktime.Latency / 1000000000.0;
1121 else
1123 /* If the clock time incremented, reduce the latency by that
1124 * much since it's that much closer to the source offset it got
1125 * earlier.
1127 ALuint64 diff = clocktime.ClockTime - srcclock;
1128 values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) /
1129 1000000000.0;
1131 return AL_TRUE;
1133 case AL_POSITION:
1134 values[0] = Source->Position[0];
1135 values[1] = Source->Position[1];
1136 values[2] = Source->Position[2];
1137 return AL_TRUE;
1139 case AL_VELOCITY:
1140 values[0] = Source->Velocity[0];
1141 values[1] = Source->Velocity[1];
1142 values[2] = Source->Velocity[2];
1143 return AL_TRUE;
1145 case AL_DIRECTION:
1146 values[0] = Source->Direction[0];
1147 values[1] = Source->Direction[1];
1148 values[2] = Source->Direction[2];
1149 return AL_TRUE;
1151 case AL_ORIENTATION:
1152 values[0] = Source->Orientation[0][0];
1153 values[1] = Source->Orientation[0][1];
1154 values[2] = Source->Orientation[0][2];
1155 values[3] = Source->Orientation[1][0];
1156 values[4] = Source->Orientation[1][1];
1157 values[5] = Source->Orientation[1][2];
1158 return AL_TRUE;
1160 /* 1x int */
1161 case AL_SOURCE_RELATIVE:
1162 case AL_LOOPING:
1163 case AL_SOURCE_STATE:
1164 case AL_BUFFERS_QUEUED:
1165 case AL_BUFFERS_PROCESSED:
1166 case AL_SOURCE_TYPE:
1167 case AL_DIRECT_FILTER_GAINHF_AUTO:
1168 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1169 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1170 case AL_DIRECT_CHANNELS_SOFT:
1171 case AL_BYTE_LENGTH_SOFT:
1172 case AL_SAMPLE_LENGTH_SOFT:
1173 case AL_DISTANCE_MODEL:
1174 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1175 *values = (ALdouble)ivals[0];
1176 return err;
1178 case AL_BUFFER:
1179 case AL_DIRECT_FILTER:
1180 case AL_AUXILIARY_SEND_FILTER:
1181 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1182 break;
1185 ERR("Unexpected property: 0x%04x\n", prop);
1186 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1189 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1191 ALbufferlistitem *BufferList;
1192 ALdouble dvals[6];
1193 ALboolean err;
1195 switch(prop)
1197 case AL_SOURCE_RELATIVE:
1198 *values = Source->HeadRelative;
1199 return AL_TRUE;
1201 case AL_LOOPING:
1202 *values = ATOMIC_LOAD(&Source->looping);
1203 return AL_TRUE;
1205 case AL_BUFFER:
1206 ReadLock(&Source->queue_lock);
1207 BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) :
1208 ATOMIC_LOAD(&Source->current_buffer);
1209 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1210 ReadUnlock(&Source->queue_lock);
1211 return AL_TRUE;
1213 case AL_SOURCE_STATE:
1214 *values = Source->state;
1215 return AL_TRUE;
1217 case AL_BYTE_LENGTH_SOFT:
1218 ReadLock(&Source->queue_lock);
1219 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1220 *values = 0;
1221 else
1223 ALint length = 0;
1224 do {
1225 ALbuffer *buffer = BufferList->buffer;
1226 if(buffer && buffer->SampleLen > 0)
1228 ALuint byte_align, sample_align;
1229 if(buffer->OriginalType == UserFmtIMA4)
1231 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1232 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1233 sample_align = buffer->OriginalAlign;
1235 else if(buffer->OriginalType == UserFmtMSADPCM)
1237 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1238 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1239 sample_align = buffer->OriginalAlign;
1241 else
1243 ALsizei align = buffer->OriginalAlign;
1244 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1245 sample_align = buffer->OriginalAlign;
1248 length += buffer->SampleLen / sample_align * byte_align;
1250 } while((BufferList=BufferList->next) != NULL);
1251 *values = length;
1253 ReadUnlock(&Source->queue_lock);
1254 return AL_TRUE;
1256 case AL_SAMPLE_LENGTH_SOFT:
1257 ReadLock(&Source->queue_lock);
1258 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1259 *values = 0;
1260 else
1262 ALint length = 0;
1263 do {
1264 ALbuffer *buffer = BufferList->buffer;
1265 if(buffer) length += buffer->SampleLen;
1266 } while((BufferList=BufferList->next) != NULL);
1267 *values = length;
1269 ReadUnlock(&Source->queue_lock);
1270 return AL_TRUE;
1272 case AL_BUFFERS_QUEUED:
1273 ReadLock(&Source->queue_lock);
1274 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1275 *values = 0;
1276 else
1278 ALsizei count = 0;
1279 do {
1280 ++count;
1281 } while((BufferList=BufferList->next) != NULL);
1282 *values = count;
1284 ReadUnlock(&Source->queue_lock);
1285 return AL_TRUE;
1287 case AL_BUFFERS_PROCESSED:
1288 ReadLock(&Source->queue_lock);
1289 if(ATOMIC_LOAD(&Source->looping) || Source->SourceType != AL_STREAMING)
1291 /* Buffers on a looping source are in a perpetual state of
1292 * PENDING, so don't report any as PROCESSED */
1293 *values = 0;
1295 else
1297 const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue);
1298 const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer);
1299 ALsizei played = 0;
1300 while(BufferList && BufferList != Current)
1302 played++;
1303 BufferList = BufferList->next;
1305 *values = played;
1307 ReadUnlock(&Source->queue_lock);
1308 return AL_TRUE;
1310 case AL_SOURCE_TYPE:
1311 *values = Source->SourceType;
1312 return AL_TRUE;
1314 case AL_DIRECT_FILTER_GAINHF_AUTO:
1315 *values = Source->DryGainHFAuto;
1316 return AL_TRUE;
1318 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1319 *values = Source->WetGainAuto;
1320 return AL_TRUE;
1322 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1323 *values = Source->WetGainHFAuto;
1324 return AL_TRUE;
1326 case AL_DIRECT_CHANNELS_SOFT:
1327 *values = Source->DirectChannels;
1328 return AL_TRUE;
1330 case AL_DISTANCE_MODEL:
1331 *values = Source->DistanceModel;
1332 return AL_TRUE;
1334 /* 1x float/double */
1335 case AL_CONE_INNER_ANGLE:
1336 case AL_CONE_OUTER_ANGLE:
1337 case AL_PITCH:
1338 case AL_GAIN:
1339 case AL_MIN_GAIN:
1340 case AL_MAX_GAIN:
1341 case AL_REFERENCE_DISTANCE:
1342 case AL_ROLLOFF_FACTOR:
1343 case AL_CONE_OUTER_GAIN:
1344 case AL_MAX_DISTANCE:
1345 case AL_SEC_OFFSET:
1346 case AL_SAMPLE_OFFSET:
1347 case AL_BYTE_OFFSET:
1348 case AL_DOPPLER_FACTOR:
1349 case AL_AIR_ABSORPTION_FACTOR:
1350 case AL_ROOM_ROLLOFF_FACTOR:
1351 case AL_CONE_OUTER_GAINHF:
1352 case AL_SEC_LENGTH_SOFT:
1353 case AL_SOURCE_RADIUS:
1354 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1355 *values = (ALint)dvals[0];
1356 return err;
1358 /* 3x float/double */
1359 case AL_POSITION:
1360 case AL_VELOCITY:
1361 case AL_DIRECTION:
1362 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1364 values[0] = (ALint)dvals[0];
1365 values[1] = (ALint)dvals[1];
1366 values[2] = (ALint)dvals[2];
1368 return err;
1370 /* 6x float/double */
1371 case AL_ORIENTATION:
1372 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1374 values[0] = (ALint)dvals[0];
1375 values[1] = (ALint)dvals[1];
1376 values[2] = (ALint)dvals[2];
1377 values[3] = (ALint)dvals[3];
1378 values[4] = (ALint)dvals[4];
1379 values[5] = (ALint)dvals[5];
1381 return err;
1383 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1384 break; /* i64 only */
1385 case AL_SEC_OFFSET_LATENCY_SOFT:
1386 break; /* Double only */
1387 case AL_STEREO_ANGLES:
1388 break; /* Float/double only */
1390 case AL_DIRECT_FILTER:
1391 case AL_AUXILIARY_SEND_FILTER:
1392 break; /* ??? */
1395 ERR("Unexpected property: 0x%04x\n", prop);
1396 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1399 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1401 ALCdevice *device = Context->Device;
1402 ClockLatency clocktime;
1403 ALuint64 srcclock;
1404 ALdouble dvals[6];
1405 ALint ivals[3];
1406 ALboolean err;
1408 switch(prop)
1410 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1411 /* Get the source offset with the clock time first. Then get the
1412 * clock time with the device latency. Order is important.
1414 values[0] = GetSourceSampleOffset(Source, device, &srcclock);
1415 clocktime = V0(device->Backend,getClockLatency)();
1416 if(srcclock == (ALuint64)clocktime.ClockTime)
1417 values[1] = clocktime.Latency;
1418 else
1420 /* If the clock time incremented, reduce the latency by that
1421 * much since it's that much closer to the source offset it got
1422 * earlier.
1424 ALuint64 diff = clocktime.ClockTime - srcclock;
1425 values[1] = clocktime.Latency - minu64(clocktime.Latency, diff);
1427 return AL_TRUE;
1429 /* 1x float/double */
1430 case AL_CONE_INNER_ANGLE:
1431 case AL_CONE_OUTER_ANGLE:
1432 case AL_PITCH:
1433 case AL_GAIN:
1434 case AL_MIN_GAIN:
1435 case AL_MAX_GAIN:
1436 case AL_REFERENCE_DISTANCE:
1437 case AL_ROLLOFF_FACTOR:
1438 case AL_CONE_OUTER_GAIN:
1439 case AL_MAX_DISTANCE:
1440 case AL_SEC_OFFSET:
1441 case AL_SAMPLE_OFFSET:
1442 case AL_BYTE_OFFSET:
1443 case AL_DOPPLER_FACTOR:
1444 case AL_AIR_ABSORPTION_FACTOR:
1445 case AL_ROOM_ROLLOFF_FACTOR:
1446 case AL_CONE_OUTER_GAINHF:
1447 case AL_SEC_LENGTH_SOFT:
1448 case AL_SOURCE_RADIUS:
1449 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1450 *values = (ALint64)dvals[0];
1451 return err;
1453 /* 3x float/double */
1454 case AL_POSITION:
1455 case AL_VELOCITY:
1456 case AL_DIRECTION:
1457 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1459 values[0] = (ALint64)dvals[0];
1460 values[1] = (ALint64)dvals[1];
1461 values[2] = (ALint64)dvals[2];
1463 return err;
1465 /* 6x float/double */
1466 case AL_ORIENTATION:
1467 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1469 values[0] = (ALint64)dvals[0];
1470 values[1] = (ALint64)dvals[1];
1471 values[2] = (ALint64)dvals[2];
1472 values[3] = (ALint64)dvals[3];
1473 values[4] = (ALint64)dvals[4];
1474 values[5] = (ALint64)dvals[5];
1476 return err;
1478 /* 1x int */
1479 case AL_SOURCE_RELATIVE:
1480 case AL_LOOPING:
1481 case AL_SOURCE_STATE:
1482 case AL_BUFFERS_QUEUED:
1483 case AL_BUFFERS_PROCESSED:
1484 case AL_BYTE_LENGTH_SOFT:
1485 case AL_SAMPLE_LENGTH_SOFT:
1486 case AL_SOURCE_TYPE:
1487 case AL_DIRECT_FILTER_GAINHF_AUTO:
1488 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1489 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1490 case AL_DIRECT_CHANNELS_SOFT:
1491 case AL_DISTANCE_MODEL:
1492 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1493 *values = ivals[0];
1494 return err;
1496 /* 1x uint */
1497 case AL_BUFFER:
1498 case AL_DIRECT_FILTER:
1499 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1500 *values = (ALuint)ivals[0];
1501 return err;
1503 /* 3x uint */
1504 case AL_AUXILIARY_SEND_FILTER:
1505 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1507 values[0] = (ALuint)ivals[0];
1508 values[1] = (ALuint)ivals[1];
1509 values[2] = (ALuint)ivals[2];
1511 return err;
1513 case AL_SEC_OFFSET_LATENCY_SOFT:
1514 break; /* Double only */
1515 case AL_STEREO_ANGLES:
1516 break; /* Float/double only */
1519 ERR("Unexpected property: 0x%04x\n", prop);
1520 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1524 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1526 ALCcontext *context;
1527 ALsizei cur = 0;
1528 ALenum err;
1530 context = GetContextRef();
1531 if(!context) return;
1533 if(!(n >= 0))
1534 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1535 for(cur = 0;cur < n;cur++)
1537 ALsource *source = al_calloc(16, sizeof(ALsource));
1538 if(!source)
1540 alDeleteSources(cur, sources);
1541 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1543 InitSourceParams(source);
1545 err = NewThunkEntry(&source->id);
1546 if(err == AL_NO_ERROR)
1547 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1548 if(err != AL_NO_ERROR)
1550 FreeThunkEntry(source->id);
1551 memset(source, 0, sizeof(ALsource));
1552 al_free(source);
1554 alDeleteSources(cur, sources);
1555 SET_ERROR_AND_GOTO(context, err, done);
1558 sources[cur] = source->id;
1561 done:
1562 ALCcontext_DecRef(context);
1566 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1568 ALCcontext *context;
1569 ALsource *Source;
1570 ALsizei i;
1572 context = GetContextRef();
1573 if(!context) return;
1575 LockSourcesWrite(context);
1576 if(!(n >= 0))
1577 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1579 /* Check that all Sources are valid */
1580 for(i = 0;i < n;i++)
1582 if(LookupSource(context, sources[i]) == NULL)
1583 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1585 for(i = 0;i < n;i++)
1587 ALvoice *voice, *voice_end;
1589 if((Source=RemoveSource(context, sources[i])) == NULL)
1590 continue;
1591 FreeThunkEntry(Source->id);
1593 LockContext(context);
1594 voice = context->Voices;
1595 voice_end = voice + context->VoiceCount;
1596 while(voice != voice_end)
1598 ALsource *old = Source;
1599 if(COMPARE_EXCHANGE(&voice->Source, &old, NULL))
1600 break;
1601 voice++;
1603 UnlockContext(context);
1605 DeinitSource(Source);
1607 memset(Source, 0, sizeof(*Source));
1608 al_free(Source);
1611 done:
1612 UnlockSourcesWrite(context);
1613 ALCcontext_DecRef(context);
1617 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1619 ALCcontext *context;
1620 ALboolean ret;
1622 context = GetContextRef();
1623 if(!context) return AL_FALSE;
1625 LockSourcesRead(context);
1626 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1627 UnlockSourcesRead(context);
1629 ALCcontext_DecRef(context);
1631 return ret;
1635 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1637 ALCcontext *Context;
1638 ALsource *Source;
1640 Context = GetContextRef();
1641 if(!Context) return;
1643 WriteLock(&Context->PropLock);
1644 LockSourcesRead(Context);
1645 if((Source=LookupSource(Context, source)) == NULL)
1646 alSetError(Context, AL_INVALID_NAME);
1647 else if(!(FloatValsByProp(param) == 1))
1648 alSetError(Context, AL_INVALID_ENUM);
1649 else
1650 SetSourcefv(Source, Context, param, &value);
1651 UnlockSourcesRead(Context);
1652 WriteUnlock(&Context->PropLock);
1654 ALCcontext_DecRef(Context);
1657 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1659 ALCcontext *Context;
1660 ALsource *Source;
1662 Context = GetContextRef();
1663 if(!Context) return;
1665 WriteLock(&Context->PropLock);
1666 LockSourcesRead(Context);
1667 if((Source=LookupSource(Context, source)) == NULL)
1668 alSetError(Context, AL_INVALID_NAME);
1669 else if(!(FloatValsByProp(param) == 3))
1670 alSetError(Context, AL_INVALID_ENUM);
1671 else
1673 ALfloat fvals[3] = { value1, value2, value3 };
1674 SetSourcefv(Source, Context, param, fvals);
1676 UnlockSourcesRead(Context);
1677 WriteUnlock(&Context->PropLock);
1679 ALCcontext_DecRef(Context);
1682 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1684 ALCcontext *Context;
1685 ALsource *Source;
1687 Context = GetContextRef();
1688 if(!Context) return;
1690 WriteLock(&Context->PropLock);
1691 LockSourcesRead(Context);
1692 if((Source=LookupSource(Context, source)) == NULL)
1693 alSetError(Context, AL_INVALID_NAME);
1694 else if(!values)
1695 alSetError(Context, AL_INVALID_VALUE);
1696 else if(!(FloatValsByProp(param) > 0))
1697 alSetError(Context, AL_INVALID_ENUM);
1698 else
1699 SetSourcefv(Source, Context, param, values);
1700 UnlockSourcesRead(Context);
1701 WriteUnlock(&Context->PropLock);
1703 ALCcontext_DecRef(Context);
1707 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1709 ALCcontext *Context;
1710 ALsource *Source;
1712 Context = GetContextRef();
1713 if(!Context) return;
1715 WriteLock(&Context->PropLock);
1716 LockSourcesRead(Context);
1717 if((Source=LookupSource(Context, source)) == NULL)
1718 alSetError(Context, AL_INVALID_NAME);
1719 else if(!(DoubleValsByProp(param) == 1))
1720 alSetError(Context, AL_INVALID_ENUM);
1721 else
1723 ALfloat fval = (ALfloat)value;
1724 SetSourcefv(Source, Context, param, &fval);
1726 UnlockSourcesRead(Context);
1727 WriteUnlock(&Context->PropLock);
1729 ALCcontext_DecRef(Context);
1732 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1734 ALCcontext *Context;
1735 ALsource *Source;
1737 Context = GetContextRef();
1738 if(!Context) return;
1740 WriteLock(&Context->PropLock);
1741 LockSourcesRead(Context);
1742 if((Source=LookupSource(Context, source)) == NULL)
1743 alSetError(Context, AL_INVALID_NAME);
1744 else if(!(DoubleValsByProp(param) == 3))
1745 alSetError(Context, AL_INVALID_ENUM);
1746 else
1748 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1749 SetSourcefv(Source, Context, param, fvals);
1751 UnlockSourcesRead(Context);
1752 WriteUnlock(&Context->PropLock);
1754 ALCcontext_DecRef(Context);
1757 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1759 ALCcontext *Context;
1760 ALsource *Source;
1761 ALint count;
1763 Context = GetContextRef();
1764 if(!Context) return;
1766 WriteLock(&Context->PropLock);
1767 LockSourcesRead(Context);
1768 if((Source=LookupSource(Context, source)) == NULL)
1769 alSetError(Context, AL_INVALID_NAME);
1770 else if(!values)
1771 alSetError(Context, AL_INVALID_VALUE);
1772 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1773 alSetError(Context, AL_INVALID_ENUM);
1774 else
1776 ALfloat fvals[6];
1777 ALint i;
1779 for(i = 0;i < count;i++)
1780 fvals[i] = (ALfloat)values[i];
1781 SetSourcefv(Source, Context, param, fvals);
1783 UnlockSourcesRead(Context);
1784 WriteUnlock(&Context->PropLock);
1786 ALCcontext_DecRef(Context);
1790 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1792 ALCcontext *Context;
1793 ALsource *Source;
1795 Context = GetContextRef();
1796 if(!Context) return;
1798 WriteLock(&Context->PropLock);
1799 LockSourcesRead(Context);
1800 if((Source=LookupSource(Context, source)) == NULL)
1801 alSetError(Context, AL_INVALID_NAME);
1802 else if(!(IntValsByProp(param) == 1))
1803 alSetError(Context, AL_INVALID_ENUM);
1804 else
1805 SetSourceiv(Source, Context, param, &value);
1806 UnlockSourcesRead(Context);
1807 WriteUnlock(&Context->PropLock);
1809 ALCcontext_DecRef(Context);
1812 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1814 ALCcontext *Context;
1815 ALsource *Source;
1817 Context = GetContextRef();
1818 if(!Context) return;
1820 WriteLock(&Context->PropLock);
1821 LockSourcesRead(Context);
1822 if((Source=LookupSource(Context, source)) == NULL)
1823 alSetError(Context, AL_INVALID_NAME);
1824 else if(!(IntValsByProp(param) == 3))
1825 alSetError(Context, AL_INVALID_ENUM);
1826 else
1828 ALint ivals[3] = { value1, value2, value3 };
1829 SetSourceiv(Source, Context, param, ivals);
1831 UnlockSourcesRead(Context);
1832 WriteUnlock(&Context->PropLock);
1834 ALCcontext_DecRef(Context);
1837 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1839 ALCcontext *Context;
1840 ALsource *Source;
1842 Context = GetContextRef();
1843 if(!Context) return;
1845 WriteLock(&Context->PropLock);
1846 LockSourcesRead(Context);
1847 if((Source=LookupSource(Context, source)) == NULL)
1848 alSetError(Context, AL_INVALID_NAME);
1849 else if(!values)
1850 alSetError(Context, AL_INVALID_VALUE);
1851 else if(!(IntValsByProp(param) > 0))
1852 alSetError(Context, AL_INVALID_ENUM);
1853 else
1854 SetSourceiv(Source, Context, param, values);
1855 UnlockSourcesRead(Context);
1856 WriteUnlock(&Context->PropLock);
1858 ALCcontext_DecRef(Context);
1862 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1864 ALCcontext *Context;
1865 ALsource *Source;
1867 Context = GetContextRef();
1868 if(!Context) return;
1870 WriteLock(&Context->PropLock);
1871 LockSourcesRead(Context);
1872 if((Source=LookupSource(Context, source)) == NULL)
1873 alSetError(Context, AL_INVALID_NAME);
1874 else if(!(Int64ValsByProp(param) == 1))
1875 alSetError(Context, AL_INVALID_ENUM);
1876 else
1877 SetSourcei64v(Source, Context, param, &value);
1878 UnlockSourcesRead(Context);
1879 WriteUnlock(&Context->PropLock);
1881 ALCcontext_DecRef(Context);
1884 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1886 ALCcontext *Context;
1887 ALsource *Source;
1889 Context = GetContextRef();
1890 if(!Context) return;
1892 WriteLock(&Context->PropLock);
1893 LockSourcesRead(Context);
1894 if((Source=LookupSource(Context, source)) == NULL)
1895 alSetError(Context, AL_INVALID_NAME);
1896 else if(!(Int64ValsByProp(param) == 3))
1897 alSetError(Context, AL_INVALID_ENUM);
1898 else
1900 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1901 SetSourcei64v(Source, Context, param, i64vals);
1903 UnlockSourcesRead(Context);
1904 WriteUnlock(&Context->PropLock);
1906 ALCcontext_DecRef(Context);
1909 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1911 ALCcontext *Context;
1912 ALsource *Source;
1914 Context = GetContextRef();
1915 if(!Context) return;
1917 WriteLock(&Context->PropLock);
1918 LockSourcesRead(Context);
1919 if((Source=LookupSource(Context, source)) == NULL)
1920 alSetError(Context, AL_INVALID_NAME);
1921 else if(!values)
1922 alSetError(Context, AL_INVALID_VALUE);
1923 else if(!(Int64ValsByProp(param) > 0))
1924 alSetError(Context, AL_INVALID_ENUM);
1925 else
1926 SetSourcei64v(Source, Context, param, values);
1927 UnlockSourcesRead(Context);
1928 WriteUnlock(&Context->PropLock);
1930 ALCcontext_DecRef(Context);
1934 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1936 ALCcontext *Context;
1937 ALsource *Source;
1939 Context = GetContextRef();
1940 if(!Context) return;
1942 ReadLock(&Context->PropLock);
1943 LockSourcesRead(Context);
1944 if((Source=LookupSource(Context, source)) == NULL)
1945 alSetError(Context, AL_INVALID_NAME);
1946 else if(!value)
1947 alSetError(Context, AL_INVALID_VALUE);
1948 else if(!(FloatValsByProp(param) == 1))
1949 alSetError(Context, AL_INVALID_ENUM);
1950 else
1952 ALdouble dval;
1953 if(GetSourcedv(Source, Context, param, &dval))
1954 *value = (ALfloat)dval;
1956 UnlockSourcesRead(Context);
1957 ReadUnlock(&Context->PropLock);
1959 ALCcontext_DecRef(Context);
1963 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1965 ALCcontext *Context;
1966 ALsource *Source;
1968 Context = GetContextRef();
1969 if(!Context) return;
1971 ReadLock(&Context->PropLock);
1972 LockSourcesRead(Context);
1973 if((Source=LookupSource(Context, source)) == NULL)
1974 alSetError(Context, AL_INVALID_NAME);
1975 else if(!(value1 && value2 && value3))
1976 alSetError(Context, AL_INVALID_VALUE);
1977 else if(!(FloatValsByProp(param) == 3))
1978 alSetError(Context, AL_INVALID_ENUM);
1979 else
1981 ALdouble dvals[3];
1982 if(GetSourcedv(Source, Context, param, dvals))
1984 *value1 = (ALfloat)dvals[0];
1985 *value2 = (ALfloat)dvals[1];
1986 *value3 = (ALfloat)dvals[2];
1989 UnlockSourcesRead(Context);
1990 ReadUnlock(&Context->PropLock);
1992 ALCcontext_DecRef(Context);
1996 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1998 ALCcontext *Context;
1999 ALsource *Source;
2000 ALint count;
2002 Context = GetContextRef();
2003 if(!Context) return;
2005 ReadLock(&Context->PropLock);
2006 LockSourcesRead(Context);
2007 if((Source=LookupSource(Context, source)) == NULL)
2008 alSetError(Context, AL_INVALID_NAME);
2009 else if(!values)
2010 alSetError(Context, AL_INVALID_VALUE);
2011 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
2012 alSetError(Context, AL_INVALID_ENUM);
2013 else
2015 ALdouble dvals[6];
2016 if(GetSourcedv(Source, Context, param, dvals))
2018 ALint i;
2019 for(i = 0;i < count;i++)
2020 values[i] = (ALfloat)dvals[i];
2023 UnlockSourcesRead(Context);
2024 ReadUnlock(&Context->PropLock);
2026 ALCcontext_DecRef(Context);
2030 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
2032 ALCcontext *Context;
2033 ALsource *Source;
2035 Context = GetContextRef();
2036 if(!Context) return;
2038 ReadLock(&Context->PropLock);
2039 LockSourcesRead(Context);
2040 if((Source=LookupSource(Context, source)) == NULL)
2041 alSetError(Context, AL_INVALID_NAME);
2042 else if(!value)
2043 alSetError(Context, AL_INVALID_VALUE);
2044 else if(!(DoubleValsByProp(param) == 1))
2045 alSetError(Context, AL_INVALID_ENUM);
2046 else
2047 GetSourcedv(Source, Context, param, value);
2048 UnlockSourcesRead(Context);
2049 ReadUnlock(&Context->PropLock);
2051 ALCcontext_DecRef(Context);
2054 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
2056 ALCcontext *Context;
2057 ALsource *Source;
2059 Context = GetContextRef();
2060 if(!Context) return;
2062 ReadLock(&Context->PropLock);
2063 LockSourcesRead(Context);
2064 if((Source=LookupSource(Context, source)) == NULL)
2065 alSetError(Context, AL_INVALID_NAME);
2066 else if(!(value1 && value2 && value3))
2067 alSetError(Context, AL_INVALID_VALUE);
2068 else if(!(DoubleValsByProp(param) == 3))
2069 alSetError(Context, AL_INVALID_ENUM);
2070 else
2072 ALdouble dvals[3];
2073 if(GetSourcedv(Source, Context, param, dvals))
2075 *value1 = dvals[0];
2076 *value2 = dvals[1];
2077 *value3 = dvals[2];
2080 UnlockSourcesRead(Context);
2081 ReadUnlock(&Context->PropLock);
2083 ALCcontext_DecRef(Context);
2086 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
2088 ALCcontext *Context;
2089 ALsource *Source;
2091 Context = GetContextRef();
2092 if(!Context) return;
2094 ReadLock(&Context->PropLock);
2095 LockSourcesRead(Context);
2096 if((Source=LookupSource(Context, source)) == NULL)
2097 alSetError(Context, AL_INVALID_NAME);
2098 else if(!values)
2099 alSetError(Context, AL_INVALID_VALUE);
2100 else if(!(DoubleValsByProp(param) > 0))
2101 alSetError(Context, AL_INVALID_ENUM);
2102 else
2103 GetSourcedv(Source, Context, param, values);
2104 UnlockSourcesRead(Context);
2105 ReadUnlock(&Context->PropLock);
2107 ALCcontext_DecRef(Context);
2111 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2113 ALCcontext *Context;
2114 ALsource *Source;
2116 Context = GetContextRef();
2117 if(!Context) return;
2119 ReadLock(&Context->PropLock);
2120 LockSourcesRead(Context);
2121 if((Source=LookupSource(Context, source)) == NULL)
2122 alSetError(Context, AL_INVALID_NAME);
2123 else if(!value)
2124 alSetError(Context, AL_INVALID_VALUE);
2125 else if(!(IntValsByProp(param) == 1))
2126 alSetError(Context, AL_INVALID_ENUM);
2127 else
2128 GetSourceiv(Source, Context, param, value);
2129 UnlockSourcesRead(Context);
2130 ReadUnlock(&Context->PropLock);
2132 ALCcontext_DecRef(Context);
2136 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2138 ALCcontext *Context;
2139 ALsource *Source;
2141 Context = GetContextRef();
2142 if(!Context) return;
2144 ReadLock(&Context->PropLock);
2145 LockSourcesRead(Context);
2146 if((Source=LookupSource(Context, source)) == NULL)
2147 alSetError(Context, AL_INVALID_NAME);
2148 else if(!(value1 && value2 && value3))
2149 alSetError(Context, AL_INVALID_VALUE);
2150 else if(!(IntValsByProp(param) == 3))
2151 alSetError(Context, AL_INVALID_ENUM);
2152 else
2154 ALint ivals[3];
2155 if(GetSourceiv(Source, Context, param, ivals))
2157 *value1 = ivals[0];
2158 *value2 = ivals[1];
2159 *value3 = ivals[2];
2162 UnlockSourcesRead(Context);
2163 ReadUnlock(&Context->PropLock);
2165 ALCcontext_DecRef(Context);
2169 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2171 ALCcontext *Context;
2172 ALsource *Source;
2174 Context = GetContextRef();
2175 if(!Context) return;
2177 ReadLock(&Context->PropLock);
2178 LockSourcesRead(Context);
2179 if((Source=LookupSource(Context, source)) == NULL)
2180 alSetError(Context, AL_INVALID_NAME);
2181 else if(!values)
2182 alSetError(Context, AL_INVALID_VALUE);
2183 else if(!(IntValsByProp(param) > 0))
2184 alSetError(Context, AL_INVALID_ENUM);
2185 else
2186 GetSourceiv(Source, Context, param, values);
2187 UnlockSourcesRead(Context);
2188 ReadUnlock(&Context->PropLock);
2190 ALCcontext_DecRef(Context);
2194 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2196 ALCcontext *Context;
2197 ALsource *Source;
2199 Context = GetContextRef();
2200 if(!Context) return;
2202 ReadLock(&Context->PropLock);
2203 LockSourcesRead(Context);
2204 if((Source=LookupSource(Context, source)) == NULL)
2205 alSetError(Context, AL_INVALID_NAME);
2206 else if(!value)
2207 alSetError(Context, AL_INVALID_VALUE);
2208 else if(!(Int64ValsByProp(param) == 1))
2209 alSetError(Context, AL_INVALID_ENUM);
2210 else
2211 GetSourcei64v(Source, Context, param, value);
2212 UnlockSourcesRead(Context);
2213 ReadUnlock(&Context->PropLock);
2215 ALCcontext_DecRef(Context);
2218 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2220 ALCcontext *Context;
2221 ALsource *Source;
2223 Context = GetContextRef();
2224 if(!Context) return;
2226 ReadLock(&Context->PropLock);
2227 LockSourcesRead(Context);
2228 if((Source=LookupSource(Context, source)) == NULL)
2229 alSetError(Context, AL_INVALID_NAME);
2230 else if(!(value1 && value2 && value3))
2231 alSetError(Context, AL_INVALID_VALUE);
2232 else if(!(Int64ValsByProp(param) == 3))
2233 alSetError(Context, AL_INVALID_ENUM);
2234 else
2236 ALint64 i64vals[3];
2237 if(GetSourcei64v(Source, Context, param, i64vals))
2239 *value1 = i64vals[0];
2240 *value2 = i64vals[1];
2241 *value3 = i64vals[2];
2244 UnlockSourcesRead(Context);
2245 ReadUnlock(&Context->PropLock);
2247 ALCcontext_DecRef(Context);
2250 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2252 ALCcontext *Context;
2253 ALsource *Source;
2255 Context = GetContextRef();
2256 if(!Context) return;
2258 ReadLock(&Context->PropLock);
2259 LockSourcesRead(Context);
2260 if((Source=LookupSource(Context, source)) == NULL)
2261 alSetError(Context, AL_INVALID_NAME);
2262 else if(!values)
2263 alSetError(Context, AL_INVALID_VALUE);
2264 else if(!(Int64ValsByProp(param) > 0))
2265 alSetError(Context, AL_INVALID_ENUM);
2266 else
2267 GetSourcei64v(Source, Context, param, values);
2268 UnlockSourcesRead(Context);
2269 ReadUnlock(&Context->PropLock);
2271 ALCcontext_DecRef(Context);
2275 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2277 alSourcePlayv(1, &source);
2279 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2281 ALCcontext *context;
2282 ALsource *source;
2283 ALsizei i;
2285 context = GetContextRef();
2286 if(!context) return;
2288 LockSourcesRead(context);
2289 if(!(n >= 0))
2290 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2291 for(i = 0;i < n;i++)
2293 if(!LookupSource(context, sources[i]))
2294 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2297 LockContext(context);
2298 while(n > context->MaxVoices-context->VoiceCount)
2300 ALvoice *temp = NULL;
2301 ALsizei newcount;
2303 newcount = context->MaxVoices << 1;
2304 if(newcount > 0)
2305 temp = al_malloc(16, newcount * sizeof(context->Voices[0]));
2306 if(!temp)
2308 UnlockContext(context);
2309 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2311 memcpy(temp, context->Voices, context->MaxVoices * sizeof(temp[0]));
2312 memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0]));
2314 al_free(context->Voices);
2315 context->Voices = temp;
2316 context->MaxVoices = newcount;
2319 for(i = 0;i < n;i++)
2321 source = LookupSource(context, sources[i]);
2322 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
2323 source->new_state = AL_PLAYING;
2324 else
2325 SetSourceState(source, context, AL_PLAYING);
2327 UnlockContext(context);
2329 done:
2330 UnlockSourcesRead(context);
2331 ALCcontext_DecRef(context);
2334 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2336 alSourcePausev(1, &source);
2338 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2340 ALCcontext *context;
2341 ALsource *source;
2342 ALsizei i;
2344 context = GetContextRef();
2345 if(!context) return;
2347 LockSourcesRead(context);
2348 if(!(n >= 0))
2349 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2350 for(i = 0;i < n;i++)
2352 if(!LookupSource(context, sources[i]))
2353 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2356 LockContext(context);
2357 for(i = 0;i < n;i++)
2359 source = LookupSource(context, sources[i]);
2360 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
2361 source->new_state = AL_PAUSED;
2362 else
2363 SetSourceState(source, context, AL_PAUSED);
2365 UnlockContext(context);
2367 done:
2368 UnlockSourcesRead(context);
2369 ALCcontext_DecRef(context);
2372 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2374 alSourceStopv(1, &source);
2376 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2378 ALCcontext *context;
2379 ALsource *source;
2380 ALsizei i;
2382 context = GetContextRef();
2383 if(!context) return;
2385 LockSourcesRead(context);
2386 if(!(n >= 0))
2387 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2388 for(i = 0;i < n;i++)
2390 if(!LookupSource(context, sources[i]))
2391 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2394 LockContext(context);
2395 for(i = 0;i < n;i++)
2397 source = LookupSource(context, sources[i]);
2398 source->new_state = AL_NONE;
2399 SetSourceState(source, context, AL_STOPPED);
2401 UnlockContext(context);
2403 done:
2404 UnlockSourcesRead(context);
2405 ALCcontext_DecRef(context);
2408 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2410 alSourceRewindv(1, &source);
2412 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2414 ALCcontext *context;
2415 ALsource *source;
2416 ALsizei i;
2418 context = GetContextRef();
2419 if(!context) return;
2421 LockSourcesRead(context);
2422 if(!(n >= 0))
2423 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2424 for(i = 0;i < n;i++)
2426 if(!LookupSource(context, sources[i]))
2427 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2430 LockContext(context);
2431 for(i = 0;i < n;i++)
2433 source = LookupSource(context, sources[i]);
2434 source->new_state = AL_NONE;
2435 SetSourceState(source, context, AL_INITIAL);
2437 UnlockContext(context);
2439 done:
2440 UnlockSourcesRead(context);
2441 ALCcontext_DecRef(context);
2445 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2447 ALCdevice *device;
2448 ALCcontext *context;
2449 ALsource *source;
2450 ALsizei i;
2451 ALbufferlistitem *BufferListStart;
2452 ALbufferlistitem *BufferList;
2453 ALbuffer *BufferFmt = NULL;
2455 if(nb == 0)
2456 return;
2458 context = GetContextRef();
2459 if(!context) return;
2461 device = context->Device;
2463 LockSourcesRead(context);
2464 if(!(nb >= 0))
2465 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2466 if((source=LookupSource(context, src)) == NULL)
2467 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2469 WriteLock(&source->queue_lock);
2470 if(source->SourceType == AL_STATIC)
2472 WriteUnlock(&source->queue_lock);
2473 /* Can't queue on a Static Source */
2474 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2477 /* Check for a valid Buffer, for its frequency and format */
2478 BufferList = ATOMIC_LOAD(&source->queue);
2479 while(BufferList)
2481 if(BufferList->buffer)
2483 BufferFmt = BufferList->buffer;
2484 break;
2486 BufferList = BufferList->next;
2489 LockBuffersRead(device);
2490 BufferListStart = NULL;
2491 BufferList = NULL;
2492 for(i = 0;i < nb;i++)
2494 ALbuffer *buffer = NULL;
2495 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2497 WriteUnlock(&source->queue_lock);
2498 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2501 if(!BufferListStart)
2503 BufferListStart = malloc(sizeof(ALbufferlistitem));
2504 BufferList = BufferListStart;
2506 else
2508 BufferList->next = malloc(sizeof(ALbufferlistitem));
2509 BufferList = BufferList->next;
2511 BufferList->buffer = buffer;
2512 BufferList->next = NULL;
2513 if(!buffer) continue;
2515 /* Hold a read lock on each buffer being queued while checking all
2516 * provided buffers. This is done so other threads don't see an extra
2517 * reference on some buffers if this operation ends up failing. */
2518 ReadLock(&buffer->lock);
2519 IncrementRef(&buffer->ref);
2521 if(BufferFmt == NULL)
2523 BufferFmt = buffer;
2525 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2526 source->SampleSize = BytesFromFmt(buffer->FmtType);
2528 else if(BufferFmt->Frequency != buffer->Frequency ||
2529 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2530 BufferFmt->OriginalType != buffer->OriginalType)
2532 WriteUnlock(&source->queue_lock);
2533 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2535 buffer_error:
2536 /* A buffer failed (invalid ID or format), so unlock and release
2537 * each buffer we had. */
2538 while(BufferListStart)
2540 ALbufferlistitem *next = BufferListStart->next;
2541 if((buffer=BufferListStart->buffer) != NULL)
2543 DecrementRef(&buffer->ref);
2544 ReadUnlock(&buffer->lock);
2546 free(BufferListStart);
2547 BufferListStart = next;
2549 UnlockBuffersRead(device);
2550 goto done;
2553 /* All buffers good, unlock them now. */
2554 BufferList = BufferListStart;
2555 while(BufferList != NULL)
2557 ALbuffer *buffer = BufferList->buffer;
2558 if(buffer) ReadUnlock(&buffer->lock);
2559 BufferList = BufferList->next;
2561 UnlockBuffersRead(device);
2563 /* Source is now streaming */
2564 source->SourceType = AL_STREAMING;
2566 BufferList = NULL;
2567 if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
2569 /* Queue head is not NULL, append to the end of the queue */
2570 while(BufferList->next != NULL)
2571 BufferList = BufferList->next;
2572 BufferList->next = BufferListStart;
2574 /* If the current buffer was at the end (NULL), put it at the start of the newly queued
2575 * buffers.
2577 BufferList = NULL;
2578 ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
2579 WriteUnlock(&source->queue_lock);
2581 done:
2582 UnlockSourcesRead(context);
2583 ALCcontext_DecRef(context);
2586 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2588 ALCcontext *context;
2589 ALsource *source;
2590 ALbufferlistitem *OldHead;
2591 ALbufferlistitem *OldTail;
2592 ALbufferlistitem *Current;
2593 ALsizei i = 0;
2595 if(nb == 0)
2596 return;
2598 context = GetContextRef();
2599 if(!context) return;
2601 LockSourcesRead(context);
2602 if(!(nb >= 0))
2603 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2605 if((source=LookupSource(context, src)) == NULL)
2606 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2608 WriteLock(&source->queue_lock);
2609 if(ATOMIC_LOAD(&source->looping) || source->SourceType != AL_STREAMING)
2611 WriteUnlock(&source->queue_lock);
2612 /* Trying to unqueue buffers on a looping or non-streaming source. */
2613 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2616 /* Find the new buffer queue head */
2617 OldTail = ATOMIC_LOAD(&source->queue);
2618 Current = ATOMIC_LOAD(&source->current_buffer);
2619 if(OldTail != Current)
2621 for(i = 1;i < nb;i++)
2623 ALbufferlistitem *next = OldTail->next;
2624 if(!next || next == Current) break;
2625 OldTail = next;
2628 if(i != nb)
2630 WriteUnlock(&source->queue_lock);
2631 /* Trying to unqueue pending buffers. */
2632 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2635 /* Swap it, and cut the new head from the old. */
2636 OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, OldTail->next);
2637 if(OldTail->next)
2639 ALCdevice *device = context->Device;
2640 uint count;
2642 /* Once the active mix (if any) is done, it's safe to cut the old tail
2643 * from the new head.
2645 if(((count=ReadRef(&device->MixCount))&1) != 0)
2647 while(count == ReadRef(&device->MixCount))
2648 althrd_yield();
2650 OldTail->next = NULL;
2652 WriteUnlock(&source->queue_lock);
2654 while(OldHead != NULL)
2656 ALbufferlistitem *next = OldHead->next;
2657 ALbuffer *buffer = OldHead->buffer;
2659 if(!buffer)
2660 *(buffers++) = 0;
2661 else
2663 *(buffers++) = buffer->id;
2664 DecrementRef(&buffer->ref);
2667 free(OldHead);
2668 OldHead = next;
2671 done:
2672 UnlockSourcesRead(context);
2673 ALCcontext_DecRef(context);
2677 static void InitSourceParams(ALsource *Source)
2679 ALuint i;
2681 RWLockInit(&Source->queue_lock);
2683 Source->InnerAngle = 360.0f;
2684 Source->OuterAngle = 360.0f;
2685 Source->Pitch = 1.0f;
2686 Source->Position[0] = 0.0f;
2687 Source->Position[1] = 0.0f;
2688 Source->Position[2] = 0.0f;
2689 Source->Velocity[0] = 0.0f;
2690 Source->Velocity[1] = 0.0f;
2691 Source->Velocity[2] = 0.0f;
2692 Source->Direction[0] = 0.0f;
2693 Source->Direction[1] = 0.0f;
2694 Source->Direction[2] = 0.0f;
2695 Source->Orientation[0][0] = 0.0f;
2696 Source->Orientation[0][1] = 0.0f;
2697 Source->Orientation[0][2] = -1.0f;
2698 Source->Orientation[1][0] = 0.0f;
2699 Source->Orientation[1][1] = 1.0f;
2700 Source->Orientation[1][2] = 0.0f;
2701 Source->RefDistance = 1.0f;
2702 Source->MaxDistance = FLT_MAX;
2703 Source->RollOffFactor = 1.0f;
2704 Source->Gain = 1.0f;
2705 Source->MinGain = 0.0f;
2706 Source->MaxGain = 1.0f;
2707 Source->OuterGain = 0.0f;
2708 Source->OuterGainHF = 1.0f;
2710 Source->DryGainHFAuto = AL_TRUE;
2711 Source->WetGainAuto = AL_TRUE;
2712 Source->WetGainHFAuto = AL_TRUE;
2713 Source->AirAbsorptionFactor = 0.0f;
2714 Source->RoomRolloffFactor = 0.0f;
2715 Source->DopplerFactor = 1.0f;
2716 Source->DirectChannels = AL_FALSE;
2718 Source->StereoPan[0] = DEG2RAD( 30.0f);
2719 Source->StereoPan[1] = DEG2RAD(-30.0f);
2721 Source->Radius = 0.0f;
2723 Source->DistanceModel = DefaultDistanceModel;
2725 Source->Direct.Gain = 1.0f;
2726 Source->Direct.GainHF = 1.0f;
2727 Source->Direct.HFReference = LOWPASSFREQREF;
2728 Source->Direct.GainLF = 1.0f;
2729 Source->Direct.LFReference = HIGHPASSFREQREF;
2730 for(i = 0;i < MAX_SENDS;i++)
2732 Source->Send[i].Gain = 1.0f;
2733 Source->Send[i].GainHF = 1.0f;
2734 Source->Send[i].HFReference = LOWPASSFREQREF;
2735 Source->Send[i].GainLF = 1.0f;
2736 Source->Send[i].LFReference = HIGHPASSFREQREF;
2739 Source->Offset = 0.0;
2740 Source->OffsetType = AL_NONE;
2741 Source->SourceType = AL_UNDETERMINED;
2742 Source->state = AL_INITIAL;
2743 Source->new_state = AL_NONE;
2745 ATOMIC_INIT(&Source->queue, NULL);
2746 ATOMIC_INIT(&Source->current_buffer, NULL);
2748 ATOMIC_INIT(&Source->position, 0);
2749 ATOMIC_INIT(&Source->position_fraction, 0);
2751 ATOMIC_INIT(&Source->looping, AL_FALSE);
2753 ATOMIC_INIT(&Source->Update, NULL);
2754 ATOMIC_INIT(&Source->FreeList, NULL);
2757 static void DeinitSource(ALsource *source)
2759 ALbufferlistitem *BufferList;
2760 struct ALsourceProps *props;
2761 size_t count = 0;
2762 size_t i;
2764 props = ATOMIC_LOAD(&source->Update);
2765 if(props) al_free(props);
2767 props = ATOMIC_LOAD(&source->FreeList, almemory_order_relaxed);
2768 while(props)
2770 struct ALsourceProps *next;
2771 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2772 al_free(props);
2773 props = next;
2774 ++count;
2776 /* This is excessively spammy if it traces every source destruction, so
2777 * just warn if it was unexpectedly large.
2779 if(count > 3)
2780 WARN("Freed "SZFMT" Source property objects\n", count);
2782 BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NULL);
2783 while(BufferList != NULL)
2785 ALbufferlistitem *next = BufferList->next;
2786 if(BufferList->buffer != NULL)
2787 DecrementRef(&BufferList->buffer->ref);
2788 free(BufferList);
2789 BufferList = next;
2792 for(i = 0;i < MAX_SENDS;++i)
2794 if(source->Send[i].Slot)
2795 DecrementRef(&source->Send[i].Slot->ref);
2796 source->Send[i].Slot = NULL;
2800 static void UpdateSourceProps(ALsource *source, ALuint num_sends, ALCcontext *context)
2802 struct ALsourceProps *props;
2803 size_t i;
2805 /* Get an unused property container, or allocate a new one as needed. */
2806 props = ATOMIC_LOAD(&source->FreeList, almemory_order_acquire);
2807 if(!props)
2808 props = al_calloc(16, sizeof(*props));
2809 else
2811 struct ALsourceProps *next;
2812 do {
2813 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2814 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*,
2815 &source->FreeList, &props, next, almemory_order_seq_cst,
2816 almemory_order_consume) == 0);
2819 /* Copy in current property values. */
2820 ATOMIC_STORE(&props->Pitch, source->Pitch, almemory_order_relaxed);
2821 ATOMIC_STORE(&props->Gain, source->Gain, almemory_order_relaxed);
2822 ATOMIC_STORE(&props->OuterGain, source->OuterGain, almemory_order_relaxed);
2823 ATOMIC_STORE(&props->MinGain, source->MinGain, almemory_order_relaxed);
2824 ATOMIC_STORE(&props->MaxGain, source->MaxGain, almemory_order_relaxed);
2825 ATOMIC_STORE(&props->InnerAngle, source->InnerAngle, almemory_order_relaxed);
2826 ATOMIC_STORE(&props->OuterAngle, source->OuterAngle, almemory_order_relaxed);
2827 ATOMIC_STORE(&props->RefDistance, source->RefDistance, almemory_order_relaxed);
2828 ATOMIC_STORE(&props->MaxDistance, source->MaxDistance, almemory_order_relaxed);
2829 ATOMIC_STORE(&props->RollOffFactor, source->RollOffFactor, almemory_order_relaxed);
2830 for(i = 0;i < 3;i++)
2831 ATOMIC_STORE(&props->Position[i], source->Position[i], almemory_order_relaxed);
2832 for(i = 0;i < 3;i++)
2833 ATOMIC_STORE(&props->Velocity[i], source->Velocity[i], almemory_order_relaxed);
2834 for(i = 0;i < 3;i++)
2835 ATOMIC_STORE(&props->Direction[i], source->Direction[i], almemory_order_relaxed);
2836 for(i = 0;i < 2;i++)
2838 size_t j;
2839 for(j = 0;j < 3;j++)
2840 ATOMIC_STORE(&props->Orientation[i][j], source->Orientation[i][j],
2841 almemory_order_relaxed);
2843 ATOMIC_STORE(&props->HeadRelative, source->HeadRelative, almemory_order_relaxed);
2844 ATOMIC_STORE(&props->DistanceModel,
2845 context->SourceDistanceModel ? source->DistanceModel : context->DistanceModel,
2846 almemory_order_relaxed
2848 ATOMIC_STORE(&props->DirectChannels, source->DirectChannels, almemory_order_relaxed);
2850 ATOMIC_STORE(&props->DryGainHFAuto, source->DryGainHFAuto, almemory_order_relaxed);
2851 ATOMIC_STORE(&props->WetGainAuto, source->WetGainAuto, almemory_order_relaxed);
2852 ATOMIC_STORE(&props->WetGainHFAuto, source->WetGainHFAuto, almemory_order_relaxed);
2853 ATOMIC_STORE(&props->OuterGainHF, source->OuterGainHF, almemory_order_relaxed);
2855 ATOMIC_STORE(&props->AirAbsorptionFactor, source->AirAbsorptionFactor, almemory_order_relaxed);
2856 ATOMIC_STORE(&props->RoomRolloffFactor, source->RoomRolloffFactor, almemory_order_relaxed);
2857 ATOMIC_STORE(&props->DopplerFactor, source->DopplerFactor, almemory_order_relaxed);
2859 ATOMIC_STORE(&props->StereoPan[0], source->StereoPan[0], almemory_order_relaxed);
2860 ATOMIC_STORE(&props->StereoPan[1], source->StereoPan[1], almemory_order_relaxed);
2862 ATOMIC_STORE(&props->Radius, source->Radius, almemory_order_relaxed);
2864 ATOMIC_STORE(&props->Direct.Gain, source->Direct.Gain, almemory_order_relaxed);
2865 ATOMIC_STORE(&props->Direct.GainHF, source->Direct.GainHF, almemory_order_relaxed);
2866 ATOMIC_STORE(&props->Direct.HFReference, source->Direct.HFReference, almemory_order_relaxed);
2867 ATOMIC_STORE(&props->Direct.GainLF, source->Direct.GainLF, almemory_order_relaxed);
2868 ATOMIC_STORE(&props->Direct.LFReference, source->Direct.LFReference, almemory_order_relaxed);
2870 for(i = 0;i < num_sends;i++)
2872 ATOMIC_STORE(&props->Send[i].Slot, source->Send[i].Slot, almemory_order_relaxed);
2873 ATOMIC_STORE(&props->Send[i].Gain, source->Send[i].Gain, almemory_order_relaxed);
2874 ATOMIC_STORE(&props->Send[i].GainHF, source->Send[i].GainHF, almemory_order_relaxed);
2875 ATOMIC_STORE(&props->Send[i].HFReference, source->Send[i].HFReference,
2876 almemory_order_relaxed);
2877 ATOMIC_STORE(&props->Send[i].GainLF, source->Send[i].GainLF, almemory_order_relaxed);
2878 ATOMIC_STORE(&props->Send[i].LFReference, source->Send[i].LFReference,
2879 almemory_order_relaxed);
2882 /* Set the new container for updating internal parameters. */
2883 props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, props, almemory_order_acq_rel);
2884 if(props)
2886 /* If there was an unused update container, put it back in the
2887 * freelist.
2889 struct ALsourceProps *first = ATOMIC_LOAD(&source->FreeList);
2890 do {
2891 ATOMIC_STORE(&props->next, first, almemory_order_relaxed);
2892 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*,
2893 &source->FreeList, &first, props) == 0);
2897 void UpdateAllSourceProps(ALCcontext *context)
2899 ALuint num_sends = context->Device->NumAuxSends;
2900 uint updates;
2901 ALsizei pos;
2903 /* Tell the mixer to stop applying updates, then wait for any active
2904 * updating to finish, before providing source updates.
2906 ATOMIC_STORE(&context->HoldUpdates, AL_TRUE);
2907 while(((updates=ReadRef(&context->UpdateCount))&1) != 0)
2908 althrd_yield();
2909 for(pos = 0;pos < context->VoiceCount;pos++)
2911 ALvoice *voice = &context->Voices[pos];
2912 ALsource *source = voice->Source;
2913 if(source != NULL && (source->state == AL_PLAYING ||
2914 source->state == AL_PAUSED))
2915 UpdateSourceProps(source, num_sends, context);
2917 /* Now with all updates declared, let the mixer continue applying them so
2918 * they all happen at once.
2920 ATOMIC_STORE(&context->HoldUpdates, AL_FALSE);
2924 /* SetSourceState
2926 * Sets the source's new play state given its current state.
2928 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2930 WriteLock(&Source->queue_lock);
2931 if(state == AL_PLAYING)
2933 ALCdevice *device = Context->Device;
2934 ALbufferlistitem *BufferList;
2935 ALboolean discontinuity;
2936 ALvoice *voice = NULL;
2937 ALsizei i;
2939 /* Check that there is a queue containing at least one valid, non zero
2940 * length Buffer. */
2941 BufferList = ATOMIC_LOAD(&Source->queue);
2942 while(BufferList)
2944 ALbuffer *buffer;
2945 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2946 break;
2947 BufferList = BufferList->next;
2950 if(Source->state != AL_PAUSED)
2952 Source->state = AL_PLAYING;
2953 ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed);
2954 ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed);
2955 ATOMIC_STORE(&Source->position_fraction, 0);
2956 discontinuity = AL_TRUE;
2958 else
2960 Source->state = AL_PLAYING;
2961 discontinuity = AL_FALSE;
2964 // Check if an Offset has been set
2965 if(Source->OffsetType != AL_NONE)
2967 ApplyOffset(Source);
2968 /* discontinuity = AL_TRUE;??? */
2971 /* If there's nothing to play, or device is disconnected, go right to
2972 * stopped */
2973 if(!BufferList || !device->Connected)
2974 goto do_stop;
2976 /* Make sure this source isn't already active, while looking for an
2977 * unused active source slot to put it in. */
2978 for(i = 0;i < Context->VoiceCount;i++)
2980 ALsource *old = Source;
2981 if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL))
2983 if(voice == NULL)
2985 voice = &Context->Voices[i];
2986 voice->Source = Source;
2988 break;
2990 old = NULL;
2991 if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source))
2992 voice = &Context->Voices[i];
2994 if(voice == NULL)
2996 voice = &Context->Voices[Context->VoiceCount++];
2997 voice->Source = Source;
3000 if(discontinuity)
3002 /* Clear previous samples if playback is discontinuous. */
3003 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
3005 /* Clear the stepping value so the mixer knows not to mix this
3006 * until the update gets applied.
3008 voice->Step = 0;
3011 voice->Moving = AL_FALSE;
3012 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
3014 ALsizei j;
3015 for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
3016 voice->Chan[i].Direct.Hrtf.State.History[j] = 0.0f;
3017 for(j = 0;j < HRIR_LENGTH;j++)
3019 voice->Chan[i].Direct.Hrtf.State.Values[j][0] = 0.0f;
3020 voice->Chan[i].Direct.Hrtf.State.Values[j][1] = 0.0f;
3024 UpdateSourceProps(Source, device->NumAuxSends, Context);
3026 else if(state == AL_PAUSED)
3028 if(Source->state == AL_PLAYING)
3029 Source->state = AL_PAUSED;
3031 else if(state == AL_STOPPED)
3033 do_stop:
3034 if(Source->state != AL_INITIAL)
3036 Source->state = AL_STOPPED;
3037 ATOMIC_STORE(&Source->current_buffer, NULL);
3039 Source->OffsetType = AL_NONE;
3040 Source->Offset = 0.0;
3042 else if(state == AL_INITIAL)
3044 if(Source->state != AL_INITIAL)
3046 Source->state = AL_INITIAL;
3047 ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue),
3048 almemory_order_relaxed);
3049 ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed);
3050 ATOMIC_STORE(&Source->position_fraction, 0);
3052 Source->OffsetType = AL_NONE;
3053 Source->Offset = 0.0;
3055 WriteUnlock(&Source->queue_lock);
3058 /* GetSourceSampleOffset
3060 * Gets the current read offset for the given Source, in 32.32 fixed-point
3061 * samples. The offset is relative to the start of the queue (not the start of
3062 * the current buffer).
3064 ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime)
3066 const ALbufferlistitem *BufferList;
3067 const ALbufferlistitem *Current;
3068 ALuint64 readPos;
3069 ALuint refcount;
3071 ReadLock(&Source->queue_lock);
3072 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
3074 ReadUnlock(&Source->queue_lock);
3075 do {
3076 while(((refcount=ReadRef(&device->MixCount))&1))
3077 althrd_yield();
3078 *clocktime = GetDeviceClockTime(device);
3079 } while(refcount != ReadRef(&device->MixCount));
3080 return 0;
3083 do {
3084 while(((refcount=ReadRef(&device->MixCount))&1))
3085 althrd_yield();
3086 *clocktime = GetDeviceClockTime(device);
3088 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3089 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3091 readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << 32;
3092 readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed) <<
3093 (32-FRACTIONBITS);
3094 } while(refcount != ReadRef(&device->MixCount));
3095 while(BufferList && BufferList != Current)
3097 if(BufferList->buffer)
3098 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
3099 BufferList = BufferList->next;
3102 ReadUnlock(&Source->queue_lock);
3103 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
3106 /* GetSourceSecOffset
3108 * Gets the current read offset for the given Source, in seconds. The offset is
3109 * relative to the start of the queue (not the start of the current buffer).
3111 static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime)
3113 const ALbufferlistitem *BufferList;
3114 const ALbufferlistitem *Current;
3115 const ALbuffer *Buffer = NULL;
3116 ALuint64 readPos;
3117 ALuint refcount;
3119 ReadLock(&Source->queue_lock);
3120 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
3122 ReadUnlock(&Source->queue_lock);
3123 do {
3124 while(((refcount=ReadRef(&device->MixCount))&1))
3125 althrd_yield();
3126 *clocktime = GetDeviceClockTime(device);
3127 } while(refcount != ReadRef(&device->MixCount));
3128 return 0.0;
3131 do {
3132 while(((refcount=ReadRef(&device->MixCount))&1))
3133 althrd_yield();
3134 *clocktime = GetDeviceClockTime(device);
3136 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3137 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3139 readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed)<<FRACTIONBITS;
3140 readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed);
3141 } while(refcount != ReadRef(&device->MixCount));
3142 while(BufferList && BufferList != Current)
3144 const ALbuffer *buffer = BufferList->buffer;
3145 if(buffer != NULL)
3147 if(!Buffer) Buffer = buffer;
3148 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
3150 BufferList = BufferList->next;
3153 while(BufferList && !Buffer)
3155 Buffer = BufferList->buffer;
3156 BufferList = BufferList->next;
3158 assert(Buffer != NULL);
3160 ReadUnlock(&Source->queue_lock);
3161 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
3164 /* GetSourceOffset
3166 * Gets the current read offset for the given Source, in the appropriate format
3167 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3168 * queue (not the start of the current buffer).
3170 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device)
3172 const ALbufferlistitem *BufferList;
3173 const ALbufferlistitem *Current;
3174 const ALbuffer *Buffer = NULL;
3175 ALboolean readFin = AL_FALSE;
3176 ALuint readPos, readPosFrac;
3177 ALuint totalBufferLen;
3178 ALdouble offset = 0.0;
3179 ALboolean looping;
3180 ALuint refcount;
3182 ReadLock(&Source->queue_lock);
3183 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
3185 ReadUnlock(&Source->queue_lock);
3186 return 0.0;
3189 totalBufferLen = 0;
3190 do {
3191 while(((refcount=ReadRef(&device->MixCount))&1))
3192 althrd_yield();
3193 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3194 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3196 readPos = ATOMIC_LOAD(&Source->position, almemory_order_relaxed);
3197 readPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed);
3199 looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed);
3200 } while(refcount != ReadRef(&device->MixCount));
3202 while(BufferList != NULL)
3204 const ALbuffer *buffer;
3205 readFin = readFin || (BufferList == Current);
3206 if((buffer=BufferList->buffer) != NULL)
3208 if(!Buffer) Buffer = buffer;
3209 totalBufferLen += buffer->SampleLen;
3210 if(!readFin) readPos += buffer->SampleLen;
3212 BufferList = BufferList->next;
3214 assert(Buffer != NULL);
3216 if(looping)
3217 readPos %= totalBufferLen;
3218 else
3220 /* Wrap back to 0 */
3221 if(readPos >= totalBufferLen)
3222 readPos = readPosFrac = 0;
3225 switch(name)
3227 case AL_SEC_OFFSET:
3228 offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
3229 break;
3231 case AL_SAMPLE_OFFSET:
3232 offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
3233 break;
3235 case AL_BYTE_OFFSET:
3236 if(Buffer->OriginalType == UserFmtIMA4)
3238 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3239 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3240 ALuint FrameBlockSize = Buffer->OriginalAlign;
3242 /* Round down to nearest ADPCM block */
3243 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3245 else if(Buffer->OriginalType == UserFmtMSADPCM)
3247 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3248 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3249 ALuint FrameBlockSize = Buffer->OriginalAlign;
3251 /* Round down to nearest ADPCM block */
3252 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3254 else
3256 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3257 offset = (ALdouble)(readPos * FrameSize);
3259 break;
3262 ReadUnlock(&Source->queue_lock);
3263 return offset;
3267 /* ApplyOffset
3269 * Apply the stored playback offset to the Source. This function will update
3270 * the number of buffers "played" given the stored offset.
3272 ALboolean ApplyOffset(ALsource *Source)
3274 ALbufferlistitem *BufferList;
3275 const ALbuffer *Buffer;
3276 ALuint bufferLen, totalBufferLen;
3277 ALuint offset=0, frac=0;
3279 /* Get sample frame offset */
3280 if(!GetSampleOffset(Source, &offset, &frac))
3281 return AL_FALSE;
3283 totalBufferLen = 0;
3284 BufferList = ATOMIC_LOAD(&Source->queue);
3285 while(BufferList && totalBufferLen <= offset)
3287 Buffer = BufferList->buffer;
3288 bufferLen = Buffer ? Buffer->SampleLen : 0;
3290 if(bufferLen > offset-totalBufferLen)
3292 /* Offset is in this buffer */
3293 ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed);
3295 ATOMIC_STORE(&Source->position, offset - totalBufferLen, almemory_order_relaxed);
3296 ATOMIC_STORE(&Source->position_fraction, frac);
3297 return AL_TRUE;
3300 totalBufferLen += bufferLen;
3302 BufferList = BufferList->next;
3305 /* Offset is out of range of the queue */
3306 return AL_FALSE;
3310 /* GetSampleOffset
3312 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3313 * or Second offset supplied by the application). This takes into account the
3314 * fact that the buffer format may have been modifed since.
3316 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
3318 const ALbuffer *Buffer = NULL;
3319 const ALbufferlistitem *BufferList;
3320 ALdouble dbloff, dblfrac;
3322 /* Find the first valid Buffer in the Queue */
3323 BufferList = ATOMIC_LOAD(&Source->queue);
3324 while(BufferList)
3326 if(BufferList->buffer)
3328 Buffer = BufferList->buffer;
3329 break;
3331 BufferList = BufferList->next;
3333 if(!Buffer)
3335 Source->OffsetType = AL_NONE;
3336 Source->Offset = 0.0;
3337 return AL_FALSE;
3340 switch(Source->OffsetType)
3342 case AL_BYTE_OFFSET:
3343 /* Determine the ByteOffset (and ensure it is block aligned) */
3344 *offset = (ALuint)Source->Offset;
3345 if(Buffer->OriginalType == UserFmtIMA4)
3347 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3348 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3349 *offset *= Buffer->OriginalAlign;
3351 else if(Buffer->OriginalType == UserFmtMSADPCM)
3353 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3354 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3355 *offset *= Buffer->OriginalAlign;
3357 else
3358 *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3359 *frac = 0;
3360 break;
3362 case AL_SAMPLE_OFFSET:
3363 dblfrac = modf(Source->Offset, &dbloff);
3364 *offset = (ALuint)mind(dbloff, UINT_MAX);
3365 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3366 break;
3368 case AL_SEC_OFFSET:
3369 dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
3370 *offset = (ALuint)mind(dbloff, UINT_MAX);
3371 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3372 break;
3374 Source->OffsetType = AL_NONE;
3375 Source->Offset = 0.0;
3377 return AL_TRUE;
3381 /* ReleaseALSources
3383 * Destroys all sources in the source map.
3385 ALvoid ReleaseALSources(ALCcontext *Context)
3387 ALsizei pos;
3388 for(pos = 0;pos < Context->SourceMap.size;pos++)
3390 ALsource *temp = Context->SourceMap.values[pos];
3391 Context->SourceMap.values[pos] = NULL;
3393 DeinitSource(temp);
3395 FreeThunkEntry(temp->id);
3396 memset(temp, 0, sizeof(*temp));
3397 al_free(temp);