Use aluVector in some more places
[openal-soft.git] / OpenAL32 / alSource.c
blobb05b85c59970a0565511dccc4d03ef1682da3377
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,
112 /* AL_EXT_BFORMAT */
113 sfOrientation = AL_ORIENTATION,
114 } SrcFloatProp;
116 typedef enum SrcIntProp {
117 siMaxDistance = AL_MAX_DISTANCE,
118 siRolloffFactor = AL_ROLLOFF_FACTOR,
119 siRefDistance = AL_REFERENCE_DISTANCE,
120 siSourceRelative = AL_SOURCE_RELATIVE,
121 siConeInnerAngle = AL_CONE_INNER_ANGLE,
122 siConeOuterAngle = AL_CONE_OUTER_ANGLE,
123 siLooping = AL_LOOPING,
124 siBuffer = AL_BUFFER,
125 siSourceState = AL_SOURCE_STATE,
126 siBuffersQueued = AL_BUFFERS_QUEUED,
127 siBuffersProcessed = AL_BUFFERS_PROCESSED,
128 siSourceType = AL_SOURCE_TYPE,
129 siSecOffset = AL_SEC_OFFSET,
130 siSampleOffset = AL_SAMPLE_OFFSET,
131 siByteOffset = AL_BYTE_OFFSET,
132 siDopplerFactor = AL_DOPPLER_FACTOR,
133 siPosition = AL_POSITION,
134 siVelocity = AL_VELOCITY,
135 siDirection = AL_DIRECTION,
137 /* ALC_EXT_EFX */
138 siDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
139 siAuxSendFilterGainAutio = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
140 siAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
141 siDirectFilter = AL_DIRECT_FILTER,
142 siAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
144 /* AL_SOFT_direct_channels */
145 siDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
147 /* AL_EXT_source_distance_model */
148 siDistanceModel = AL_DISTANCE_MODEL,
150 siByteLength = AL_BYTE_LENGTH_SOFT,
151 siSampleLength = AL_SAMPLE_LENGTH_SOFT,
153 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
154 siSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
155 siByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
157 /* AL_SOFT_source_latency */
158 siSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
160 /* AL_EXT_BFORMAT */
161 siOrientation = AL_ORIENTATION,
162 } SrcIntProp;
164 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values);
165 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values);
166 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values);
168 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values);
169 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values);
170 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values);
172 static ALint FloatValsByProp(ALenum prop)
174 if(prop != (ALenum)((SrcFloatProp)prop))
175 return 0;
176 switch((SrcFloatProp)prop)
178 case sfPitch:
179 case sfGain:
180 case sfMinGain:
181 case sfMaxGain:
182 case sfMaxDistance:
183 case sfRolloffFactor:
184 case sfDopplerFactor:
185 case sfConeOuterGain:
186 case sfSecOffset:
187 case sfSampleOffset:
188 case sfByteOffset:
189 case sfConeInnerAngle:
190 case sfConeOuterAngle:
191 case sfRefDistance:
192 case sfConeOuterGainHF:
193 case sfAirAbsorptionFactor:
194 case sfRoomRolloffFactor:
195 case sfDirectFilterGainHFAuto:
196 case sfAuxSendFilterGainAuto:
197 case sfAuxSendFilterGainHFAuto:
198 case sfDirectChannelsSOFT:
199 case sfDistanceModel:
200 case sfSourceRelative:
201 case sfLooping:
202 case sfBuffer:
203 case sfSourceState:
204 case sfBuffersQueued:
205 case sfBuffersProcessed:
206 case sfSourceType:
207 case sfSecLength:
208 return 1;
210 case sfSampleRWOffsetsSOFT:
211 case sfByteRWOffsetsSOFT:
212 return 2;
214 case sfPosition:
215 case sfVelocity:
216 case sfDirection:
217 return 3;
219 case sfOrientation:
220 return 6;
222 case sfSecOffsetLatencySOFT:
223 break; /* Double only */
225 return 0;
227 static ALint DoubleValsByProp(ALenum prop)
229 if(prop != (ALenum)((SrcFloatProp)prop))
230 return 0;
231 switch((SrcFloatProp)prop)
233 case sfPitch:
234 case sfGain:
235 case sfMinGain:
236 case sfMaxGain:
237 case sfMaxDistance:
238 case sfRolloffFactor:
239 case sfDopplerFactor:
240 case sfConeOuterGain:
241 case sfSecOffset:
242 case sfSampleOffset:
243 case sfByteOffset:
244 case sfConeInnerAngle:
245 case sfConeOuterAngle:
246 case sfRefDistance:
247 case sfConeOuterGainHF:
248 case sfAirAbsorptionFactor:
249 case sfRoomRolloffFactor:
250 case sfDirectFilterGainHFAuto:
251 case sfAuxSendFilterGainAuto:
252 case sfAuxSendFilterGainHFAuto:
253 case sfDirectChannelsSOFT:
254 case sfDistanceModel:
255 case sfSourceRelative:
256 case sfLooping:
257 case sfBuffer:
258 case sfSourceState:
259 case sfBuffersQueued:
260 case sfBuffersProcessed:
261 case sfSourceType:
262 case sfSecLength:
263 return 1;
265 case sfSampleRWOffsetsSOFT:
266 case sfByteRWOffsetsSOFT:
267 case sfSecOffsetLatencySOFT:
268 return 2;
270 case sfPosition:
271 case sfVelocity:
272 case sfDirection:
273 return 3;
275 case sfOrientation:
276 return 6;
278 return 0;
281 static ALint IntValsByProp(ALenum prop)
283 if(prop != (ALenum)((SrcIntProp)prop))
284 return 0;
285 switch((SrcIntProp)prop)
287 case siMaxDistance:
288 case siRolloffFactor:
289 case siRefDistance:
290 case siSourceRelative:
291 case siConeInnerAngle:
292 case siConeOuterAngle:
293 case siLooping:
294 case siBuffer:
295 case siSourceState:
296 case siBuffersQueued:
297 case siBuffersProcessed:
298 case siSourceType:
299 case siSecOffset:
300 case siSampleOffset:
301 case siByteOffset:
302 case siDopplerFactor:
303 case siDirectFilterGainHFAuto:
304 case siAuxSendFilterGainAutio:
305 case siAuxSendFilterGainHFAuto:
306 case siDirectFilter:
307 case siDirectChannelsSOFT:
308 case siDistanceModel:
309 case siByteLength:
310 case siSampleLength:
311 return 1;
313 case siSampleRWOffsetsSOFT:
314 case siByteRWOffsetsSOFT:
315 return 2;
317 case siPosition:
318 case siVelocity:
319 case siDirection:
320 case siAuxSendFilter:
321 return 3;
323 case siOrientation:
324 return 6;
326 case siSampleOffsetLatencySOFT:
327 break; /* i64 only */
329 return 0;
331 static ALint Int64ValsByProp(ALenum prop)
333 if(prop != (ALenum)((SrcIntProp)prop))
334 return 0;
335 switch((SrcIntProp)prop)
337 case siMaxDistance:
338 case siRolloffFactor:
339 case siRefDistance:
340 case siSourceRelative:
341 case siConeInnerAngle:
342 case siConeOuterAngle:
343 case siLooping:
344 case siBuffer:
345 case siSourceState:
346 case siBuffersQueued:
347 case siBuffersProcessed:
348 case siSourceType:
349 case siSecOffset:
350 case siSampleOffset:
351 case siByteOffset:
352 case siDopplerFactor:
353 case siDirectFilterGainHFAuto:
354 case siAuxSendFilterGainAutio:
355 case siAuxSendFilterGainHFAuto:
356 case siDirectFilter:
357 case siDirectChannelsSOFT:
358 case siDistanceModel:
359 case siByteLength:
360 case siSampleLength:
361 return 1;
363 case siSampleRWOffsetsSOFT:
364 case siByteRWOffsetsSOFT:
365 case siSampleOffsetLatencySOFT:
366 return 2;
368 case siPosition:
369 case siVelocity:
370 case siDirection:
371 case siAuxSendFilter:
372 return 3;
374 case siOrientation:
375 return 6;
377 return 0;
381 #define CHECKVAL(x) do { \
382 if(!(x)) \
383 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
384 } while(0)
386 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values)
388 ALint ival;
390 switch(prop)
392 case AL_PITCH:
393 CHECKVAL(*values >= 0.0f);
395 Source->Pitch = *values;
396 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
397 return AL_TRUE;
399 case AL_CONE_INNER_ANGLE:
400 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
402 Source->InnerAngle = *values;
403 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
404 return AL_TRUE;
406 case AL_CONE_OUTER_ANGLE:
407 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
409 Source->OuterAngle = *values;
410 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
411 return AL_TRUE;
413 case AL_GAIN:
414 CHECKVAL(*values >= 0.0f);
416 Source->Gain = *values;
417 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
418 return AL_TRUE;
420 case AL_MAX_DISTANCE:
421 CHECKVAL(*values >= 0.0f);
423 Source->MaxDistance = *values;
424 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
425 return AL_TRUE;
427 case AL_ROLLOFF_FACTOR:
428 CHECKVAL(*values >= 0.0f);
430 Source->RollOffFactor = *values;
431 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
432 return AL_TRUE;
434 case AL_REFERENCE_DISTANCE:
435 CHECKVAL(*values >= 0.0f);
437 Source->RefDistance = *values;
438 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
439 return AL_TRUE;
441 case AL_MIN_GAIN:
442 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
444 Source->MinGain = *values;
445 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
446 return AL_TRUE;
448 case AL_MAX_GAIN:
449 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
451 Source->MaxGain = *values;
452 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
453 return AL_TRUE;
455 case AL_CONE_OUTER_GAIN:
456 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
458 Source->OuterGain = *values;
459 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
460 return AL_TRUE;
462 case AL_CONE_OUTER_GAINHF:
463 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
465 Source->OuterGainHF = *values;
466 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
467 return AL_TRUE;
469 case AL_AIR_ABSORPTION_FACTOR:
470 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
472 Source->AirAbsorptionFactor = *values;
473 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
474 return AL_TRUE;
476 case AL_ROOM_ROLLOFF_FACTOR:
477 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
479 Source->RoomRolloffFactor = *values;
480 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
481 return AL_TRUE;
483 case AL_DOPPLER_FACTOR:
484 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
486 Source->DopplerFactor = *values;
487 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
488 return AL_TRUE;
490 case AL_SEC_OFFSET:
491 case AL_SAMPLE_OFFSET:
492 case AL_BYTE_OFFSET:
493 CHECKVAL(*values >= 0.0f);
495 LockContext(Context);
496 Source->OffsetType = prop;
497 Source->Offset = *values;
499 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
500 !Context->DeferUpdates)
502 if(ApplyOffset(Source) == AL_FALSE)
504 UnlockContext(Context);
505 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
508 UnlockContext(Context);
509 return AL_TRUE;
512 case sfSecLength:
513 case AL_SEC_OFFSET_LATENCY_SOFT:
514 /* Query only */
515 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
518 case AL_POSITION:
519 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
521 LockContext(Context);
522 aluVectorSet(&Source->Position, values[0], values[1], values[2], 1.0f);
523 UnlockContext(Context);
524 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
525 return AL_TRUE;
527 case AL_VELOCITY:
528 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
530 LockContext(Context);
531 aluVectorSet(&Source->Velocity, values[0], values[1], values[2], 0.0f);
532 UnlockContext(Context);
533 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
534 return AL_TRUE;
536 case AL_DIRECTION:
537 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
539 LockContext(Context);
540 aluVectorSet(&Source->Direction, values[0], values[1], values[2], 0.0f);
541 UnlockContext(Context);
542 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
543 return AL_TRUE;
545 case AL_ORIENTATION:
546 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
547 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
549 LockContext(Context);
550 Source->Orientation[0][0] = values[0];
551 Source->Orientation[0][1] = values[1];
552 Source->Orientation[0][2] = values[2];
553 Source->Orientation[1][0] = values[3];
554 Source->Orientation[1][1] = values[4];
555 Source->Orientation[1][2] = values[5];
556 UnlockContext(Context);
557 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
558 return AL_TRUE;
560 case sfSampleRWOffsetsSOFT:
561 case sfByteRWOffsetsSOFT:
562 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
565 case sfSourceRelative:
566 case sfLooping:
567 case sfSourceState:
568 case sfSourceType:
569 case sfDistanceModel:
570 case sfDirectFilterGainHFAuto:
571 case sfAuxSendFilterGainAuto:
572 case sfAuxSendFilterGainHFAuto:
573 case sfDirectChannelsSOFT:
574 ival = (ALint)values[0];
575 return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival);
577 case sfBuffer:
578 case sfBuffersQueued:
579 case sfBuffersProcessed:
580 ival = (ALint)((ALuint)values[0]);
581 return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival);
584 ERR("Unexpected property: 0x%04x\n", prop);
585 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
588 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values)
590 ALCdevice *device = Context->Device;
591 ALbuffer *buffer = NULL;
592 ALfilter *filter = NULL;
593 ALeffectslot *slot = NULL;
594 ALbufferlistitem *oldlist;
595 ALbufferlistitem *newlist;
596 ALfloat fvals[6];
598 switch(prop)
600 case AL_SOURCE_RELATIVE:
601 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
603 Source->HeadRelative = (ALboolean)*values;
604 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
605 return AL_TRUE;
607 case AL_LOOPING:
608 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
610 Source->Looping = (ALboolean)*values;
611 return AL_TRUE;
613 case AL_BUFFER:
614 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
616 WriteLock(&Source->queue_lock);
617 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
619 WriteUnlock(&Source->queue_lock);
620 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
623 if(buffer != NULL)
625 /* Add the selected buffer to a one-item queue */
626 newlist = malloc(sizeof(ALbufferlistitem));
627 newlist->buffer = buffer;
628 newlist->next = NULL;
629 newlist->prev = NULL;
630 IncrementRef(&buffer->ref);
632 /* Source is now Static */
633 Source->SourceType = AL_STATIC;
635 ReadLock(&buffer->lock);
636 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
637 Source->SampleSize = BytesFromFmt(buffer->FmtType);
638 ReadUnlock(&buffer->lock);
640 else
642 /* Source is now Undetermined */
643 Source->SourceType = AL_UNDETERMINED;
644 newlist = NULL;
646 oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist);
647 ATOMIC_STORE(&Source->current_buffer, newlist);
648 WriteUnlock(&Source->queue_lock);
650 /* Delete all elements in the previous queue */
651 while(oldlist != NULL)
653 ALbufferlistitem *temp = oldlist;
654 oldlist = temp->next;
656 if(temp->buffer)
657 DecrementRef(&temp->buffer->ref);
658 free(temp);
660 return AL_TRUE;
662 case siSourceState:
663 case siSourceType:
664 case siBuffersQueued:
665 case siBuffersProcessed:
666 /* Query only */
667 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
669 case AL_SEC_OFFSET:
670 case AL_SAMPLE_OFFSET:
671 case AL_BYTE_OFFSET:
672 CHECKVAL(*values >= 0);
674 LockContext(Context);
675 Source->OffsetType = prop;
676 Source->Offset = *values;
678 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
679 !Context->DeferUpdates)
681 if(ApplyOffset(Source) == AL_FALSE)
683 UnlockContext(Context);
684 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
687 UnlockContext(Context);
688 return AL_TRUE;
691 case siByteLength:
692 case siSampleLength:
693 case siSampleRWOffsetsSOFT:
694 case siByteRWOffsetsSOFT:
695 /* Query only */
696 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
699 case AL_DIRECT_FILTER:
700 CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
702 LockContext(Context);
703 if(!filter)
705 Source->Direct.Gain = 1.0f;
706 Source->Direct.GainHF = 1.0f;
707 Source->Direct.HFReference = LOWPASSFREQREF;
708 Source->Direct.GainLF = 1.0f;
709 Source->Direct.LFReference = HIGHPASSFREQREF;
711 else
713 Source->Direct.Gain = filter->Gain;
714 Source->Direct.GainHF = filter->GainHF;
715 Source->Direct.HFReference = filter->HFReference;
716 Source->Direct.GainLF = filter->GainLF;
717 Source->Direct.LFReference = filter->LFReference;
719 UnlockContext(Context);
720 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
721 return AL_TRUE;
723 case AL_DIRECT_FILTER_GAINHF_AUTO:
724 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
726 Source->DryGainHFAuto = *values;
727 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
728 return AL_TRUE;
730 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
731 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
733 Source->WetGainAuto = *values;
734 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
735 return AL_TRUE;
737 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
738 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
740 Source->WetGainHFAuto = *values;
741 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
742 return AL_TRUE;
744 case AL_DIRECT_CHANNELS_SOFT:
745 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
747 Source->DirectChannels = *values;
748 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
749 return AL_TRUE;
751 case AL_DISTANCE_MODEL:
752 CHECKVAL(*values == AL_NONE ||
753 *values == AL_INVERSE_DISTANCE ||
754 *values == AL_INVERSE_DISTANCE_CLAMPED ||
755 *values == AL_LINEAR_DISTANCE ||
756 *values == AL_LINEAR_DISTANCE_CLAMPED ||
757 *values == AL_EXPONENT_DISTANCE ||
758 *values == AL_EXPONENT_DISTANCE_CLAMPED);
760 Source->DistanceModel = *values;
761 if(Context->SourceDistanceModel)
762 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
763 return AL_TRUE;
766 case AL_AUXILIARY_SEND_FILTER:
767 LockContext(Context);
768 if(!((ALuint)values[1] < device->NumAuxSends &&
769 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
770 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
772 UnlockContext(Context);
773 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
776 /* Add refcount on the new slot, and release the previous slot */
777 if(slot) IncrementRef(&slot->ref);
778 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
779 if(slot) DecrementRef(&slot->ref);
781 if(!filter)
783 /* Disable filter */
784 Source->Send[values[1]].Gain = 1.0f;
785 Source->Send[values[1]].GainHF = 1.0f;
786 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
787 Source->Send[values[1]].GainLF = 1.0f;
788 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
790 else
792 Source->Send[values[1]].Gain = filter->Gain;
793 Source->Send[values[1]].GainHF = filter->GainHF;
794 Source->Send[values[1]].HFReference = filter->HFReference;
795 Source->Send[values[1]].GainLF = filter->GainLF;
796 Source->Send[values[1]].LFReference = filter->LFReference;
798 UnlockContext(Context);
799 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
800 return AL_TRUE;
803 case AL_MAX_DISTANCE:
804 case AL_ROLLOFF_FACTOR:
805 case AL_CONE_INNER_ANGLE:
806 case AL_CONE_OUTER_ANGLE:
807 case AL_REFERENCE_DISTANCE:
808 case siDopplerFactor:
809 fvals[0] = (ALfloat)*values;
810 return SetSourcefv(Source, Context, (int)prop, fvals);
812 case AL_POSITION:
813 case AL_VELOCITY:
814 case AL_DIRECTION:
815 fvals[0] = (ALfloat)values[0];
816 fvals[1] = (ALfloat)values[1];
817 fvals[2] = (ALfloat)values[2];
818 return SetSourcefv(Source, Context, (int)prop, fvals);
820 case AL_ORIENTATION:
821 fvals[0] = (ALfloat)values[0];
822 fvals[1] = (ALfloat)values[1];
823 fvals[2] = (ALfloat)values[2];
824 fvals[3] = (ALfloat)values[3];
825 fvals[4] = (ALfloat)values[4];
826 fvals[5] = (ALfloat)values[5];
827 return SetSourcefv(Source, Context, (int)prop, fvals);
829 case siSampleOffsetLatencySOFT:
830 /* i64 only */
831 break;
834 ERR("Unexpected property: 0x%04x\n", prop);
835 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
838 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values)
840 ALfloat fvals[6];
841 ALint ivals[3];
843 switch(prop)
845 case siSampleRWOffsetsSOFT:
846 case siByteRWOffsetsSOFT:
847 case siSampleOffsetLatencySOFT:
848 /* Query only */
849 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
852 /* 1x int */
853 case AL_SOURCE_RELATIVE:
854 case AL_LOOPING:
855 case AL_SOURCE_STATE:
856 case AL_BYTE_OFFSET:
857 case AL_SAMPLE_OFFSET:
858 case siByteLength:
859 case siSampleLength:
860 case siSourceType:
861 case siBuffersQueued:
862 case siBuffersProcessed:
863 case AL_DIRECT_FILTER_GAINHF_AUTO:
864 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
865 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
866 case AL_DIRECT_CHANNELS_SOFT:
867 case AL_DISTANCE_MODEL:
868 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
870 ivals[0] = (ALint)*values;
871 return SetSourceiv(Source, Context, (int)prop, ivals);
873 /* 1x uint */
874 case AL_BUFFER:
875 case AL_DIRECT_FILTER:
876 CHECKVAL(*values <= UINT_MAX && *values >= 0);
878 ivals[0] = (ALuint)*values;
879 return SetSourceiv(Source, Context, (int)prop, ivals);
881 /* 3x uint */
882 case AL_AUXILIARY_SEND_FILTER:
883 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
884 values[1] <= UINT_MAX && values[1] >= 0 &&
885 values[2] <= UINT_MAX && values[2] >= 0);
887 ivals[0] = (ALuint)values[0];
888 ivals[1] = (ALuint)values[1];
889 ivals[2] = (ALuint)values[2];
890 return SetSourceiv(Source, Context, (int)prop, ivals);
892 /* 1x float */
893 case AL_MAX_DISTANCE:
894 case AL_ROLLOFF_FACTOR:
895 case AL_CONE_INNER_ANGLE:
896 case AL_CONE_OUTER_ANGLE:
897 case AL_REFERENCE_DISTANCE:
898 case AL_SEC_OFFSET:
899 case siDopplerFactor:
900 fvals[0] = (ALfloat)*values;
901 return SetSourcefv(Source, Context, (int)prop, fvals);
903 /* 3x float */
904 case AL_POSITION:
905 case AL_VELOCITY:
906 case AL_DIRECTION:
907 fvals[0] = (ALfloat)values[0];
908 fvals[1] = (ALfloat)values[1];
909 fvals[2] = (ALfloat)values[2];
910 return SetSourcefv(Source, Context, (int)prop, fvals);
912 /* 6x float */
913 case AL_ORIENTATION:
914 fvals[0] = (ALfloat)values[0];
915 fvals[1] = (ALfloat)values[1];
916 fvals[2] = (ALfloat)values[2];
917 fvals[3] = (ALfloat)values[3];
918 fvals[4] = (ALfloat)values[4];
919 fvals[5] = (ALfloat)values[5];
920 return SetSourcefv(Source, Context, (int)prop, fvals);
923 ERR("Unexpected property: 0x%04x\n", prop);
924 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
927 #undef CHECKVAL
930 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values)
932 ALbufferlistitem *BufferList;
933 ALdouble offsets[2];
934 ALdouble updateLen;
935 ALint ivals[3];
936 ALboolean err;
938 switch(prop)
940 case AL_GAIN:
941 *values = Source->Gain;
942 return AL_TRUE;
944 case AL_PITCH:
945 *values = Source->Pitch;
946 return AL_TRUE;
948 case AL_MAX_DISTANCE:
949 *values = Source->MaxDistance;
950 return AL_TRUE;
952 case AL_ROLLOFF_FACTOR:
953 *values = Source->RollOffFactor;
954 return AL_TRUE;
956 case AL_REFERENCE_DISTANCE:
957 *values = Source->RefDistance;
958 return AL_TRUE;
960 case AL_CONE_INNER_ANGLE:
961 *values = Source->InnerAngle;
962 return AL_TRUE;
964 case AL_CONE_OUTER_ANGLE:
965 *values = Source->OuterAngle;
966 return AL_TRUE;
968 case AL_MIN_GAIN:
969 *values = Source->MinGain;
970 return AL_TRUE;
972 case AL_MAX_GAIN:
973 *values = Source->MaxGain;
974 return AL_TRUE;
976 case AL_CONE_OUTER_GAIN:
977 *values = Source->OuterGain;
978 return AL_TRUE;
980 case AL_SEC_OFFSET:
981 case AL_SAMPLE_OFFSET:
982 case AL_BYTE_OFFSET:
983 LockContext(Context);
984 ReadLock(&Source->queue_lock);
985 GetSourceOffsets(Source, prop, offsets, 0.0);
986 ReadUnlock(&Source->queue_lock);
987 UnlockContext(Context);
988 *values = offsets[0];
989 return AL_TRUE;
991 case AL_CONE_OUTER_GAINHF:
992 *values = Source->OuterGainHF;
993 return AL_TRUE;
995 case AL_AIR_ABSORPTION_FACTOR:
996 *values = Source->AirAbsorptionFactor;
997 return AL_TRUE;
999 case AL_ROOM_ROLLOFF_FACTOR:
1000 *values = Source->RoomRolloffFactor;
1001 return AL_TRUE;
1003 case AL_DOPPLER_FACTOR:
1004 *values = Source->DopplerFactor;
1005 return AL_TRUE;
1007 case sfSecLength:
1008 ReadLock(&Source->queue_lock);
1009 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1010 *values = 0;
1011 else
1013 ALint length = 0;
1014 ALsizei freq = 1;
1015 do {
1016 ALbuffer *buffer = BufferList->buffer;
1017 if(buffer && buffer->SampleLen > 0)
1019 freq = buffer->Frequency;
1020 length += buffer->SampleLen;
1022 } while((BufferList=BufferList->next) != NULL);
1023 *values = (ALdouble)length / (ALdouble)freq;
1025 ReadUnlock(&Source->queue_lock);
1026 return AL_TRUE;
1028 case AL_SAMPLE_RW_OFFSETS_SOFT:
1029 case AL_BYTE_RW_OFFSETS_SOFT:
1030 LockContext(Context);
1031 ReadLock(&Source->queue_lock);
1032 updateLen = (ALdouble)Context->Device->UpdateSize /
1033 Context->Device->Frequency;
1034 GetSourceOffsets(Source, prop, values, updateLen);
1035 ReadUnlock(&Source->queue_lock);
1036 UnlockContext(Context);
1037 return AL_TRUE;
1039 case AL_SEC_OFFSET_LATENCY_SOFT:
1040 LockContext(Context);
1041 ReadLock(&Source->queue_lock);
1042 values[0] = GetSourceSecOffset(Source);
1043 ReadUnlock(&Source->queue_lock);
1044 values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) /
1045 1000000000.0;
1046 UnlockContext(Context);
1047 return AL_TRUE;
1049 case AL_POSITION:
1050 LockContext(Context);
1051 values[0] = Source->Position.v[0];
1052 values[1] = Source->Position.v[1];
1053 values[2] = Source->Position.v[2];
1054 UnlockContext(Context);
1055 return AL_TRUE;
1057 case AL_VELOCITY:
1058 LockContext(Context);
1059 values[0] = Source->Velocity.v[0];
1060 values[1] = Source->Velocity.v[1];
1061 values[2] = Source->Velocity.v[2];
1062 UnlockContext(Context);
1063 return AL_TRUE;
1065 case AL_DIRECTION:
1066 LockContext(Context);
1067 values[0] = Source->Direction.v[0];
1068 values[1] = Source->Direction.v[1];
1069 values[2] = Source->Direction.v[2];
1070 UnlockContext(Context);
1071 return AL_TRUE;
1073 case AL_ORIENTATION:
1074 LockContext(Context);
1075 values[0] = Source->Orientation[0][0];
1076 values[1] = Source->Orientation[0][1];
1077 values[2] = Source->Orientation[0][2];
1078 values[3] = Source->Orientation[1][0];
1079 values[4] = Source->Orientation[1][1];
1080 values[5] = Source->Orientation[1][2];
1081 UnlockContext(Context);
1082 return AL_TRUE;
1084 case AL_SOURCE_RELATIVE:
1085 case AL_LOOPING:
1086 case AL_BUFFER:
1087 case AL_SOURCE_STATE:
1088 case AL_BUFFERS_QUEUED:
1089 case AL_BUFFERS_PROCESSED:
1090 case AL_SOURCE_TYPE:
1091 case AL_DIRECT_FILTER_GAINHF_AUTO:
1092 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1093 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1094 case AL_DIRECT_CHANNELS_SOFT:
1095 case AL_DISTANCE_MODEL:
1096 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1097 *values = (ALdouble)ivals[0];
1098 return err;
1101 ERR("Unexpected property: 0x%04x\n", prop);
1102 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1105 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values)
1107 ALbufferlistitem *BufferList;
1108 ALdouble dvals[6];
1109 ALboolean err;
1111 switch(prop)
1113 case AL_SOURCE_RELATIVE:
1114 *values = Source->HeadRelative;
1115 return AL_TRUE;
1117 case AL_LOOPING:
1118 *values = Source->Looping;
1119 return AL_TRUE;
1121 case AL_BUFFER:
1122 ReadLock(&Source->queue_lock);
1123 BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) :
1124 ATOMIC_LOAD(&Source->current_buffer);
1125 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1126 ReadUnlock(&Source->queue_lock);
1127 return AL_TRUE;
1129 case AL_SOURCE_STATE:
1130 *values = Source->state;
1131 return AL_TRUE;
1133 case siByteLength:
1134 ReadLock(&Source->queue_lock);
1135 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1136 *values = 0;
1137 else
1139 ALint length = 0;
1140 do {
1141 ALbuffer *buffer = BufferList->buffer;
1142 if(buffer && buffer->SampleLen > 0)
1144 ALuint byte_align, sample_align;
1145 if(buffer->OriginalType == UserFmtIMA4)
1147 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1148 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1149 sample_align = buffer->OriginalAlign;
1151 else if(buffer->OriginalType == UserFmtMSADPCM)
1153 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1154 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1155 sample_align = buffer->OriginalAlign;
1157 else
1159 ALsizei align = buffer->OriginalAlign;
1160 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1161 sample_align = buffer->OriginalAlign;
1164 length += buffer->SampleLen / sample_align * byte_align;
1166 } while((BufferList=BufferList->next) != NULL);
1167 *values = length;
1169 ReadUnlock(&Source->queue_lock);
1170 return AL_TRUE;
1172 case siSampleLength:
1173 ReadLock(&Source->queue_lock);
1174 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1175 *values = 0;
1176 else
1178 ALint length = 0;
1179 do {
1180 ALbuffer *buffer = BufferList->buffer;
1181 if(buffer) length += buffer->SampleLen;
1182 } while((BufferList=BufferList->next) != NULL);
1183 *values = length;
1185 ReadUnlock(&Source->queue_lock);
1186 return AL_TRUE;
1188 case AL_BUFFERS_QUEUED:
1189 ReadLock(&Source->queue_lock);
1190 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1191 *values = 0;
1192 else
1194 ALsizei count = 0;
1195 do {
1196 ++count;
1197 } while((BufferList=BufferList->next) != NULL);
1198 *values = count;
1200 ReadUnlock(&Source->queue_lock);
1201 return AL_TRUE;
1203 case AL_BUFFERS_PROCESSED:
1204 ReadLock(&Source->queue_lock);
1205 if(Source->Looping || Source->SourceType != AL_STREAMING)
1207 /* Buffers on a looping source are in a perpetual state of
1208 * PENDING, so don't report any as PROCESSED */
1209 *values = 0;
1211 else
1213 const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue);
1214 const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer);
1215 ALsizei played = 0;
1216 while(BufferList && BufferList != Current)
1218 played++;
1219 BufferList = BufferList->next;
1221 *values = played;
1223 ReadUnlock(&Source->queue_lock);
1224 return AL_TRUE;
1226 case AL_SOURCE_TYPE:
1227 *values = Source->SourceType;
1228 return AL_TRUE;
1230 case AL_DIRECT_FILTER_GAINHF_AUTO:
1231 *values = Source->DryGainHFAuto;
1232 return AL_TRUE;
1234 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1235 *values = Source->WetGainAuto;
1236 return AL_TRUE;
1238 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1239 *values = Source->WetGainHFAuto;
1240 return AL_TRUE;
1242 case AL_DIRECT_CHANNELS_SOFT:
1243 *values = Source->DirectChannels;
1244 return AL_TRUE;
1246 case AL_DISTANCE_MODEL:
1247 *values = Source->DistanceModel;
1248 return AL_TRUE;
1250 case AL_MAX_DISTANCE:
1251 case AL_ROLLOFF_FACTOR:
1252 case AL_REFERENCE_DISTANCE:
1253 case AL_CONE_INNER_ANGLE:
1254 case AL_CONE_OUTER_ANGLE:
1255 case AL_SEC_OFFSET:
1256 case AL_SAMPLE_OFFSET:
1257 case AL_BYTE_OFFSET:
1258 case AL_DOPPLER_FACTOR:
1259 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1260 *values = (ALint)dvals[0];
1261 return err;
1263 case AL_SAMPLE_RW_OFFSETS_SOFT:
1264 case AL_BYTE_RW_OFFSETS_SOFT:
1265 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1267 values[0] = (ALint)dvals[0];
1268 values[1] = (ALint)dvals[1];
1270 return err;
1272 case AL_POSITION:
1273 case AL_VELOCITY:
1274 case AL_DIRECTION:
1275 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1277 values[0] = (ALint)dvals[0];
1278 values[1] = (ALint)dvals[1];
1279 values[2] = (ALint)dvals[2];
1281 return err;
1283 case AL_ORIENTATION:
1284 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1286 values[0] = (ALint)dvals[0];
1287 values[1] = (ALint)dvals[1];
1288 values[2] = (ALint)dvals[2];
1289 values[3] = (ALint)dvals[3];
1290 values[4] = (ALint)dvals[4];
1291 values[5] = (ALint)dvals[5];
1293 return err;
1295 case siSampleOffsetLatencySOFT:
1296 /* i64 only */
1297 break;
1299 case siDirectFilter:
1300 case siAuxSendFilter:
1301 /* ??? */
1302 break;
1305 ERR("Unexpected property: 0x%04x\n", prop);
1306 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1309 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values)
1311 ALdouble dvals[6];
1312 ALint ivals[3];
1313 ALboolean err;
1315 switch(prop)
1317 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1318 LockContext(Context);
1319 ReadLock(&Source->queue_lock);
1320 values[0] = GetSourceOffset(Source);
1321 ReadUnlock(&Source->queue_lock);
1322 values[1] = ALCdevice_GetLatency(Context->Device);
1323 UnlockContext(Context);
1324 return AL_TRUE;
1326 case AL_MAX_DISTANCE:
1327 case AL_ROLLOFF_FACTOR:
1328 case AL_REFERENCE_DISTANCE:
1329 case AL_CONE_INNER_ANGLE:
1330 case AL_CONE_OUTER_ANGLE:
1331 case AL_SEC_OFFSET:
1332 case AL_SAMPLE_OFFSET:
1333 case AL_BYTE_OFFSET:
1334 case AL_DOPPLER_FACTOR:
1335 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1336 *values = (ALint64)dvals[0];
1337 return err;
1339 case AL_SAMPLE_RW_OFFSETS_SOFT:
1340 case AL_BYTE_RW_OFFSETS_SOFT:
1341 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1343 values[0] = (ALint64)dvals[0];
1344 values[1] = (ALint64)dvals[1];
1346 return err;
1348 case AL_POSITION:
1349 case AL_VELOCITY:
1350 case AL_DIRECTION:
1351 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1353 values[0] = (ALint64)dvals[0];
1354 values[1] = (ALint64)dvals[1];
1355 values[2] = (ALint64)dvals[2];
1357 return err;
1359 case AL_ORIENTATION:
1360 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1362 values[0] = (ALint64)dvals[0];
1363 values[1] = (ALint64)dvals[1];
1364 values[2] = (ALint64)dvals[2];
1365 values[3] = (ALint64)dvals[3];
1366 values[4] = (ALint64)dvals[4];
1367 values[5] = (ALint64)dvals[5];
1369 return err;
1371 case AL_SOURCE_RELATIVE:
1372 case AL_LOOPING:
1373 case AL_SOURCE_STATE:
1374 case AL_BUFFERS_QUEUED:
1375 case AL_BUFFERS_PROCESSED:
1376 case siByteLength:
1377 case siSampleLength:
1378 case AL_SOURCE_TYPE:
1379 case AL_DIRECT_FILTER_GAINHF_AUTO:
1380 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1381 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1382 case AL_DIRECT_CHANNELS_SOFT:
1383 case AL_DISTANCE_MODEL:
1384 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1385 *values = ivals[0];
1386 return err;
1388 case siBuffer:
1389 case siDirectFilter:
1390 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1391 *values = (ALuint)ivals[0];
1392 return err;
1394 case siAuxSendFilter:
1395 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1397 values[0] = (ALuint)ivals[0];
1398 values[1] = (ALuint)ivals[1];
1399 values[2] = (ALuint)ivals[2];
1401 return err;
1404 ERR("Unexpected property: 0x%04x\n", prop);
1405 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1409 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1411 ALCcontext *context;
1412 ALsizei cur = 0;
1413 ALenum err;
1415 context = GetContextRef();
1416 if(!context) return;
1418 if(!(n >= 0))
1419 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1420 for(cur = 0;cur < n;cur++)
1422 ALsource *source = al_calloc(16, sizeof(ALsource));
1423 if(!source)
1425 alDeleteSources(cur, sources);
1426 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1428 InitSourceParams(source);
1430 err = NewThunkEntry(&source->id);
1431 if(err == AL_NO_ERROR)
1432 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1433 if(err != AL_NO_ERROR)
1435 FreeThunkEntry(source->id);
1436 memset(source, 0, sizeof(ALsource));
1437 al_free(source);
1439 alDeleteSources(cur, sources);
1440 SET_ERROR_AND_GOTO(context, err, done);
1443 sources[cur] = source->id;
1446 done:
1447 ALCcontext_DecRef(context);
1451 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1453 ALCcontext *context;
1454 ALbufferlistitem *BufferList;
1455 ALsource *Source;
1456 ALsizei i, j;
1458 context = GetContextRef();
1459 if(!context) return;
1461 if(!(n >= 0))
1462 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1464 /* Check that all Sources are valid */
1465 for(i = 0;i < n;i++)
1467 if(LookupSource(context, sources[i]) == NULL)
1468 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1470 for(i = 0;i < n;i++)
1472 ALvoice *voice, *voice_end;
1474 if((Source=RemoveSource(context, sources[i])) == NULL)
1475 continue;
1476 FreeThunkEntry(Source->id);
1478 LockContext(context);
1479 voice = context->Voices;
1480 voice_end = voice + context->VoiceCount;
1481 while(voice != voice_end)
1483 ALsource *old = Source;
1484 if(COMPARE_EXCHANGE(&voice->Source, &old, NULL))
1485 break;
1486 voice++;
1488 UnlockContext(context);
1490 BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, NULL);
1491 while(BufferList != NULL)
1493 ALbufferlistitem *next = BufferList->next;
1494 if(BufferList->buffer != NULL)
1495 DecrementRef(&BufferList->buffer->ref);
1496 free(BufferList);
1497 BufferList = next;
1500 for(j = 0;j < MAX_SENDS;++j)
1502 if(Source->Send[j].Slot)
1503 DecrementRef(&Source->Send[j].Slot->ref);
1504 Source->Send[j].Slot = NULL;
1507 memset(Source, 0, sizeof(*Source));
1508 al_free(Source);
1511 done:
1512 ALCcontext_DecRef(context);
1516 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1518 ALCcontext *context;
1519 ALboolean ret;
1521 context = GetContextRef();
1522 if(!context) return AL_FALSE;
1524 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1526 ALCcontext_DecRef(context);
1528 return ret;
1532 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1534 ALCcontext *Context;
1535 ALsource *Source;
1537 Context = GetContextRef();
1538 if(!Context) return;
1540 if((Source=LookupSource(Context, source)) == NULL)
1541 alSetError(Context, AL_INVALID_NAME);
1542 else if(!(FloatValsByProp(param) == 1))
1543 alSetError(Context, AL_INVALID_ENUM);
1544 else
1545 SetSourcefv(Source, Context, param, &value);
1547 ALCcontext_DecRef(Context);
1550 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1552 ALCcontext *Context;
1553 ALsource *Source;
1555 Context = GetContextRef();
1556 if(!Context) return;
1558 if((Source=LookupSource(Context, source)) == NULL)
1559 alSetError(Context, AL_INVALID_NAME);
1560 else if(!(FloatValsByProp(param) == 3))
1561 alSetError(Context, AL_INVALID_ENUM);
1562 else
1564 ALfloat fvals[3] = { value1, value2, value3 };
1565 SetSourcefv(Source, Context, param, fvals);
1568 ALCcontext_DecRef(Context);
1571 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1573 ALCcontext *Context;
1574 ALsource *Source;
1576 Context = GetContextRef();
1577 if(!Context) return;
1579 if((Source=LookupSource(Context, source)) == NULL)
1580 alSetError(Context, AL_INVALID_NAME);
1581 else if(!values)
1582 alSetError(Context, AL_INVALID_VALUE);
1583 else if(!(FloatValsByProp(param) > 0))
1584 alSetError(Context, AL_INVALID_ENUM);
1585 else
1586 SetSourcefv(Source, Context, param, values);
1588 ALCcontext_DecRef(Context);
1592 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1594 ALCcontext *Context;
1595 ALsource *Source;
1597 Context = GetContextRef();
1598 if(!Context) return;
1600 if((Source=LookupSource(Context, source)) == NULL)
1601 alSetError(Context, AL_INVALID_NAME);
1602 else if(!(DoubleValsByProp(param) == 1))
1603 alSetError(Context, AL_INVALID_ENUM);
1604 else
1606 ALfloat fval = (ALfloat)value;
1607 SetSourcefv(Source, Context, param, &fval);
1610 ALCcontext_DecRef(Context);
1613 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1615 ALCcontext *Context;
1616 ALsource *Source;
1618 Context = GetContextRef();
1619 if(!Context) return;
1621 if((Source=LookupSource(Context, source)) == NULL)
1622 alSetError(Context, AL_INVALID_NAME);
1623 else if(!(DoubleValsByProp(param) == 3))
1624 alSetError(Context, AL_INVALID_ENUM);
1625 else
1627 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1628 SetSourcefv(Source, Context, param, fvals);
1631 ALCcontext_DecRef(Context);
1634 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1636 ALCcontext *Context;
1637 ALsource *Source;
1638 ALint count;
1640 Context = GetContextRef();
1641 if(!Context) return;
1643 if((Source=LookupSource(Context, source)) == NULL)
1644 alSetError(Context, AL_INVALID_NAME);
1645 else if(!values)
1646 alSetError(Context, AL_INVALID_VALUE);
1647 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 3))
1648 alSetError(Context, AL_INVALID_ENUM);
1649 else
1651 ALfloat fvals[3];
1652 ALint i;
1654 for(i = 0;i < count;i++)
1655 fvals[i] = (ALfloat)values[i];
1656 SetSourcefv(Source, Context, param, fvals);
1659 ALCcontext_DecRef(Context);
1663 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1665 ALCcontext *Context;
1666 ALsource *Source;
1668 Context = GetContextRef();
1669 if(!Context) return;
1671 if((Source=LookupSource(Context, source)) == NULL)
1672 alSetError(Context, AL_INVALID_NAME);
1673 else if(!(IntValsByProp(param) == 1))
1674 alSetError(Context, AL_INVALID_ENUM);
1675 else
1676 SetSourceiv(Source, Context, param, &value);
1678 ALCcontext_DecRef(Context);
1681 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1683 ALCcontext *Context;
1684 ALsource *Source;
1686 Context = GetContextRef();
1687 if(!Context) return;
1689 if((Source=LookupSource(Context, source)) == NULL)
1690 alSetError(Context, AL_INVALID_NAME);
1691 else if(!(IntValsByProp(param) == 3))
1692 alSetError(Context, AL_INVALID_ENUM);
1693 else
1695 ALint ivals[3] = { value1, value2, value3 };
1696 SetSourceiv(Source, Context, param, ivals);
1699 ALCcontext_DecRef(Context);
1702 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1704 ALCcontext *Context;
1705 ALsource *Source;
1707 Context = GetContextRef();
1708 if(!Context) return;
1710 if((Source=LookupSource(Context, source)) == NULL)
1711 alSetError(Context, AL_INVALID_NAME);
1712 else if(!values)
1713 alSetError(Context, AL_INVALID_VALUE);
1714 else if(!(IntValsByProp(param) > 0))
1715 alSetError(Context, AL_INVALID_ENUM);
1716 else
1717 SetSourceiv(Source, Context, param, values);
1719 ALCcontext_DecRef(Context);
1723 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1725 ALCcontext *Context;
1726 ALsource *Source;
1728 Context = GetContextRef();
1729 if(!Context) return;
1731 if((Source=LookupSource(Context, source)) == NULL)
1732 alSetError(Context, AL_INVALID_NAME);
1733 else if(!(Int64ValsByProp(param) == 1))
1734 alSetError(Context, AL_INVALID_ENUM);
1735 else
1736 SetSourcei64v(Source, Context, param, &value);
1738 ALCcontext_DecRef(Context);
1741 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1743 ALCcontext *Context;
1744 ALsource *Source;
1746 Context = GetContextRef();
1747 if(!Context) return;
1749 if((Source=LookupSource(Context, source)) == NULL)
1750 alSetError(Context, AL_INVALID_NAME);
1751 else if(!(Int64ValsByProp(param) == 3))
1752 alSetError(Context, AL_INVALID_ENUM);
1753 else
1755 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1756 SetSourcei64v(Source, Context, param, i64vals);
1759 ALCcontext_DecRef(Context);
1762 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1764 ALCcontext *Context;
1765 ALsource *Source;
1767 Context = GetContextRef();
1768 if(!Context) return;
1770 if((Source=LookupSource(Context, source)) == NULL)
1771 alSetError(Context, AL_INVALID_NAME);
1772 else if(!values)
1773 alSetError(Context, AL_INVALID_VALUE);
1774 else if(!(Int64ValsByProp(param) > 0))
1775 alSetError(Context, AL_INVALID_ENUM);
1776 else
1777 SetSourcei64v(Source, Context, param, values);
1779 ALCcontext_DecRef(Context);
1783 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1785 ALCcontext *Context;
1786 ALsource *Source;
1788 Context = GetContextRef();
1789 if(!Context) return;
1791 if((Source=LookupSource(Context, source)) == NULL)
1792 alSetError(Context, AL_INVALID_NAME);
1793 else if(!value)
1794 alSetError(Context, AL_INVALID_VALUE);
1795 else if(!(FloatValsByProp(param) == 1))
1796 alSetError(Context, AL_INVALID_ENUM);
1797 else
1799 ALdouble dval;
1800 if(GetSourcedv(Source, Context, param, &dval))
1801 *value = (ALfloat)dval;
1804 ALCcontext_DecRef(Context);
1808 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1810 ALCcontext *Context;
1811 ALsource *Source;
1813 Context = GetContextRef();
1814 if(!Context) return;
1816 if((Source=LookupSource(Context, source)) == NULL)
1817 alSetError(Context, AL_INVALID_NAME);
1818 else if(!(value1 && value2 && value3))
1819 alSetError(Context, AL_INVALID_VALUE);
1820 else if(!(FloatValsByProp(param) == 3))
1821 alSetError(Context, AL_INVALID_ENUM);
1822 else
1824 ALdouble dvals[3];
1825 if(GetSourcedv(Source, Context, param, dvals))
1827 *value1 = (ALfloat)dvals[0];
1828 *value2 = (ALfloat)dvals[1];
1829 *value3 = (ALfloat)dvals[2];
1833 ALCcontext_DecRef(Context);
1837 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1839 ALCcontext *Context;
1840 ALsource *Source;
1841 ALint count;
1843 Context = GetContextRef();
1844 if(!Context) return;
1846 if((Source=LookupSource(Context, source)) == NULL)
1847 alSetError(Context, AL_INVALID_NAME);
1848 else if(!values)
1849 alSetError(Context, AL_INVALID_VALUE);
1850 else if(!((count=FloatValsByProp(param)) > 0 && count <= 3))
1851 alSetError(Context, AL_INVALID_ENUM);
1852 else
1854 ALdouble dvals[3];
1855 if(GetSourcedv(Source, Context, param, dvals))
1857 ALint i;
1858 for(i = 0;i < count;i++)
1859 values[i] = (ALfloat)dvals[i];
1863 ALCcontext_DecRef(Context);
1867 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1869 ALCcontext *Context;
1870 ALsource *Source;
1872 Context = GetContextRef();
1873 if(!Context) return;
1875 if((Source=LookupSource(Context, source)) == NULL)
1876 alSetError(Context, AL_INVALID_NAME);
1877 else if(!value)
1878 alSetError(Context, AL_INVALID_VALUE);
1879 else if(!(DoubleValsByProp(param) == 1))
1880 alSetError(Context, AL_INVALID_ENUM);
1881 else
1882 GetSourcedv(Source, Context, param, value);
1884 ALCcontext_DecRef(Context);
1887 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1889 ALCcontext *Context;
1890 ALsource *Source;
1892 Context = GetContextRef();
1893 if(!Context) return;
1895 if((Source=LookupSource(Context, source)) == NULL)
1896 alSetError(Context, AL_INVALID_NAME);
1897 else if(!(value1 && value2 && value3))
1898 alSetError(Context, AL_INVALID_VALUE);
1899 else if(!(DoubleValsByProp(param) == 3))
1900 alSetError(Context, AL_INVALID_ENUM);
1901 else
1903 ALdouble dvals[3];
1904 if(GetSourcedv(Source, Context, param, dvals))
1906 *value1 = dvals[0];
1907 *value2 = dvals[1];
1908 *value3 = dvals[2];
1912 ALCcontext_DecRef(Context);
1915 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1917 ALCcontext *Context;
1918 ALsource *Source;
1920 Context = GetContextRef();
1921 if(!Context) return;
1923 if((Source=LookupSource(Context, source)) == NULL)
1924 alSetError(Context, AL_INVALID_NAME);
1925 else if(!values)
1926 alSetError(Context, AL_INVALID_VALUE);
1927 else if(!(DoubleValsByProp(param) > 0))
1928 alSetError(Context, AL_INVALID_ENUM);
1929 else
1930 GetSourcedv(Source, Context, param, values);
1932 ALCcontext_DecRef(Context);
1936 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1938 ALCcontext *Context;
1939 ALsource *Source;
1941 Context = GetContextRef();
1942 if(!Context) return;
1944 if((Source=LookupSource(Context, source)) == NULL)
1945 alSetError(Context, AL_INVALID_NAME);
1946 else if(!value)
1947 alSetError(Context, AL_INVALID_VALUE);
1948 else if(!(IntValsByProp(param) == 1))
1949 alSetError(Context, AL_INVALID_ENUM);
1950 else
1951 GetSourceiv(Source, Context, param, value);
1953 ALCcontext_DecRef(Context);
1957 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
1959 ALCcontext *Context;
1960 ALsource *Source;
1962 Context = GetContextRef();
1963 if(!Context) return;
1965 if((Source=LookupSource(Context, source)) == NULL)
1966 alSetError(Context, AL_INVALID_NAME);
1967 else if(!(value1 && value2 && value3))
1968 alSetError(Context, AL_INVALID_VALUE);
1969 else if(!(IntValsByProp(param) == 3))
1970 alSetError(Context, AL_INVALID_ENUM);
1971 else
1973 ALint ivals[3];
1974 if(GetSourceiv(Source, Context, param, ivals))
1976 *value1 = ivals[0];
1977 *value2 = ivals[1];
1978 *value3 = ivals[2];
1982 ALCcontext_DecRef(Context);
1986 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
1988 ALCcontext *Context;
1989 ALsource *Source;
1991 Context = GetContextRef();
1992 if(!Context) return;
1994 if((Source=LookupSource(Context, source)) == NULL)
1995 alSetError(Context, AL_INVALID_NAME);
1996 else if(!values)
1997 alSetError(Context, AL_INVALID_VALUE);
1998 else if(!(IntValsByProp(param) > 0))
1999 alSetError(Context, AL_INVALID_ENUM);
2000 else
2001 GetSourceiv(Source, Context, param, values);
2003 ALCcontext_DecRef(Context);
2007 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2009 ALCcontext *Context;
2010 ALsource *Source;
2012 Context = GetContextRef();
2013 if(!Context) return;
2015 if((Source=LookupSource(Context, source)) == NULL)
2016 alSetError(Context, AL_INVALID_NAME);
2017 else if(!value)
2018 alSetError(Context, AL_INVALID_VALUE);
2019 else if(!(Int64ValsByProp(param) == 1))
2020 alSetError(Context, AL_INVALID_ENUM);
2021 else
2022 GetSourcei64v(Source, Context, param, value);
2024 ALCcontext_DecRef(Context);
2027 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2029 ALCcontext *Context;
2030 ALsource *Source;
2032 Context = GetContextRef();
2033 if(!Context) return;
2035 if((Source=LookupSource(Context, source)) == NULL)
2036 alSetError(Context, AL_INVALID_NAME);
2037 else if(!(value1 && value2 && value3))
2038 alSetError(Context, AL_INVALID_VALUE);
2039 else if(!(Int64ValsByProp(param) == 3))
2040 alSetError(Context, AL_INVALID_ENUM);
2041 else
2043 ALint64 i64vals[3];
2044 if(GetSourcei64v(Source, Context, param, i64vals))
2046 *value1 = i64vals[0];
2047 *value2 = i64vals[1];
2048 *value3 = i64vals[2];
2052 ALCcontext_DecRef(Context);
2055 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2057 ALCcontext *Context;
2058 ALsource *Source;
2060 Context = GetContextRef();
2061 if(!Context) return;
2063 if((Source=LookupSource(Context, source)) == NULL)
2064 alSetError(Context, AL_INVALID_NAME);
2065 else if(!values)
2066 alSetError(Context, AL_INVALID_VALUE);
2067 else if(!(Int64ValsByProp(param) > 0))
2068 alSetError(Context, AL_INVALID_ENUM);
2069 else
2070 GetSourcei64v(Source, Context, param, values);
2072 ALCcontext_DecRef(Context);
2076 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2078 alSourcePlayv(1, &source);
2080 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2082 ALCcontext *context;
2083 ALsource *source;
2084 ALsizei i;
2086 context = GetContextRef();
2087 if(!context) return;
2089 if(!(n >= 0))
2090 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2091 for(i = 0;i < n;i++)
2093 if(!LookupSource(context, sources[i]))
2094 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2097 LockContext(context);
2098 while(n > context->MaxVoices-context->VoiceCount)
2100 ALvoice *temp = NULL;
2101 ALsizei newcount;
2103 newcount = context->MaxVoices << 1;
2104 if(newcount > 0)
2105 temp = realloc(context->Voices, newcount * sizeof(context->Voices[0]));
2106 if(!temp)
2108 UnlockContext(context);
2109 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2111 memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0]));
2113 context->Voices = temp;
2114 context->MaxVoices = newcount;
2117 for(i = 0;i < n;i++)
2119 source = LookupSource(context, sources[i]);
2120 if(context->DeferUpdates) source->new_state = AL_PLAYING;
2121 else SetSourceState(source, context, AL_PLAYING);
2123 UnlockContext(context);
2125 done:
2126 ALCcontext_DecRef(context);
2129 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2131 alSourcePausev(1, &source);
2133 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2135 ALCcontext *context;
2136 ALsource *source;
2137 ALsizei i;
2139 context = GetContextRef();
2140 if(!context) return;
2142 if(!(n >= 0))
2143 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2144 for(i = 0;i < n;i++)
2146 if(!LookupSource(context, sources[i]))
2147 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2150 LockContext(context);
2151 for(i = 0;i < n;i++)
2153 source = LookupSource(context, sources[i]);
2154 if(context->DeferUpdates) source->new_state = AL_PAUSED;
2155 else SetSourceState(source, context, AL_PAUSED);
2157 UnlockContext(context);
2159 done:
2160 ALCcontext_DecRef(context);
2163 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2165 alSourceStopv(1, &source);
2167 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2169 ALCcontext *context;
2170 ALsource *source;
2171 ALsizei i;
2173 context = GetContextRef();
2174 if(!context) return;
2176 if(!(n >= 0))
2177 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2178 for(i = 0;i < n;i++)
2180 if(!LookupSource(context, sources[i]))
2181 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2184 LockContext(context);
2185 for(i = 0;i < n;i++)
2187 source = LookupSource(context, sources[i]);
2188 source->new_state = AL_NONE;
2189 SetSourceState(source, context, AL_STOPPED);
2191 UnlockContext(context);
2193 done:
2194 ALCcontext_DecRef(context);
2197 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2199 alSourceRewindv(1, &source);
2201 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2203 ALCcontext *context;
2204 ALsource *source;
2205 ALsizei i;
2207 context = GetContextRef();
2208 if(!context) return;
2210 if(!(n >= 0))
2211 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2212 for(i = 0;i < n;i++)
2214 if(!LookupSource(context, sources[i]))
2215 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2218 LockContext(context);
2219 for(i = 0;i < n;i++)
2221 source = LookupSource(context, sources[i]);
2222 source->new_state = AL_NONE;
2223 SetSourceState(source, context, AL_INITIAL);
2225 UnlockContext(context);
2227 done:
2228 ALCcontext_DecRef(context);
2232 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2234 ALCdevice *device;
2235 ALCcontext *context;
2236 ALsource *source;
2237 ALsizei i;
2238 ALbufferlistitem *BufferListStart;
2239 ALbufferlistitem *BufferList;
2240 ALbuffer *BufferFmt = NULL;
2242 if(nb == 0)
2243 return;
2245 context = GetContextRef();
2246 if(!context) return;
2248 device = context->Device;
2250 if(!(nb >= 0))
2251 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2252 if((source=LookupSource(context, src)) == NULL)
2253 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2255 WriteLock(&source->queue_lock);
2256 if(source->SourceType == AL_STATIC)
2258 WriteUnlock(&source->queue_lock);
2259 /* Can't queue on a Static Source */
2260 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2263 /* Check for a valid Buffer, for its frequency and format */
2264 BufferList = ATOMIC_LOAD(&source->queue);
2265 while(BufferList)
2267 if(BufferList->buffer)
2269 BufferFmt = BufferList->buffer;
2270 break;
2272 BufferList = BufferList->next;
2275 BufferListStart = NULL;
2276 BufferList = NULL;
2277 for(i = 0;i < nb;i++)
2279 ALbuffer *buffer = NULL;
2280 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2282 WriteUnlock(&source->queue_lock);
2283 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2286 if(!BufferListStart)
2288 BufferListStart = malloc(sizeof(ALbufferlistitem));
2289 BufferListStart->buffer = buffer;
2290 BufferListStart->next = NULL;
2291 BufferListStart->prev = NULL;
2292 BufferList = BufferListStart;
2294 else
2296 BufferList->next = malloc(sizeof(ALbufferlistitem));
2297 BufferList->next->buffer = buffer;
2298 BufferList->next->next = NULL;
2299 BufferList->next->prev = BufferList;
2300 BufferList = BufferList->next;
2302 if(!buffer) continue;
2304 /* Hold a read lock on each buffer being queued while checking all
2305 * provided buffers. This is done so other threads don't see an extra
2306 * reference on some buffers if this operation ends up failing. */
2307 ReadLock(&buffer->lock);
2308 IncrementRef(&buffer->ref);
2310 if(BufferFmt == NULL)
2312 BufferFmt = buffer;
2314 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2315 source->SampleSize = BytesFromFmt(buffer->FmtType);
2317 else if(BufferFmt->Frequency != buffer->Frequency ||
2318 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2319 BufferFmt->OriginalType != buffer->OriginalType)
2321 WriteUnlock(&source->queue_lock);
2322 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2324 buffer_error:
2325 /* A buffer failed (invalid ID or format), so unlock and release
2326 * each buffer we had. */
2327 while(BufferList != NULL)
2329 ALbufferlistitem *prev = BufferList->prev;
2330 if((buffer=BufferList->buffer) != NULL)
2332 DecrementRef(&buffer->ref);
2333 ReadUnlock(&buffer->lock);
2335 free(BufferList);
2336 BufferList = prev;
2338 goto done;
2341 /* All buffers good, unlock them now. */
2342 while(BufferList != NULL)
2344 ALbuffer *buffer = BufferList->buffer;
2345 if(buffer) ReadUnlock(&buffer->lock);
2346 BufferList = BufferList->prev;
2349 /* Source is now streaming */
2350 source->SourceType = AL_STREAMING;
2352 BufferList = NULL;
2353 if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
2355 /* Queue head is not NULL, append to the end of the queue */
2356 while(BufferList->next != NULL)
2357 BufferList = BufferList->next;
2359 BufferListStart->prev = BufferList;
2360 BufferList->next = BufferListStart;
2362 BufferList = NULL;
2363 ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
2364 WriteUnlock(&source->queue_lock);
2366 done:
2367 ALCcontext_DecRef(context);
2370 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2372 ALCcontext *context;
2373 ALsource *source;
2374 ALbufferlistitem *NewHead;
2375 ALbufferlistitem *OldHead;
2376 ALbufferlistitem *Current;
2377 ALsizei i;
2379 if(nb == 0)
2380 return;
2382 context = GetContextRef();
2383 if(!context) return;
2385 if(!(nb >= 0))
2386 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2388 if((source=LookupSource(context, src)) == NULL)
2389 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2391 WriteLock(&source->queue_lock);
2392 /* Find the new buffer queue head */
2393 NewHead = ATOMIC_LOAD(&source->queue);
2394 Current = ATOMIC_LOAD(&source->current_buffer);
2395 for(i = 0;i < nb && NewHead;i++)
2397 if(NewHead == Current)
2398 break;
2399 NewHead = NewHead->next;
2401 if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
2403 WriteUnlock(&source->queue_lock);
2404 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2405 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2408 /* Swap it, and cut the new head from the old. */
2409 OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NewHead);
2410 if(NewHead)
2412 ALCdevice *device = context->Device;
2413 ALbufferlistitem *OldTail = NewHead->prev;
2414 uint count;
2416 /* Cut the new head's link back to the old body. The mixer is robust
2417 * enough to handle the link back going away. Once the active mix (if
2418 * any) is complete, it's safe to finish cutting the old tail from the
2419 * new head. */
2420 NewHead->prev = NULL;
2421 if(((count=ReadRef(&device->MixCount))&1) != 0)
2423 while(count == ReadRef(&device->MixCount))
2424 althrd_yield();
2426 OldTail->next = NULL;
2428 WriteUnlock(&source->queue_lock);
2430 while(OldHead != NULL)
2432 ALbufferlistitem *next = OldHead->next;
2433 ALbuffer *buffer = OldHead->buffer;
2435 if(!buffer)
2436 *(buffers++) = 0;
2437 else
2439 *(buffers++) = buffer->id;
2440 DecrementRef(&buffer->ref);
2443 free(OldHead);
2444 OldHead = next;
2447 done:
2448 ALCcontext_DecRef(context);
2452 static ALvoid InitSourceParams(ALsource *Source)
2454 ALuint i;
2456 RWLockInit(&Source->queue_lock);
2458 Source->InnerAngle = 360.0f;
2459 Source->OuterAngle = 360.0f;
2460 Source->Pitch = 1.0f;
2461 aluVectorSet(&Source->Position, 0.0f, 0.0f, 0.0f, 1.0f);
2462 aluVectorSet(&Source->Velocity, 0.0f, 0.0f, 0.0f, 0.0f);
2463 aluVectorSet(&Source->Direction, 0.0f, 0.0f, 0.0f, 0.0f);
2464 Source->Orientation[0][0] = 0.0f;
2465 Source->Orientation[0][1] = 0.0f;
2466 Source->Orientation[0][2] = -1.0f;
2467 Source->Orientation[1][0] = 0.0f;
2468 Source->Orientation[1][1] = 1.0f;
2469 Source->Orientation[1][2] = 0.0f;
2470 Source->RefDistance = 1.0f;
2471 Source->MaxDistance = FLT_MAX;
2472 Source->RollOffFactor = 1.0f;
2473 Source->Looping = AL_FALSE;
2474 Source->Gain = 1.0f;
2475 Source->MinGain = 0.0f;
2476 Source->MaxGain = 1.0f;
2477 Source->OuterGain = 0.0f;
2478 Source->OuterGainHF = 1.0f;
2480 Source->DryGainHFAuto = AL_TRUE;
2481 Source->WetGainAuto = AL_TRUE;
2482 Source->WetGainHFAuto = AL_TRUE;
2483 Source->AirAbsorptionFactor = 0.0f;
2484 Source->RoomRolloffFactor = 0.0f;
2485 Source->DopplerFactor = 1.0f;
2486 Source->DirectChannels = AL_FALSE;
2488 Source->Radius = 0.0f;
2490 Source->DistanceModel = DefaultDistanceModel;
2492 Source->Resampler = DefaultResampler;
2494 Source->state = AL_INITIAL;
2495 Source->new_state = AL_NONE;
2496 Source->SourceType = AL_UNDETERMINED;
2497 Source->Offset = -1.0;
2499 ATOMIC_INIT(&Source->queue, NULL);
2500 ATOMIC_INIT(&Source->current_buffer, NULL);
2502 Source->Direct.Gain = 1.0f;
2503 Source->Direct.GainHF = 1.0f;
2504 Source->Direct.HFReference = LOWPASSFREQREF;
2505 Source->Direct.GainLF = 1.0f;
2506 Source->Direct.LFReference = HIGHPASSFREQREF;
2507 for(i = 0;i < MAX_SENDS;i++)
2509 Source->Send[i].Gain = 1.0f;
2510 Source->Send[i].GainHF = 1.0f;
2511 Source->Send[i].HFReference = LOWPASSFREQREF;
2512 Source->Send[i].GainLF = 1.0f;
2513 Source->Send[i].LFReference = HIGHPASSFREQREF;
2516 ATOMIC_INIT(&Source->NeedsUpdate, AL_TRUE);
2520 /* SetSourceState
2522 * Sets the source's new play state given its current state.
2524 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2526 ReadLock(&Source->queue_lock);
2527 if(state == AL_PLAYING)
2529 ALCdevice *device = Context->Device;
2530 ALbufferlistitem *BufferList;
2531 ALvoice *voice = NULL;
2532 ALsizei i;
2534 /* Check that there is a queue containing at least one valid, non zero
2535 * length Buffer. */
2536 BufferList = ATOMIC_LOAD(&Source->queue);
2537 while(BufferList)
2539 ALbuffer *buffer;
2540 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2541 break;
2542 BufferList = BufferList->next;
2545 if(Source->state != AL_PAUSED)
2547 Source->state = AL_PLAYING;
2548 Source->position = 0;
2549 Source->position_fraction = 0;
2550 ATOMIC_STORE(&Source->current_buffer, BufferList);
2552 else
2553 Source->state = AL_PLAYING;
2555 // Check if an Offset has been set
2556 if(Source->Offset >= 0.0)
2557 ApplyOffset(Source);
2559 /* If there's nothing to play, or device is disconnected, go right to
2560 * stopped */
2561 if(!BufferList || !device->Connected)
2562 goto do_stop;
2564 /* Make sure this source isn't already active, while looking for an
2565 * unused active source slot to put it in. */
2566 for(i = 0;i < Context->VoiceCount;i++)
2568 ALsource *old = Source;
2569 if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL))
2571 if(voice == NULL)
2573 voice = &Context->Voices[i];
2574 voice->Source = Source;
2576 break;
2578 old = NULL;
2579 if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source))
2580 voice = &Context->Voices[i];
2582 if(voice == NULL)
2584 voice = &Context->Voices[Context->VoiceCount++];
2585 voice->Source = Source;
2588 voice->Direct.Moving = AL_FALSE;
2589 voice->Direct.Counter = 0;
2590 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
2592 ALsizei j;
2593 for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
2594 voice->Direct.Hrtf.State[i].History[j] = 0.0f;
2595 for(j = 0;j < HRIR_LENGTH;j++)
2597 voice->Direct.Hrtf.State[i].Values[j][0] = 0.0f;
2598 voice->Direct.Hrtf.State[i].Values[j][1] = 0.0f;
2601 for(i = 0;i < (ALsizei)device->NumAuxSends;i++)
2603 voice->Send[i].Moving = AL_FALSE;
2604 voice->Send[i].Counter = 0;
2607 if(BufferList->buffer->FmtChannels == FmtMono)
2608 voice->Update = CalcSourceParams;
2609 else
2610 voice->Update = CalcNonAttnSourceParams;
2612 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
2614 else if(state == AL_PAUSED)
2616 if(Source->state == AL_PLAYING)
2617 Source->state = AL_PAUSED;
2619 else if(state == AL_STOPPED)
2621 do_stop:
2622 if(Source->state != AL_INITIAL)
2624 Source->state = AL_STOPPED;
2625 ATOMIC_STORE(&Source->current_buffer, NULL);
2627 Source->Offset = -1.0;
2629 else if(state == AL_INITIAL)
2631 if(Source->state != AL_INITIAL)
2633 Source->state = AL_INITIAL;
2634 Source->position = 0;
2635 Source->position_fraction = 0;
2636 ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue));
2638 Source->Offset = -1.0;
2640 ReadUnlock(&Source->queue_lock);
2643 /* GetSourceOffset
2645 * Gets the current read offset for the given Source, in 32.32 fixed-point
2646 * samples. The offset is relative to the start of the queue (not the start of
2647 * the current buffer).
2649 static ALint64 GetSourceOffset(const ALsource *Source)
2651 const ALbufferlistitem *BufferList;
2652 const ALbufferlistitem *Current;
2653 ALuint64 readPos;
2655 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2656 return 0;
2658 /* NOTE: This is the offset into the *current* buffer, so add the length of
2659 * any played buffers */
2660 readPos = (ALuint64)Source->position << 32;
2661 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2662 BufferList = ATOMIC_LOAD(&Source->queue);
2663 Current = ATOMIC_LOAD(&Source->current_buffer);
2664 while(BufferList && BufferList != Current)
2666 if(BufferList->buffer)
2667 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2668 BufferList = BufferList->next;
2671 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
2674 /* GetSourceSecOffset
2676 * Gets the current read offset for the given Source, in seconds. The offset is
2677 * relative to the start of the queue (not the start of the current buffer).
2679 static ALdouble GetSourceSecOffset(const ALsource *Source)
2681 const ALbufferlistitem *BufferList;
2682 const ALbufferlistitem *Current;
2683 const ALbuffer *Buffer = NULL;
2684 ALuint64 readPos;
2686 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2687 return 0.0;
2689 /* NOTE: This is the offset into the *current* buffer, so add the length of
2690 * any played buffers */
2691 readPos = (ALuint64)Source->position << FRACTIONBITS;
2692 readPos |= (ALuint64)Source->position_fraction;
2693 BufferList = ATOMIC_LOAD(&Source->queue);
2694 Current = ATOMIC_LOAD(&Source->current_buffer);
2695 while(BufferList && BufferList != Current)
2697 const ALbuffer *buffer = BufferList->buffer;
2698 if(buffer != NULL)
2700 if(!Buffer) Buffer = buffer;
2701 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
2703 BufferList = BufferList->next;
2706 while(BufferList && !Buffer)
2708 Buffer = BufferList->buffer;
2709 BufferList = BufferList->next;
2711 assert(Buffer != NULL);
2713 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2716 /* GetSourceOffsets
2718 * Gets the current read and write offsets for the given Source, in the
2719 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2720 * the start of the queue (not the start of the current buffer).
2722 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2724 const ALbufferlistitem *BufferList;
2725 const ALbufferlistitem *Current;
2726 const ALbuffer *Buffer = NULL;
2727 ALboolean readFin = AL_FALSE;
2728 ALuint readPos, writePos;
2729 ALuint totalBufferLen;
2731 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2733 offset[0] = 0.0;
2734 offset[1] = 0.0;
2735 return;
2738 if(updateLen > 0.0 && updateLen < 0.015)
2739 updateLen = 0.015;
2741 /* NOTE: This is the offset into the *current* buffer, so add the length of
2742 * any played buffers */
2743 totalBufferLen = 0;
2744 readPos = Source->position;
2745 BufferList = ATOMIC_LOAD(&Source->queue);
2746 Current = ATOMIC_LOAD(&Source->current_buffer);
2747 while(BufferList != NULL)
2749 const ALbuffer *buffer;
2750 readFin = readFin || (BufferList == Current);
2751 if((buffer=BufferList->buffer) != NULL)
2753 if(!Buffer) Buffer = buffer;
2754 totalBufferLen += buffer->SampleLen;
2755 if(!readFin) readPos += buffer->SampleLen;
2757 BufferList = BufferList->next;
2759 assert(Buffer != NULL);
2761 if(Source->state == AL_PLAYING)
2762 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
2763 else
2764 writePos = readPos;
2766 if(Source->Looping)
2768 readPos %= totalBufferLen;
2769 writePos %= totalBufferLen;
2771 else
2773 /* Wrap positions back to 0 */
2774 if(readPos >= totalBufferLen)
2775 readPos = 0;
2776 if(writePos >= totalBufferLen)
2777 writePos = 0;
2780 switch(name)
2782 case AL_SEC_OFFSET:
2783 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2784 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2785 break;
2787 case AL_SAMPLE_OFFSET:
2788 case AL_SAMPLE_RW_OFFSETS_SOFT:
2789 offset[0] = (ALdouble)readPos;
2790 offset[1] = (ALdouble)writePos;
2791 break;
2793 case AL_BYTE_OFFSET:
2794 case AL_BYTE_RW_OFFSETS_SOFT:
2795 if(Buffer->OriginalType == UserFmtIMA4)
2797 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2798 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2799 ALuint FrameBlockSize = Buffer->OriginalAlign;
2801 /* Round down to nearest ADPCM block */
2802 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2803 if(Source->state != AL_PLAYING)
2804 offset[1] = offset[0];
2805 else
2807 /* Round up to nearest ADPCM block */
2808 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2809 FrameBlockSize * BlockSize);
2812 else if(Buffer->OriginalType == UserFmtMSADPCM)
2814 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2815 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2816 ALuint FrameBlockSize = Buffer->OriginalAlign;
2818 /* Round down to nearest ADPCM block */
2819 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2820 if(Source->state != AL_PLAYING)
2821 offset[1] = offset[0];
2822 else
2824 /* Round up to nearest ADPCM block */
2825 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2826 FrameBlockSize * BlockSize);
2829 else
2831 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2832 offset[0] = (ALdouble)(readPos * FrameSize);
2833 offset[1] = (ALdouble)(writePos * FrameSize);
2835 break;
2840 /* ApplyOffset
2842 * Apply the stored playback offset to the Source. This function will update
2843 * the number of buffers "played" given the stored offset.
2845 ALboolean ApplyOffset(ALsource *Source)
2847 ALbufferlistitem *BufferList;
2848 const ALbuffer *Buffer;
2849 ALint bufferLen, totalBufferLen;
2850 ALint offset;
2852 /* Get sample frame offset */
2853 offset = GetSampleOffset(Source);
2854 if(offset == -1)
2855 return AL_FALSE;
2857 totalBufferLen = 0;
2858 BufferList = ATOMIC_LOAD(&Source->queue);
2859 while(BufferList && totalBufferLen <= offset)
2861 Buffer = BufferList->buffer;
2862 bufferLen = Buffer ? Buffer->SampleLen : 0;
2864 if(bufferLen > offset-totalBufferLen)
2866 /* Offset is in this buffer */
2867 ATOMIC_STORE(&Source->current_buffer, BufferList);
2869 Source->position = offset - totalBufferLen;
2870 Source->position_fraction = 0;
2871 return AL_TRUE;
2874 totalBufferLen += bufferLen;
2876 BufferList = BufferList->next;
2879 /* Offset is out of range of the queue */
2880 return AL_FALSE;
2884 /* GetSampleOffset
2886 * Returns the sample offset into the Source's queue (from the Sample, Byte or
2887 * Second offset supplied by the application). This takes into account the fact
2888 * that the buffer format may have been modifed since.
2890 static ALint GetSampleOffset(ALsource *Source)
2892 const ALbuffer *Buffer = NULL;
2893 const ALbufferlistitem *BufferList;
2894 ALint Offset = -1;
2896 /* Find the first valid Buffer in the Queue */
2897 BufferList = ATOMIC_LOAD(&Source->queue);
2898 while(BufferList)
2900 if(BufferList->buffer)
2902 Buffer = BufferList->buffer;
2903 break;
2905 BufferList = BufferList->next;
2908 if(!Buffer)
2910 Source->Offset = -1.0;
2911 return -1;
2914 switch(Source->OffsetType)
2916 case AL_BYTE_OFFSET:
2917 /* Determine the ByteOffset (and ensure it is block aligned) */
2918 Offset = (ALint)Source->Offset;
2919 if(Buffer->OriginalType == UserFmtIMA4)
2921 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2922 Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2923 Offset *= Buffer->OriginalAlign;
2925 else if(Buffer->OriginalType == UserFmtMSADPCM)
2927 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2928 Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2929 Offset *= Buffer->OriginalAlign;
2931 else
2932 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2933 break;
2935 case AL_SAMPLE_OFFSET:
2936 Offset = (ALint)Source->Offset;
2937 break;
2939 case AL_SEC_OFFSET:
2940 Offset = (ALint)(Source->Offset * Buffer->Frequency);
2941 break;
2943 Source->Offset = -1.0;
2945 return Offset;
2949 /* ReleaseALSources
2951 * Destroys all sources in the source map.
2953 ALvoid ReleaseALSources(ALCcontext *Context)
2955 ALbufferlistitem *item;
2956 ALsizei pos;
2957 ALuint j;
2958 for(pos = 0;pos < Context->SourceMap.size;pos++)
2960 ALsource *temp = Context->SourceMap.array[pos].value;
2961 Context->SourceMap.array[pos].value = NULL;
2963 item = ATOMIC_EXCHANGE(ALbufferlistitem*, &temp->queue, NULL);
2964 while(item != NULL)
2966 ALbufferlistitem *next = item->next;
2967 if(item->buffer != NULL)
2968 DecrementRef(&item->buffer->ref);
2969 free(item);
2970 item = next;
2973 for(j = 0;j < MAX_SENDS;++j)
2975 if(temp->Send[j].Slot)
2976 DecrementRef(&temp->Send[j].Slot->ref);
2977 temp->Send[j].Slot = NULL;
2980 FreeThunkEntry(temp->id);
2981 memset(temp, 0, sizeof(*temp));
2982 al_free(temp);