Move the input channel array out of the DirectParams and SendParams
[openal-soft.git] / OpenAL32 / alSource.c
blob4a50d217f22bbe7a4ecaea19af3a58eda798266b
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 Source->Looping = (ALboolean)*values;
646 DO_UPDATEPROPS();
647 return AL_TRUE;
649 case AL_BUFFER:
650 LockBuffersRead(device);
651 if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL))
653 UnlockBuffersRead(device);
654 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
657 WriteLock(&Source->queue_lock);
658 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
660 WriteUnlock(&Source->queue_lock);
661 UnlockBuffersRead(device);
662 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
665 if(buffer != NULL)
667 /* Add the selected buffer to a one-item queue */
668 newlist = malloc(sizeof(ALbufferlistitem));
669 newlist->buffer = buffer;
670 newlist->next = NULL;
671 IncrementRef(&buffer->ref);
673 /* Source is now Static */
674 Source->SourceType = AL_STATIC;
676 ReadLock(&buffer->lock);
677 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
678 Source->SampleSize = BytesFromFmt(buffer->FmtType);
679 ReadUnlock(&buffer->lock);
681 else
683 /* Source is now Undetermined */
684 Source->SourceType = AL_UNDETERMINED;
685 newlist = NULL;
687 oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist);
688 ATOMIC_STORE(&Source->current_buffer, newlist);
689 WriteUnlock(&Source->queue_lock);
690 UnlockBuffersRead(device);
692 /* Delete all elements in the previous queue */
693 while(oldlist != NULL)
695 ALbufferlistitem *temp = oldlist;
696 oldlist = temp->next;
698 if(temp->buffer)
699 DecrementRef(&temp->buffer->ref);
700 free(temp);
702 return AL_TRUE;
704 case AL_SEC_OFFSET:
705 case AL_SAMPLE_OFFSET:
706 case AL_BYTE_OFFSET:
707 CHECKVAL(*values >= 0);
709 Source->OffsetType = prop;
710 Source->Offset = *values;
712 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
713 !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire))
715 LockContext(Context);
716 WriteLock(&Source->queue_lock);
717 if(ApplyOffset(Source) == AL_FALSE)
719 WriteUnlock(&Source->queue_lock);
720 UnlockContext(Context);
721 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
723 WriteUnlock(&Source->queue_lock);
724 UnlockContext(Context);
726 return AL_TRUE;
728 case AL_DIRECT_FILTER:
729 LockFiltersRead(device);
730 if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL))
732 UnlockFiltersRead(device);
733 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
736 if(!filter)
738 Source->Direct.Gain = 1.0f;
739 Source->Direct.GainHF = 1.0f;
740 Source->Direct.HFReference = LOWPASSFREQREF;
741 Source->Direct.GainLF = 1.0f;
742 Source->Direct.LFReference = HIGHPASSFREQREF;
744 else
746 Source->Direct.Gain = filter->Gain;
747 Source->Direct.GainHF = filter->GainHF;
748 Source->Direct.HFReference = filter->HFReference;
749 Source->Direct.GainLF = filter->GainLF;
750 Source->Direct.LFReference = filter->LFReference;
752 UnlockFiltersRead(device);
753 DO_UPDATEPROPS();
754 return AL_TRUE;
756 case AL_DIRECT_FILTER_GAINHF_AUTO:
757 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
759 Source->DryGainHFAuto = *values;
760 DO_UPDATEPROPS();
761 return AL_TRUE;
763 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
764 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
766 Source->WetGainAuto = *values;
767 DO_UPDATEPROPS();
768 return AL_TRUE;
770 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
771 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
773 Source->WetGainHFAuto = *values;
774 DO_UPDATEPROPS();
775 return AL_TRUE;
777 case AL_DIRECT_CHANNELS_SOFT:
778 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
780 Source->DirectChannels = *values;
781 DO_UPDATEPROPS();
782 return AL_TRUE;
784 case AL_DISTANCE_MODEL:
785 CHECKVAL(*values == AL_NONE ||
786 *values == AL_INVERSE_DISTANCE ||
787 *values == AL_INVERSE_DISTANCE_CLAMPED ||
788 *values == AL_LINEAR_DISTANCE ||
789 *values == AL_LINEAR_DISTANCE_CLAMPED ||
790 *values == AL_EXPONENT_DISTANCE ||
791 *values == AL_EXPONENT_DISTANCE_CLAMPED);
793 Source->DistanceModel = *values;
794 if(Context->SourceDistanceModel)
795 DO_UPDATEPROPS();
796 return AL_TRUE;
799 case AL_AUXILIARY_SEND_FILTER:
800 LockEffectSlotsRead(Context);
801 LockFiltersRead(device);
802 if(!((ALuint)values[1] < device->NumAuxSends &&
803 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
804 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
806 UnlockFiltersRead(device);
807 UnlockEffectSlotsRead(Context);
808 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
811 if(!filter)
813 /* Disable filter */
814 Source->Send[values[1]].Gain = 1.0f;
815 Source->Send[values[1]].GainHF = 1.0f;
816 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
817 Source->Send[values[1]].GainLF = 1.0f;
818 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
820 else
822 Source->Send[values[1]].Gain = filter->Gain;
823 Source->Send[values[1]].GainHF = filter->GainHF;
824 Source->Send[values[1]].HFReference = filter->HFReference;
825 Source->Send[values[1]].GainLF = filter->GainLF;
826 Source->Send[values[1]].LFReference = filter->LFReference;
828 UnlockFiltersRead(device);
830 if(slot != Source->Send[values[1]].Slot &&
831 (Source->state == AL_PLAYING || Source->state == AL_PAUSED))
833 /* Add refcount on the new slot, and release the previous slot */
834 if(slot) IncrementRef(&slot->ref);
835 if(Source->Send[values[1]].Slot)
836 DecrementRef(&Source->Send[values[1]].Slot->ref);
837 Source->Send[values[1]].Slot = slot;
839 /* We must force an update if the auxiliary slot changed on a
840 * playing source, in case the slot is about to be deleted.
842 UpdateSourceProps(Source, device->NumAuxSends, Context);
844 else
846 if(slot) IncrementRef(&slot->ref);
847 if(Source->Send[values[1]].Slot)
848 DecrementRef(&Source->Send[values[1]].Slot->ref);
849 Source->Send[values[1]].Slot = slot;
850 DO_UPDATEPROPS();
852 UnlockEffectSlotsRead(Context);
854 return AL_TRUE;
857 /* 1x float */
858 case AL_CONE_INNER_ANGLE:
859 case AL_CONE_OUTER_ANGLE:
860 case AL_PITCH:
861 case AL_GAIN:
862 case AL_MIN_GAIN:
863 case AL_MAX_GAIN:
864 case AL_REFERENCE_DISTANCE:
865 case AL_ROLLOFF_FACTOR:
866 case AL_CONE_OUTER_GAIN:
867 case AL_MAX_DISTANCE:
868 case AL_DOPPLER_FACTOR:
869 case AL_CONE_OUTER_GAINHF:
870 case AL_AIR_ABSORPTION_FACTOR:
871 case AL_ROOM_ROLLOFF_FACTOR:
872 case AL_SOURCE_RADIUS:
873 fvals[0] = (ALfloat)*values;
874 return SetSourcefv(Source, Context, (int)prop, fvals);
876 /* 3x float */
877 case AL_POSITION:
878 case AL_VELOCITY:
879 case AL_DIRECTION:
880 fvals[0] = (ALfloat)values[0];
881 fvals[1] = (ALfloat)values[1];
882 fvals[2] = (ALfloat)values[2];
883 return SetSourcefv(Source, Context, (int)prop, fvals);
885 /* 6x float */
886 case AL_ORIENTATION:
887 fvals[0] = (ALfloat)values[0];
888 fvals[1] = (ALfloat)values[1];
889 fvals[2] = (ALfloat)values[2];
890 fvals[3] = (ALfloat)values[3];
891 fvals[4] = (ALfloat)values[4];
892 fvals[5] = (ALfloat)values[5];
893 return SetSourcefv(Source, Context, (int)prop, fvals);
895 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
896 case AL_SEC_OFFSET_LATENCY_SOFT:
897 case AL_STEREO_ANGLES:
898 break;
901 ERR("Unexpected property: 0x%04x\n", prop);
902 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
905 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
907 ALfloat fvals[6];
908 ALint ivals[3];
910 switch(prop)
912 case AL_SOURCE_TYPE:
913 case AL_BUFFERS_QUEUED:
914 case AL_BUFFERS_PROCESSED:
915 case AL_SOURCE_STATE:
916 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
917 case AL_BYTE_LENGTH_SOFT:
918 case AL_SAMPLE_LENGTH_SOFT:
919 case AL_SEC_LENGTH_SOFT:
920 /* Query only */
921 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
924 /* 1x int */
925 case AL_SOURCE_RELATIVE:
926 case AL_LOOPING:
927 case AL_SEC_OFFSET:
928 case AL_SAMPLE_OFFSET:
929 case AL_BYTE_OFFSET:
930 case AL_DIRECT_FILTER_GAINHF_AUTO:
931 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
932 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
933 case AL_DIRECT_CHANNELS_SOFT:
934 case AL_DISTANCE_MODEL:
935 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
937 ivals[0] = (ALint)*values;
938 return SetSourceiv(Source, Context, (int)prop, ivals);
940 /* 1x uint */
941 case AL_BUFFER:
942 case AL_DIRECT_FILTER:
943 CHECKVAL(*values <= UINT_MAX && *values >= 0);
945 ivals[0] = (ALuint)*values;
946 return SetSourceiv(Source, Context, (int)prop, ivals);
948 /* 3x uint */
949 case AL_AUXILIARY_SEND_FILTER:
950 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
951 values[1] <= UINT_MAX && values[1] >= 0 &&
952 values[2] <= UINT_MAX && values[2] >= 0);
954 ivals[0] = (ALuint)values[0];
955 ivals[1] = (ALuint)values[1];
956 ivals[2] = (ALuint)values[2];
957 return SetSourceiv(Source, Context, (int)prop, ivals);
959 /* 1x float */
960 case AL_CONE_INNER_ANGLE:
961 case AL_CONE_OUTER_ANGLE:
962 case AL_PITCH:
963 case AL_GAIN:
964 case AL_MIN_GAIN:
965 case AL_MAX_GAIN:
966 case AL_REFERENCE_DISTANCE:
967 case AL_ROLLOFF_FACTOR:
968 case AL_CONE_OUTER_GAIN:
969 case AL_MAX_DISTANCE:
970 case AL_DOPPLER_FACTOR:
971 case AL_CONE_OUTER_GAINHF:
972 case AL_AIR_ABSORPTION_FACTOR:
973 case AL_ROOM_ROLLOFF_FACTOR:
974 case AL_SOURCE_RADIUS:
975 fvals[0] = (ALfloat)*values;
976 return SetSourcefv(Source, Context, (int)prop, fvals);
978 /* 3x float */
979 case AL_POSITION:
980 case AL_VELOCITY:
981 case AL_DIRECTION:
982 fvals[0] = (ALfloat)values[0];
983 fvals[1] = (ALfloat)values[1];
984 fvals[2] = (ALfloat)values[2];
985 return SetSourcefv(Source, Context, (int)prop, fvals);
987 /* 6x float */
988 case AL_ORIENTATION:
989 fvals[0] = (ALfloat)values[0];
990 fvals[1] = (ALfloat)values[1];
991 fvals[2] = (ALfloat)values[2];
992 fvals[3] = (ALfloat)values[3];
993 fvals[4] = (ALfloat)values[4];
994 fvals[5] = (ALfloat)values[5];
995 return SetSourcefv(Source, Context, (int)prop, fvals);
997 case AL_SEC_OFFSET_LATENCY_SOFT:
998 case AL_STEREO_ANGLES:
999 break;
1002 ERR("Unexpected property: 0x%04x\n", prop);
1003 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1006 #undef CHECKVAL
1009 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
1011 ALCdevice *device = Context->Device;
1012 ALbufferlistitem *BufferList;
1013 ClockLatency clocktime;
1014 ALuint64 srcclock;
1015 ALint ivals[3];
1016 ALboolean err;
1018 switch(prop)
1020 case AL_GAIN:
1021 *values = Source->Gain;
1022 return AL_TRUE;
1024 case AL_PITCH:
1025 *values = Source->Pitch;
1026 return AL_TRUE;
1028 case AL_MAX_DISTANCE:
1029 *values = Source->MaxDistance;
1030 return AL_TRUE;
1032 case AL_ROLLOFF_FACTOR:
1033 *values = Source->RollOffFactor;
1034 return AL_TRUE;
1036 case AL_REFERENCE_DISTANCE:
1037 *values = Source->RefDistance;
1038 return AL_TRUE;
1040 case AL_CONE_INNER_ANGLE:
1041 *values = Source->InnerAngle;
1042 return AL_TRUE;
1044 case AL_CONE_OUTER_ANGLE:
1045 *values = Source->OuterAngle;
1046 return AL_TRUE;
1048 case AL_MIN_GAIN:
1049 *values = Source->MinGain;
1050 return AL_TRUE;
1052 case AL_MAX_GAIN:
1053 *values = Source->MaxGain;
1054 return AL_TRUE;
1056 case AL_CONE_OUTER_GAIN:
1057 *values = Source->OuterGain;
1058 return AL_TRUE;
1060 case AL_SEC_OFFSET:
1061 case AL_SAMPLE_OFFSET:
1062 case AL_BYTE_OFFSET:
1063 *values = GetSourceOffset(Source, prop, device);
1064 return AL_TRUE;
1066 case AL_CONE_OUTER_GAINHF:
1067 *values = Source->OuterGainHF;
1068 return AL_TRUE;
1070 case AL_AIR_ABSORPTION_FACTOR:
1071 *values = Source->AirAbsorptionFactor;
1072 return AL_TRUE;
1074 case AL_ROOM_ROLLOFF_FACTOR:
1075 *values = Source->RoomRolloffFactor;
1076 return AL_TRUE;
1078 case AL_DOPPLER_FACTOR:
1079 *values = Source->DopplerFactor;
1080 return AL_TRUE;
1082 case AL_SEC_LENGTH_SOFT:
1083 ReadLock(&Source->queue_lock);
1084 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1085 *values = 0;
1086 else
1088 ALint length = 0;
1089 ALsizei freq = 1;
1090 do {
1091 ALbuffer *buffer = BufferList->buffer;
1092 if(buffer && buffer->SampleLen > 0)
1094 freq = buffer->Frequency;
1095 length += buffer->SampleLen;
1097 } while((BufferList=BufferList->next) != NULL);
1098 *values = (ALdouble)length / (ALdouble)freq;
1100 ReadUnlock(&Source->queue_lock);
1101 return AL_TRUE;
1103 case AL_SOURCE_RADIUS:
1104 *values = Source->Radius;
1105 return AL_TRUE;
1107 case AL_STEREO_ANGLES:
1108 values[0] = Source->StereoPan[0];
1109 values[1] = Source->StereoPan[1];
1110 return AL_TRUE;
1112 case AL_SEC_OFFSET_LATENCY_SOFT:
1113 /* Get the source offset with the clock time first. Then get the
1114 * clock time with the device latency. Order is important.
1116 values[0] = GetSourceSecOffset(Source, device, &srcclock);
1117 clocktime = V0(device->Backend,getClockLatency)();
1118 if(srcclock == (ALuint64)clocktime.ClockTime)
1119 values[1] = (ALdouble)clocktime.Latency / 1000000000.0;
1120 else
1122 /* If the clock time incremented, reduce the latency by that
1123 * much since it's that much closer to the source offset it got
1124 * earlier.
1126 ALuint64 diff = clocktime.ClockTime - srcclock;
1127 values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) /
1128 1000000000.0;
1130 return AL_TRUE;
1132 case AL_POSITION:
1133 values[0] = Source->Position[0];
1134 values[1] = Source->Position[1];
1135 values[2] = Source->Position[2];
1136 return AL_TRUE;
1138 case AL_VELOCITY:
1139 values[0] = Source->Velocity[0];
1140 values[1] = Source->Velocity[1];
1141 values[2] = Source->Velocity[2];
1142 return AL_TRUE;
1144 case AL_DIRECTION:
1145 values[0] = Source->Direction[0];
1146 values[1] = Source->Direction[1];
1147 values[2] = Source->Direction[2];
1148 return AL_TRUE;
1150 case AL_ORIENTATION:
1151 values[0] = Source->Orientation[0][0];
1152 values[1] = Source->Orientation[0][1];
1153 values[2] = Source->Orientation[0][2];
1154 values[3] = Source->Orientation[1][0];
1155 values[4] = Source->Orientation[1][1];
1156 values[5] = Source->Orientation[1][2];
1157 return AL_TRUE;
1159 /* 1x int */
1160 case AL_SOURCE_RELATIVE:
1161 case AL_LOOPING:
1162 case AL_SOURCE_STATE:
1163 case AL_BUFFERS_QUEUED:
1164 case AL_BUFFERS_PROCESSED:
1165 case AL_SOURCE_TYPE:
1166 case AL_DIRECT_FILTER_GAINHF_AUTO:
1167 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1168 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1169 case AL_DIRECT_CHANNELS_SOFT:
1170 case AL_BYTE_LENGTH_SOFT:
1171 case AL_SAMPLE_LENGTH_SOFT:
1172 case AL_DISTANCE_MODEL:
1173 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1174 *values = (ALdouble)ivals[0];
1175 return err;
1177 case AL_BUFFER:
1178 case AL_DIRECT_FILTER:
1179 case AL_AUXILIARY_SEND_FILTER:
1180 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1181 break;
1184 ERR("Unexpected property: 0x%04x\n", prop);
1185 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1188 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1190 ALbufferlistitem *BufferList;
1191 ALdouble dvals[6];
1192 ALboolean err;
1194 switch(prop)
1196 case AL_SOURCE_RELATIVE:
1197 *values = Source->HeadRelative;
1198 return AL_TRUE;
1200 case AL_LOOPING:
1201 *values = Source->Looping;
1202 return AL_TRUE;
1204 case AL_BUFFER:
1205 ReadLock(&Source->queue_lock);
1206 BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) :
1207 ATOMIC_LOAD(&Source->current_buffer);
1208 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1209 ReadUnlock(&Source->queue_lock);
1210 return AL_TRUE;
1212 case AL_SOURCE_STATE:
1213 *values = Source->state;
1214 return AL_TRUE;
1216 case AL_BYTE_LENGTH_SOFT:
1217 ReadLock(&Source->queue_lock);
1218 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1219 *values = 0;
1220 else
1222 ALint length = 0;
1223 do {
1224 ALbuffer *buffer = BufferList->buffer;
1225 if(buffer && buffer->SampleLen > 0)
1227 ALuint byte_align, sample_align;
1228 if(buffer->OriginalType == UserFmtIMA4)
1230 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1231 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1232 sample_align = buffer->OriginalAlign;
1234 else if(buffer->OriginalType == UserFmtMSADPCM)
1236 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1237 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1238 sample_align = buffer->OriginalAlign;
1240 else
1242 ALsizei align = buffer->OriginalAlign;
1243 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1244 sample_align = buffer->OriginalAlign;
1247 length += buffer->SampleLen / sample_align * byte_align;
1249 } while((BufferList=BufferList->next) != NULL);
1250 *values = length;
1252 ReadUnlock(&Source->queue_lock);
1253 return AL_TRUE;
1255 case AL_SAMPLE_LENGTH_SOFT:
1256 ReadLock(&Source->queue_lock);
1257 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1258 *values = 0;
1259 else
1261 ALint length = 0;
1262 do {
1263 ALbuffer *buffer = BufferList->buffer;
1264 if(buffer) length += buffer->SampleLen;
1265 } while((BufferList=BufferList->next) != NULL);
1266 *values = length;
1268 ReadUnlock(&Source->queue_lock);
1269 return AL_TRUE;
1271 case AL_BUFFERS_QUEUED:
1272 ReadLock(&Source->queue_lock);
1273 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1274 *values = 0;
1275 else
1277 ALsizei count = 0;
1278 do {
1279 ++count;
1280 } while((BufferList=BufferList->next) != NULL);
1281 *values = count;
1283 ReadUnlock(&Source->queue_lock);
1284 return AL_TRUE;
1286 case AL_BUFFERS_PROCESSED:
1287 ReadLock(&Source->queue_lock);
1288 if(Source->Looping || Source->SourceType != AL_STREAMING)
1290 /* Buffers on a looping source are in a perpetual state of
1291 * PENDING, so don't report any as PROCESSED */
1292 *values = 0;
1294 else
1296 const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue);
1297 const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer);
1298 ALsizei played = 0;
1299 while(BufferList && BufferList != Current)
1301 played++;
1302 BufferList = BufferList->next;
1304 *values = played;
1306 ReadUnlock(&Source->queue_lock);
1307 return AL_TRUE;
1309 case AL_SOURCE_TYPE:
1310 *values = Source->SourceType;
1311 return AL_TRUE;
1313 case AL_DIRECT_FILTER_GAINHF_AUTO:
1314 *values = Source->DryGainHFAuto;
1315 return AL_TRUE;
1317 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1318 *values = Source->WetGainAuto;
1319 return AL_TRUE;
1321 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1322 *values = Source->WetGainHFAuto;
1323 return AL_TRUE;
1325 case AL_DIRECT_CHANNELS_SOFT:
1326 *values = Source->DirectChannels;
1327 return AL_TRUE;
1329 case AL_DISTANCE_MODEL:
1330 *values = Source->DistanceModel;
1331 return AL_TRUE;
1333 /* 1x float/double */
1334 case AL_CONE_INNER_ANGLE:
1335 case AL_CONE_OUTER_ANGLE:
1336 case AL_PITCH:
1337 case AL_GAIN:
1338 case AL_MIN_GAIN:
1339 case AL_MAX_GAIN:
1340 case AL_REFERENCE_DISTANCE:
1341 case AL_ROLLOFF_FACTOR:
1342 case AL_CONE_OUTER_GAIN:
1343 case AL_MAX_DISTANCE:
1344 case AL_SEC_OFFSET:
1345 case AL_SAMPLE_OFFSET:
1346 case AL_BYTE_OFFSET:
1347 case AL_DOPPLER_FACTOR:
1348 case AL_AIR_ABSORPTION_FACTOR:
1349 case AL_ROOM_ROLLOFF_FACTOR:
1350 case AL_CONE_OUTER_GAINHF:
1351 case AL_SEC_LENGTH_SOFT:
1352 case AL_SOURCE_RADIUS:
1353 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1354 *values = (ALint)dvals[0];
1355 return err;
1357 /* 3x float/double */
1358 case AL_POSITION:
1359 case AL_VELOCITY:
1360 case AL_DIRECTION:
1361 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1363 values[0] = (ALint)dvals[0];
1364 values[1] = (ALint)dvals[1];
1365 values[2] = (ALint)dvals[2];
1367 return err;
1369 /* 6x float/double */
1370 case AL_ORIENTATION:
1371 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1373 values[0] = (ALint)dvals[0];
1374 values[1] = (ALint)dvals[1];
1375 values[2] = (ALint)dvals[2];
1376 values[3] = (ALint)dvals[3];
1377 values[4] = (ALint)dvals[4];
1378 values[5] = (ALint)dvals[5];
1380 return err;
1382 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1383 break; /* i64 only */
1384 case AL_SEC_OFFSET_LATENCY_SOFT:
1385 break; /* Double only */
1386 case AL_STEREO_ANGLES:
1387 break; /* Float/double only */
1389 case AL_DIRECT_FILTER:
1390 case AL_AUXILIARY_SEND_FILTER:
1391 break; /* ??? */
1394 ERR("Unexpected property: 0x%04x\n", prop);
1395 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1398 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1400 ALCdevice *device = Context->Device;
1401 ClockLatency clocktime;
1402 ALuint64 srcclock;
1403 ALdouble dvals[6];
1404 ALint ivals[3];
1405 ALboolean err;
1407 switch(prop)
1409 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1410 /* Get the source offset with the clock time first. Then get the
1411 * clock time with the device latency. Order is important.
1413 values[0] = GetSourceSampleOffset(Source, device, &srcclock);
1414 clocktime = V0(device->Backend,getClockLatency)();
1415 if(srcclock == (ALuint64)clocktime.ClockTime)
1416 values[1] = clocktime.Latency;
1417 else
1419 /* If the clock time incremented, reduce the latency by that
1420 * much since it's that much closer to the source offset it got
1421 * earlier.
1423 ALuint64 diff = clocktime.ClockTime - srcclock;
1424 values[1] = clocktime.Latency - minu64(clocktime.Latency, diff);
1426 return AL_TRUE;
1428 /* 1x float/double */
1429 case AL_CONE_INNER_ANGLE:
1430 case AL_CONE_OUTER_ANGLE:
1431 case AL_PITCH:
1432 case AL_GAIN:
1433 case AL_MIN_GAIN:
1434 case AL_MAX_GAIN:
1435 case AL_REFERENCE_DISTANCE:
1436 case AL_ROLLOFF_FACTOR:
1437 case AL_CONE_OUTER_GAIN:
1438 case AL_MAX_DISTANCE:
1439 case AL_SEC_OFFSET:
1440 case AL_SAMPLE_OFFSET:
1441 case AL_BYTE_OFFSET:
1442 case AL_DOPPLER_FACTOR:
1443 case AL_AIR_ABSORPTION_FACTOR:
1444 case AL_ROOM_ROLLOFF_FACTOR:
1445 case AL_CONE_OUTER_GAINHF:
1446 case AL_SEC_LENGTH_SOFT:
1447 case AL_SOURCE_RADIUS:
1448 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1449 *values = (ALint64)dvals[0];
1450 return err;
1452 /* 3x float/double */
1453 case AL_POSITION:
1454 case AL_VELOCITY:
1455 case AL_DIRECTION:
1456 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1458 values[0] = (ALint64)dvals[0];
1459 values[1] = (ALint64)dvals[1];
1460 values[2] = (ALint64)dvals[2];
1462 return err;
1464 /* 6x float/double */
1465 case AL_ORIENTATION:
1466 if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1468 values[0] = (ALint64)dvals[0];
1469 values[1] = (ALint64)dvals[1];
1470 values[2] = (ALint64)dvals[2];
1471 values[3] = (ALint64)dvals[3];
1472 values[4] = (ALint64)dvals[4];
1473 values[5] = (ALint64)dvals[5];
1475 return err;
1477 /* 1x int */
1478 case AL_SOURCE_RELATIVE:
1479 case AL_LOOPING:
1480 case AL_SOURCE_STATE:
1481 case AL_BUFFERS_QUEUED:
1482 case AL_BUFFERS_PROCESSED:
1483 case AL_BYTE_LENGTH_SOFT:
1484 case AL_SAMPLE_LENGTH_SOFT:
1485 case AL_SOURCE_TYPE:
1486 case AL_DIRECT_FILTER_GAINHF_AUTO:
1487 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1488 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1489 case AL_DIRECT_CHANNELS_SOFT:
1490 case AL_DISTANCE_MODEL:
1491 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1492 *values = ivals[0];
1493 return err;
1495 /* 1x uint */
1496 case AL_BUFFER:
1497 case AL_DIRECT_FILTER:
1498 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1499 *values = (ALuint)ivals[0];
1500 return err;
1502 /* 3x uint */
1503 case AL_AUXILIARY_SEND_FILTER:
1504 if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1506 values[0] = (ALuint)ivals[0];
1507 values[1] = (ALuint)ivals[1];
1508 values[2] = (ALuint)ivals[2];
1510 return err;
1512 case AL_SEC_OFFSET_LATENCY_SOFT:
1513 break; /* Double only */
1514 case AL_STEREO_ANGLES:
1515 break; /* Float/double only */
1518 ERR("Unexpected property: 0x%04x\n", prop);
1519 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1523 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1525 ALCcontext *context;
1526 ALsizei cur = 0;
1527 ALenum err;
1529 context = GetContextRef();
1530 if(!context) return;
1532 if(!(n >= 0))
1533 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1534 for(cur = 0;cur < n;cur++)
1536 ALsource *source = al_calloc(16, sizeof(ALsource));
1537 if(!source)
1539 alDeleteSources(cur, sources);
1540 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1542 InitSourceParams(source);
1544 err = NewThunkEntry(&source->id);
1545 if(err == AL_NO_ERROR)
1546 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1547 if(err != AL_NO_ERROR)
1549 FreeThunkEntry(source->id);
1550 memset(source, 0, sizeof(ALsource));
1551 al_free(source);
1553 alDeleteSources(cur, sources);
1554 SET_ERROR_AND_GOTO(context, err, done);
1557 sources[cur] = source->id;
1560 done:
1561 ALCcontext_DecRef(context);
1565 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1567 ALCcontext *context;
1568 ALsource *Source;
1569 ALsizei i;
1571 context = GetContextRef();
1572 if(!context) return;
1574 LockSourcesWrite(context);
1575 if(!(n >= 0))
1576 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1578 /* Check that all Sources are valid */
1579 for(i = 0;i < n;i++)
1581 if(LookupSource(context, sources[i]) == NULL)
1582 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1584 for(i = 0;i < n;i++)
1586 ALvoice *voice, *voice_end;
1588 if((Source=RemoveSource(context, sources[i])) == NULL)
1589 continue;
1590 FreeThunkEntry(Source->id);
1592 LockContext(context);
1593 voice = context->Voices;
1594 voice_end = voice + context->VoiceCount;
1595 while(voice != voice_end)
1597 ALsource *old = Source;
1598 if(COMPARE_EXCHANGE(&voice->Source, &old, NULL))
1599 break;
1600 voice++;
1602 UnlockContext(context);
1604 DeinitSource(Source);
1606 memset(Source, 0, sizeof(*Source));
1607 al_free(Source);
1610 done:
1611 UnlockSourcesWrite(context);
1612 ALCcontext_DecRef(context);
1616 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1618 ALCcontext *context;
1619 ALboolean ret;
1621 context = GetContextRef();
1622 if(!context) return AL_FALSE;
1624 LockSourcesRead(context);
1625 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1626 UnlockSourcesRead(context);
1628 ALCcontext_DecRef(context);
1630 return ret;
1634 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1636 ALCcontext *Context;
1637 ALsource *Source;
1639 Context = GetContextRef();
1640 if(!Context) return;
1642 WriteLock(&Context->PropLock);
1643 LockSourcesRead(Context);
1644 if((Source=LookupSource(Context, source)) == NULL)
1645 alSetError(Context, AL_INVALID_NAME);
1646 else if(!(FloatValsByProp(param) == 1))
1647 alSetError(Context, AL_INVALID_ENUM);
1648 else
1649 SetSourcefv(Source, Context, param, &value);
1650 UnlockSourcesRead(Context);
1651 WriteUnlock(&Context->PropLock);
1653 ALCcontext_DecRef(Context);
1656 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1658 ALCcontext *Context;
1659 ALsource *Source;
1661 Context = GetContextRef();
1662 if(!Context) return;
1664 WriteLock(&Context->PropLock);
1665 LockSourcesRead(Context);
1666 if((Source=LookupSource(Context, source)) == NULL)
1667 alSetError(Context, AL_INVALID_NAME);
1668 else if(!(FloatValsByProp(param) == 3))
1669 alSetError(Context, AL_INVALID_ENUM);
1670 else
1672 ALfloat fvals[3] = { value1, value2, value3 };
1673 SetSourcefv(Source, Context, param, fvals);
1675 UnlockSourcesRead(Context);
1676 WriteUnlock(&Context->PropLock);
1678 ALCcontext_DecRef(Context);
1681 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1683 ALCcontext *Context;
1684 ALsource *Source;
1686 Context = GetContextRef();
1687 if(!Context) return;
1689 WriteLock(&Context->PropLock);
1690 LockSourcesRead(Context);
1691 if((Source=LookupSource(Context, source)) == NULL)
1692 alSetError(Context, AL_INVALID_NAME);
1693 else if(!values)
1694 alSetError(Context, AL_INVALID_VALUE);
1695 else if(!(FloatValsByProp(param) > 0))
1696 alSetError(Context, AL_INVALID_ENUM);
1697 else
1698 SetSourcefv(Source, Context, param, values);
1699 UnlockSourcesRead(Context);
1700 WriteUnlock(&Context->PropLock);
1702 ALCcontext_DecRef(Context);
1706 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1708 ALCcontext *Context;
1709 ALsource *Source;
1711 Context = GetContextRef();
1712 if(!Context) return;
1714 WriteLock(&Context->PropLock);
1715 LockSourcesRead(Context);
1716 if((Source=LookupSource(Context, source)) == NULL)
1717 alSetError(Context, AL_INVALID_NAME);
1718 else if(!(DoubleValsByProp(param) == 1))
1719 alSetError(Context, AL_INVALID_ENUM);
1720 else
1722 ALfloat fval = (ALfloat)value;
1723 SetSourcefv(Source, Context, param, &fval);
1725 UnlockSourcesRead(Context);
1726 WriteUnlock(&Context->PropLock);
1728 ALCcontext_DecRef(Context);
1731 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1733 ALCcontext *Context;
1734 ALsource *Source;
1736 Context = GetContextRef();
1737 if(!Context) return;
1739 WriteLock(&Context->PropLock);
1740 LockSourcesRead(Context);
1741 if((Source=LookupSource(Context, source)) == NULL)
1742 alSetError(Context, AL_INVALID_NAME);
1743 else if(!(DoubleValsByProp(param) == 3))
1744 alSetError(Context, AL_INVALID_ENUM);
1745 else
1747 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1748 SetSourcefv(Source, Context, param, fvals);
1750 UnlockSourcesRead(Context);
1751 WriteUnlock(&Context->PropLock);
1753 ALCcontext_DecRef(Context);
1756 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1758 ALCcontext *Context;
1759 ALsource *Source;
1760 ALint count;
1762 Context = GetContextRef();
1763 if(!Context) return;
1765 WriteLock(&Context->PropLock);
1766 LockSourcesRead(Context);
1767 if((Source=LookupSource(Context, source)) == NULL)
1768 alSetError(Context, AL_INVALID_NAME);
1769 else if(!values)
1770 alSetError(Context, AL_INVALID_VALUE);
1771 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1772 alSetError(Context, AL_INVALID_ENUM);
1773 else
1775 ALfloat fvals[6];
1776 ALint i;
1778 for(i = 0;i < count;i++)
1779 fvals[i] = (ALfloat)values[i];
1780 SetSourcefv(Source, Context, param, fvals);
1782 UnlockSourcesRead(Context);
1783 WriteUnlock(&Context->PropLock);
1785 ALCcontext_DecRef(Context);
1789 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1791 ALCcontext *Context;
1792 ALsource *Source;
1794 Context = GetContextRef();
1795 if(!Context) return;
1797 WriteLock(&Context->PropLock);
1798 LockSourcesRead(Context);
1799 if((Source=LookupSource(Context, source)) == NULL)
1800 alSetError(Context, AL_INVALID_NAME);
1801 else if(!(IntValsByProp(param) == 1))
1802 alSetError(Context, AL_INVALID_ENUM);
1803 else
1804 SetSourceiv(Source, Context, param, &value);
1805 UnlockSourcesRead(Context);
1806 WriteUnlock(&Context->PropLock);
1808 ALCcontext_DecRef(Context);
1811 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1813 ALCcontext *Context;
1814 ALsource *Source;
1816 Context = GetContextRef();
1817 if(!Context) return;
1819 WriteLock(&Context->PropLock);
1820 LockSourcesRead(Context);
1821 if((Source=LookupSource(Context, source)) == NULL)
1822 alSetError(Context, AL_INVALID_NAME);
1823 else if(!(IntValsByProp(param) == 3))
1824 alSetError(Context, AL_INVALID_ENUM);
1825 else
1827 ALint ivals[3] = { value1, value2, value3 };
1828 SetSourceiv(Source, Context, param, ivals);
1830 UnlockSourcesRead(Context);
1831 WriteUnlock(&Context->PropLock);
1833 ALCcontext_DecRef(Context);
1836 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1838 ALCcontext *Context;
1839 ALsource *Source;
1841 Context = GetContextRef();
1842 if(!Context) return;
1844 WriteLock(&Context->PropLock);
1845 LockSourcesRead(Context);
1846 if((Source=LookupSource(Context, source)) == NULL)
1847 alSetError(Context, AL_INVALID_NAME);
1848 else if(!values)
1849 alSetError(Context, AL_INVALID_VALUE);
1850 else if(!(IntValsByProp(param) > 0))
1851 alSetError(Context, AL_INVALID_ENUM);
1852 else
1853 SetSourceiv(Source, Context, param, values);
1854 UnlockSourcesRead(Context);
1855 WriteUnlock(&Context->PropLock);
1857 ALCcontext_DecRef(Context);
1861 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1863 ALCcontext *Context;
1864 ALsource *Source;
1866 Context = GetContextRef();
1867 if(!Context) return;
1869 WriteLock(&Context->PropLock);
1870 LockSourcesRead(Context);
1871 if((Source=LookupSource(Context, source)) == NULL)
1872 alSetError(Context, AL_INVALID_NAME);
1873 else if(!(Int64ValsByProp(param) == 1))
1874 alSetError(Context, AL_INVALID_ENUM);
1875 else
1876 SetSourcei64v(Source, Context, param, &value);
1877 UnlockSourcesRead(Context);
1878 WriteUnlock(&Context->PropLock);
1880 ALCcontext_DecRef(Context);
1883 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1885 ALCcontext *Context;
1886 ALsource *Source;
1888 Context = GetContextRef();
1889 if(!Context) return;
1891 WriteLock(&Context->PropLock);
1892 LockSourcesRead(Context);
1893 if((Source=LookupSource(Context, source)) == NULL)
1894 alSetError(Context, AL_INVALID_NAME);
1895 else if(!(Int64ValsByProp(param) == 3))
1896 alSetError(Context, AL_INVALID_ENUM);
1897 else
1899 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1900 SetSourcei64v(Source, Context, param, i64vals);
1902 UnlockSourcesRead(Context);
1903 WriteUnlock(&Context->PropLock);
1905 ALCcontext_DecRef(Context);
1908 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1910 ALCcontext *Context;
1911 ALsource *Source;
1913 Context = GetContextRef();
1914 if(!Context) return;
1916 WriteLock(&Context->PropLock);
1917 LockSourcesRead(Context);
1918 if((Source=LookupSource(Context, source)) == NULL)
1919 alSetError(Context, AL_INVALID_NAME);
1920 else if(!values)
1921 alSetError(Context, AL_INVALID_VALUE);
1922 else if(!(Int64ValsByProp(param) > 0))
1923 alSetError(Context, AL_INVALID_ENUM);
1924 else
1925 SetSourcei64v(Source, Context, param, values);
1926 UnlockSourcesRead(Context);
1927 WriteUnlock(&Context->PropLock);
1929 ALCcontext_DecRef(Context);
1933 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1935 ALCcontext *Context;
1936 ALsource *Source;
1938 Context = GetContextRef();
1939 if(!Context) return;
1941 ReadLock(&Context->PropLock);
1942 LockSourcesRead(Context);
1943 if((Source=LookupSource(Context, source)) == NULL)
1944 alSetError(Context, AL_INVALID_NAME);
1945 else if(!value)
1946 alSetError(Context, AL_INVALID_VALUE);
1947 else if(!(FloatValsByProp(param) == 1))
1948 alSetError(Context, AL_INVALID_ENUM);
1949 else
1951 ALdouble dval;
1952 if(GetSourcedv(Source, Context, param, &dval))
1953 *value = (ALfloat)dval;
1955 UnlockSourcesRead(Context);
1956 ReadUnlock(&Context->PropLock);
1958 ALCcontext_DecRef(Context);
1962 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1964 ALCcontext *Context;
1965 ALsource *Source;
1967 Context = GetContextRef();
1968 if(!Context) return;
1970 ReadLock(&Context->PropLock);
1971 LockSourcesRead(Context);
1972 if((Source=LookupSource(Context, source)) == NULL)
1973 alSetError(Context, AL_INVALID_NAME);
1974 else if(!(value1 && value2 && value3))
1975 alSetError(Context, AL_INVALID_VALUE);
1976 else if(!(FloatValsByProp(param) == 3))
1977 alSetError(Context, AL_INVALID_ENUM);
1978 else
1980 ALdouble dvals[3];
1981 if(GetSourcedv(Source, Context, param, dvals))
1983 *value1 = (ALfloat)dvals[0];
1984 *value2 = (ALfloat)dvals[1];
1985 *value3 = (ALfloat)dvals[2];
1988 UnlockSourcesRead(Context);
1989 ReadUnlock(&Context->PropLock);
1991 ALCcontext_DecRef(Context);
1995 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1997 ALCcontext *Context;
1998 ALsource *Source;
1999 ALint count;
2001 Context = GetContextRef();
2002 if(!Context) return;
2004 ReadLock(&Context->PropLock);
2005 LockSourcesRead(Context);
2006 if((Source=LookupSource(Context, source)) == NULL)
2007 alSetError(Context, AL_INVALID_NAME);
2008 else if(!values)
2009 alSetError(Context, AL_INVALID_VALUE);
2010 else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
2011 alSetError(Context, AL_INVALID_ENUM);
2012 else
2014 ALdouble dvals[6];
2015 if(GetSourcedv(Source, Context, param, dvals))
2017 ALint i;
2018 for(i = 0;i < count;i++)
2019 values[i] = (ALfloat)dvals[i];
2022 UnlockSourcesRead(Context);
2023 ReadUnlock(&Context->PropLock);
2025 ALCcontext_DecRef(Context);
2029 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
2031 ALCcontext *Context;
2032 ALsource *Source;
2034 Context = GetContextRef();
2035 if(!Context) return;
2037 ReadLock(&Context->PropLock);
2038 LockSourcesRead(Context);
2039 if((Source=LookupSource(Context, source)) == NULL)
2040 alSetError(Context, AL_INVALID_NAME);
2041 else if(!value)
2042 alSetError(Context, AL_INVALID_VALUE);
2043 else if(!(DoubleValsByProp(param) == 1))
2044 alSetError(Context, AL_INVALID_ENUM);
2045 else
2046 GetSourcedv(Source, Context, param, value);
2047 UnlockSourcesRead(Context);
2048 ReadUnlock(&Context->PropLock);
2050 ALCcontext_DecRef(Context);
2053 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
2055 ALCcontext *Context;
2056 ALsource *Source;
2058 Context = GetContextRef();
2059 if(!Context) return;
2061 ReadLock(&Context->PropLock);
2062 LockSourcesRead(Context);
2063 if((Source=LookupSource(Context, source)) == NULL)
2064 alSetError(Context, AL_INVALID_NAME);
2065 else if(!(value1 && value2 && value3))
2066 alSetError(Context, AL_INVALID_VALUE);
2067 else if(!(DoubleValsByProp(param) == 3))
2068 alSetError(Context, AL_INVALID_ENUM);
2069 else
2071 ALdouble dvals[3];
2072 if(GetSourcedv(Source, Context, param, dvals))
2074 *value1 = dvals[0];
2075 *value2 = dvals[1];
2076 *value3 = dvals[2];
2079 UnlockSourcesRead(Context);
2080 ReadUnlock(&Context->PropLock);
2082 ALCcontext_DecRef(Context);
2085 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
2087 ALCcontext *Context;
2088 ALsource *Source;
2090 Context = GetContextRef();
2091 if(!Context) return;
2093 ReadLock(&Context->PropLock);
2094 LockSourcesRead(Context);
2095 if((Source=LookupSource(Context, source)) == NULL)
2096 alSetError(Context, AL_INVALID_NAME);
2097 else if(!values)
2098 alSetError(Context, AL_INVALID_VALUE);
2099 else if(!(DoubleValsByProp(param) > 0))
2100 alSetError(Context, AL_INVALID_ENUM);
2101 else
2102 GetSourcedv(Source, Context, param, values);
2103 UnlockSourcesRead(Context);
2104 ReadUnlock(&Context->PropLock);
2106 ALCcontext_DecRef(Context);
2110 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
2112 ALCcontext *Context;
2113 ALsource *Source;
2115 Context = GetContextRef();
2116 if(!Context) return;
2118 ReadLock(&Context->PropLock);
2119 LockSourcesRead(Context);
2120 if((Source=LookupSource(Context, source)) == NULL)
2121 alSetError(Context, AL_INVALID_NAME);
2122 else if(!value)
2123 alSetError(Context, AL_INVALID_VALUE);
2124 else if(!(IntValsByProp(param) == 1))
2125 alSetError(Context, AL_INVALID_ENUM);
2126 else
2127 GetSourceiv(Source, Context, param, value);
2128 UnlockSourcesRead(Context);
2129 ReadUnlock(&Context->PropLock);
2131 ALCcontext_DecRef(Context);
2135 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2137 ALCcontext *Context;
2138 ALsource *Source;
2140 Context = GetContextRef();
2141 if(!Context) return;
2143 ReadLock(&Context->PropLock);
2144 LockSourcesRead(Context);
2145 if((Source=LookupSource(Context, source)) == NULL)
2146 alSetError(Context, AL_INVALID_NAME);
2147 else if(!(value1 && value2 && value3))
2148 alSetError(Context, AL_INVALID_VALUE);
2149 else if(!(IntValsByProp(param) == 3))
2150 alSetError(Context, AL_INVALID_ENUM);
2151 else
2153 ALint ivals[3];
2154 if(GetSourceiv(Source, Context, param, ivals))
2156 *value1 = ivals[0];
2157 *value2 = ivals[1];
2158 *value3 = ivals[2];
2161 UnlockSourcesRead(Context);
2162 ReadUnlock(&Context->PropLock);
2164 ALCcontext_DecRef(Context);
2168 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2170 ALCcontext *Context;
2171 ALsource *Source;
2173 Context = GetContextRef();
2174 if(!Context) return;
2176 ReadLock(&Context->PropLock);
2177 LockSourcesRead(Context);
2178 if((Source=LookupSource(Context, source)) == NULL)
2179 alSetError(Context, AL_INVALID_NAME);
2180 else if(!values)
2181 alSetError(Context, AL_INVALID_VALUE);
2182 else if(!(IntValsByProp(param) > 0))
2183 alSetError(Context, AL_INVALID_ENUM);
2184 else
2185 GetSourceiv(Source, Context, param, values);
2186 UnlockSourcesRead(Context);
2187 ReadUnlock(&Context->PropLock);
2189 ALCcontext_DecRef(Context);
2193 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2195 ALCcontext *Context;
2196 ALsource *Source;
2198 Context = GetContextRef();
2199 if(!Context) return;
2201 ReadLock(&Context->PropLock);
2202 LockSourcesRead(Context);
2203 if((Source=LookupSource(Context, source)) == NULL)
2204 alSetError(Context, AL_INVALID_NAME);
2205 else if(!value)
2206 alSetError(Context, AL_INVALID_VALUE);
2207 else if(!(Int64ValsByProp(param) == 1))
2208 alSetError(Context, AL_INVALID_ENUM);
2209 else
2210 GetSourcei64v(Source, Context, param, value);
2211 UnlockSourcesRead(Context);
2212 ReadUnlock(&Context->PropLock);
2214 ALCcontext_DecRef(Context);
2217 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2219 ALCcontext *Context;
2220 ALsource *Source;
2222 Context = GetContextRef();
2223 if(!Context) return;
2225 ReadLock(&Context->PropLock);
2226 LockSourcesRead(Context);
2227 if((Source=LookupSource(Context, source)) == NULL)
2228 alSetError(Context, AL_INVALID_NAME);
2229 else if(!(value1 && value2 && value3))
2230 alSetError(Context, AL_INVALID_VALUE);
2231 else if(!(Int64ValsByProp(param) == 3))
2232 alSetError(Context, AL_INVALID_ENUM);
2233 else
2235 ALint64 i64vals[3];
2236 if(GetSourcei64v(Source, Context, param, i64vals))
2238 *value1 = i64vals[0];
2239 *value2 = i64vals[1];
2240 *value3 = i64vals[2];
2243 UnlockSourcesRead(Context);
2244 ReadUnlock(&Context->PropLock);
2246 ALCcontext_DecRef(Context);
2249 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2251 ALCcontext *Context;
2252 ALsource *Source;
2254 Context = GetContextRef();
2255 if(!Context) return;
2257 ReadLock(&Context->PropLock);
2258 LockSourcesRead(Context);
2259 if((Source=LookupSource(Context, source)) == NULL)
2260 alSetError(Context, AL_INVALID_NAME);
2261 else if(!values)
2262 alSetError(Context, AL_INVALID_VALUE);
2263 else if(!(Int64ValsByProp(param) > 0))
2264 alSetError(Context, AL_INVALID_ENUM);
2265 else
2266 GetSourcei64v(Source, Context, param, values);
2267 UnlockSourcesRead(Context);
2268 ReadUnlock(&Context->PropLock);
2270 ALCcontext_DecRef(Context);
2274 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2276 alSourcePlayv(1, &source);
2278 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2280 ALCcontext *context;
2281 ALsource *source;
2282 ALsizei i;
2284 context = GetContextRef();
2285 if(!context) return;
2287 LockSourcesRead(context);
2288 if(!(n >= 0))
2289 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2290 for(i = 0;i < n;i++)
2292 if(!LookupSource(context, sources[i]))
2293 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2296 LockContext(context);
2297 while(n > context->MaxVoices-context->VoiceCount)
2299 ALvoice *temp = NULL;
2300 ALsizei newcount;
2302 newcount = context->MaxVoices << 1;
2303 if(newcount > 0)
2304 temp = al_malloc(16, newcount * sizeof(context->Voices[0]));
2305 if(!temp)
2307 UnlockContext(context);
2308 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2310 memcpy(temp, context->Voices, context->MaxVoices * sizeof(temp[0]));
2311 memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0]));
2313 al_free(context->Voices);
2314 context->Voices = temp;
2315 context->MaxVoices = newcount;
2318 for(i = 0;i < n;i++)
2320 source = LookupSource(context, sources[i]);
2321 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
2322 source->new_state = AL_PLAYING;
2323 else
2324 SetSourceState(source, context, AL_PLAYING);
2326 UnlockContext(context);
2328 done:
2329 UnlockSourcesRead(context);
2330 ALCcontext_DecRef(context);
2333 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2335 alSourcePausev(1, &source);
2337 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2339 ALCcontext *context;
2340 ALsource *source;
2341 ALsizei i;
2343 context = GetContextRef();
2344 if(!context) return;
2346 LockSourcesRead(context);
2347 if(!(n >= 0))
2348 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2349 for(i = 0;i < n;i++)
2351 if(!LookupSource(context, sources[i]))
2352 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2355 LockContext(context);
2356 for(i = 0;i < n;i++)
2358 source = LookupSource(context, sources[i]);
2359 if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
2360 source->new_state = AL_PAUSED;
2361 else
2362 SetSourceState(source, context, AL_PAUSED);
2364 UnlockContext(context);
2366 done:
2367 UnlockSourcesRead(context);
2368 ALCcontext_DecRef(context);
2371 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2373 alSourceStopv(1, &source);
2375 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2377 ALCcontext *context;
2378 ALsource *source;
2379 ALsizei i;
2381 context = GetContextRef();
2382 if(!context) return;
2384 LockSourcesRead(context);
2385 if(!(n >= 0))
2386 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2387 for(i = 0;i < n;i++)
2389 if(!LookupSource(context, sources[i]))
2390 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2393 LockContext(context);
2394 for(i = 0;i < n;i++)
2396 source = LookupSource(context, sources[i]);
2397 source->new_state = AL_NONE;
2398 SetSourceState(source, context, AL_STOPPED);
2400 UnlockContext(context);
2402 done:
2403 UnlockSourcesRead(context);
2404 ALCcontext_DecRef(context);
2407 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2409 alSourceRewindv(1, &source);
2411 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2413 ALCcontext *context;
2414 ALsource *source;
2415 ALsizei i;
2417 context = GetContextRef();
2418 if(!context) return;
2420 LockSourcesRead(context);
2421 if(!(n >= 0))
2422 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2423 for(i = 0;i < n;i++)
2425 if(!LookupSource(context, sources[i]))
2426 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2429 LockContext(context);
2430 for(i = 0;i < n;i++)
2432 source = LookupSource(context, sources[i]);
2433 source->new_state = AL_NONE;
2434 SetSourceState(source, context, AL_INITIAL);
2436 UnlockContext(context);
2438 done:
2439 UnlockSourcesRead(context);
2440 ALCcontext_DecRef(context);
2444 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2446 ALCdevice *device;
2447 ALCcontext *context;
2448 ALsource *source;
2449 ALsizei i;
2450 ALbufferlistitem *BufferListStart;
2451 ALbufferlistitem *BufferList;
2452 ALbuffer *BufferFmt = NULL;
2454 if(nb == 0)
2455 return;
2457 context = GetContextRef();
2458 if(!context) return;
2460 device = context->Device;
2462 LockSourcesRead(context);
2463 if(!(nb >= 0))
2464 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2465 if((source=LookupSource(context, src)) == NULL)
2466 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2468 WriteLock(&source->queue_lock);
2469 if(source->SourceType == AL_STATIC)
2471 WriteUnlock(&source->queue_lock);
2472 /* Can't queue on a Static Source */
2473 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2476 /* Check for a valid Buffer, for its frequency and format */
2477 BufferList = ATOMIC_LOAD(&source->queue);
2478 while(BufferList)
2480 if(BufferList->buffer)
2482 BufferFmt = BufferList->buffer;
2483 break;
2485 BufferList = BufferList->next;
2488 LockBuffersRead(device);
2489 BufferListStart = NULL;
2490 BufferList = NULL;
2491 for(i = 0;i < nb;i++)
2493 ALbuffer *buffer = NULL;
2494 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2496 WriteUnlock(&source->queue_lock);
2497 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2500 if(!BufferListStart)
2502 BufferListStart = malloc(sizeof(ALbufferlistitem));
2503 BufferList = BufferListStart;
2505 else
2507 BufferList->next = malloc(sizeof(ALbufferlistitem));
2508 BufferList = BufferList->next;
2510 BufferList->buffer = buffer;
2511 BufferList->next = NULL;
2512 if(!buffer) continue;
2514 /* Hold a read lock on each buffer being queued while checking all
2515 * provided buffers. This is done so other threads don't see an extra
2516 * reference on some buffers if this operation ends up failing. */
2517 ReadLock(&buffer->lock);
2518 IncrementRef(&buffer->ref);
2520 if(BufferFmt == NULL)
2522 BufferFmt = buffer;
2524 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2525 source->SampleSize = BytesFromFmt(buffer->FmtType);
2527 else if(BufferFmt->Frequency != buffer->Frequency ||
2528 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2529 BufferFmt->OriginalType != buffer->OriginalType)
2531 WriteUnlock(&source->queue_lock);
2532 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2534 buffer_error:
2535 /* A buffer failed (invalid ID or format), so unlock and release
2536 * each buffer we had. */
2537 while(BufferListStart)
2539 ALbufferlistitem *next = BufferListStart->next;
2540 if((buffer=BufferListStart->buffer) != NULL)
2542 DecrementRef(&buffer->ref);
2543 ReadUnlock(&buffer->lock);
2545 free(BufferListStart);
2546 BufferListStart = next;
2548 UnlockBuffersRead(device);
2549 goto done;
2552 /* All buffers good, unlock them now. */
2553 BufferList = BufferListStart;
2554 while(BufferList != NULL)
2556 ALbuffer *buffer = BufferList->buffer;
2557 if(buffer) ReadUnlock(&buffer->lock);
2558 BufferList = BufferList->next;
2560 UnlockBuffersRead(device);
2562 /* Source is now streaming */
2563 source->SourceType = AL_STREAMING;
2565 BufferList = NULL;
2566 if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
2568 /* Queue head is not NULL, append to the end of the queue */
2569 while(BufferList->next != NULL)
2570 BufferList = BufferList->next;
2571 BufferList->next = BufferListStart;
2573 /* If the current buffer was at the end (NULL), put it at the start of the newly queued
2574 * buffers.
2576 BufferList = NULL;
2577 ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
2578 WriteUnlock(&source->queue_lock);
2580 done:
2581 UnlockSourcesRead(context);
2582 ALCcontext_DecRef(context);
2585 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2587 ALCcontext *context;
2588 ALsource *source;
2589 ALbufferlistitem *OldHead;
2590 ALbufferlistitem *OldTail;
2591 ALbufferlistitem *Current;
2592 ALsizei i = 0;
2594 if(nb == 0)
2595 return;
2597 context = GetContextRef();
2598 if(!context) return;
2600 LockSourcesRead(context);
2601 if(!(nb >= 0))
2602 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2604 if((source=LookupSource(context, src)) == NULL)
2605 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2607 WriteLock(&source->queue_lock);
2608 /* Find the new buffer queue head */
2609 OldTail = ATOMIC_LOAD(&source->queue);
2610 Current = ATOMIC_LOAD(&source->current_buffer);
2611 if(OldTail != Current)
2613 for(i = 1;i < nb;i++)
2615 ALbufferlistitem *next = OldTail->next;
2616 if(!next || next == Current) break;
2617 OldTail = next;
2620 if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
2622 WriteUnlock(&source->queue_lock);
2623 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2624 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2627 /* Swap it, and cut the new head from the old. */
2628 OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, OldTail->next);
2629 if(OldTail->next)
2631 ALCdevice *device = context->Device;
2632 uint count;
2634 /* Once the active mix (if any) is done, it's safe to cut the old tail
2635 * from the new head.
2637 if(((count=ReadRef(&device->MixCount))&1) != 0)
2639 while(count == ReadRef(&device->MixCount))
2640 althrd_yield();
2642 OldTail->next = NULL;
2644 WriteUnlock(&source->queue_lock);
2646 while(OldHead != NULL)
2648 ALbufferlistitem *next = OldHead->next;
2649 ALbuffer *buffer = OldHead->buffer;
2651 if(!buffer)
2652 *(buffers++) = 0;
2653 else
2655 *(buffers++) = buffer->id;
2656 DecrementRef(&buffer->ref);
2659 free(OldHead);
2660 OldHead = next;
2663 done:
2664 UnlockSourcesRead(context);
2665 ALCcontext_DecRef(context);
2669 static void InitSourceParams(ALsource *Source)
2671 ALuint i;
2673 RWLockInit(&Source->queue_lock);
2675 Source->InnerAngle = 360.0f;
2676 Source->OuterAngle = 360.0f;
2677 Source->Pitch = 1.0f;
2678 Source->Position[0] = 0.0f;
2679 Source->Position[1] = 0.0f;
2680 Source->Position[2] = 0.0f;
2681 Source->Velocity[0] = 0.0f;
2682 Source->Velocity[1] = 0.0f;
2683 Source->Velocity[2] = 0.0f;
2684 Source->Direction[0] = 0.0f;
2685 Source->Direction[1] = 0.0f;
2686 Source->Direction[2] = 0.0f;
2687 Source->Orientation[0][0] = 0.0f;
2688 Source->Orientation[0][1] = 0.0f;
2689 Source->Orientation[0][2] = -1.0f;
2690 Source->Orientation[1][0] = 0.0f;
2691 Source->Orientation[1][1] = 1.0f;
2692 Source->Orientation[1][2] = 0.0f;
2693 Source->RefDistance = 1.0f;
2694 Source->MaxDistance = FLT_MAX;
2695 Source->RollOffFactor = 1.0f;
2696 Source->Looping = AL_FALSE;
2697 Source->Gain = 1.0f;
2698 Source->MinGain = 0.0f;
2699 Source->MaxGain = 1.0f;
2700 Source->OuterGain = 0.0f;
2701 Source->OuterGainHF = 1.0f;
2703 Source->DryGainHFAuto = AL_TRUE;
2704 Source->WetGainAuto = AL_TRUE;
2705 Source->WetGainHFAuto = AL_TRUE;
2706 Source->AirAbsorptionFactor = 0.0f;
2707 Source->RoomRolloffFactor = 0.0f;
2708 Source->DopplerFactor = 1.0f;
2709 Source->DirectChannels = AL_FALSE;
2711 Source->StereoPan[0] = DEG2RAD( 30.0f);
2712 Source->StereoPan[1] = DEG2RAD(-30.0f);
2714 Source->Radius = 0.0f;
2716 Source->DistanceModel = DefaultDistanceModel;
2718 Source->Direct.Gain = 1.0f;
2719 Source->Direct.GainHF = 1.0f;
2720 Source->Direct.HFReference = LOWPASSFREQREF;
2721 Source->Direct.GainLF = 1.0f;
2722 Source->Direct.LFReference = HIGHPASSFREQREF;
2723 for(i = 0;i < MAX_SENDS;i++)
2725 Source->Send[i].Gain = 1.0f;
2726 Source->Send[i].GainHF = 1.0f;
2727 Source->Send[i].HFReference = LOWPASSFREQREF;
2728 Source->Send[i].GainLF = 1.0f;
2729 Source->Send[i].LFReference = HIGHPASSFREQREF;
2732 Source->Offset = 0.0;
2733 Source->OffsetType = AL_NONE;
2734 Source->SourceType = AL_UNDETERMINED;
2735 Source->state = AL_INITIAL;
2736 Source->new_state = AL_NONE;
2738 ATOMIC_INIT(&Source->queue, NULL);
2739 ATOMIC_INIT(&Source->current_buffer, NULL);
2741 ATOMIC_INIT(&Source->position, 0);
2742 ATOMIC_INIT(&Source->position_fraction, 0);
2744 ATOMIC_INIT(&Source->Update, NULL);
2745 ATOMIC_INIT(&Source->FreeList, NULL);
2748 static void DeinitSource(ALsource *source)
2750 ALbufferlistitem *BufferList;
2751 struct ALsourceProps *props;
2752 size_t count = 0;
2753 size_t i;
2755 props = ATOMIC_LOAD(&source->Update);
2756 if(props) al_free(props);
2758 props = ATOMIC_LOAD(&source->FreeList, almemory_order_relaxed);
2759 while(props)
2761 struct ALsourceProps *next;
2762 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2763 al_free(props);
2764 props = next;
2765 ++count;
2767 /* This is excessively spammy if it traces every source destruction, so
2768 * just warn if it was unexpectedly large.
2770 if(count > 3)
2771 WARN("Freed "SZFMT" Source property objects\n", count);
2773 BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NULL);
2774 while(BufferList != NULL)
2776 ALbufferlistitem *next = BufferList->next;
2777 if(BufferList->buffer != NULL)
2778 DecrementRef(&BufferList->buffer->ref);
2779 free(BufferList);
2780 BufferList = next;
2783 for(i = 0;i < MAX_SENDS;++i)
2785 if(source->Send[i].Slot)
2786 DecrementRef(&source->Send[i].Slot->ref);
2787 source->Send[i].Slot = NULL;
2791 static void UpdateSourceProps(ALsource *source, ALuint num_sends, ALCcontext *context)
2793 struct ALsourceProps *props;
2794 size_t i;
2796 /* Get an unused property container, or allocate a new one as needed. */
2797 props = ATOMIC_LOAD(&source->FreeList, almemory_order_acquire);
2798 if(!props)
2799 props = al_calloc(16, sizeof(*props));
2800 else
2802 struct ALsourceProps *next;
2803 do {
2804 next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
2805 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*,
2806 &source->FreeList, &props, next, almemory_order_seq_cst,
2807 almemory_order_consume) == 0);
2810 /* Copy in current property values. */
2811 ATOMIC_STORE(&props->Pitch, source->Pitch, almemory_order_relaxed);
2812 ATOMIC_STORE(&props->Gain, source->Gain, almemory_order_relaxed);
2813 ATOMIC_STORE(&props->OuterGain, source->OuterGain, almemory_order_relaxed);
2814 ATOMIC_STORE(&props->MinGain, source->MinGain, almemory_order_relaxed);
2815 ATOMIC_STORE(&props->MaxGain, source->MaxGain, almemory_order_relaxed);
2816 ATOMIC_STORE(&props->InnerAngle, source->InnerAngle, almemory_order_relaxed);
2817 ATOMIC_STORE(&props->OuterAngle, source->OuterAngle, almemory_order_relaxed);
2818 ATOMIC_STORE(&props->RefDistance, source->RefDistance, almemory_order_relaxed);
2819 ATOMIC_STORE(&props->MaxDistance, source->MaxDistance, almemory_order_relaxed);
2820 ATOMIC_STORE(&props->RollOffFactor, source->RollOffFactor, almemory_order_relaxed);
2821 for(i = 0;i < 3;i++)
2822 ATOMIC_STORE(&props->Position[i], source->Position[i], almemory_order_relaxed);
2823 for(i = 0;i < 3;i++)
2824 ATOMIC_STORE(&props->Velocity[i], source->Velocity[i], almemory_order_relaxed);
2825 for(i = 0;i < 3;i++)
2826 ATOMIC_STORE(&props->Direction[i], source->Direction[i], almemory_order_relaxed);
2827 for(i = 0;i < 2;i++)
2829 size_t j;
2830 for(j = 0;j < 3;j++)
2831 ATOMIC_STORE(&props->Orientation[i][j], source->Orientation[i][j],
2832 almemory_order_relaxed);
2834 ATOMIC_STORE(&props->HeadRelative, source->HeadRelative, almemory_order_relaxed);
2835 ATOMIC_STORE(&props->Looping, source->Looping, almemory_order_relaxed);
2836 ATOMIC_STORE(&props->DistanceModel,
2837 context->SourceDistanceModel ? source->DistanceModel : context->DistanceModel,
2838 almemory_order_relaxed
2840 ATOMIC_STORE(&props->DirectChannels, source->DirectChannels, almemory_order_relaxed);
2842 ATOMIC_STORE(&props->DryGainHFAuto, source->DryGainHFAuto, almemory_order_relaxed);
2843 ATOMIC_STORE(&props->WetGainAuto, source->WetGainAuto, almemory_order_relaxed);
2844 ATOMIC_STORE(&props->WetGainHFAuto, source->WetGainHFAuto, almemory_order_relaxed);
2845 ATOMIC_STORE(&props->OuterGainHF, source->OuterGainHF, almemory_order_relaxed);
2847 ATOMIC_STORE(&props->AirAbsorptionFactor, source->AirAbsorptionFactor, almemory_order_relaxed);
2848 ATOMIC_STORE(&props->RoomRolloffFactor, source->RoomRolloffFactor, almemory_order_relaxed);
2849 ATOMIC_STORE(&props->DopplerFactor, source->DopplerFactor, almemory_order_relaxed);
2851 ATOMIC_STORE(&props->StereoPan[0], source->StereoPan[0], almemory_order_relaxed);
2852 ATOMIC_STORE(&props->StereoPan[1], source->StereoPan[1], almemory_order_relaxed);
2854 ATOMIC_STORE(&props->Radius, source->Radius, almemory_order_relaxed);
2856 ATOMIC_STORE(&props->Direct.Gain, source->Direct.Gain, almemory_order_relaxed);
2857 ATOMIC_STORE(&props->Direct.GainHF, source->Direct.GainHF, almemory_order_relaxed);
2858 ATOMIC_STORE(&props->Direct.HFReference, source->Direct.HFReference, almemory_order_relaxed);
2859 ATOMIC_STORE(&props->Direct.GainLF, source->Direct.GainLF, almemory_order_relaxed);
2860 ATOMIC_STORE(&props->Direct.LFReference, source->Direct.LFReference, almemory_order_relaxed);
2862 for(i = 0;i < num_sends;i++)
2864 ATOMIC_STORE(&props->Send[i].Slot, source->Send[i].Slot, almemory_order_relaxed);
2865 ATOMIC_STORE(&props->Send[i].Gain, source->Send[i].Gain, almemory_order_relaxed);
2866 ATOMIC_STORE(&props->Send[i].GainHF, source->Send[i].GainHF, almemory_order_relaxed);
2867 ATOMIC_STORE(&props->Send[i].HFReference, source->Send[i].HFReference,
2868 almemory_order_relaxed);
2869 ATOMIC_STORE(&props->Send[i].GainLF, source->Send[i].GainLF, almemory_order_relaxed);
2870 ATOMIC_STORE(&props->Send[i].LFReference, source->Send[i].LFReference,
2871 almemory_order_relaxed);
2874 /* Set the new container for updating internal parameters. */
2875 props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, props, almemory_order_acq_rel);
2876 if(props)
2878 /* If there was an unused update container, put it back in the
2879 * freelist.
2881 struct ALsourceProps *first = ATOMIC_LOAD(&source->FreeList);
2882 do {
2883 ATOMIC_STORE(&props->next, first, almemory_order_relaxed);
2884 } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*,
2885 &source->FreeList, &first, props) == 0);
2889 void UpdateAllSourceProps(ALCcontext *context)
2891 ALuint num_sends = context->Device->NumAuxSends;
2892 uint updates;
2893 ALsizei pos;
2895 /* Tell the mixer to stop applying updates, then wait for any active
2896 * updating to finish, before providing source updates.
2898 ATOMIC_STORE(&context->HoldUpdates, AL_TRUE);
2899 while(((updates=ReadRef(&context->UpdateCount))&1) != 0)
2900 althrd_yield();
2901 for(pos = 0;pos < context->VoiceCount;pos++)
2903 ALvoice *voice = &context->Voices[pos];
2904 ALsource *source = voice->Source;
2905 if(source != NULL && (source->state == AL_PLAYING ||
2906 source->state == AL_PAUSED))
2907 UpdateSourceProps(source, num_sends, context);
2909 /* Now with all updates declared, let the mixer continue applying them so
2910 * they all happen at once.
2912 ATOMIC_STORE(&context->HoldUpdates, AL_FALSE);
2916 /* SetSourceState
2918 * Sets the source's new play state given its current state.
2920 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2922 WriteLock(&Source->queue_lock);
2923 if(state == AL_PLAYING)
2925 ALCdevice *device = Context->Device;
2926 ALbufferlistitem *BufferList;
2927 ALboolean discontinuity;
2928 ALvoice *voice = NULL;
2929 ALsizei i;
2931 /* Check that there is a queue containing at least one valid, non zero
2932 * length Buffer. */
2933 BufferList = ATOMIC_LOAD(&Source->queue);
2934 while(BufferList)
2936 ALbuffer *buffer;
2937 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2938 break;
2939 BufferList = BufferList->next;
2942 if(Source->state != AL_PAUSED)
2944 Source->state = AL_PLAYING;
2945 ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed);
2946 ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed);
2947 ATOMIC_STORE(&Source->position_fraction, 0);
2948 discontinuity = AL_TRUE;
2950 else
2952 Source->state = AL_PLAYING;
2953 discontinuity = AL_FALSE;
2956 // Check if an Offset has been set
2957 if(Source->OffsetType != AL_NONE)
2959 ApplyOffset(Source);
2960 /* discontinuity = AL_TRUE;??? */
2963 /* If there's nothing to play, or device is disconnected, go right to
2964 * stopped */
2965 if(!BufferList || !device->Connected)
2966 goto do_stop;
2968 /* Make sure this source isn't already active, while looking for an
2969 * unused active source slot to put it in. */
2970 for(i = 0;i < Context->VoiceCount;i++)
2972 ALsource *old = Source;
2973 if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL))
2975 if(voice == NULL)
2977 voice = &Context->Voices[i];
2978 voice->Source = Source;
2980 break;
2982 old = NULL;
2983 if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source))
2984 voice = &Context->Voices[i];
2986 if(voice == NULL)
2988 voice = &Context->Voices[Context->VoiceCount++];
2989 voice->Source = Source;
2992 if(discontinuity)
2994 /* Clear previous samples if playback is discontinuous. */
2995 memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
2997 /* Clear the stepping value so the mixer knows not to mix this
2998 * until the update gets applied.
3000 voice->Step = 0;
3003 voice->Moving = AL_FALSE;
3004 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
3006 ALsizei j;
3007 for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
3008 voice->Chan[i].Direct.Hrtf.State.History[j] = 0.0f;
3009 for(j = 0;j < HRIR_LENGTH;j++)
3011 voice->Chan[i].Direct.Hrtf.State.Values[j][0] = 0.0f;
3012 voice->Chan[i].Direct.Hrtf.State.Values[j][1] = 0.0f;
3016 UpdateSourceProps(Source, device->NumAuxSends, Context);
3018 else if(state == AL_PAUSED)
3020 if(Source->state == AL_PLAYING)
3021 Source->state = AL_PAUSED;
3023 else if(state == AL_STOPPED)
3025 do_stop:
3026 if(Source->state != AL_INITIAL)
3028 Source->state = AL_STOPPED;
3029 ATOMIC_STORE(&Source->current_buffer, NULL);
3031 Source->OffsetType = AL_NONE;
3032 Source->Offset = 0.0;
3034 else if(state == AL_INITIAL)
3036 if(Source->state != AL_INITIAL)
3038 Source->state = AL_INITIAL;
3039 ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue),
3040 almemory_order_relaxed);
3041 ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed);
3042 ATOMIC_STORE(&Source->position_fraction, 0);
3044 Source->OffsetType = AL_NONE;
3045 Source->Offset = 0.0;
3047 WriteUnlock(&Source->queue_lock);
3050 /* GetSourceSampleOffset
3052 * Gets the current read offset for the given Source, in 32.32 fixed-point
3053 * samples. The offset is relative to the start of the queue (not the start of
3054 * the current buffer).
3056 ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime)
3058 const ALbufferlistitem *BufferList;
3059 const ALbufferlistitem *Current;
3060 ALuint64 readPos;
3061 ALuint refcount;
3063 ReadLock(&Source->queue_lock);
3064 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
3066 ReadUnlock(&Source->queue_lock);
3067 do {
3068 while(((refcount=ReadRef(&device->MixCount))&1))
3069 althrd_yield();
3070 *clocktime = GetDeviceClockTime(device);
3071 } while(refcount != ReadRef(&device->MixCount));
3072 return 0;
3075 do {
3076 while(((refcount=ReadRef(&device->MixCount))&1))
3077 althrd_yield();
3078 *clocktime = GetDeviceClockTime(device);
3080 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3081 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3083 readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << 32;
3084 readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed) <<
3085 (32-FRACTIONBITS);
3086 } while(refcount != ReadRef(&device->MixCount));
3087 while(BufferList && BufferList != Current)
3089 if(BufferList->buffer)
3090 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
3091 BufferList = BufferList->next;
3094 ReadUnlock(&Source->queue_lock);
3095 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
3098 /* GetSourceSecOffset
3100 * Gets the current read offset for the given Source, in seconds. The offset is
3101 * relative to the start of the queue (not the start of the current buffer).
3103 static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime)
3105 const ALbufferlistitem *BufferList;
3106 const ALbufferlistitem *Current;
3107 const ALbuffer *Buffer = NULL;
3108 ALuint64 readPos;
3109 ALuint refcount;
3111 ReadLock(&Source->queue_lock);
3112 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
3114 ReadUnlock(&Source->queue_lock);
3115 do {
3116 while(((refcount=ReadRef(&device->MixCount))&1))
3117 althrd_yield();
3118 *clocktime = GetDeviceClockTime(device);
3119 } while(refcount != ReadRef(&device->MixCount));
3120 return 0.0;
3123 do {
3124 while(((refcount=ReadRef(&device->MixCount))&1))
3125 althrd_yield();
3126 *clocktime = GetDeviceClockTime(device);
3128 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3129 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3131 readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed)<<FRACTIONBITS;
3132 readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed);
3133 } while(refcount != ReadRef(&device->MixCount));
3134 while(BufferList && BufferList != Current)
3136 const ALbuffer *buffer = BufferList->buffer;
3137 if(buffer != NULL)
3139 if(!Buffer) Buffer = buffer;
3140 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
3142 BufferList = BufferList->next;
3145 while(BufferList && !Buffer)
3147 Buffer = BufferList->buffer;
3148 BufferList = BufferList->next;
3150 assert(Buffer != NULL);
3152 ReadUnlock(&Source->queue_lock);
3153 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
3156 /* GetSourceOffset
3158 * Gets the current read offset for the given Source, in the appropriate format
3159 * (Bytes, Samples or Seconds). The offset is relative to the start of the
3160 * queue (not the start of the current buffer).
3162 static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device)
3164 const ALbufferlistitem *BufferList;
3165 const ALbufferlistitem *Current;
3166 const ALbuffer *Buffer = NULL;
3167 ALboolean readFin = AL_FALSE;
3168 ALuint readPos, readPosFrac;
3169 ALuint totalBufferLen;
3170 ALdouble offset = 0.0;
3171 ALuint refcount;
3173 ReadLock(&Source->queue_lock);
3174 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
3176 ReadUnlock(&Source->queue_lock);
3177 return 0.0;
3180 totalBufferLen = 0;
3181 do {
3182 while(((refcount=ReadRef(&device->MixCount))&1))
3183 althrd_yield();
3184 BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed);
3185 Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed);
3187 readPos = ATOMIC_LOAD(&Source->position, almemory_order_relaxed);
3188 readPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed);
3189 } while(refcount != ReadRef(&device->MixCount));
3191 while(BufferList != NULL)
3193 const ALbuffer *buffer;
3194 readFin = readFin || (BufferList == Current);
3195 if((buffer=BufferList->buffer) != NULL)
3197 if(!Buffer) Buffer = buffer;
3198 totalBufferLen += buffer->SampleLen;
3199 if(!readFin) readPos += buffer->SampleLen;
3201 BufferList = BufferList->next;
3203 assert(Buffer != NULL);
3205 if(Source->Looping)
3206 readPos %= totalBufferLen;
3207 else
3209 /* Wrap back to 0 */
3210 if(readPos >= totalBufferLen)
3211 readPos = readPosFrac = 0;
3214 switch(name)
3216 case AL_SEC_OFFSET:
3217 offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
3218 break;
3220 case AL_SAMPLE_OFFSET:
3221 offset = readPos + (ALdouble)readPosFrac/FRACTIONONE;
3222 break;
3224 case AL_BYTE_OFFSET:
3225 if(Buffer->OriginalType == UserFmtIMA4)
3227 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3228 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3229 ALuint FrameBlockSize = Buffer->OriginalAlign;
3231 /* Round down to nearest ADPCM block */
3232 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3234 else if(Buffer->OriginalType == UserFmtMSADPCM)
3236 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3237 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
3238 ALuint FrameBlockSize = Buffer->OriginalAlign;
3240 /* Round down to nearest ADPCM block */
3241 offset = (ALdouble)(readPos / FrameBlockSize * BlockSize);
3243 else
3245 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3246 offset = (ALdouble)(readPos * FrameSize);
3248 break;
3251 ReadUnlock(&Source->queue_lock);
3252 return offset;
3256 /* ApplyOffset
3258 * Apply the stored playback offset to the Source. This function will update
3259 * the number of buffers "played" given the stored offset.
3261 ALboolean ApplyOffset(ALsource *Source)
3263 ALbufferlistitem *BufferList;
3264 const ALbuffer *Buffer;
3265 ALuint bufferLen, totalBufferLen;
3266 ALuint offset=0, frac=0;
3268 /* Get sample frame offset */
3269 if(!GetSampleOffset(Source, &offset, &frac))
3270 return AL_FALSE;
3272 totalBufferLen = 0;
3273 BufferList = ATOMIC_LOAD(&Source->queue);
3274 while(BufferList && totalBufferLen <= offset)
3276 Buffer = BufferList->buffer;
3277 bufferLen = Buffer ? Buffer->SampleLen : 0;
3279 if(bufferLen > offset-totalBufferLen)
3281 /* Offset is in this buffer */
3282 ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed);
3284 ATOMIC_STORE(&Source->position, offset - totalBufferLen, almemory_order_relaxed);
3285 ATOMIC_STORE(&Source->position_fraction, frac);
3286 return AL_TRUE;
3289 totalBufferLen += bufferLen;
3291 BufferList = BufferList->next;
3294 /* Offset is out of range of the queue */
3295 return AL_FALSE;
3299 /* GetSampleOffset
3301 * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3302 * or Second offset supplied by the application). This takes into account the
3303 * fact that the buffer format may have been modifed since.
3305 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
3307 const ALbuffer *Buffer = NULL;
3308 const ALbufferlistitem *BufferList;
3309 ALdouble dbloff, dblfrac;
3311 /* Find the first valid Buffer in the Queue */
3312 BufferList = ATOMIC_LOAD(&Source->queue);
3313 while(BufferList)
3315 if(BufferList->buffer)
3317 Buffer = BufferList->buffer;
3318 break;
3320 BufferList = BufferList->next;
3322 if(!Buffer)
3324 Source->OffsetType = AL_NONE;
3325 Source->Offset = 0.0;
3326 return AL_FALSE;
3329 switch(Source->OffsetType)
3331 case AL_BYTE_OFFSET:
3332 /* Determine the ByteOffset (and ensure it is block aligned) */
3333 *offset = (ALuint)Source->Offset;
3334 if(Buffer->OriginalType == UserFmtIMA4)
3336 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3337 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3338 *offset *= Buffer->OriginalAlign;
3340 else if(Buffer->OriginalType == UserFmtMSADPCM)
3342 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3343 *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3344 *offset *= Buffer->OriginalAlign;
3346 else
3347 *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3348 *frac = 0;
3349 break;
3351 case AL_SAMPLE_OFFSET:
3352 dblfrac = modf(Source->Offset, &dbloff);
3353 *offset = (ALuint)mind(dbloff, UINT_MAX);
3354 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3355 break;
3357 case AL_SEC_OFFSET:
3358 dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
3359 *offset = (ALuint)mind(dbloff, UINT_MAX);
3360 *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3361 break;
3363 Source->OffsetType = AL_NONE;
3364 Source->Offset = 0.0;
3366 return AL_TRUE;
3370 /* ReleaseALSources
3372 * Destroys all sources in the source map.
3374 ALvoid ReleaseALSources(ALCcontext *Context)
3376 ALsizei pos;
3377 for(pos = 0;pos < Context->SourceMap.size;pos++)
3379 ALsource *temp = Context->SourceMap.values[pos];
3380 Context->SourceMap.values[pos] = NULL;
3382 DeinitSource(temp);
3384 FreeThunkEntry(temp->id);
3385 memset(temp, 0, sizeof(*temp));
3386 al_free(temp);