Rename the source's Orientation to Direction
[openal-soft.git] / OpenAL32 / alSource.c
bloba148a21a7565c6a73901a4dd7793714eea0b6871
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <math.h>
25 #include <float.h>
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alMain.h"
30 #include "alError.h"
31 #include "alSource.h"
32 #include "alBuffer.h"
33 #include "alThunk.h"
34 #include "alAuxEffectSlot.h"
36 #include "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->Direction[0] = values[0];
527 Source->Direction[1] = values[1];
528 Source->Direction[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 LockContext(Context);
939 ReadLock(&Source->queue_lock);
940 GetSourceOffsets(Source, prop, offsets, 0.0);
941 ReadUnlock(&Source->queue_lock);
942 UnlockContext(Context);
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 LockContext(Context);
986 ReadLock(&Source->queue_lock);
987 updateLen = (ALdouble)Context->Device->UpdateSize /
988 Context->Device->Frequency;
989 GetSourceOffsets(Source, prop, values, updateLen);
990 ReadUnlock(&Source->queue_lock);
991 UnlockContext(Context);
992 return AL_TRUE;
994 case AL_SEC_OFFSET_LATENCY_SOFT:
995 LockContext(Context);
996 ReadLock(&Source->queue_lock);
997 values[0] = GetSourceSecOffset(Source);
998 ReadUnlock(&Source->queue_lock);
999 values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) /
1000 1000000000.0;
1001 UnlockContext(Context);
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->Direction[0];
1023 values[1] = Source->Direction[1];
1024 values[2] = Source->Direction[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 LockContext(Context);
1251 ReadLock(&Source->queue_lock);
1252 values[0] = GetSourceOffset(Source);
1253 ReadUnlock(&Source->queue_lock);
1254 values[1] = ALCdevice_GetLatency(Context->Device);
1255 UnlockContext(Context);
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 ALvoice *voice, *voice_end;
1394 if((Source=RemoveSource(context, sources[i])) == NULL)
1395 continue;
1396 FreeThunkEntry(Source->id);
1398 LockContext(context);
1399 voice = context->Voices;
1400 voice_end = voice + context->VoiceCount;
1401 while(voice != voice_end)
1403 ALsource *old = Source;
1404 if(COMPARE_EXCHANGE(&voice->Source, &old, NULL))
1405 break;
1406 voice++;
1408 UnlockContext(context);
1410 BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, NULL);
1411 while(BufferList != NULL)
1413 ALbufferlistitem *next = BufferList->next;
1414 if(BufferList->buffer != NULL)
1415 DecrementRef(&BufferList->buffer->ref);
1416 free(BufferList);
1417 BufferList = next;
1420 for(j = 0;j < MAX_SENDS;++j)
1422 if(Source->Send[j].Slot)
1423 DecrementRef(&Source->Send[j].Slot->ref);
1424 Source->Send[j].Slot = NULL;
1427 memset(Source, 0, sizeof(*Source));
1428 al_free(Source);
1431 done:
1432 ALCcontext_DecRef(context);
1436 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1438 ALCcontext *context;
1439 ALboolean ret;
1441 context = GetContextRef();
1442 if(!context) return AL_FALSE;
1444 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1446 ALCcontext_DecRef(context);
1448 return ret;
1452 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1454 ALCcontext *Context;
1455 ALsource *Source;
1457 Context = GetContextRef();
1458 if(!Context) return;
1460 if((Source=LookupSource(Context, source)) == NULL)
1461 alSetError(Context, AL_INVALID_NAME);
1462 else if(!(FloatValsByProp(param) == 1))
1463 alSetError(Context, AL_INVALID_ENUM);
1464 else
1465 SetSourcefv(Source, Context, param, &value);
1467 ALCcontext_DecRef(Context);
1470 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1472 ALCcontext *Context;
1473 ALsource *Source;
1475 Context = GetContextRef();
1476 if(!Context) return;
1478 if((Source=LookupSource(Context, source)) == NULL)
1479 alSetError(Context, AL_INVALID_NAME);
1480 else if(!(FloatValsByProp(param) == 3))
1481 alSetError(Context, AL_INVALID_ENUM);
1482 else
1484 ALfloat fvals[3] = { value1, value2, value3 };
1485 SetSourcefv(Source, Context, param, fvals);
1488 ALCcontext_DecRef(Context);
1491 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1493 ALCcontext *Context;
1494 ALsource *Source;
1496 Context = GetContextRef();
1497 if(!Context) return;
1499 if((Source=LookupSource(Context, source)) == NULL)
1500 alSetError(Context, AL_INVALID_NAME);
1501 else if(!values)
1502 alSetError(Context, AL_INVALID_VALUE);
1503 else if(!(FloatValsByProp(param) > 0))
1504 alSetError(Context, AL_INVALID_ENUM);
1505 else
1506 SetSourcefv(Source, Context, param, values);
1508 ALCcontext_DecRef(Context);
1512 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1514 ALCcontext *Context;
1515 ALsource *Source;
1517 Context = GetContextRef();
1518 if(!Context) return;
1520 if((Source=LookupSource(Context, source)) == NULL)
1521 alSetError(Context, AL_INVALID_NAME);
1522 else if(!(DoubleValsByProp(param) == 1))
1523 alSetError(Context, AL_INVALID_ENUM);
1524 else
1526 ALfloat fval = (ALfloat)value;
1527 SetSourcefv(Source, Context, param, &fval);
1530 ALCcontext_DecRef(Context);
1533 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1535 ALCcontext *Context;
1536 ALsource *Source;
1538 Context = GetContextRef();
1539 if(!Context) return;
1541 if((Source=LookupSource(Context, source)) == NULL)
1542 alSetError(Context, AL_INVALID_NAME);
1543 else if(!(DoubleValsByProp(param) == 3))
1544 alSetError(Context, AL_INVALID_ENUM);
1545 else
1547 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1548 SetSourcefv(Source, Context, param, fvals);
1551 ALCcontext_DecRef(Context);
1554 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1556 ALCcontext *Context;
1557 ALsource *Source;
1558 ALint count;
1560 Context = GetContextRef();
1561 if(!Context) return;
1563 if((Source=LookupSource(Context, source)) == NULL)
1564 alSetError(Context, AL_INVALID_NAME);
1565 else if(!values)
1566 alSetError(Context, AL_INVALID_VALUE);
1567 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 3))
1568 alSetError(Context, AL_INVALID_ENUM);
1569 else
1571 ALfloat fvals[3];
1572 ALint i;
1574 for(i = 0;i < count;i++)
1575 fvals[i] = (ALfloat)values[i];
1576 SetSourcefv(Source, Context, param, fvals);
1579 ALCcontext_DecRef(Context);
1583 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1585 ALCcontext *Context;
1586 ALsource *Source;
1588 Context = GetContextRef();
1589 if(!Context) return;
1591 if((Source=LookupSource(Context, source)) == NULL)
1592 alSetError(Context, AL_INVALID_NAME);
1593 else if(!(IntValsByProp(param) == 1))
1594 alSetError(Context, AL_INVALID_ENUM);
1595 else
1596 SetSourceiv(Source, Context, param, &value);
1598 ALCcontext_DecRef(Context);
1601 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1603 ALCcontext *Context;
1604 ALsource *Source;
1606 Context = GetContextRef();
1607 if(!Context) return;
1609 if((Source=LookupSource(Context, source)) == NULL)
1610 alSetError(Context, AL_INVALID_NAME);
1611 else if(!(IntValsByProp(param) == 3))
1612 alSetError(Context, AL_INVALID_ENUM);
1613 else
1615 ALint ivals[3] = { value1, value2, value3 };
1616 SetSourceiv(Source, Context, param, ivals);
1619 ALCcontext_DecRef(Context);
1622 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1624 ALCcontext *Context;
1625 ALsource *Source;
1627 Context = GetContextRef();
1628 if(!Context) return;
1630 if((Source=LookupSource(Context, source)) == NULL)
1631 alSetError(Context, AL_INVALID_NAME);
1632 else if(!values)
1633 alSetError(Context, AL_INVALID_VALUE);
1634 else if(!(IntValsByProp(param) > 0))
1635 alSetError(Context, AL_INVALID_ENUM);
1636 else
1637 SetSourceiv(Source, Context, param, values);
1639 ALCcontext_DecRef(Context);
1643 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1645 ALCcontext *Context;
1646 ALsource *Source;
1648 Context = GetContextRef();
1649 if(!Context) return;
1651 if((Source=LookupSource(Context, source)) == NULL)
1652 alSetError(Context, AL_INVALID_NAME);
1653 else if(!(Int64ValsByProp(param) == 1))
1654 alSetError(Context, AL_INVALID_ENUM);
1655 else
1656 SetSourcei64v(Source, Context, param, &value);
1658 ALCcontext_DecRef(Context);
1661 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1663 ALCcontext *Context;
1664 ALsource *Source;
1666 Context = GetContextRef();
1667 if(!Context) return;
1669 if((Source=LookupSource(Context, source)) == NULL)
1670 alSetError(Context, AL_INVALID_NAME);
1671 else if(!(Int64ValsByProp(param) == 3))
1672 alSetError(Context, AL_INVALID_ENUM);
1673 else
1675 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1676 SetSourcei64v(Source, Context, param, i64vals);
1679 ALCcontext_DecRef(Context);
1682 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1684 ALCcontext *Context;
1685 ALsource *Source;
1687 Context = GetContextRef();
1688 if(!Context) return;
1690 if((Source=LookupSource(Context, source)) == NULL)
1691 alSetError(Context, AL_INVALID_NAME);
1692 else if(!values)
1693 alSetError(Context, AL_INVALID_VALUE);
1694 else if(!(Int64ValsByProp(param) > 0))
1695 alSetError(Context, AL_INVALID_ENUM);
1696 else
1697 SetSourcei64v(Source, Context, param, values);
1699 ALCcontext_DecRef(Context);
1703 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1705 ALCcontext *Context;
1706 ALsource *Source;
1708 Context = GetContextRef();
1709 if(!Context) return;
1711 if((Source=LookupSource(Context, source)) == NULL)
1712 alSetError(Context, AL_INVALID_NAME);
1713 else if(!value)
1714 alSetError(Context, AL_INVALID_VALUE);
1715 else if(!(FloatValsByProp(param) == 1))
1716 alSetError(Context, AL_INVALID_ENUM);
1717 else
1719 ALdouble dval;
1720 if(GetSourcedv(Source, Context, param, &dval))
1721 *value = (ALfloat)dval;
1724 ALCcontext_DecRef(Context);
1728 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1730 ALCcontext *Context;
1731 ALsource *Source;
1733 Context = GetContextRef();
1734 if(!Context) return;
1736 if((Source=LookupSource(Context, source)) == NULL)
1737 alSetError(Context, AL_INVALID_NAME);
1738 else if(!(value1 && value2 && value3))
1739 alSetError(Context, AL_INVALID_VALUE);
1740 else if(!(FloatValsByProp(param) == 3))
1741 alSetError(Context, AL_INVALID_ENUM);
1742 else
1744 ALdouble dvals[3];
1745 if(GetSourcedv(Source, Context, param, dvals))
1747 *value1 = (ALfloat)dvals[0];
1748 *value2 = (ALfloat)dvals[1];
1749 *value3 = (ALfloat)dvals[2];
1753 ALCcontext_DecRef(Context);
1757 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1759 ALCcontext *Context;
1760 ALsource *Source;
1761 ALint count;
1763 Context = GetContextRef();
1764 if(!Context) return;
1766 if((Source=LookupSource(Context, source)) == NULL)
1767 alSetError(Context, AL_INVALID_NAME);
1768 else if(!values)
1769 alSetError(Context, AL_INVALID_VALUE);
1770 else if(!((count=FloatValsByProp(param)) > 0 && count <= 3))
1771 alSetError(Context, AL_INVALID_ENUM);
1772 else
1774 ALdouble dvals[3];
1775 if(GetSourcedv(Source, Context, param, dvals))
1777 ALint i;
1778 for(i = 0;i < count;i++)
1779 values[i] = (ALfloat)dvals[i];
1783 ALCcontext_DecRef(Context);
1787 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1789 ALCcontext *Context;
1790 ALsource *Source;
1792 Context = GetContextRef();
1793 if(!Context) return;
1795 if((Source=LookupSource(Context, source)) == NULL)
1796 alSetError(Context, AL_INVALID_NAME);
1797 else if(!value)
1798 alSetError(Context, AL_INVALID_VALUE);
1799 else if(!(DoubleValsByProp(param) == 1))
1800 alSetError(Context, AL_INVALID_ENUM);
1801 else
1802 GetSourcedv(Source, Context, param, value);
1804 ALCcontext_DecRef(Context);
1807 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1809 ALCcontext *Context;
1810 ALsource *Source;
1812 Context = GetContextRef();
1813 if(!Context) return;
1815 if((Source=LookupSource(Context, source)) == NULL)
1816 alSetError(Context, AL_INVALID_NAME);
1817 else if(!(value1 && value2 && value3))
1818 alSetError(Context, AL_INVALID_VALUE);
1819 else if(!(DoubleValsByProp(param) == 3))
1820 alSetError(Context, AL_INVALID_ENUM);
1821 else
1823 ALdouble dvals[3];
1824 if(GetSourcedv(Source, Context, param, dvals))
1826 *value1 = dvals[0];
1827 *value2 = dvals[1];
1828 *value3 = dvals[2];
1832 ALCcontext_DecRef(Context);
1835 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1837 ALCcontext *Context;
1838 ALsource *Source;
1840 Context = GetContextRef();
1841 if(!Context) return;
1843 if((Source=LookupSource(Context, source)) == NULL)
1844 alSetError(Context, AL_INVALID_NAME);
1845 else if(!values)
1846 alSetError(Context, AL_INVALID_VALUE);
1847 else if(!(DoubleValsByProp(param) > 0))
1848 alSetError(Context, AL_INVALID_ENUM);
1849 else
1850 GetSourcedv(Source, Context, param, values);
1852 ALCcontext_DecRef(Context);
1856 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1858 ALCcontext *Context;
1859 ALsource *Source;
1861 Context = GetContextRef();
1862 if(!Context) return;
1864 if((Source=LookupSource(Context, source)) == NULL)
1865 alSetError(Context, AL_INVALID_NAME);
1866 else if(!value)
1867 alSetError(Context, AL_INVALID_VALUE);
1868 else if(!(IntValsByProp(param) == 1))
1869 alSetError(Context, AL_INVALID_ENUM);
1870 else
1871 GetSourceiv(Source, Context, param, value);
1873 ALCcontext_DecRef(Context);
1877 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
1879 ALCcontext *Context;
1880 ALsource *Source;
1882 Context = GetContextRef();
1883 if(!Context) return;
1885 if((Source=LookupSource(Context, source)) == NULL)
1886 alSetError(Context, AL_INVALID_NAME);
1887 else if(!(value1 && value2 && value3))
1888 alSetError(Context, AL_INVALID_VALUE);
1889 else if(!(IntValsByProp(param) == 3))
1890 alSetError(Context, AL_INVALID_ENUM);
1891 else
1893 ALint ivals[3];
1894 if(GetSourceiv(Source, Context, param, ivals))
1896 *value1 = ivals[0];
1897 *value2 = ivals[1];
1898 *value3 = ivals[2];
1902 ALCcontext_DecRef(Context);
1906 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
1908 ALCcontext *Context;
1909 ALsource *Source;
1911 Context = GetContextRef();
1912 if(!Context) return;
1914 if((Source=LookupSource(Context, source)) == NULL)
1915 alSetError(Context, AL_INVALID_NAME);
1916 else if(!values)
1917 alSetError(Context, AL_INVALID_VALUE);
1918 else if(!(IntValsByProp(param) > 0))
1919 alSetError(Context, AL_INVALID_ENUM);
1920 else
1921 GetSourceiv(Source, Context, param, values);
1923 ALCcontext_DecRef(Context);
1927 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
1929 ALCcontext *Context;
1930 ALsource *Source;
1932 Context = GetContextRef();
1933 if(!Context) return;
1935 if((Source=LookupSource(Context, source)) == NULL)
1936 alSetError(Context, AL_INVALID_NAME);
1937 else if(!value)
1938 alSetError(Context, AL_INVALID_VALUE);
1939 else if(!(Int64ValsByProp(param) == 1))
1940 alSetError(Context, AL_INVALID_ENUM);
1941 else
1942 GetSourcei64v(Source, Context, param, value);
1944 ALCcontext_DecRef(Context);
1947 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
1949 ALCcontext *Context;
1950 ALsource *Source;
1952 Context = GetContextRef();
1953 if(!Context) return;
1955 if((Source=LookupSource(Context, source)) == NULL)
1956 alSetError(Context, AL_INVALID_NAME);
1957 else if(!(value1 && value2 && value3))
1958 alSetError(Context, AL_INVALID_VALUE);
1959 else if(!(Int64ValsByProp(param) == 3))
1960 alSetError(Context, AL_INVALID_ENUM);
1961 else
1963 ALint64 i64vals[3];
1964 if(GetSourcei64v(Source, Context, param, i64vals))
1966 *value1 = i64vals[0];
1967 *value2 = i64vals[1];
1968 *value3 = i64vals[2];
1972 ALCcontext_DecRef(Context);
1975 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
1977 ALCcontext *Context;
1978 ALsource *Source;
1980 Context = GetContextRef();
1981 if(!Context) return;
1983 if((Source=LookupSource(Context, source)) == NULL)
1984 alSetError(Context, AL_INVALID_NAME);
1985 else if(!values)
1986 alSetError(Context, AL_INVALID_VALUE);
1987 else if(!(Int64ValsByProp(param) > 0))
1988 alSetError(Context, AL_INVALID_ENUM);
1989 else
1990 GetSourcei64v(Source, Context, param, values);
1992 ALCcontext_DecRef(Context);
1996 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1998 alSourcePlayv(1, &source);
2000 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2002 ALCcontext *context;
2003 ALsource *source;
2004 ALsizei i;
2006 context = GetContextRef();
2007 if(!context) return;
2009 if(!(n >= 0))
2010 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2011 for(i = 0;i < n;i++)
2013 if(!LookupSource(context, sources[i]))
2014 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2017 LockContext(context);
2018 while(n > context->MaxVoices-context->VoiceCount)
2020 ALvoice *temp = NULL;
2021 ALsizei newcount;
2023 newcount = context->MaxVoices << 1;
2024 if(newcount > 0)
2025 temp = realloc(context->Voices, newcount * sizeof(context->Voices[0]));
2026 if(!temp)
2028 UnlockContext(context);
2029 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2031 memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0]));
2033 context->Voices = temp;
2034 context->MaxVoices = newcount;
2037 for(i = 0;i < n;i++)
2039 source = LookupSource(context, sources[i]);
2040 if(context->DeferUpdates) source->new_state = AL_PLAYING;
2041 else SetSourceState(source, context, AL_PLAYING);
2043 UnlockContext(context);
2045 done:
2046 ALCcontext_DecRef(context);
2049 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2051 alSourcePausev(1, &source);
2053 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2055 ALCcontext *context;
2056 ALsource *source;
2057 ALsizei i;
2059 context = GetContextRef();
2060 if(!context) return;
2062 if(!(n >= 0))
2063 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2064 for(i = 0;i < n;i++)
2066 if(!LookupSource(context, sources[i]))
2067 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2070 LockContext(context);
2071 for(i = 0;i < n;i++)
2073 source = LookupSource(context, sources[i]);
2074 if(context->DeferUpdates) source->new_state = AL_PAUSED;
2075 else SetSourceState(source, context, AL_PAUSED);
2077 UnlockContext(context);
2079 done:
2080 ALCcontext_DecRef(context);
2083 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2085 alSourceStopv(1, &source);
2087 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2089 ALCcontext *context;
2090 ALsource *source;
2091 ALsizei i;
2093 context = GetContextRef();
2094 if(!context) return;
2096 if(!(n >= 0))
2097 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2098 for(i = 0;i < n;i++)
2100 if(!LookupSource(context, sources[i]))
2101 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2104 LockContext(context);
2105 for(i = 0;i < n;i++)
2107 source = LookupSource(context, sources[i]);
2108 source->new_state = AL_NONE;
2109 SetSourceState(source, context, AL_STOPPED);
2111 UnlockContext(context);
2113 done:
2114 ALCcontext_DecRef(context);
2117 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2119 alSourceRewindv(1, &source);
2121 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2123 ALCcontext *context;
2124 ALsource *source;
2125 ALsizei i;
2127 context = GetContextRef();
2128 if(!context) return;
2130 if(!(n >= 0))
2131 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2132 for(i = 0;i < n;i++)
2134 if(!LookupSource(context, sources[i]))
2135 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2138 LockContext(context);
2139 for(i = 0;i < n;i++)
2141 source = LookupSource(context, sources[i]);
2142 source->new_state = AL_NONE;
2143 SetSourceState(source, context, AL_INITIAL);
2145 UnlockContext(context);
2147 done:
2148 ALCcontext_DecRef(context);
2152 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2154 ALCdevice *device;
2155 ALCcontext *context;
2156 ALsource *source;
2157 ALsizei i;
2158 ALbufferlistitem *BufferListStart;
2159 ALbufferlistitem *BufferList;
2160 ALbuffer *BufferFmt = NULL;
2162 if(nb == 0)
2163 return;
2165 context = GetContextRef();
2166 if(!context) return;
2168 device = context->Device;
2170 if(!(nb >= 0))
2171 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2172 if((source=LookupSource(context, src)) == NULL)
2173 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2175 WriteLock(&source->queue_lock);
2176 if(source->SourceType == AL_STATIC)
2178 WriteUnlock(&source->queue_lock);
2179 /* Can't queue on a Static Source */
2180 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2183 /* Check for a valid Buffer, for its frequency and format */
2184 BufferList = ATOMIC_LOAD(&source->queue);
2185 while(BufferList)
2187 if(BufferList->buffer)
2189 BufferFmt = BufferList->buffer;
2190 break;
2192 BufferList = BufferList->next;
2195 BufferListStart = NULL;
2196 BufferList = NULL;
2197 for(i = 0;i < nb;i++)
2199 ALbuffer *buffer = NULL;
2200 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2202 WriteUnlock(&source->queue_lock);
2203 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2206 if(!BufferListStart)
2208 BufferListStart = malloc(sizeof(ALbufferlistitem));
2209 BufferListStart->buffer = buffer;
2210 BufferListStart->next = NULL;
2211 BufferListStart->prev = NULL;
2212 BufferList = BufferListStart;
2214 else
2216 BufferList->next = malloc(sizeof(ALbufferlistitem));
2217 BufferList->next->buffer = buffer;
2218 BufferList->next->next = NULL;
2219 BufferList->next->prev = BufferList;
2220 BufferList = BufferList->next;
2222 if(!buffer) continue;
2224 /* Hold a read lock on each buffer being queued while checking all
2225 * provided buffers. This is done so other threads don't see an extra
2226 * reference on some buffers if this operation ends up failing. */
2227 ReadLock(&buffer->lock);
2228 IncrementRef(&buffer->ref);
2230 if(BufferFmt == NULL)
2232 BufferFmt = buffer;
2234 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2235 source->SampleSize = BytesFromFmt(buffer->FmtType);
2237 else if(BufferFmt->Frequency != buffer->Frequency ||
2238 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2239 BufferFmt->OriginalType != buffer->OriginalType)
2241 WriteUnlock(&source->queue_lock);
2242 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2244 buffer_error:
2245 /* A buffer failed (invalid ID or format), so unlock and release
2246 * each buffer we had. */
2247 while(BufferList != NULL)
2249 ALbufferlistitem *prev = BufferList->prev;
2250 if((buffer=BufferList->buffer) != NULL)
2252 DecrementRef(&buffer->ref);
2253 ReadUnlock(&buffer->lock);
2255 free(BufferList);
2256 BufferList = prev;
2258 goto done;
2261 /* All buffers good, unlock them now. */
2262 while(BufferList != NULL)
2264 ALbuffer *buffer = BufferList->buffer;
2265 if(buffer) ReadUnlock(&buffer->lock);
2266 BufferList = BufferList->prev;
2269 /* Source is now streaming */
2270 source->SourceType = AL_STREAMING;
2272 BufferList = NULL;
2273 if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
2275 /* Queue head is not NULL, append to the end of the queue */
2276 while(BufferList->next != NULL)
2277 BufferList = BufferList->next;
2279 BufferListStart->prev = BufferList;
2280 BufferList->next = BufferListStart;
2282 BufferList = NULL;
2283 ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
2284 WriteUnlock(&source->queue_lock);
2286 done:
2287 ALCcontext_DecRef(context);
2290 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2292 ALCcontext *context;
2293 ALsource *source;
2294 ALbufferlistitem *NewHead;
2295 ALbufferlistitem *OldHead;
2296 ALbufferlistitem *Current;
2297 ALsizei i;
2299 if(nb == 0)
2300 return;
2302 context = GetContextRef();
2303 if(!context) return;
2305 if(!(nb >= 0))
2306 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2308 if((source=LookupSource(context, src)) == NULL)
2309 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2311 WriteLock(&source->queue_lock);
2312 /* Find the new buffer queue head */
2313 NewHead = ATOMIC_LOAD(&source->queue);
2314 Current = ATOMIC_LOAD(&source->current_buffer);
2315 for(i = 0;i < nb && NewHead;i++)
2317 if(NewHead == Current)
2318 break;
2319 NewHead = NewHead->next;
2321 if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
2323 WriteUnlock(&source->queue_lock);
2324 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2325 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2328 /* Swap it, and cut the new head from the old. */
2329 OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NewHead);
2330 if(NewHead)
2332 ALCdevice *device = context->Device;
2333 ALbufferlistitem *OldTail = NewHead->prev;
2334 uint count;
2336 /* Cut the new head's link back to the old body. The mixer is robust
2337 * enough to handle the link back going away. Once the active mix (if
2338 * any) is complete, it's safe to finish cutting the old tail from the
2339 * new head. */
2340 NewHead->prev = NULL;
2341 if(((count=ReadRef(&device->MixCount))&1) != 0)
2343 while(count == ReadRef(&device->MixCount))
2344 althrd_yield();
2346 OldTail->next = NULL;
2348 WriteUnlock(&source->queue_lock);
2350 while(OldHead != NULL)
2352 ALbufferlistitem *next = OldHead->next;
2353 ALbuffer *buffer = OldHead->buffer;
2355 if(!buffer)
2356 *(buffers++) = 0;
2357 else
2359 *(buffers++) = buffer->id;
2360 DecrementRef(&buffer->ref);
2363 free(OldHead);
2364 OldHead = next;
2367 done:
2368 ALCcontext_DecRef(context);
2372 static ALvoid InitSourceParams(ALsource *Source)
2374 ALuint i;
2376 RWLockInit(&Source->queue_lock);
2378 Source->InnerAngle = 360.0f;
2379 Source->OuterAngle = 360.0f;
2380 Source->Pitch = 1.0f;
2381 Source->Position[0] = 0.0f;
2382 Source->Position[1] = 0.0f;
2383 Source->Position[2] = 0.0f;
2384 Source->Direction[0] = 0.0f;
2385 Source->Direction[1] = 0.0f;
2386 Source->Direction[2] = 0.0f;
2387 Source->Velocity[0] = 0.0f;
2388 Source->Velocity[1] = 0.0f;
2389 Source->Velocity[2] = 0.0f;
2390 Source->RefDistance = 1.0f;
2391 Source->MaxDistance = FLT_MAX;
2392 Source->RollOffFactor = 1.0f;
2393 Source->Looping = AL_FALSE;
2394 Source->Gain = 1.0f;
2395 Source->MinGain = 0.0f;
2396 Source->MaxGain = 1.0f;
2397 Source->OuterGain = 0.0f;
2398 Source->OuterGainHF = 1.0f;
2400 Source->DryGainHFAuto = AL_TRUE;
2401 Source->WetGainAuto = AL_TRUE;
2402 Source->WetGainHFAuto = AL_TRUE;
2403 Source->AirAbsorptionFactor = 0.0f;
2404 Source->RoomRolloffFactor = 0.0f;
2405 Source->DopplerFactor = 1.0f;
2406 Source->DirectChannels = AL_FALSE;
2408 Source->Radius = 0.0f;
2410 Source->DistanceModel = DefaultDistanceModel;
2412 Source->Resampler = DefaultResampler;
2414 Source->state = AL_INITIAL;
2415 Source->new_state = AL_NONE;
2416 Source->SourceType = AL_UNDETERMINED;
2417 Source->Offset = -1.0;
2419 ATOMIC_INIT(&Source->queue, NULL);
2420 ATOMIC_INIT(&Source->current_buffer, NULL);
2422 Source->Direct.Gain = 1.0f;
2423 Source->Direct.GainHF = 1.0f;
2424 Source->Direct.HFReference = LOWPASSFREQREF;
2425 Source->Direct.GainLF = 1.0f;
2426 Source->Direct.LFReference = HIGHPASSFREQREF;
2427 for(i = 0;i < MAX_SENDS;i++)
2429 Source->Send[i].Gain = 1.0f;
2430 Source->Send[i].GainHF = 1.0f;
2431 Source->Send[i].HFReference = LOWPASSFREQREF;
2432 Source->Send[i].GainLF = 1.0f;
2433 Source->Send[i].LFReference = HIGHPASSFREQREF;
2436 ATOMIC_INIT(&Source->NeedsUpdate, AL_TRUE);
2440 /* SetSourceState
2442 * Sets the source's new play state given its current state.
2444 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2446 ReadLock(&Source->queue_lock);
2447 if(state == AL_PLAYING)
2449 ALCdevice *device = Context->Device;
2450 ALbufferlistitem *BufferList;
2451 ALvoice *voice = NULL;
2452 ALsizei i;
2454 /* Check that there is a queue containing at least one valid, non zero
2455 * length Buffer. */
2456 BufferList = ATOMIC_LOAD(&Source->queue);
2457 while(BufferList)
2459 ALbuffer *buffer;
2460 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2461 break;
2462 BufferList = BufferList->next;
2465 if(Source->state != AL_PAUSED)
2467 Source->state = AL_PLAYING;
2468 Source->position = 0;
2469 Source->position_fraction = 0;
2470 ATOMIC_STORE(&Source->current_buffer, BufferList);
2472 else
2473 Source->state = AL_PLAYING;
2475 // Check if an Offset has been set
2476 if(Source->Offset >= 0.0)
2477 ApplyOffset(Source);
2479 /* If there's nothing to play, or device is disconnected, go right to
2480 * stopped */
2481 if(!BufferList || !device->Connected)
2482 goto do_stop;
2484 /* Make sure this source isn't already active, while looking for an
2485 * unused active source slot to put it in. */
2486 for(i = 0;i < Context->VoiceCount;i++)
2488 ALsource *old = Source;
2489 if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL))
2491 if(voice == NULL)
2493 voice = &Context->Voices[i];
2494 voice->Source = Source;
2496 break;
2498 old = NULL;
2499 if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source))
2500 voice = &Context->Voices[i];
2502 if(voice == NULL)
2504 voice = &Context->Voices[Context->VoiceCount++];
2505 voice->Source = Source;
2508 voice->Direct.Moving = AL_FALSE;
2509 voice->Direct.Counter = 0;
2510 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
2512 ALsizei j;
2513 for(j = 0;j < SRC_HISTORY_LENGTH;j++)
2514 voice->Direct.Mix.Hrtf.State[i].History[j] = 0.0f;
2515 for(j = 0;j < HRIR_LENGTH;j++)
2517 voice->Direct.Mix.Hrtf.State[i].Values[j][0] = 0.0f;
2518 voice->Direct.Mix.Hrtf.State[i].Values[j][1] = 0.0f;
2521 for(i = 0;i < (ALsizei)device->NumAuxSends;i++)
2523 voice->Send[i].Counter = 0;
2524 voice->Send[i].Moving = AL_FALSE;
2527 if(BufferList->buffer->FmtChannels == FmtMono)
2528 voice->Update = CalcSourceParams;
2529 else
2530 voice->Update = CalcNonAttnSourceParams;
2532 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
2534 else if(state == AL_PAUSED)
2536 if(Source->state == AL_PLAYING)
2537 Source->state = AL_PAUSED;
2539 else if(state == AL_STOPPED)
2541 do_stop:
2542 if(Source->state != AL_INITIAL)
2544 Source->state = AL_STOPPED;
2545 ATOMIC_STORE(&Source->current_buffer, NULL);
2547 Source->Offset = -1.0;
2549 else if(state == AL_INITIAL)
2551 if(Source->state != AL_INITIAL)
2553 Source->state = AL_INITIAL;
2554 Source->position = 0;
2555 Source->position_fraction = 0;
2556 ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue));
2558 Source->Offset = -1.0;
2560 ReadUnlock(&Source->queue_lock);
2563 /* GetSourceOffset
2565 * Gets the current read offset for the given Source, in 32.32 fixed-point
2566 * samples. The offset is relative to the start of the queue (not the start of
2567 * the current buffer).
2569 static ALint64 GetSourceOffset(const ALsource *Source)
2571 const ALbufferlistitem *BufferList;
2572 const ALbufferlistitem *Current;
2573 ALuint64 readPos;
2575 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2576 return 0;
2578 /* NOTE: This is the offset into the *current* buffer, so add the length of
2579 * any played buffers */
2580 readPos = (ALuint64)Source->position << 32;
2581 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2582 BufferList = ATOMIC_LOAD(&Source->queue);
2583 Current = ATOMIC_LOAD(&Source->current_buffer);
2584 while(BufferList && BufferList != Current)
2586 if(BufferList->buffer)
2587 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2588 BufferList = BufferList->next;
2591 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
2594 /* GetSourceSecOffset
2596 * Gets the current read offset for the given Source, in seconds. The offset is
2597 * relative to the start of the queue (not the start of the current buffer).
2599 static ALdouble GetSourceSecOffset(const ALsource *Source)
2601 const ALbufferlistitem *BufferList;
2602 const ALbufferlistitem *Current;
2603 const ALbuffer *Buffer = NULL;
2604 ALuint64 readPos;
2606 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2607 return 0.0;
2609 /* NOTE: This is the offset into the *current* buffer, so add the length of
2610 * any played buffers */
2611 readPos = (ALuint64)Source->position << FRACTIONBITS;
2612 readPos |= (ALuint64)Source->position_fraction;
2613 BufferList = ATOMIC_LOAD(&Source->queue);
2614 Current = ATOMIC_LOAD(&Source->current_buffer);
2615 while(BufferList && BufferList != Current)
2617 const ALbuffer *buffer = BufferList->buffer;
2618 if(buffer != NULL)
2620 if(!Buffer) Buffer = buffer;
2621 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
2623 BufferList = BufferList->next;
2626 while(BufferList && !Buffer)
2628 Buffer = BufferList->buffer;
2629 BufferList = BufferList->next;
2631 assert(Buffer != NULL);
2633 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2636 /* GetSourceOffsets
2638 * Gets the current read and write offsets for the given Source, in the
2639 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2640 * the start of the queue (not the start of the current buffer).
2642 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2644 const ALbufferlistitem *BufferList;
2645 const ALbufferlistitem *Current;
2646 const ALbuffer *Buffer = NULL;
2647 ALboolean readFin = AL_FALSE;
2648 ALuint readPos, writePos;
2649 ALuint totalBufferLen;
2651 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2653 offset[0] = 0.0;
2654 offset[1] = 0.0;
2655 return;
2658 if(updateLen > 0.0 && updateLen < 0.015)
2659 updateLen = 0.015;
2661 /* NOTE: This is the offset into the *current* buffer, so add the length of
2662 * any played buffers */
2663 totalBufferLen = 0;
2664 readPos = Source->position;
2665 BufferList = ATOMIC_LOAD(&Source->queue);
2666 Current = ATOMIC_LOAD(&Source->current_buffer);
2667 while(BufferList != NULL)
2669 const ALbuffer *buffer;
2670 readFin = readFin || (BufferList == Current);
2671 if((buffer=BufferList->buffer) != NULL)
2673 if(!Buffer) Buffer = buffer;
2674 totalBufferLen += buffer->SampleLen;
2675 if(!readFin) readPos += buffer->SampleLen;
2677 BufferList = BufferList->next;
2679 assert(Buffer != NULL);
2681 if(Source->state == AL_PLAYING)
2682 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
2683 else
2684 writePos = readPos;
2686 if(Source->Looping)
2688 readPos %= totalBufferLen;
2689 writePos %= totalBufferLen;
2691 else
2693 /* Wrap positions back to 0 */
2694 if(readPos >= totalBufferLen)
2695 readPos = 0;
2696 if(writePos >= totalBufferLen)
2697 writePos = 0;
2700 switch(name)
2702 case AL_SEC_OFFSET:
2703 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2704 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2705 break;
2707 case AL_SAMPLE_OFFSET:
2708 case AL_SAMPLE_RW_OFFSETS_SOFT:
2709 offset[0] = (ALdouble)readPos;
2710 offset[1] = (ALdouble)writePos;
2711 break;
2713 case AL_BYTE_OFFSET:
2714 case AL_BYTE_RW_OFFSETS_SOFT:
2715 if(Buffer->OriginalType == UserFmtIMA4)
2717 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2718 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2719 ALuint FrameBlockSize = Buffer->OriginalAlign;
2721 /* Round down to nearest ADPCM block */
2722 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2723 if(Source->state != AL_PLAYING)
2724 offset[1] = offset[0];
2725 else
2727 /* Round up to nearest ADPCM block */
2728 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2729 FrameBlockSize * BlockSize);
2732 else if(Buffer->OriginalType == UserFmtMSADPCM)
2734 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2735 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2736 ALuint FrameBlockSize = Buffer->OriginalAlign;
2738 /* Round down to nearest ADPCM block */
2739 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2740 if(Source->state != AL_PLAYING)
2741 offset[1] = offset[0];
2742 else
2744 /* Round up to nearest ADPCM block */
2745 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2746 FrameBlockSize * BlockSize);
2749 else
2751 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2752 offset[0] = (ALdouble)(readPos * FrameSize);
2753 offset[1] = (ALdouble)(writePos * FrameSize);
2755 break;
2760 /* ApplyOffset
2762 * Apply the stored playback offset to the Source. This function will update
2763 * the number of buffers "played" given the stored offset.
2765 ALboolean ApplyOffset(ALsource *Source)
2767 ALbufferlistitem *BufferList;
2768 const ALbuffer *Buffer;
2769 ALint bufferLen, totalBufferLen;
2770 ALint offset;
2772 /* Get sample frame offset */
2773 offset = GetSampleOffset(Source);
2774 if(offset == -1)
2775 return AL_FALSE;
2777 totalBufferLen = 0;
2778 BufferList = ATOMIC_LOAD(&Source->queue);
2779 while(BufferList && totalBufferLen <= offset)
2781 Buffer = BufferList->buffer;
2782 bufferLen = Buffer ? Buffer->SampleLen : 0;
2784 if(bufferLen > offset-totalBufferLen)
2786 /* Offset is in this buffer */
2787 ATOMIC_STORE(&Source->current_buffer, BufferList);
2789 Source->position = offset - totalBufferLen;
2790 Source->position_fraction = 0;
2791 return AL_TRUE;
2794 totalBufferLen += bufferLen;
2796 BufferList = BufferList->next;
2799 /* Offset is out of range of the queue */
2800 return AL_FALSE;
2804 /* GetSampleOffset
2806 * Returns the sample offset into the Source's queue (from the Sample, Byte or
2807 * Second offset supplied by the application). This takes into account the fact
2808 * that the buffer format may have been modifed since.
2810 static ALint GetSampleOffset(ALsource *Source)
2812 const ALbuffer *Buffer = NULL;
2813 const ALbufferlistitem *BufferList;
2814 ALint Offset = -1;
2816 /* Find the first valid Buffer in the Queue */
2817 BufferList = ATOMIC_LOAD(&Source->queue);
2818 while(BufferList)
2820 if(BufferList->buffer)
2822 Buffer = BufferList->buffer;
2823 break;
2825 BufferList = BufferList->next;
2828 if(!Buffer)
2830 Source->Offset = -1.0;
2831 return -1;
2834 switch(Source->OffsetType)
2836 case AL_BYTE_OFFSET:
2837 /* Determine the ByteOffset (and ensure it is block aligned) */
2838 Offset = (ALint)Source->Offset;
2839 if(Buffer->OriginalType == UserFmtIMA4)
2841 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2842 Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2843 Offset *= Buffer->OriginalAlign;
2845 else if(Buffer->OriginalType == UserFmtMSADPCM)
2847 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2848 Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2849 Offset *= Buffer->OriginalAlign;
2851 else
2852 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2853 break;
2855 case AL_SAMPLE_OFFSET:
2856 Offset = (ALint)Source->Offset;
2857 break;
2859 case AL_SEC_OFFSET:
2860 Offset = (ALint)(Source->Offset * Buffer->Frequency);
2861 break;
2863 Source->Offset = -1.0;
2865 return Offset;
2869 /* ReleaseALSources
2871 * Destroys all sources in the source map.
2873 ALvoid ReleaseALSources(ALCcontext *Context)
2875 ALbufferlistitem *item;
2876 ALsizei pos;
2877 ALuint j;
2878 for(pos = 0;pos < Context->SourceMap.size;pos++)
2880 ALsource *temp = Context->SourceMap.array[pos].value;
2881 Context->SourceMap.array[pos].value = NULL;
2883 item = ATOMIC_EXCHANGE(ALbufferlistitem*, &temp->queue, NULL);
2884 while(item != NULL)
2886 ALbufferlistitem *next = item->next;
2887 if(item->buffer != NULL)
2888 DecrementRef(&item->buffer->ref);
2889 free(item);
2890 item = next;
2893 for(j = 0;j < MAX_SENDS;++j)
2895 if(temp->Send[j].Slot)
2896 DecrementRef(&temp->Send[j].Slot->ref);
2897 temp->Send[j].Slot = NULL;
2900 FreeThunkEntry(temp->id);
2901 memset(temp, 0, sizeof(*temp));
2902 al_free(temp);