Use an ATOMIC_INIT macro instead of ATOMIC_LOAD_UNSAFE
[openal-soft.git] / OpenAL32 / alSource.c
blob155a7f8bde8efce1859b2f070d7746379a5648cf
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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <math.h>
25 #include <float.h>
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alMain.h"
30 #include "alError.h"
31 #include "alSource.h"
32 #include "alBuffer.h"
33 #include "alThunk.h"
34 #include "alAuxEffectSlot.h"
36 #include "threads.h"
39 enum Resampler DefaultResampler = LinearResampler;
40 const ALsizei ResamplerPadding[ResamplerMax] = {
41 0, /* Point */
42 1, /* Linear */
43 2, /* Cubic */
45 const ALsizei ResamplerPrePadding[ResamplerMax] = {
46 0, /* Point */
47 0, /* Linear */
48 1, /* Cubic */
52 extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
53 extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
55 static ALvoid InitSourceParams(ALsource *Source);
56 static ALint64 GetSourceOffset(const ALsource *Source);
57 static ALdouble GetSourceSecOffset(const ALsource *Source);
58 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
59 static ALint GetSampleOffset(ALsource *Source);
61 typedef enum SrcFloatProp {
62 sfPitch = AL_PITCH,
63 sfGain = AL_GAIN,
64 sfMinGain = AL_MIN_GAIN,
65 sfMaxGain = AL_MAX_GAIN,
66 sfMaxDistance = AL_MAX_DISTANCE,
67 sfRolloffFactor = AL_ROLLOFF_FACTOR,
68 sfDopplerFactor = AL_DOPPLER_FACTOR,
69 sfConeOuterGain = AL_CONE_OUTER_GAIN,
70 sfSecOffset = AL_SEC_OFFSET,
71 sfSampleOffset = AL_SAMPLE_OFFSET,
72 sfByteOffset = AL_BYTE_OFFSET,
73 sfConeInnerAngle = AL_CONE_INNER_ANGLE,
74 sfConeOuterAngle = AL_CONE_OUTER_ANGLE,
75 sfRefDistance = AL_REFERENCE_DISTANCE,
77 sfPosition = AL_POSITION,
78 sfVelocity = AL_VELOCITY,
79 sfDirection = AL_DIRECTION,
81 sfSourceRelative = AL_SOURCE_RELATIVE,
82 sfLooping = AL_LOOPING,
83 sfBuffer = AL_BUFFER,
84 sfSourceState = AL_SOURCE_STATE,
85 sfBuffersQueued = AL_BUFFERS_QUEUED,
86 sfBuffersProcessed = AL_BUFFERS_PROCESSED,
87 sfSourceType = AL_SOURCE_TYPE,
89 /* ALC_EXT_EFX */
90 sfConeOuterGainHF = AL_CONE_OUTER_GAINHF,
91 sfAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
92 sfRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
93 sfDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
94 sfAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
95 sfAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
97 /* AL_SOFT_direct_channels */
98 sfDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
100 /* AL_EXT_source_distance_model */
101 sfDistanceModel = AL_DISTANCE_MODEL,
103 sfSecLength = AL_SEC_LENGTH_SOFT,
105 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
106 sfSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
107 sfByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
109 /* AL_SOFT_source_latency */
110 sfSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
111 } SrcFloatProp;
113 typedef enum SrcIntProp {
114 siMaxDistance = AL_MAX_DISTANCE,
115 siRolloffFactor = AL_ROLLOFF_FACTOR,
116 siRefDistance = AL_REFERENCE_DISTANCE,
117 siSourceRelative = AL_SOURCE_RELATIVE,
118 siConeInnerAngle = AL_CONE_INNER_ANGLE,
119 siConeOuterAngle = AL_CONE_OUTER_ANGLE,
120 siLooping = AL_LOOPING,
121 siBuffer = AL_BUFFER,
122 siSourceState = AL_SOURCE_STATE,
123 siBuffersQueued = AL_BUFFERS_QUEUED,
124 siBuffersProcessed = AL_BUFFERS_PROCESSED,
125 siSourceType = AL_SOURCE_TYPE,
126 siSecOffset = AL_SEC_OFFSET,
127 siSampleOffset = AL_SAMPLE_OFFSET,
128 siByteOffset = AL_BYTE_OFFSET,
129 siDopplerFactor = AL_DOPPLER_FACTOR,
130 siPosition = AL_POSITION,
131 siVelocity = AL_VELOCITY,
132 siDirection = AL_DIRECTION,
134 /* ALC_EXT_EFX */
135 siDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
136 siAuxSendFilterGainAutio = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
137 siAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
138 siDirectFilter = AL_DIRECT_FILTER,
139 siAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
141 /* AL_SOFT_direct_channels */
142 siDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
144 /* AL_EXT_source_distance_model */
145 siDistanceModel = AL_DISTANCE_MODEL,
147 siByteLength = AL_BYTE_LENGTH_SOFT,
148 siSampleLength = AL_SAMPLE_LENGTH_SOFT,
150 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
151 siSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
152 siByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
154 /* AL_SOFT_source_latency */
155 siSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
156 } SrcIntProp;
158 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values);
159 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values);
160 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values);
162 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values);
163 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values);
164 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values);
166 static ALint FloatValsByProp(ALenum prop)
168 if(prop != (ALenum)((SrcFloatProp)prop))
169 return 0;
170 switch((SrcFloatProp)prop)
172 case sfPitch:
173 case sfGain:
174 case sfMinGain:
175 case sfMaxGain:
176 case sfMaxDistance:
177 case sfRolloffFactor:
178 case sfDopplerFactor:
179 case sfConeOuterGain:
180 case sfSecOffset:
181 case sfSampleOffset:
182 case sfByteOffset:
183 case sfConeInnerAngle:
184 case sfConeOuterAngle:
185 case sfRefDistance:
186 case sfConeOuterGainHF:
187 case sfAirAbsorptionFactor:
188 case sfRoomRolloffFactor:
189 case sfDirectFilterGainHFAuto:
190 case sfAuxSendFilterGainAuto:
191 case sfAuxSendFilterGainHFAuto:
192 case sfDirectChannelsSOFT:
193 case sfDistanceModel:
194 case sfSourceRelative:
195 case sfLooping:
196 case sfBuffer:
197 case sfSourceState:
198 case sfBuffersQueued:
199 case sfBuffersProcessed:
200 case sfSourceType:
201 case sfSecLength:
202 return 1;
204 case sfSampleRWOffsetsSOFT:
205 case sfByteRWOffsetsSOFT:
206 return 2;
208 case sfPosition:
209 case sfVelocity:
210 case sfDirection:
211 return 3;
213 case sfSecOffsetLatencySOFT:
214 break; /* Double only */
216 return 0;
218 static ALint DoubleValsByProp(ALenum prop)
220 if(prop != (ALenum)((SrcFloatProp)prop))
221 return 0;
222 switch((SrcFloatProp)prop)
224 case sfPitch:
225 case sfGain:
226 case sfMinGain:
227 case sfMaxGain:
228 case sfMaxDistance:
229 case sfRolloffFactor:
230 case sfDopplerFactor:
231 case sfConeOuterGain:
232 case sfSecOffset:
233 case sfSampleOffset:
234 case sfByteOffset:
235 case sfConeInnerAngle:
236 case sfConeOuterAngle:
237 case sfRefDistance:
238 case sfConeOuterGainHF:
239 case sfAirAbsorptionFactor:
240 case sfRoomRolloffFactor:
241 case sfDirectFilterGainHFAuto:
242 case sfAuxSendFilterGainAuto:
243 case sfAuxSendFilterGainHFAuto:
244 case sfDirectChannelsSOFT:
245 case sfDistanceModel:
246 case sfSourceRelative:
247 case sfLooping:
248 case sfBuffer:
249 case sfSourceState:
250 case sfBuffersQueued:
251 case sfBuffersProcessed:
252 case sfSourceType:
253 case sfSecLength:
254 return 1;
256 case sfSampleRWOffsetsSOFT:
257 case sfByteRWOffsetsSOFT:
258 case sfSecOffsetLatencySOFT:
259 return 2;
261 case sfPosition:
262 case sfVelocity:
263 case sfDirection:
264 return 3;
266 return 0;
269 static ALint IntValsByProp(ALenum prop)
271 if(prop != (ALenum)((SrcIntProp)prop))
272 return 0;
273 switch((SrcIntProp)prop)
275 case siMaxDistance:
276 case siRolloffFactor:
277 case siRefDistance:
278 case siSourceRelative:
279 case siConeInnerAngle:
280 case siConeOuterAngle:
281 case siLooping:
282 case siBuffer:
283 case siSourceState:
284 case siBuffersQueued:
285 case siBuffersProcessed:
286 case siSourceType:
287 case siSecOffset:
288 case siSampleOffset:
289 case siByteOffset:
290 case siDopplerFactor:
291 case siDirectFilterGainHFAuto:
292 case siAuxSendFilterGainAutio:
293 case siAuxSendFilterGainHFAuto:
294 case siDirectFilter:
295 case siDirectChannelsSOFT:
296 case siDistanceModel:
297 case siByteLength:
298 case siSampleLength:
299 return 1;
301 case siSampleRWOffsetsSOFT:
302 case siByteRWOffsetsSOFT:
303 return 2;
305 case siPosition:
306 case siVelocity:
307 case siDirection:
308 case siAuxSendFilter:
309 return 3;
311 case siSampleOffsetLatencySOFT:
312 break; /* i64 only */
314 return 0;
316 static ALint Int64ValsByProp(ALenum prop)
318 if(prop != (ALenum)((SrcIntProp)prop))
319 return 0;
320 switch((SrcIntProp)prop)
322 case siMaxDistance:
323 case siRolloffFactor:
324 case siRefDistance:
325 case siSourceRelative:
326 case siConeInnerAngle:
327 case siConeOuterAngle:
328 case siLooping:
329 case siBuffer:
330 case siSourceState:
331 case siBuffersQueued:
332 case siBuffersProcessed:
333 case siSourceType:
334 case siSecOffset:
335 case siSampleOffset:
336 case siByteOffset:
337 case siDopplerFactor:
338 case siDirectFilterGainHFAuto:
339 case siAuxSendFilterGainAutio:
340 case siAuxSendFilterGainHFAuto:
341 case siDirectFilter:
342 case siDirectChannelsSOFT:
343 case siDistanceModel:
344 case siByteLength:
345 case siSampleLength:
346 return 1;
348 case siSampleRWOffsetsSOFT:
349 case siByteRWOffsetsSOFT:
350 case siSampleOffsetLatencySOFT:
351 return 2;
353 case siPosition:
354 case siVelocity:
355 case siDirection:
356 case siAuxSendFilter:
357 return 3;
359 return 0;
363 #define CHECKVAL(x) do { \
364 if(!(x)) \
365 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
366 } while(0)
368 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values)
370 ALint ival;
372 switch(prop)
374 case AL_PITCH:
375 CHECKVAL(*values >= 0.0f);
377 Source->Pitch = *values;
378 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
379 return AL_TRUE;
381 case AL_CONE_INNER_ANGLE:
382 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
384 Source->InnerAngle = *values;
385 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
386 return AL_TRUE;
388 case AL_CONE_OUTER_ANGLE:
389 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
391 Source->OuterAngle = *values;
392 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
393 return AL_TRUE;
395 case AL_GAIN:
396 CHECKVAL(*values >= 0.0f);
398 Source->Gain = *values;
399 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
400 return AL_TRUE;
402 case AL_MAX_DISTANCE:
403 CHECKVAL(*values >= 0.0f);
405 Source->MaxDistance = *values;
406 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
407 return AL_TRUE;
409 case AL_ROLLOFF_FACTOR:
410 CHECKVAL(*values >= 0.0f);
412 Source->RollOffFactor = *values;
413 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
414 return AL_TRUE;
416 case AL_REFERENCE_DISTANCE:
417 CHECKVAL(*values >= 0.0f);
419 Source->RefDistance = *values;
420 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
421 return AL_TRUE;
423 case AL_MIN_GAIN:
424 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
426 Source->MinGain = *values;
427 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
428 return AL_TRUE;
430 case AL_MAX_GAIN:
431 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
433 Source->MaxGain = *values;
434 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
435 return AL_TRUE;
437 case AL_CONE_OUTER_GAIN:
438 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
440 Source->OuterGain = *values;
441 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
442 return AL_TRUE;
444 case AL_CONE_OUTER_GAINHF:
445 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
447 Source->OuterGainHF = *values;
448 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
449 return AL_TRUE;
451 case AL_AIR_ABSORPTION_FACTOR:
452 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
454 Source->AirAbsorptionFactor = *values;
455 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
456 return AL_TRUE;
458 case AL_ROOM_ROLLOFF_FACTOR:
459 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
461 Source->RoomRolloffFactor = *values;
462 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
463 return AL_TRUE;
465 case AL_DOPPLER_FACTOR:
466 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
468 Source->DopplerFactor = *values;
469 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
470 return AL_TRUE;
472 case AL_SEC_OFFSET:
473 case AL_SAMPLE_OFFSET:
474 case AL_BYTE_OFFSET:
475 CHECKVAL(*values >= 0.0f);
477 LockContext(Context);
478 Source->OffsetType = prop;
479 Source->Offset = *values;
481 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
482 !Context->DeferUpdates)
484 if(ApplyOffset(Source) == AL_FALSE)
486 UnlockContext(Context);
487 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
490 UnlockContext(Context);
491 return AL_TRUE;
494 case sfSecLength:
495 case AL_SEC_OFFSET_LATENCY_SOFT:
496 /* Query only */
497 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
500 case AL_POSITION:
501 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
503 LockContext(Context);
504 Source->Position[0] = values[0];
505 Source->Position[1] = values[1];
506 Source->Position[2] = values[2];
507 UnlockContext(Context);
508 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
509 return AL_TRUE;
511 case AL_VELOCITY:
512 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
514 LockContext(Context);
515 Source->Velocity[0] = values[0];
516 Source->Velocity[1] = values[1];
517 Source->Velocity[2] = values[2];
518 UnlockContext(Context);
519 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
520 return AL_TRUE;
522 case AL_DIRECTION:
523 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
525 LockContext(Context);
526 Source->Orientation[0] = values[0];
527 Source->Orientation[1] = values[1];
528 Source->Orientation[2] = values[2];
529 UnlockContext(Context);
530 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
531 return AL_TRUE;
534 case sfSampleRWOffsetsSOFT:
535 case sfByteRWOffsetsSOFT:
536 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
539 case sfSourceRelative:
540 case sfLooping:
541 case sfSourceState:
542 case sfSourceType:
543 case sfDistanceModel:
544 case sfDirectFilterGainHFAuto:
545 case sfAuxSendFilterGainAuto:
546 case sfAuxSendFilterGainHFAuto:
547 case sfDirectChannelsSOFT:
548 ival = (ALint)values[0];
549 return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival);
551 case sfBuffer:
552 case sfBuffersQueued:
553 case sfBuffersProcessed:
554 ival = (ALint)((ALuint)values[0]);
555 return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival);
558 ERR("Unexpected property: 0x%04x\n", prop);
559 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
562 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values)
564 ALCdevice *device = Context->Device;
565 ALbuffer *buffer = NULL;
566 ALfilter *filter = NULL;
567 ALeffectslot *slot = NULL;
568 ALbufferlistitem *oldlist;
569 ALbufferlistitem *newlist;
570 ALfloat fvals[3];
572 switch(prop)
574 case AL_SOURCE_RELATIVE:
575 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
577 Source->HeadRelative = (ALboolean)*values;
578 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
579 return AL_TRUE;
581 case AL_LOOPING:
582 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
584 Source->Looping = (ALboolean)*values;
585 return AL_TRUE;
587 case AL_BUFFER:
588 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
590 WriteLock(&Source->queue_lock);
591 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
593 WriteUnlock(&Source->queue_lock);
594 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
597 if(buffer != NULL)
599 /* Add the selected buffer to a one-item queue */
600 newlist = malloc(sizeof(ALbufferlistitem));
601 newlist->buffer = buffer;
602 newlist->next = NULL;
603 newlist->prev = NULL;
604 IncrementRef(&buffer->ref);
606 /* Source is now Static */
607 Source->SourceType = AL_STATIC;
609 ReadLock(&buffer->lock);
610 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
611 Source->SampleSize = BytesFromFmt(buffer->FmtType);
612 ReadUnlock(&buffer->lock);
614 else
616 /* Source is now Undetermined */
617 Source->SourceType = AL_UNDETERMINED;
618 newlist = NULL;
620 oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist);
621 ATOMIC_STORE(&Source->current_buffer, newlist);
622 WriteUnlock(&Source->queue_lock);
624 /* Delete all elements in the previous queue */
625 while(oldlist != NULL)
627 ALbufferlistitem *temp = oldlist;
628 oldlist = temp->next;
630 if(temp->buffer)
631 DecrementRef(&temp->buffer->ref);
632 free(temp);
634 return AL_TRUE;
636 case siSourceState:
637 case siSourceType:
638 case siBuffersQueued:
639 case siBuffersProcessed:
640 /* Query only */
641 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
643 case AL_SEC_OFFSET:
644 case AL_SAMPLE_OFFSET:
645 case AL_BYTE_OFFSET:
646 CHECKVAL(*values >= 0);
648 LockContext(Context);
649 Source->OffsetType = prop;
650 Source->Offset = *values;
652 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
653 !Context->DeferUpdates)
655 if(ApplyOffset(Source) == AL_FALSE)
657 UnlockContext(Context);
658 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
661 UnlockContext(Context);
662 return AL_TRUE;
665 case siByteLength:
666 case siSampleLength:
667 case siSampleRWOffsetsSOFT:
668 case siByteRWOffsetsSOFT:
669 /* Query only */
670 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
673 case AL_DIRECT_FILTER:
674 CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
676 LockContext(Context);
677 if(!filter)
679 Source->Direct.Gain = 1.0f;
680 Source->Direct.GainHF = 1.0f;
681 Source->Direct.HFReference = LOWPASSFREQREF;
682 Source->Direct.GainLF = 1.0f;
683 Source->Direct.LFReference = HIGHPASSFREQREF;
685 else
687 Source->Direct.Gain = filter->Gain;
688 Source->Direct.GainHF = filter->GainHF;
689 Source->Direct.HFReference = filter->HFReference;
690 Source->Direct.GainLF = filter->GainLF;
691 Source->Direct.LFReference = filter->LFReference;
693 UnlockContext(Context);
694 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
695 return AL_TRUE;
697 case AL_DIRECT_FILTER_GAINHF_AUTO:
698 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
700 Source->DryGainHFAuto = *values;
701 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
702 return AL_TRUE;
704 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
705 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
707 Source->WetGainAuto = *values;
708 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
709 return AL_TRUE;
711 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
712 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
714 Source->WetGainHFAuto = *values;
715 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
716 return AL_TRUE;
718 case AL_DIRECT_CHANNELS_SOFT:
719 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
721 Source->DirectChannels = *values;
722 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
723 return AL_TRUE;
725 case AL_DISTANCE_MODEL:
726 CHECKVAL(*values == AL_NONE ||
727 *values == AL_INVERSE_DISTANCE ||
728 *values == AL_INVERSE_DISTANCE_CLAMPED ||
729 *values == AL_LINEAR_DISTANCE ||
730 *values == AL_LINEAR_DISTANCE_CLAMPED ||
731 *values == AL_EXPONENT_DISTANCE ||
732 *values == AL_EXPONENT_DISTANCE_CLAMPED);
734 Source->DistanceModel = *values;
735 if(Context->SourceDistanceModel)
736 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
737 return AL_TRUE;
740 case AL_AUXILIARY_SEND_FILTER:
741 LockContext(Context);
742 if(!((ALuint)values[1] < device->NumAuxSends &&
743 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
744 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
746 UnlockContext(Context);
747 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
750 /* Add refcount on the new slot, and release the previous slot */
751 if(slot) IncrementRef(&slot->ref);
752 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
753 if(slot) DecrementRef(&slot->ref);
755 if(!filter)
757 /* Disable filter */
758 Source->Send[values[1]].Gain = 1.0f;
759 Source->Send[values[1]].GainHF = 1.0f;
760 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
761 Source->Send[values[1]].GainLF = 1.0f;
762 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
764 else
766 Source->Send[values[1]].Gain = filter->Gain;
767 Source->Send[values[1]].GainHF = filter->GainHF;
768 Source->Send[values[1]].HFReference = filter->HFReference;
769 Source->Send[values[1]].GainLF = filter->GainLF;
770 Source->Send[values[1]].LFReference = filter->LFReference;
772 UnlockContext(Context);
773 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
774 return AL_TRUE;
777 case AL_MAX_DISTANCE:
778 case AL_ROLLOFF_FACTOR:
779 case AL_CONE_INNER_ANGLE:
780 case AL_CONE_OUTER_ANGLE:
781 case AL_REFERENCE_DISTANCE:
782 case siDopplerFactor:
783 fvals[0] = (ALfloat)*values;
784 return SetSourcefv(Source, Context, (int)prop, fvals);
786 case AL_POSITION:
787 case AL_VELOCITY:
788 case AL_DIRECTION:
789 fvals[0] = (ALfloat)values[0];
790 fvals[1] = (ALfloat)values[1];
791 fvals[2] = (ALfloat)values[2];
792 return SetSourcefv(Source, Context, (int)prop, fvals);
794 case siSampleOffsetLatencySOFT:
795 /* i64 only */
796 break;
799 ERR("Unexpected property: 0x%04x\n", prop);
800 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
803 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values)
805 ALfloat fvals[3];
806 ALint ivals[3];
808 switch(prop)
810 case siSampleRWOffsetsSOFT:
811 case siByteRWOffsetsSOFT:
812 case siSampleOffsetLatencySOFT:
813 /* Query only */
814 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
817 /* 1x int */
818 case AL_SOURCE_RELATIVE:
819 case AL_LOOPING:
820 case AL_SOURCE_STATE:
821 case AL_BYTE_OFFSET:
822 case AL_SAMPLE_OFFSET:
823 case siByteLength:
824 case siSampleLength:
825 case siSourceType:
826 case siBuffersQueued:
827 case siBuffersProcessed:
828 case AL_DIRECT_FILTER_GAINHF_AUTO:
829 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
830 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
831 case AL_DIRECT_CHANNELS_SOFT:
832 case AL_DISTANCE_MODEL:
833 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
835 ivals[0] = (ALint)*values;
836 return SetSourceiv(Source, Context, (int)prop, ivals);
838 /* 1x uint */
839 case AL_BUFFER:
840 case AL_DIRECT_FILTER:
841 CHECKVAL(*values <= UINT_MAX && *values >= 0);
843 ivals[0] = (ALuint)*values;
844 return SetSourceiv(Source, Context, (int)prop, ivals);
846 /* 3x uint */
847 case AL_AUXILIARY_SEND_FILTER:
848 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
849 values[1] <= UINT_MAX && values[1] >= 0 &&
850 values[2] <= UINT_MAX && values[2] >= 0);
852 ivals[0] = (ALuint)values[0];
853 ivals[1] = (ALuint)values[1];
854 ivals[2] = (ALuint)values[2];
855 return SetSourceiv(Source, Context, (int)prop, ivals);
857 /* 1x float */
858 case AL_MAX_DISTANCE:
859 case AL_ROLLOFF_FACTOR:
860 case AL_CONE_INNER_ANGLE:
861 case AL_CONE_OUTER_ANGLE:
862 case AL_REFERENCE_DISTANCE:
863 case AL_SEC_OFFSET:
864 case siDopplerFactor:
865 fvals[0] = (ALfloat)*values;
866 return SetSourcefv(Source, Context, (int)prop, fvals);
868 /* 3x float */
869 case AL_POSITION:
870 case AL_VELOCITY:
871 case AL_DIRECTION:
872 fvals[0] = (ALfloat)values[0];
873 fvals[1] = (ALfloat)values[1];
874 fvals[2] = (ALfloat)values[2];
875 return SetSourcefv(Source, Context, (int)prop, fvals);
878 ERR("Unexpected property: 0x%04x\n", prop);
879 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
882 #undef CHECKVAL
885 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values)
887 ALbufferlistitem *BufferList;
888 ALdouble offsets[2];
889 ALdouble updateLen;
890 ALint ivals[3];
891 ALboolean err;
893 switch(prop)
895 case AL_GAIN:
896 *values = Source->Gain;
897 return AL_TRUE;
899 case AL_PITCH:
900 *values = Source->Pitch;
901 return AL_TRUE;
903 case AL_MAX_DISTANCE:
904 *values = Source->MaxDistance;
905 return AL_TRUE;
907 case AL_ROLLOFF_FACTOR:
908 *values = Source->RollOffFactor;
909 return AL_TRUE;
911 case AL_REFERENCE_DISTANCE:
912 *values = Source->RefDistance;
913 return AL_TRUE;
915 case AL_CONE_INNER_ANGLE:
916 *values = Source->InnerAngle;
917 return AL_TRUE;
919 case AL_CONE_OUTER_ANGLE:
920 *values = Source->OuterAngle;
921 return AL_TRUE;
923 case AL_MIN_GAIN:
924 *values = Source->MinGain;
925 return AL_TRUE;
927 case AL_MAX_GAIN:
928 *values = Source->MaxGain;
929 return AL_TRUE;
931 case AL_CONE_OUTER_GAIN:
932 *values = Source->OuterGain;
933 return AL_TRUE;
935 case AL_SEC_OFFSET:
936 case AL_SAMPLE_OFFSET:
937 case AL_BYTE_OFFSET:
938 ReadLock(&Source->queue_lock);
939 LockContext(Context);
940 GetSourceOffsets(Source, prop, offsets, 0.0);
941 UnlockContext(Context);
942 ReadUnlock(&Source->queue_lock);
943 *values = offsets[0];
944 return AL_TRUE;
946 case AL_CONE_OUTER_GAINHF:
947 *values = Source->OuterGainHF;
948 return AL_TRUE;
950 case AL_AIR_ABSORPTION_FACTOR:
951 *values = Source->AirAbsorptionFactor;
952 return AL_TRUE;
954 case AL_ROOM_ROLLOFF_FACTOR:
955 *values = Source->RoomRolloffFactor;
956 return AL_TRUE;
958 case AL_DOPPLER_FACTOR:
959 *values = Source->DopplerFactor;
960 return AL_TRUE;
962 case sfSecLength:
963 ReadLock(&Source->queue_lock);
964 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
965 *values = 0;
966 else
968 ALint length = 0;
969 ALsizei freq = 1;
970 do {
971 ALbuffer *buffer = BufferList->buffer;
972 if(buffer && buffer->SampleLen > 0)
974 freq = buffer->Frequency;
975 length += buffer->SampleLen;
977 } while((BufferList=BufferList->next) != NULL);
978 *values = (ALdouble)length / (ALdouble)freq;
980 ReadUnlock(&Source->queue_lock);
981 return AL_TRUE;
983 case AL_SAMPLE_RW_OFFSETS_SOFT:
984 case AL_BYTE_RW_OFFSETS_SOFT:
985 ReadLock(&Source->queue_lock);
986 LockContext(Context);
987 updateLen = (ALdouble)Context->Device->UpdateSize /
988 Context->Device->Frequency;
989 GetSourceOffsets(Source, prop, values, updateLen);
990 UnlockContext(Context);
991 ReadUnlock(&Source->queue_lock);
992 return AL_TRUE;
994 case AL_SEC_OFFSET_LATENCY_SOFT:
995 ReadLock(&Source->queue_lock);
996 LockContext(Context);
997 values[0] = GetSourceSecOffset(Source);
998 values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) /
999 1000000000.0;
1000 UnlockContext(Context);
1001 ReadUnlock(&Source->queue_lock);
1002 return AL_TRUE;
1004 case AL_POSITION:
1005 LockContext(Context);
1006 values[0] = Source->Position[0];
1007 values[1] = Source->Position[1];
1008 values[2] = Source->Position[2];
1009 UnlockContext(Context);
1010 return AL_TRUE;
1012 case AL_VELOCITY:
1013 LockContext(Context);
1014 values[0] = Source->Velocity[0];
1015 values[1] = Source->Velocity[1];
1016 values[2] = Source->Velocity[2];
1017 UnlockContext(Context);
1018 return AL_TRUE;
1020 case AL_DIRECTION:
1021 LockContext(Context);
1022 values[0] = Source->Orientation[0];
1023 values[1] = Source->Orientation[1];
1024 values[2] = Source->Orientation[2];
1025 UnlockContext(Context);
1026 return AL_TRUE;
1028 case AL_SOURCE_RELATIVE:
1029 case AL_LOOPING:
1030 case AL_BUFFER:
1031 case AL_SOURCE_STATE:
1032 case AL_BUFFERS_QUEUED:
1033 case AL_BUFFERS_PROCESSED:
1034 case AL_SOURCE_TYPE:
1035 case AL_DIRECT_FILTER_GAINHF_AUTO:
1036 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1037 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1038 case AL_DIRECT_CHANNELS_SOFT:
1039 case AL_DISTANCE_MODEL:
1040 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1041 *values = (ALdouble)ivals[0];
1042 return err;
1045 ERR("Unexpected property: 0x%04x\n", prop);
1046 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1049 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values)
1051 ALbufferlistitem *BufferList;
1052 ALdouble dvals[3];
1053 ALboolean err;
1055 switch(prop)
1057 case AL_SOURCE_RELATIVE:
1058 *values = Source->HeadRelative;
1059 return AL_TRUE;
1061 case AL_LOOPING:
1062 *values = Source->Looping;
1063 return AL_TRUE;
1065 case AL_BUFFER:
1066 ReadLock(&Source->queue_lock);
1067 BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) :
1068 ATOMIC_LOAD(&Source->current_buffer);
1069 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1070 ReadUnlock(&Source->queue_lock);
1071 return AL_TRUE;
1073 case AL_SOURCE_STATE:
1074 *values = Source->state;
1075 return AL_TRUE;
1077 case siByteLength:
1078 ReadLock(&Source->queue_lock);
1079 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1080 *values = 0;
1081 else
1083 ALint length = 0;
1084 do {
1085 ALbuffer *buffer = BufferList->buffer;
1086 if(buffer && buffer->SampleLen > 0)
1088 ALuint byte_align, sample_align;
1089 if(buffer->OriginalType == UserFmtIMA4)
1091 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1092 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1093 sample_align = buffer->OriginalAlign;
1095 else if(buffer->OriginalType == UserFmtMSADPCM)
1097 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1098 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1099 sample_align = buffer->OriginalAlign;
1101 else
1103 ALsizei align = buffer->OriginalAlign;
1104 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1105 sample_align = buffer->OriginalAlign;
1108 length += buffer->SampleLen / sample_align * byte_align;
1110 } while((BufferList=BufferList->next) != NULL);
1111 *values = length;
1113 ReadUnlock(&Source->queue_lock);
1114 return AL_TRUE;
1116 case siSampleLength:
1117 ReadLock(&Source->queue_lock);
1118 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1119 *values = 0;
1120 else
1122 ALint length = 0;
1123 do {
1124 ALbuffer *buffer = BufferList->buffer;
1125 if(buffer) length += buffer->SampleLen;
1126 } while((BufferList=BufferList->next) != NULL);
1127 *values = length;
1129 ReadUnlock(&Source->queue_lock);
1130 return AL_TRUE;
1132 case AL_BUFFERS_QUEUED:
1133 ReadLock(&Source->queue_lock);
1134 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1135 *values = 0;
1136 else
1138 ALsizei count = 0;
1139 do {
1140 ++count;
1141 } while((BufferList=BufferList->next) != NULL);
1142 *values = count;
1144 ReadUnlock(&Source->queue_lock);
1145 return AL_TRUE;
1147 case AL_BUFFERS_PROCESSED:
1148 ReadLock(&Source->queue_lock);
1149 if(Source->Looping || Source->SourceType != AL_STREAMING)
1151 /* Buffers on a looping source are in a perpetual state of
1152 * PENDING, so don't report any as PROCESSED */
1153 *values = 0;
1155 else
1157 const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue);
1158 const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer);
1159 ALsizei played = 0;
1160 while(BufferList && BufferList != Current)
1162 played++;
1163 BufferList = BufferList->next;
1165 *values = played;
1167 ReadUnlock(&Source->queue_lock);
1168 return AL_TRUE;
1170 case AL_SOURCE_TYPE:
1171 *values = Source->SourceType;
1172 return AL_TRUE;
1174 case AL_DIRECT_FILTER_GAINHF_AUTO:
1175 *values = Source->DryGainHFAuto;
1176 return AL_TRUE;
1178 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1179 *values = Source->WetGainAuto;
1180 return AL_TRUE;
1182 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1183 *values = Source->WetGainHFAuto;
1184 return AL_TRUE;
1186 case AL_DIRECT_CHANNELS_SOFT:
1187 *values = Source->DirectChannels;
1188 return AL_TRUE;
1190 case AL_DISTANCE_MODEL:
1191 *values = Source->DistanceModel;
1192 return AL_TRUE;
1194 case AL_MAX_DISTANCE:
1195 case AL_ROLLOFF_FACTOR:
1196 case AL_REFERENCE_DISTANCE:
1197 case AL_CONE_INNER_ANGLE:
1198 case AL_CONE_OUTER_ANGLE:
1199 case AL_SEC_OFFSET:
1200 case AL_SAMPLE_OFFSET:
1201 case AL_BYTE_OFFSET:
1202 case AL_DOPPLER_FACTOR:
1203 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1204 *values = (ALint)dvals[0];
1205 return err;
1207 case AL_SAMPLE_RW_OFFSETS_SOFT:
1208 case AL_BYTE_RW_OFFSETS_SOFT:
1209 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1211 values[0] = (ALint)dvals[0];
1212 values[1] = (ALint)dvals[1];
1214 return err;
1216 case AL_POSITION:
1217 case AL_VELOCITY:
1218 case AL_DIRECTION:
1219 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1221 values[0] = (ALint)dvals[0];
1222 values[1] = (ALint)dvals[1];
1223 values[2] = (ALint)dvals[2];
1225 return err;
1227 case siSampleOffsetLatencySOFT:
1228 /* i64 only */
1229 break;
1231 case siDirectFilter:
1232 case siAuxSendFilter:
1233 /* ??? */
1234 break;
1237 ERR("Unexpected property: 0x%04x\n", prop);
1238 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1241 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values)
1243 ALdouble dvals[3];
1244 ALint ivals[3];
1245 ALboolean err;
1247 switch(prop)
1249 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1250 ReadLock(&Source->queue_lock);
1251 LockContext(Context);
1252 values[0] = GetSourceOffset(Source);
1253 values[1] = ALCdevice_GetLatency(Context->Device);
1254 UnlockContext(Context);
1255 ReadUnlock(&Source->queue_lock);
1256 return AL_TRUE;
1258 case AL_MAX_DISTANCE:
1259 case AL_ROLLOFF_FACTOR:
1260 case AL_REFERENCE_DISTANCE:
1261 case AL_CONE_INNER_ANGLE:
1262 case AL_CONE_OUTER_ANGLE:
1263 case AL_SEC_OFFSET:
1264 case AL_SAMPLE_OFFSET:
1265 case AL_BYTE_OFFSET:
1266 case AL_DOPPLER_FACTOR:
1267 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1268 *values = (ALint64)dvals[0];
1269 return err;
1271 case AL_SAMPLE_RW_OFFSETS_SOFT:
1272 case AL_BYTE_RW_OFFSETS_SOFT:
1273 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1275 values[0] = (ALint64)dvals[0];
1276 values[1] = (ALint64)dvals[1];
1278 return err;
1280 case AL_POSITION:
1281 case AL_VELOCITY:
1282 case AL_DIRECTION:
1283 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1285 values[0] = (ALint64)dvals[0];
1286 values[1] = (ALint64)dvals[1];
1287 values[2] = (ALint64)dvals[2];
1289 return err;
1291 case AL_SOURCE_RELATIVE:
1292 case AL_LOOPING:
1293 case AL_SOURCE_STATE:
1294 case AL_BUFFERS_QUEUED:
1295 case AL_BUFFERS_PROCESSED:
1296 case siByteLength:
1297 case siSampleLength:
1298 case AL_SOURCE_TYPE:
1299 case AL_DIRECT_FILTER_GAINHF_AUTO:
1300 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1301 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1302 case AL_DIRECT_CHANNELS_SOFT:
1303 case AL_DISTANCE_MODEL:
1304 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1305 *values = ivals[0];
1306 return err;
1308 case siBuffer:
1309 case siDirectFilter:
1310 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1311 *values = (ALuint)ivals[0];
1312 return err;
1314 case siAuxSendFilter:
1315 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1317 values[0] = (ALuint)ivals[0];
1318 values[1] = (ALuint)ivals[1];
1319 values[2] = (ALuint)ivals[2];
1321 return err;
1324 ERR("Unexpected property: 0x%04x\n", prop);
1325 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1329 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1331 ALCcontext *context;
1332 ALsizei cur = 0;
1333 ALenum err;
1335 context = GetContextRef();
1336 if(!context) return;
1338 if(!(n >= 0))
1339 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1340 for(cur = 0;cur < n;cur++)
1342 ALsource *source = al_calloc(16, sizeof(ALsource));
1343 if(!source)
1345 alDeleteSources(cur, sources);
1346 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1348 InitSourceParams(source);
1350 err = NewThunkEntry(&source->id);
1351 if(err == AL_NO_ERROR)
1352 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1353 if(err != AL_NO_ERROR)
1355 FreeThunkEntry(source->id);
1356 memset(source, 0, sizeof(ALsource));
1357 al_free(source);
1359 alDeleteSources(cur, sources);
1360 SET_ERROR_AND_GOTO(context, err, done);
1363 sources[cur] = source->id;
1366 done:
1367 ALCcontext_DecRef(context);
1371 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1373 ALCcontext *context;
1374 ALbufferlistitem *BufferList;
1375 ALsource *Source;
1376 ALsizei i, j;
1378 context = GetContextRef();
1379 if(!context) return;
1381 if(!(n >= 0))
1382 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1384 /* Check that all Sources are valid */
1385 for(i = 0;i < n;i++)
1387 if(LookupSource(context, sources[i]) == NULL)
1388 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1390 for(i = 0;i < n;i++)
1392 ALactivesource **srclist, **srclistend;
1394 if((Source=RemoveSource(context, sources[i])) == NULL)
1395 continue;
1396 FreeThunkEntry(Source->id);
1398 LockContext(context);
1399 srclist = context->ActiveSources;
1400 srclistend = srclist + context->ActiveSourceCount;
1401 while(srclist != srclistend)
1403 if((*srclist)->Source == Source)
1405 ALactivesource *temp = *(--srclistend);
1406 *srclistend = *srclist;
1407 *srclist = temp;
1408 --(context->ActiveSourceCount);
1409 break;
1411 srclist++;
1413 UnlockContext(context);
1415 BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, NULL);
1416 while(BufferList != NULL)
1418 ALbufferlistitem *next = BufferList->next;
1419 if(BufferList->buffer != NULL)
1420 DecrementRef(&BufferList->buffer->ref);
1421 free(BufferList);
1422 BufferList = next;
1425 for(j = 0;j < MAX_SENDS;++j)
1427 if(Source->Send[j].Slot)
1428 DecrementRef(&Source->Send[j].Slot->ref);
1429 Source->Send[j].Slot = NULL;
1432 memset(Source, 0, sizeof(*Source));
1433 al_free(Source);
1436 done:
1437 ALCcontext_DecRef(context);
1441 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1443 ALCcontext *context;
1444 ALboolean ret;
1446 context = GetContextRef();
1447 if(!context) return AL_FALSE;
1449 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1451 ALCcontext_DecRef(context);
1453 return ret;
1457 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1459 ALCcontext *Context;
1460 ALsource *Source;
1462 Context = GetContextRef();
1463 if(!Context) return;
1465 if((Source=LookupSource(Context, source)) == NULL)
1466 alSetError(Context, AL_INVALID_NAME);
1467 else if(!(FloatValsByProp(param) == 1))
1468 alSetError(Context, AL_INVALID_ENUM);
1469 else
1470 SetSourcefv(Source, Context, param, &value);
1472 ALCcontext_DecRef(Context);
1475 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1477 ALCcontext *Context;
1478 ALsource *Source;
1480 Context = GetContextRef();
1481 if(!Context) return;
1483 if((Source=LookupSource(Context, source)) == NULL)
1484 alSetError(Context, AL_INVALID_NAME);
1485 else if(!(FloatValsByProp(param) == 3))
1486 alSetError(Context, AL_INVALID_ENUM);
1487 else
1489 ALfloat fvals[3] = { value1, value2, value3 };
1490 SetSourcefv(Source, Context, param, fvals);
1493 ALCcontext_DecRef(Context);
1496 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1498 ALCcontext *Context;
1499 ALsource *Source;
1501 Context = GetContextRef();
1502 if(!Context) return;
1504 if((Source=LookupSource(Context, source)) == NULL)
1505 alSetError(Context, AL_INVALID_NAME);
1506 else if(!values)
1507 alSetError(Context, AL_INVALID_VALUE);
1508 else if(!(FloatValsByProp(param) > 0))
1509 alSetError(Context, AL_INVALID_ENUM);
1510 else
1511 SetSourcefv(Source, Context, param, values);
1513 ALCcontext_DecRef(Context);
1517 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1519 ALCcontext *Context;
1520 ALsource *Source;
1522 Context = GetContextRef();
1523 if(!Context) return;
1525 if((Source=LookupSource(Context, source)) == NULL)
1526 alSetError(Context, AL_INVALID_NAME);
1527 else if(!(DoubleValsByProp(param) == 1))
1528 alSetError(Context, AL_INVALID_ENUM);
1529 else
1531 ALfloat fval = (ALfloat)value;
1532 SetSourcefv(Source, Context, param, &fval);
1535 ALCcontext_DecRef(Context);
1538 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1540 ALCcontext *Context;
1541 ALsource *Source;
1543 Context = GetContextRef();
1544 if(!Context) return;
1546 if((Source=LookupSource(Context, source)) == NULL)
1547 alSetError(Context, AL_INVALID_NAME);
1548 else if(!(DoubleValsByProp(param) == 3))
1549 alSetError(Context, AL_INVALID_ENUM);
1550 else
1552 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1553 SetSourcefv(Source, Context, param, fvals);
1556 ALCcontext_DecRef(Context);
1559 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1561 ALCcontext *Context;
1562 ALsource *Source;
1563 ALint count;
1565 Context = GetContextRef();
1566 if(!Context) return;
1568 if((Source=LookupSource(Context, source)) == NULL)
1569 alSetError(Context, AL_INVALID_NAME);
1570 else if(!values)
1571 alSetError(Context, AL_INVALID_VALUE);
1572 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 3))
1573 alSetError(Context, AL_INVALID_ENUM);
1574 else
1576 ALfloat fvals[3];
1577 ALint i;
1579 for(i = 0;i < count;i++)
1580 fvals[i] = (ALfloat)values[i];
1581 SetSourcefv(Source, Context, param, fvals);
1584 ALCcontext_DecRef(Context);
1588 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1590 ALCcontext *Context;
1591 ALsource *Source;
1593 Context = GetContextRef();
1594 if(!Context) return;
1596 if((Source=LookupSource(Context, source)) == NULL)
1597 alSetError(Context, AL_INVALID_NAME);
1598 else if(!(IntValsByProp(param) == 1))
1599 alSetError(Context, AL_INVALID_ENUM);
1600 else
1601 SetSourceiv(Source, Context, param, &value);
1603 ALCcontext_DecRef(Context);
1606 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1608 ALCcontext *Context;
1609 ALsource *Source;
1611 Context = GetContextRef();
1612 if(!Context) return;
1614 if((Source=LookupSource(Context, source)) == NULL)
1615 alSetError(Context, AL_INVALID_NAME);
1616 else if(!(IntValsByProp(param) == 3))
1617 alSetError(Context, AL_INVALID_ENUM);
1618 else
1620 ALint ivals[3] = { value1, value2, value3 };
1621 SetSourceiv(Source, Context, param, ivals);
1624 ALCcontext_DecRef(Context);
1627 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1629 ALCcontext *Context;
1630 ALsource *Source;
1632 Context = GetContextRef();
1633 if(!Context) return;
1635 if((Source=LookupSource(Context, source)) == NULL)
1636 alSetError(Context, AL_INVALID_NAME);
1637 else if(!values)
1638 alSetError(Context, AL_INVALID_VALUE);
1639 else if(!(IntValsByProp(param) > 0))
1640 alSetError(Context, AL_INVALID_ENUM);
1641 else
1642 SetSourceiv(Source, Context, param, values);
1644 ALCcontext_DecRef(Context);
1648 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1650 ALCcontext *Context;
1651 ALsource *Source;
1653 Context = GetContextRef();
1654 if(!Context) return;
1656 if((Source=LookupSource(Context, source)) == NULL)
1657 alSetError(Context, AL_INVALID_NAME);
1658 else if(!(Int64ValsByProp(param) == 1))
1659 alSetError(Context, AL_INVALID_ENUM);
1660 else
1661 SetSourcei64v(Source, Context, param, &value);
1663 ALCcontext_DecRef(Context);
1666 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1668 ALCcontext *Context;
1669 ALsource *Source;
1671 Context = GetContextRef();
1672 if(!Context) return;
1674 if((Source=LookupSource(Context, source)) == NULL)
1675 alSetError(Context, AL_INVALID_NAME);
1676 else if(!(Int64ValsByProp(param) == 3))
1677 alSetError(Context, AL_INVALID_ENUM);
1678 else
1680 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1681 SetSourcei64v(Source, Context, param, i64vals);
1684 ALCcontext_DecRef(Context);
1687 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1689 ALCcontext *Context;
1690 ALsource *Source;
1692 Context = GetContextRef();
1693 if(!Context) return;
1695 if((Source=LookupSource(Context, source)) == NULL)
1696 alSetError(Context, AL_INVALID_NAME);
1697 else if(!values)
1698 alSetError(Context, AL_INVALID_VALUE);
1699 else if(!(Int64ValsByProp(param) > 0))
1700 alSetError(Context, AL_INVALID_ENUM);
1701 else
1702 SetSourcei64v(Source, Context, param, values);
1704 ALCcontext_DecRef(Context);
1708 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1710 ALCcontext *Context;
1711 ALsource *Source;
1713 Context = GetContextRef();
1714 if(!Context) return;
1716 if((Source=LookupSource(Context, source)) == NULL)
1717 alSetError(Context, AL_INVALID_NAME);
1718 else if(!value)
1719 alSetError(Context, AL_INVALID_VALUE);
1720 else if(!(FloatValsByProp(param) == 1))
1721 alSetError(Context, AL_INVALID_ENUM);
1722 else
1724 ALdouble dval;
1725 if(GetSourcedv(Source, Context, param, &dval))
1726 *value = (ALfloat)dval;
1729 ALCcontext_DecRef(Context);
1733 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1735 ALCcontext *Context;
1736 ALsource *Source;
1738 Context = GetContextRef();
1739 if(!Context) return;
1741 if((Source=LookupSource(Context, source)) == NULL)
1742 alSetError(Context, AL_INVALID_NAME);
1743 else if(!(value1 && value2 && value3))
1744 alSetError(Context, AL_INVALID_VALUE);
1745 else if(!(FloatValsByProp(param) == 3))
1746 alSetError(Context, AL_INVALID_ENUM);
1747 else
1749 ALdouble dvals[3];
1750 if(GetSourcedv(Source, Context, param, dvals))
1752 *value1 = (ALfloat)dvals[0];
1753 *value2 = (ALfloat)dvals[1];
1754 *value3 = (ALfloat)dvals[2];
1758 ALCcontext_DecRef(Context);
1762 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1764 ALCcontext *Context;
1765 ALsource *Source;
1766 ALint count;
1768 Context = GetContextRef();
1769 if(!Context) return;
1771 if((Source=LookupSource(Context, source)) == NULL)
1772 alSetError(Context, AL_INVALID_NAME);
1773 else if(!values)
1774 alSetError(Context, AL_INVALID_VALUE);
1775 else if(!((count=FloatValsByProp(param)) > 0 && count <= 3))
1776 alSetError(Context, AL_INVALID_ENUM);
1777 else
1779 ALdouble dvals[3];
1780 if(GetSourcedv(Source, Context, param, dvals))
1782 ALint i;
1783 for(i = 0;i < count;i++)
1784 values[i] = (ALfloat)dvals[i];
1788 ALCcontext_DecRef(Context);
1792 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1794 ALCcontext *Context;
1795 ALsource *Source;
1797 Context = GetContextRef();
1798 if(!Context) return;
1800 if((Source=LookupSource(Context, source)) == NULL)
1801 alSetError(Context, AL_INVALID_NAME);
1802 else if(!value)
1803 alSetError(Context, AL_INVALID_VALUE);
1804 else if(!(DoubleValsByProp(param) == 1))
1805 alSetError(Context, AL_INVALID_ENUM);
1806 else
1807 GetSourcedv(Source, Context, param, value);
1809 ALCcontext_DecRef(Context);
1812 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1814 ALCcontext *Context;
1815 ALsource *Source;
1817 Context = GetContextRef();
1818 if(!Context) return;
1820 if((Source=LookupSource(Context, source)) == NULL)
1821 alSetError(Context, AL_INVALID_NAME);
1822 else if(!(value1 && value2 && value3))
1823 alSetError(Context, AL_INVALID_VALUE);
1824 else if(!(DoubleValsByProp(param) == 3))
1825 alSetError(Context, AL_INVALID_ENUM);
1826 else
1828 ALdouble dvals[3];
1829 if(GetSourcedv(Source, Context, param, dvals))
1831 *value1 = dvals[0];
1832 *value2 = dvals[1];
1833 *value3 = dvals[2];
1837 ALCcontext_DecRef(Context);
1840 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1842 ALCcontext *Context;
1843 ALsource *Source;
1845 Context = GetContextRef();
1846 if(!Context) return;
1848 if((Source=LookupSource(Context, source)) == NULL)
1849 alSetError(Context, AL_INVALID_NAME);
1850 else if(!values)
1851 alSetError(Context, AL_INVALID_VALUE);
1852 else if(!(DoubleValsByProp(param) > 0))
1853 alSetError(Context, AL_INVALID_ENUM);
1854 else
1855 GetSourcedv(Source, Context, param, values);
1857 ALCcontext_DecRef(Context);
1861 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1863 ALCcontext *Context;
1864 ALsource *Source;
1866 Context = GetContextRef();
1867 if(!Context) return;
1869 if((Source=LookupSource(Context, source)) == NULL)
1870 alSetError(Context, AL_INVALID_NAME);
1871 else if(!value)
1872 alSetError(Context, AL_INVALID_VALUE);
1873 else if(!(IntValsByProp(param) == 1))
1874 alSetError(Context, AL_INVALID_ENUM);
1875 else
1876 GetSourceiv(Source, Context, param, value);
1878 ALCcontext_DecRef(Context);
1882 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
1884 ALCcontext *Context;
1885 ALsource *Source;
1887 Context = GetContextRef();
1888 if(!Context) return;
1890 if((Source=LookupSource(Context, source)) == NULL)
1891 alSetError(Context, AL_INVALID_NAME);
1892 else if(!(value1 && value2 && value3))
1893 alSetError(Context, AL_INVALID_VALUE);
1894 else if(!(IntValsByProp(param) == 3))
1895 alSetError(Context, AL_INVALID_ENUM);
1896 else
1898 ALint ivals[3];
1899 if(GetSourceiv(Source, Context, param, ivals))
1901 *value1 = ivals[0];
1902 *value2 = ivals[1];
1903 *value3 = ivals[2];
1907 ALCcontext_DecRef(Context);
1911 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
1913 ALCcontext *Context;
1914 ALsource *Source;
1916 Context = GetContextRef();
1917 if(!Context) return;
1919 if((Source=LookupSource(Context, source)) == NULL)
1920 alSetError(Context, AL_INVALID_NAME);
1921 else if(!values)
1922 alSetError(Context, AL_INVALID_VALUE);
1923 else if(!(IntValsByProp(param) > 0))
1924 alSetError(Context, AL_INVALID_ENUM);
1925 else
1926 GetSourceiv(Source, Context, param, values);
1928 ALCcontext_DecRef(Context);
1932 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
1934 ALCcontext *Context;
1935 ALsource *Source;
1937 Context = GetContextRef();
1938 if(!Context) return;
1940 if((Source=LookupSource(Context, source)) == NULL)
1941 alSetError(Context, AL_INVALID_NAME);
1942 else if(!value)
1943 alSetError(Context, AL_INVALID_VALUE);
1944 else if(!(Int64ValsByProp(param) == 1))
1945 alSetError(Context, AL_INVALID_ENUM);
1946 else
1947 GetSourcei64v(Source, Context, param, value);
1949 ALCcontext_DecRef(Context);
1952 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
1954 ALCcontext *Context;
1955 ALsource *Source;
1957 Context = GetContextRef();
1958 if(!Context) return;
1960 if((Source=LookupSource(Context, source)) == NULL)
1961 alSetError(Context, AL_INVALID_NAME);
1962 else if(!(value1 && value2 && value3))
1963 alSetError(Context, AL_INVALID_VALUE);
1964 else if(!(Int64ValsByProp(param) == 3))
1965 alSetError(Context, AL_INVALID_ENUM);
1966 else
1968 ALint64 i64vals[3];
1969 if(GetSourcei64v(Source, Context, param, i64vals))
1971 *value1 = i64vals[0];
1972 *value2 = i64vals[1];
1973 *value3 = i64vals[2];
1977 ALCcontext_DecRef(Context);
1980 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
1982 ALCcontext *Context;
1983 ALsource *Source;
1985 Context = GetContextRef();
1986 if(!Context) return;
1988 if((Source=LookupSource(Context, source)) == NULL)
1989 alSetError(Context, AL_INVALID_NAME);
1990 else if(!values)
1991 alSetError(Context, AL_INVALID_VALUE);
1992 else if(!(Int64ValsByProp(param) > 0))
1993 alSetError(Context, AL_INVALID_ENUM);
1994 else
1995 GetSourcei64v(Source, Context, param, values);
1997 ALCcontext_DecRef(Context);
2001 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2003 alSourcePlayv(1, &source);
2005 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2007 ALCcontext *context;
2008 ALsource *source;
2009 ALsizei i;
2011 context = GetContextRef();
2012 if(!context) return;
2014 if(!(n >= 0))
2015 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2016 for(i = 0;i < n;i++)
2018 if(!LookupSource(context, sources[i]))
2019 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2022 LockContext(context);
2023 while(n > context->MaxActiveSources-context->ActiveSourceCount)
2025 ALactivesource **temp = NULL;
2026 ALsizei newcount;
2028 newcount = context->MaxActiveSources << 1;
2029 if(newcount > 0)
2030 temp = realloc(context->ActiveSources,
2031 newcount * sizeof(context->ActiveSources[0]));
2032 if(!temp)
2034 UnlockContext(context);
2035 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2037 for(i = context->MaxActiveSources;i < newcount;i++)
2038 temp[i] = NULL;
2040 context->ActiveSources = temp;
2041 context->MaxActiveSources = newcount;
2044 for(i = 0;i < n;i++)
2046 source = LookupSource(context, sources[i]);
2047 if(context->DeferUpdates) source->new_state = AL_PLAYING;
2048 else SetSourceState(source, context, AL_PLAYING);
2050 UnlockContext(context);
2052 done:
2053 ALCcontext_DecRef(context);
2056 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2058 alSourcePausev(1, &source);
2060 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2062 ALCcontext *context;
2063 ALsource *source;
2064 ALsizei i;
2066 context = GetContextRef();
2067 if(!context) return;
2069 if(!(n >= 0))
2070 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2071 for(i = 0;i < n;i++)
2073 if(!LookupSource(context, sources[i]))
2074 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2077 LockContext(context);
2078 for(i = 0;i < n;i++)
2080 source = LookupSource(context, sources[i]);
2081 if(context->DeferUpdates) source->new_state = AL_PAUSED;
2082 else SetSourceState(source, context, AL_PAUSED);
2084 UnlockContext(context);
2086 done:
2087 ALCcontext_DecRef(context);
2090 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2092 alSourceStopv(1, &source);
2094 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2096 ALCcontext *context;
2097 ALsource *source;
2098 ALsizei i;
2100 context = GetContextRef();
2101 if(!context) return;
2103 if(!(n >= 0))
2104 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2105 for(i = 0;i < n;i++)
2107 if(!LookupSource(context, sources[i]))
2108 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2111 LockContext(context);
2112 for(i = 0;i < n;i++)
2114 source = LookupSource(context, sources[i]);
2115 source->new_state = AL_NONE;
2116 SetSourceState(source, context, AL_STOPPED);
2118 UnlockContext(context);
2120 done:
2121 ALCcontext_DecRef(context);
2124 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2126 alSourceRewindv(1, &source);
2128 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2130 ALCcontext *context;
2131 ALsource *source;
2132 ALsizei i;
2134 context = GetContextRef();
2135 if(!context) return;
2137 if(!(n >= 0))
2138 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2139 for(i = 0;i < n;i++)
2141 if(!LookupSource(context, sources[i]))
2142 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2145 LockContext(context);
2146 for(i = 0;i < n;i++)
2148 source = LookupSource(context, sources[i]);
2149 source->new_state = AL_NONE;
2150 SetSourceState(source, context, AL_INITIAL);
2152 UnlockContext(context);
2154 done:
2155 ALCcontext_DecRef(context);
2159 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2161 ALCdevice *device;
2162 ALCcontext *context;
2163 ALsource *source;
2164 ALsizei i;
2165 ALbufferlistitem *BufferListStart;
2166 ALbufferlistitem *BufferList;
2167 ALbuffer *BufferFmt = NULL;
2169 if(nb == 0)
2170 return;
2172 context = GetContextRef();
2173 if(!context) return;
2175 device = context->Device;
2177 if(!(nb >= 0))
2178 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2179 if((source=LookupSource(context, src)) == NULL)
2180 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2182 WriteLock(&source->queue_lock);
2183 if(source->SourceType == AL_STATIC)
2185 WriteUnlock(&source->queue_lock);
2186 /* Can't queue on a Static Source */
2187 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2190 /* Check for a valid Buffer, for its frequency and format */
2191 BufferList = ATOMIC_LOAD(&source->queue);
2192 while(BufferList)
2194 if(BufferList->buffer)
2196 BufferFmt = BufferList->buffer;
2197 break;
2199 BufferList = BufferList->next;
2202 BufferListStart = NULL;
2203 BufferList = NULL;
2204 for(i = 0;i < nb;i++)
2206 ALbuffer *buffer = NULL;
2207 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2209 WriteUnlock(&source->queue_lock);
2210 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2213 if(!BufferListStart)
2215 BufferListStart = malloc(sizeof(ALbufferlistitem));
2216 BufferListStart->buffer = buffer;
2217 BufferListStart->next = NULL;
2218 BufferListStart->prev = NULL;
2219 BufferList = BufferListStart;
2221 else
2223 BufferList->next = malloc(sizeof(ALbufferlistitem));
2224 BufferList->next->buffer = buffer;
2225 BufferList->next->next = NULL;
2226 BufferList->next->prev = BufferList;
2227 BufferList = BufferList->next;
2229 if(!buffer) continue;
2231 /* Hold a read lock on each buffer being queued while checking all
2232 * provided buffers. This is done so other threads don't see an extra
2233 * reference on some buffers if this operation ends up failing. */
2234 ReadLock(&buffer->lock);
2235 IncrementRef(&buffer->ref);
2237 if(BufferFmt == NULL)
2239 BufferFmt = buffer;
2241 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2242 source->SampleSize = BytesFromFmt(buffer->FmtType);
2244 else if(BufferFmt->Frequency != buffer->Frequency ||
2245 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2246 BufferFmt->OriginalType != buffer->OriginalType)
2248 WriteUnlock(&source->queue_lock);
2249 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2251 buffer_error:
2252 /* A buffer failed (invalid ID or format), so unlock and release
2253 * each buffer we had. */
2254 while(BufferList != NULL)
2256 ALbufferlistitem *prev = BufferList->prev;
2257 if((buffer=BufferList->buffer) != NULL)
2259 DecrementRef(&buffer->ref);
2260 ReadUnlock(&buffer->lock);
2262 free(BufferList);
2263 BufferList = prev;
2265 goto done;
2268 /* All buffers good, unlock them now. */
2269 while(BufferList != NULL)
2271 ALbuffer *buffer = BufferList->buffer;
2272 if(buffer) ReadUnlock(&buffer->lock);
2273 BufferList = BufferList->prev;
2276 /* Source is now streaming */
2277 source->SourceType = AL_STREAMING;
2279 BufferList = NULL;
2280 if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
2282 /* Queue head is not NULL, append to the end of the queue */
2283 while(BufferList->next != NULL)
2284 BufferList = BufferList->next;
2286 BufferListStart->prev = BufferList;
2287 BufferList->next = BufferListStart;
2289 BufferList = NULL;
2290 ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
2291 WriteUnlock(&source->queue_lock);
2293 done:
2294 ALCcontext_DecRef(context);
2297 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2299 ALCcontext *context;
2300 ALsource *source;
2301 ALbufferlistitem *NewHead;
2302 ALbufferlistitem *OldHead;
2303 ALbufferlistitem *Current;
2304 ALsizei i;
2306 if(nb == 0)
2307 return;
2309 context = GetContextRef();
2310 if(!context) return;
2312 if(!(nb >= 0))
2313 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2315 if((source=LookupSource(context, src)) == NULL)
2316 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2318 WriteLock(&source->queue_lock);
2319 /* Find the new buffer queue head */
2320 NewHead = ATOMIC_LOAD(&source->queue);
2321 Current = ATOMIC_LOAD(&source->current_buffer);
2322 for(i = 0;i < nb && NewHead;i++)
2324 if(NewHead == Current)
2325 break;
2326 NewHead = NewHead->next;
2328 if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
2330 WriteUnlock(&source->queue_lock);
2331 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2332 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2335 /* Swap it, and cut the new head from the old. */
2336 OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NewHead);
2337 if(NewHead)
2339 ALCdevice *device = context->Device;
2340 ALbufferlistitem *OldTail = NewHead->prev;
2341 uint count;
2343 /* Cut the new head's link back to the old body. The mixer is robust
2344 * enough to handle the link back going away. Once the active mix (if
2345 * any) is complete, it's safe to finish cutting the old tail from the
2346 * new head. */
2347 NewHead->prev = NULL;
2348 if(((count=ReadRef(&device->MixCount))&1) != 0)
2350 while(count == ReadRef(&device->MixCount))
2351 althrd_yield();
2353 OldTail->next = NULL;
2355 WriteUnlock(&source->queue_lock);
2357 while(OldHead != NULL)
2359 ALbufferlistitem *next = OldHead->next;
2360 ALbuffer *buffer = OldHead->buffer;
2362 if(!buffer)
2363 *(buffers++) = 0;
2364 else
2366 *(buffers++) = buffer->id;
2367 DecrementRef(&buffer->ref);
2370 free(OldHead);
2371 OldHead = next;
2374 done:
2375 ALCcontext_DecRef(context);
2379 static ALvoid InitSourceParams(ALsource *Source)
2381 ALuint i;
2383 RWLockInit(&Source->queue_lock);
2385 Source->InnerAngle = 360.0f;
2386 Source->OuterAngle = 360.0f;
2387 Source->Pitch = 1.0f;
2388 Source->Position[0] = 0.0f;
2389 Source->Position[1] = 0.0f;
2390 Source->Position[2] = 0.0f;
2391 Source->Orientation[0] = 0.0f;
2392 Source->Orientation[1] = 0.0f;
2393 Source->Orientation[2] = 0.0f;
2394 Source->Velocity[0] = 0.0f;
2395 Source->Velocity[1] = 0.0f;
2396 Source->Velocity[2] = 0.0f;
2397 Source->RefDistance = 1.0f;
2398 Source->MaxDistance = FLT_MAX;
2399 Source->RollOffFactor = 1.0f;
2400 Source->Looping = AL_FALSE;
2401 Source->Gain = 1.0f;
2402 Source->MinGain = 0.0f;
2403 Source->MaxGain = 1.0f;
2404 Source->OuterGain = 0.0f;
2405 Source->OuterGainHF = 1.0f;
2407 Source->DryGainHFAuto = AL_TRUE;
2408 Source->WetGainAuto = AL_TRUE;
2409 Source->WetGainHFAuto = AL_TRUE;
2410 Source->AirAbsorptionFactor = 0.0f;
2411 Source->RoomRolloffFactor = 0.0f;
2412 Source->DopplerFactor = 1.0f;
2413 Source->DirectChannels = AL_FALSE;
2415 Source->Radius = 0.0f;
2417 Source->DistanceModel = DefaultDistanceModel;
2419 Source->Resampler = DefaultResampler;
2421 Source->state = AL_INITIAL;
2422 Source->new_state = AL_NONE;
2423 Source->SourceType = AL_UNDETERMINED;
2424 Source->Offset = -1.0;
2426 ATOMIC_INIT(&Source->queue, NULL);
2427 ATOMIC_INIT(&Source->current_buffer, NULL);
2429 Source->Direct.Gain = 1.0f;
2430 Source->Direct.GainHF = 1.0f;
2431 Source->Direct.HFReference = LOWPASSFREQREF;
2432 Source->Direct.GainLF = 1.0f;
2433 Source->Direct.LFReference = HIGHPASSFREQREF;
2434 for(i = 0;i < MAX_SENDS;i++)
2436 Source->Send[i].Gain = 1.0f;
2437 Source->Send[i].GainHF = 1.0f;
2438 Source->Send[i].HFReference = LOWPASSFREQREF;
2439 Source->Send[i].GainLF = 1.0f;
2440 Source->Send[i].LFReference = HIGHPASSFREQREF;
2443 ATOMIC_INIT(&Source->NeedsUpdate, AL_TRUE);
2447 /* SetSourceState
2449 * Sets the source's new play state given its current state.
2451 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2453 ReadLock(&Source->queue_lock);
2454 if(state == AL_PLAYING)
2456 ALCdevice *device = Context->Device;
2457 ALbufferlistitem *BufferList;
2458 ALactivesource *src = NULL;
2459 ALsizei j, k;
2461 /* Check that there is a queue containing at least one valid, non zero
2462 * length Buffer. */
2463 BufferList = ATOMIC_LOAD(&Source->queue);
2464 while(BufferList)
2466 ALbuffer *buffer;
2467 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2468 break;
2469 BufferList = BufferList->next;
2472 if(Source->state != AL_PAUSED)
2474 Source->state = AL_PLAYING;
2475 Source->position = 0;
2476 Source->position_fraction = 0;
2477 ATOMIC_STORE(&Source->current_buffer, BufferList);
2479 else
2480 Source->state = AL_PLAYING;
2482 // Check if an Offset has been set
2483 if(Source->Offset >= 0.0)
2484 ApplyOffset(Source);
2486 /* If there's nothing to play, or device is disconnected, go right to
2487 * stopped */
2488 if(!BufferList || !device->Connected)
2489 goto do_stop;
2491 for(j = 0;j < Context->ActiveSourceCount;j++)
2493 if(Context->ActiveSources[j]->Source == Source)
2495 src = Context->ActiveSources[j];
2496 break;
2499 if(src == NULL)
2501 src = Context->ActiveSources[Context->ActiveSourceCount];
2502 if(src == NULL)
2504 src = al_malloc(16, sizeof(src[0]));
2505 Context->ActiveSources[Context->ActiveSourceCount] = src;
2507 memset(src, 0, sizeof(*src));
2508 Context->ActiveSourceCount++;
2510 src->Source = Source;
2512 else
2514 ALuint i;
2516 src->Direct.Moving = AL_FALSE;
2517 src->Direct.Counter = 0;
2518 for(j = 0;j < MAX_INPUT_CHANNELS;j++)
2520 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
2521 src->Direct.Mix.Hrtf.State[j].History[k] = 0.0f;
2522 for(k = 0;k < HRIR_LENGTH;k++)
2524 src->Direct.Mix.Hrtf.State[j].Values[k][0] = 0.0f;
2525 src->Direct.Mix.Hrtf.State[j].Values[k][1] = 0.0f;
2528 for(i = 0;i < device->NumAuxSends;i++)
2530 src->Send[i].Counter = 0;
2531 src->Send[i].Moving = AL_FALSE;
2535 if(BufferList->buffer->FmtChannels == FmtMono)
2536 src->Update = CalcSourceParams;
2537 else
2538 src->Update = CalcNonAttnSourceParams;
2540 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
2542 else if(state == AL_PAUSED)
2544 if(Source->state == AL_PLAYING)
2545 Source->state = AL_PAUSED;
2547 else if(state == AL_STOPPED)
2549 do_stop:
2550 if(Source->state != AL_INITIAL)
2552 Source->state = AL_STOPPED;
2553 ATOMIC_STORE(&Source->current_buffer, NULL);
2555 Source->Offset = -1.0;
2557 else if(state == AL_INITIAL)
2559 if(Source->state != AL_INITIAL)
2561 Source->state = AL_INITIAL;
2562 Source->position = 0;
2563 Source->position_fraction = 0;
2564 ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue));
2566 Source->Offset = -1.0;
2568 ReadUnlock(&Source->queue_lock);
2571 /* GetSourceOffset
2573 * Gets the current read offset for the given Source, in 32.32 fixed-point
2574 * samples. The offset is relative to the start of the queue (not the start of
2575 * the current buffer).
2577 static ALint64 GetSourceOffset(const ALsource *Source)
2579 const ALbufferlistitem *BufferList;
2580 const ALbufferlistitem *Current;
2581 ALuint64 readPos;
2583 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2584 return 0;
2586 /* NOTE: This is the offset into the *current* buffer, so add the length of
2587 * any played buffers */
2588 readPos = (ALuint64)Source->position << 32;
2589 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2590 BufferList = ATOMIC_LOAD(&Source->queue);
2591 Current = ATOMIC_LOAD(&Source->current_buffer);
2592 while(BufferList && BufferList != Current)
2594 if(BufferList->buffer)
2595 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2596 BufferList = BufferList->next;
2599 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
2602 /* GetSourceSecOffset
2604 * Gets the current read offset for the given Source, in seconds. The offset is
2605 * relative to the start of the queue (not the start of the current buffer).
2607 static ALdouble GetSourceSecOffset(const ALsource *Source)
2609 const ALbufferlistitem *BufferList;
2610 const ALbufferlistitem *Current;
2611 const ALbuffer *Buffer = NULL;
2612 ALuint64 readPos;
2614 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2615 return 0.0;
2617 /* NOTE: This is the offset into the *current* buffer, so add the length of
2618 * any played buffers */
2619 readPos = (ALuint64)Source->position << FRACTIONBITS;
2620 readPos |= (ALuint64)Source->position_fraction;
2621 BufferList = ATOMIC_LOAD(&Source->queue);
2622 Current = ATOMIC_LOAD(&Source->current_buffer);
2623 while(BufferList && BufferList != Current)
2625 const ALbuffer *buffer = BufferList->buffer;
2626 if(buffer != NULL)
2628 if(!Buffer) Buffer = buffer;
2629 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
2631 BufferList = BufferList->next;
2634 while(BufferList && !Buffer)
2636 Buffer = BufferList->buffer;
2637 BufferList = BufferList->next;
2639 assert(Buffer != NULL);
2641 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2644 /* GetSourceOffsets
2646 * Gets the current read and write offsets for the given Source, in the
2647 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2648 * the start of the queue (not the start of the current buffer).
2650 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2652 const ALbufferlistitem *BufferList;
2653 const ALbufferlistitem *Current;
2654 const ALbuffer *Buffer = NULL;
2655 ALboolean readFin = AL_FALSE;
2656 ALuint readPos, writePos;
2657 ALuint totalBufferLen;
2659 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2661 offset[0] = 0.0;
2662 offset[1] = 0.0;
2663 return;
2666 if(updateLen > 0.0 && updateLen < 0.015)
2667 updateLen = 0.015;
2669 /* NOTE: This is the offset into the *current* buffer, so add the length of
2670 * any played buffers */
2671 totalBufferLen = 0;
2672 readPos = Source->position;
2673 BufferList = ATOMIC_LOAD(&Source->queue);
2674 Current = ATOMIC_LOAD(&Source->current_buffer);
2675 while(BufferList != NULL)
2677 const ALbuffer *buffer;
2678 readFin = readFin || (BufferList == Current);
2679 if((buffer=BufferList->buffer) != NULL)
2681 if(!Buffer) Buffer = buffer;
2682 totalBufferLen += buffer->SampleLen;
2683 if(!readFin) readPos += buffer->SampleLen;
2685 BufferList = BufferList->next;
2687 assert(Buffer != NULL);
2689 if(Source->state == AL_PLAYING)
2690 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
2691 else
2692 writePos = readPos;
2694 if(Source->Looping)
2696 readPos %= totalBufferLen;
2697 writePos %= totalBufferLen;
2699 else
2701 /* Wrap positions back to 0 */
2702 if(readPos >= totalBufferLen)
2703 readPos = 0;
2704 if(writePos >= totalBufferLen)
2705 writePos = 0;
2708 switch(name)
2710 case AL_SEC_OFFSET:
2711 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2712 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2713 break;
2715 case AL_SAMPLE_OFFSET:
2716 case AL_SAMPLE_RW_OFFSETS_SOFT:
2717 offset[0] = (ALdouble)readPos;
2718 offset[1] = (ALdouble)writePos;
2719 break;
2721 case AL_BYTE_OFFSET:
2722 case AL_BYTE_RW_OFFSETS_SOFT:
2723 if(Buffer->OriginalType == UserFmtIMA4)
2725 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2726 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2727 ALuint FrameBlockSize = Buffer->OriginalAlign;
2729 /* Round down to nearest ADPCM block */
2730 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2731 if(Source->state != AL_PLAYING)
2732 offset[1] = offset[0];
2733 else
2735 /* Round up to nearest ADPCM block */
2736 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2737 FrameBlockSize * BlockSize);
2740 else if(Buffer->OriginalType == UserFmtMSADPCM)
2742 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2743 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2744 ALuint FrameBlockSize = Buffer->OriginalAlign;
2746 /* Round down to nearest ADPCM block */
2747 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2748 if(Source->state != AL_PLAYING)
2749 offset[1] = offset[0];
2750 else
2752 /* Round up to nearest ADPCM block */
2753 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2754 FrameBlockSize * BlockSize);
2757 else
2759 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2760 offset[0] = (ALdouble)(readPos * FrameSize);
2761 offset[1] = (ALdouble)(writePos * FrameSize);
2763 break;
2768 /* ApplyOffset
2770 * Apply the stored playback offset to the Source. This function will update
2771 * the number of buffers "played" given the stored offset.
2773 ALboolean ApplyOffset(ALsource *Source)
2775 ALbufferlistitem *BufferList;
2776 const ALbuffer *Buffer;
2777 ALint bufferLen, totalBufferLen;
2778 ALint offset;
2780 /* Get sample frame offset */
2781 offset = GetSampleOffset(Source);
2782 if(offset == -1)
2783 return AL_FALSE;
2785 totalBufferLen = 0;
2786 BufferList = ATOMIC_LOAD(&Source->queue);
2787 while(BufferList && totalBufferLen <= offset)
2789 Buffer = BufferList->buffer;
2790 bufferLen = Buffer ? Buffer->SampleLen : 0;
2792 if(bufferLen > offset-totalBufferLen)
2794 /* Offset is in this buffer */
2795 ATOMIC_STORE(&Source->current_buffer, BufferList);
2797 Source->position = offset - totalBufferLen;
2798 Source->position_fraction = 0;
2799 return AL_TRUE;
2802 totalBufferLen += bufferLen;
2804 BufferList = BufferList->next;
2807 /* Offset is out of range of the queue */
2808 return AL_FALSE;
2812 /* GetSampleOffset
2814 * Returns the sample offset into the Source's queue (from the Sample, Byte or
2815 * Second offset supplied by the application). This takes into account the fact
2816 * that the buffer format may have been modifed since.
2818 static ALint GetSampleOffset(ALsource *Source)
2820 const ALbuffer *Buffer = NULL;
2821 const ALbufferlistitem *BufferList;
2822 ALint Offset = -1;
2824 /* Find the first valid Buffer in the Queue */
2825 BufferList = ATOMIC_LOAD(&Source->queue);
2826 while(BufferList)
2828 if(BufferList->buffer)
2830 Buffer = BufferList->buffer;
2831 break;
2833 BufferList = BufferList->next;
2836 if(!Buffer)
2838 Source->Offset = -1.0;
2839 return -1;
2842 switch(Source->OffsetType)
2844 case AL_BYTE_OFFSET:
2845 /* Determine the ByteOffset (and ensure it is block aligned) */
2846 Offset = (ALint)Source->Offset;
2847 if(Buffer->OriginalType == UserFmtIMA4)
2849 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2850 Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2851 Offset *= Buffer->OriginalAlign;
2853 else if(Buffer->OriginalType == UserFmtMSADPCM)
2855 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2856 Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2857 Offset *= Buffer->OriginalAlign;
2859 else
2860 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2861 break;
2863 case AL_SAMPLE_OFFSET:
2864 Offset = (ALint)Source->Offset;
2865 break;
2867 case AL_SEC_OFFSET:
2868 Offset = (ALint)(Source->Offset * Buffer->Frequency);
2869 break;
2871 Source->Offset = -1.0;
2873 return Offset;
2877 /* ReleaseALSources
2879 * Destroys all sources in the source map.
2881 ALvoid ReleaseALSources(ALCcontext *Context)
2883 ALbufferlistitem *item;
2884 ALsizei pos;
2885 ALuint j;
2886 for(pos = 0;pos < Context->SourceMap.size;pos++)
2888 ALsource *temp = Context->SourceMap.array[pos].value;
2889 Context->SourceMap.array[pos].value = NULL;
2891 item = ATOMIC_EXCHANGE(ALbufferlistitem*, &temp->queue, NULL);
2892 while(item != NULL)
2894 ALbufferlistitem *next = item->next;
2895 if(item->buffer != NULL)
2896 DecrementRef(&item->buffer->ref);
2897 free(item);
2898 item = next;
2901 for(j = 0;j < MAX_SENDS;++j)
2903 if(temp->Send[j].Slot)
2904 DecrementRef(&temp->Send[j].Slot->ref);
2905 temp->Send[j].Slot = NULL;
2908 FreeThunkEntry(temp->id);
2909 memset(temp, 0, sizeof(*temp));
2910 al_free(temp);