Multiply samples with the cubic coeffs before transposing
[openal-soft.git] / OpenAL32 / alSource.c
blobbe3768f373dc45b7d9cd6c320aa6a6110b67842f
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 Source->Position[0] = values[0];
523 Source->Position[1] = values[1];
524 Source->Position[2] = values[2];
525 UnlockContext(Context);
526 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
527 return AL_TRUE;
529 case AL_VELOCITY:
530 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
532 LockContext(Context);
533 Source->Velocity[0] = values[0];
534 Source->Velocity[1] = values[1];
535 Source->Velocity[2] = values[2];
536 UnlockContext(Context);
537 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
538 return AL_TRUE;
540 case AL_DIRECTION:
541 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
543 LockContext(Context);
544 Source->Direction[0] = values[0];
545 Source->Direction[1] = values[1];
546 Source->Direction[2] = values[2];
547 UnlockContext(Context);
548 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
549 return AL_TRUE;
551 case AL_ORIENTATION:
552 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
553 isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
555 LockContext(Context);
556 Source->Orientation[0][0] = values[0];
557 Source->Orientation[0][1] = values[1];
558 Source->Orientation[0][2] = values[2];
559 Source->Orientation[1][0] = values[3];
560 Source->Orientation[1][1] = values[4];
561 Source->Orientation[1][2] = values[5];
562 UnlockContext(Context);
563 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
564 return AL_TRUE;
566 case sfSampleRWOffsetsSOFT:
567 case sfByteRWOffsetsSOFT:
568 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
571 case sfSourceRelative:
572 case sfLooping:
573 case sfSourceState:
574 case sfSourceType:
575 case sfDistanceModel:
576 case sfDirectFilterGainHFAuto:
577 case sfAuxSendFilterGainAuto:
578 case sfAuxSendFilterGainHFAuto:
579 case sfDirectChannelsSOFT:
580 ival = (ALint)values[0];
581 return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival);
583 case sfBuffer:
584 case sfBuffersQueued:
585 case sfBuffersProcessed:
586 ival = (ALint)((ALuint)values[0]);
587 return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival);
590 ERR("Unexpected property: 0x%04x\n", prop);
591 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
594 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values)
596 ALCdevice *device = Context->Device;
597 ALbuffer *buffer = NULL;
598 ALfilter *filter = NULL;
599 ALeffectslot *slot = NULL;
600 ALbufferlistitem *oldlist;
601 ALbufferlistitem *newlist;
602 ALfloat fvals[6];
604 switch(prop)
606 case AL_SOURCE_RELATIVE:
607 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
609 Source->HeadRelative = (ALboolean)*values;
610 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
611 return AL_TRUE;
613 case AL_LOOPING:
614 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
616 Source->Looping = (ALboolean)*values;
617 return AL_TRUE;
619 case AL_BUFFER:
620 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
622 WriteLock(&Source->queue_lock);
623 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
625 WriteUnlock(&Source->queue_lock);
626 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
629 if(buffer != NULL)
631 /* Add the selected buffer to a one-item queue */
632 newlist = malloc(sizeof(ALbufferlistitem));
633 newlist->buffer = buffer;
634 newlist->next = NULL;
635 newlist->prev = NULL;
636 IncrementRef(&buffer->ref);
638 /* Source is now Static */
639 Source->SourceType = AL_STATIC;
641 ReadLock(&buffer->lock);
642 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
643 Source->SampleSize = BytesFromFmt(buffer->FmtType);
644 ReadUnlock(&buffer->lock);
646 else
648 /* Source is now Undetermined */
649 Source->SourceType = AL_UNDETERMINED;
650 newlist = NULL;
652 oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist);
653 ATOMIC_STORE(&Source->current_buffer, newlist);
654 WriteUnlock(&Source->queue_lock);
656 /* Delete all elements in the previous queue */
657 while(oldlist != NULL)
659 ALbufferlistitem *temp = oldlist;
660 oldlist = temp->next;
662 if(temp->buffer)
663 DecrementRef(&temp->buffer->ref);
664 free(temp);
666 return AL_TRUE;
668 case siSourceState:
669 case siSourceType:
670 case siBuffersQueued:
671 case siBuffersProcessed:
672 /* Query only */
673 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
675 case AL_SEC_OFFSET:
676 case AL_SAMPLE_OFFSET:
677 case AL_BYTE_OFFSET:
678 CHECKVAL(*values >= 0);
680 LockContext(Context);
681 Source->OffsetType = prop;
682 Source->Offset = *values;
684 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
685 !Context->DeferUpdates)
687 if(ApplyOffset(Source) == AL_FALSE)
689 UnlockContext(Context);
690 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
693 UnlockContext(Context);
694 return AL_TRUE;
697 case siByteLength:
698 case siSampleLength:
699 case siSampleRWOffsetsSOFT:
700 case siByteRWOffsetsSOFT:
701 /* Query only */
702 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
705 case AL_DIRECT_FILTER:
706 CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
708 LockContext(Context);
709 if(!filter)
711 Source->Direct.Gain = 1.0f;
712 Source->Direct.GainHF = 1.0f;
713 Source->Direct.HFReference = LOWPASSFREQREF;
714 Source->Direct.GainLF = 1.0f;
715 Source->Direct.LFReference = HIGHPASSFREQREF;
717 else
719 Source->Direct.Gain = filter->Gain;
720 Source->Direct.GainHF = filter->GainHF;
721 Source->Direct.HFReference = filter->HFReference;
722 Source->Direct.GainLF = filter->GainLF;
723 Source->Direct.LFReference = filter->LFReference;
725 UnlockContext(Context);
726 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
727 return AL_TRUE;
729 case AL_DIRECT_FILTER_GAINHF_AUTO:
730 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
732 Source->DryGainHFAuto = *values;
733 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
734 return AL_TRUE;
736 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
737 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
739 Source->WetGainAuto = *values;
740 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
741 return AL_TRUE;
743 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
744 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
746 Source->WetGainHFAuto = *values;
747 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
748 return AL_TRUE;
750 case AL_DIRECT_CHANNELS_SOFT:
751 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
753 Source->DirectChannels = *values;
754 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
755 return AL_TRUE;
757 case AL_DISTANCE_MODEL:
758 CHECKVAL(*values == AL_NONE ||
759 *values == AL_INVERSE_DISTANCE ||
760 *values == AL_INVERSE_DISTANCE_CLAMPED ||
761 *values == AL_LINEAR_DISTANCE ||
762 *values == AL_LINEAR_DISTANCE_CLAMPED ||
763 *values == AL_EXPONENT_DISTANCE ||
764 *values == AL_EXPONENT_DISTANCE_CLAMPED);
766 Source->DistanceModel = *values;
767 if(Context->SourceDistanceModel)
768 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
769 return AL_TRUE;
772 case AL_AUXILIARY_SEND_FILTER:
773 LockContext(Context);
774 if(!((ALuint)values[1] < device->NumAuxSends &&
775 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
776 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
778 UnlockContext(Context);
779 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
782 /* Add refcount on the new slot, and release the previous slot */
783 if(slot) IncrementRef(&slot->ref);
784 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
785 if(slot) DecrementRef(&slot->ref);
787 if(!filter)
789 /* Disable filter */
790 Source->Send[values[1]].Gain = 1.0f;
791 Source->Send[values[1]].GainHF = 1.0f;
792 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
793 Source->Send[values[1]].GainLF = 1.0f;
794 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
796 else
798 Source->Send[values[1]].Gain = filter->Gain;
799 Source->Send[values[1]].GainHF = filter->GainHF;
800 Source->Send[values[1]].HFReference = filter->HFReference;
801 Source->Send[values[1]].GainLF = filter->GainLF;
802 Source->Send[values[1]].LFReference = filter->LFReference;
804 UnlockContext(Context);
805 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
806 return AL_TRUE;
809 case AL_MAX_DISTANCE:
810 case AL_ROLLOFF_FACTOR:
811 case AL_CONE_INNER_ANGLE:
812 case AL_CONE_OUTER_ANGLE:
813 case AL_REFERENCE_DISTANCE:
814 case siDopplerFactor:
815 fvals[0] = (ALfloat)*values;
816 return SetSourcefv(Source, Context, (int)prop, fvals);
818 case AL_POSITION:
819 case AL_VELOCITY:
820 case AL_DIRECTION:
821 fvals[0] = (ALfloat)values[0];
822 fvals[1] = (ALfloat)values[1];
823 fvals[2] = (ALfloat)values[2];
824 return SetSourcefv(Source, Context, (int)prop, fvals);
826 case AL_ORIENTATION:
827 fvals[0] = (ALfloat)values[0];
828 fvals[1] = (ALfloat)values[1];
829 fvals[2] = (ALfloat)values[2];
830 fvals[3] = (ALfloat)values[3];
831 fvals[4] = (ALfloat)values[4];
832 fvals[5] = (ALfloat)values[5];
833 return SetSourcefv(Source, Context, (int)prop, fvals);
835 case siSampleOffsetLatencySOFT:
836 /* i64 only */
837 break;
840 ERR("Unexpected property: 0x%04x\n", prop);
841 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
844 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values)
846 ALfloat fvals[6];
847 ALint ivals[3];
849 switch(prop)
851 case siSampleRWOffsetsSOFT:
852 case siByteRWOffsetsSOFT:
853 case siSampleOffsetLatencySOFT:
854 /* Query only */
855 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
858 /* 1x int */
859 case AL_SOURCE_RELATIVE:
860 case AL_LOOPING:
861 case AL_SOURCE_STATE:
862 case AL_BYTE_OFFSET:
863 case AL_SAMPLE_OFFSET:
864 case siByteLength:
865 case siSampleLength:
866 case siSourceType:
867 case siBuffersQueued:
868 case siBuffersProcessed:
869 case AL_DIRECT_FILTER_GAINHF_AUTO:
870 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
871 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
872 case AL_DIRECT_CHANNELS_SOFT:
873 case AL_DISTANCE_MODEL:
874 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
876 ivals[0] = (ALint)*values;
877 return SetSourceiv(Source, Context, (int)prop, ivals);
879 /* 1x uint */
880 case AL_BUFFER:
881 case AL_DIRECT_FILTER:
882 CHECKVAL(*values <= UINT_MAX && *values >= 0);
884 ivals[0] = (ALuint)*values;
885 return SetSourceiv(Source, Context, (int)prop, ivals);
887 /* 3x uint */
888 case AL_AUXILIARY_SEND_FILTER:
889 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
890 values[1] <= UINT_MAX && values[1] >= 0 &&
891 values[2] <= UINT_MAX && values[2] >= 0);
893 ivals[0] = (ALuint)values[0];
894 ivals[1] = (ALuint)values[1];
895 ivals[2] = (ALuint)values[2];
896 return SetSourceiv(Source, Context, (int)prop, ivals);
898 /* 1x float */
899 case AL_MAX_DISTANCE:
900 case AL_ROLLOFF_FACTOR:
901 case AL_CONE_INNER_ANGLE:
902 case AL_CONE_OUTER_ANGLE:
903 case AL_REFERENCE_DISTANCE:
904 case AL_SEC_OFFSET:
905 case siDopplerFactor:
906 fvals[0] = (ALfloat)*values;
907 return SetSourcefv(Source, Context, (int)prop, fvals);
909 /* 3x float */
910 case AL_POSITION:
911 case AL_VELOCITY:
912 case AL_DIRECTION:
913 fvals[0] = (ALfloat)values[0];
914 fvals[1] = (ALfloat)values[1];
915 fvals[2] = (ALfloat)values[2];
916 return SetSourcefv(Source, Context, (int)prop, fvals);
918 /* 6x float */
919 case AL_ORIENTATION:
920 fvals[0] = (ALfloat)values[0];
921 fvals[1] = (ALfloat)values[1];
922 fvals[2] = (ALfloat)values[2];
923 fvals[3] = (ALfloat)values[3];
924 fvals[4] = (ALfloat)values[4];
925 fvals[5] = (ALfloat)values[5];
926 return SetSourcefv(Source, Context, (int)prop, fvals);
929 ERR("Unexpected property: 0x%04x\n", prop);
930 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
933 #undef CHECKVAL
936 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values)
938 ALbufferlistitem *BufferList;
939 ALdouble offsets[2];
940 ALdouble updateLen;
941 ALint ivals[3];
942 ALboolean err;
944 switch(prop)
946 case AL_GAIN:
947 *values = Source->Gain;
948 return AL_TRUE;
950 case AL_PITCH:
951 *values = Source->Pitch;
952 return AL_TRUE;
954 case AL_MAX_DISTANCE:
955 *values = Source->MaxDistance;
956 return AL_TRUE;
958 case AL_ROLLOFF_FACTOR:
959 *values = Source->RollOffFactor;
960 return AL_TRUE;
962 case AL_REFERENCE_DISTANCE:
963 *values = Source->RefDistance;
964 return AL_TRUE;
966 case AL_CONE_INNER_ANGLE:
967 *values = Source->InnerAngle;
968 return AL_TRUE;
970 case AL_CONE_OUTER_ANGLE:
971 *values = Source->OuterAngle;
972 return AL_TRUE;
974 case AL_MIN_GAIN:
975 *values = Source->MinGain;
976 return AL_TRUE;
978 case AL_MAX_GAIN:
979 *values = Source->MaxGain;
980 return AL_TRUE;
982 case AL_CONE_OUTER_GAIN:
983 *values = Source->OuterGain;
984 return AL_TRUE;
986 case AL_SEC_OFFSET:
987 case AL_SAMPLE_OFFSET:
988 case AL_BYTE_OFFSET:
989 LockContext(Context);
990 ReadLock(&Source->queue_lock);
991 GetSourceOffsets(Source, prop, offsets, 0.0);
992 ReadUnlock(&Source->queue_lock);
993 UnlockContext(Context);
994 *values = offsets[0];
995 return AL_TRUE;
997 case AL_CONE_OUTER_GAINHF:
998 *values = Source->OuterGainHF;
999 return AL_TRUE;
1001 case AL_AIR_ABSORPTION_FACTOR:
1002 *values = Source->AirAbsorptionFactor;
1003 return AL_TRUE;
1005 case AL_ROOM_ROLLOFF_FACTOR:
1006 *values = Source->RoomRolloffFactor;
1007 return AL_TRUE;
1009 case AL_DOPPLER_FACTOR:
1010 *values = Source->DopplerFactor;
1011 return AL_TRUE;
1013 case sfSecLength:
1014 ReadLock(&Source->queue_lock);
1015 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1016 *values = 0;
1017 else
1019 ALint length = 0;
1020 ALsizei freq = 1;
1021 do {
1022 ALbuffer *buffer = BufferList->buffer;
1023 if(buffer && buffer->SampleLen > 0)
1025 freq = buffer->Frequency;
1026 length += buffer->SampleLen;
1028 } while((BufferList=BufferList->next) != NULL);
1029 *values = (ALdouble)length / (ALdouble)freq;
1031 ReadUnlock(&Source->queue_lock);
1032 return AL_TRUE;
1034 case AL_SAMPLE_RW_OFFSETS_SOFT:
1035 case AL_BYTE_RW_OFFSETS_SOFT:
1036 LockContext(Context);
1037 ReadLock(&Source->queue_lock);
1038 updateLen = (ALdouble)Context->Device->UpdateSize /
1039 Context->Device->Frequency;
1040 GetSourceOffsets(Source, prop, values, updateLen);
1041 ReadUnlock(&Source->queue_lock);
1042 UnlockContext(Context);
1043 return AL_TRUE;
1045 case AL_SEC_OFFSET_LATENCY_SOFT:
1046 LockContext(Context);
1047 ReadLock(&Source->queue_lock);
1048 values[0] = GetSourceSecOffset(Source);
1049 ReadUnlock(&Source->queue_lock);
1050 values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) /
1051 1000000000.0;
1052 UnlockContext(Context);
1053 return AL_TRUE;
1055 case AL_POSITION:
1056 LockContext(Context);
1057 values[0] = Source->Position[0];
1058 values[1] = Source->Position[1];
1059 values[2] = Source->Position[2];
1060 UnlockContext(Context);
1061 return AL_TRUE;
1063 case AL_VELOCITY:
1064 LockContext(Context);
1065 values[0] = Source->Velocity[0];
1066 values[1] = Source->Velocity[1];
1067 values[2] = Source->Velocity[2];
1068 UnlockContext(Context);
1069 return AL_TRUE;
1071 case AL_DIRECTION:
1072 LockContext(Context);
1073 values[0] = Source->Direction[0];
1074 values[1] = Source->Direction[1];
1075 values[2] = Source->Direction[2];
1076 UnlockContext(Context);
1077 return AL_TRUE;
1079 case AL_ORIENTATION:
1080 LockContext(Context);
1081 values[0] = Source->Orientation[0][0];
1082 values[1] = Source->Orientation[0][1];
1083 values[2] = Source->Orientation[0][2];
1084 values[3] = Source->Orientation[1][0];
1085 values[4] = Source->Orientation[1][1];
1086 values[5] = Source->Orientation[1][2];
1087 UnlockContext(Context);
1088 return AL_TRUE;
1090 case AL_SOURCE_RELATIVE:
1091 case AL_LOOPING:
1092 case AL_BUFFER:
1093 case AL_SOURCE_STATE:
1094 case AL_BUFFERS_QUEUED:
1095 case AL_BUFFERS_PROCESSED:
1096 case AL_SOURCE_TYPE:
1097 case AL_DIRECT_FILTER_GAINHF_AUTO:
1098 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1099 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1100 case AL_DIRECT_CHANNELS_SOFT:
1101 case AL_DISTANCE_MODEL:
1102 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1103 *values = (ALdouble)ivals[0];
1104 return err;
1107 ERR("Unexpected property: 0x%04x\n", prop);
1108 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1111 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values)
1113 ALbufferlistitem *BufferList;
1114 ALdouble dvals[6];
1115 ALboolean err;
1117 switch(prop)
1119 case AL_SOURCE_RELATIVE:
1120 *values = Source->HeadRelative;
1121 return AL_TRUE;
1123 case AL_LOOPING:
1124 *values = Source->Looping;
1125 return AL_TRUE;
1127 case AL_BUFFER:
1128 ReadLock(&Source->queue_lock);
1129 BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) :
1130 ATOMIC_LOAD(&Source->current_buffer);
1131 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1132 ReadUnlock(&Source->queue_lock);
1133 return AL_TRUE;
1135 case AL_SOURCE_STATE:
1136 *values = Source->state;
1137 return AL_TRUE;
1139 case siByteLength:
1140 ReadLock(&Source->queue_lock);
1141 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1142 *values = 0;
1143 else
1145 ALint length = 0;
1146 do {
1147 ALbuffer *buffer = BufferList->buffer;
1148 if(buffer && buffer->SampleLen > 0)
1150 ALuint byte_align, sample_align;
1151 if(buffer->OriginalType == UserFmtIMA4)
1153 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1154 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1155 sample_align = buffer->OriginalAlign;
1157 else if(buffer->OriginalType == UserFmtMSADPCM)
1159 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1160 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1161 sample_align = buffer->OriginalAlign;
1163 else
1165 ALsizei align = buffer->OriginalAlign;
1166 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1167 sample_align = buffer->OriginalAlign;
1170 length += buffer->SampleLen / sample_align * byte_align;
1172 } while((BufferList=BufferList->next) != NULL);
1173 *values = length;
1175 ReadUnlock(&Source->queue_lock);
1176 return AL_TRUE;
1178 case siSampleLength:
1179 ReadLock(&Source->queue_lock);
1180 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1181 *values = 0;
1182 else
1184 ALint length = 0;
1185 do {
1186 ALbuffer *buffer = BufferList->buffer;
1187 if(buffer) length += buffer->SampleLen;
1188 } while((BufferList=BufferList->next) != NULL);
1189 *values = length;
1191 ReadUnlock(&Source->queue_lock);
1192 return AL_TRUE;
1194 case AL_BUFFERS_QUEUED:
1195 ReadLock(&Source->queue_lock);
1196 if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1197 *values = 0;
1198 else
1200 ALsizei count = 0;
1201 do {
1202 ++count;
1203 } while((BufferList=BufferList->next) != NULL);
1204 *values = count;
1206 ReadUnlock(&Source->queue_lock);
1207 return AL_TRUE;
1209 case AL_BUFFERS_PROCESSED:
1210 ReadLock(&Source->queue_lock);
1211 if(Source->Looping || Source->SourceType != AL_STREAMING)
1213 /* Buffers on a looping source are in a perpetual state of
1214 * PENDING, so don't report any as PROCESSED */
1215 *values = 0;
1217 else
1219 const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue);
1220 const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer);
1221 ALsizei played = 0;
1222 while(BufferList && BufferList != Current)
1224 played++;
1225 BufferList = BufferList->next;
1227 *values = played;
1229 ReadUnlock(&Source->queue_lock);
1230 return AL_TRUE;
1232 case AL_SOURCE_TYPE:
1233 *values = Source->SourceType;
1234 return AL_TRUE;
1236 case AL_DIRECT_FILTER_GAINHF_AUTO:
1237 *values = Source->DryGainHFAuto;
1238 return AL_TRUE;
1240 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1241 *values = Source->WetGainAuto;
1242 return AL_TRUE;
1244 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1245 *values = Source->WetGainHFAuto;
1246 return AL_TRUE;
1248 case AL_DIRECT_CHANNELS_SOFT:
1249 *values = Source->DirectChannels;
1250 return AL_TRUE;
1252 case AL_DISTANCE_MODEL:
1253 *values = Source->DistanceModel;
1254 return AL_TRUE;
1256 case AL_MAX_DISTANCE:
1257 case AL_ROLLOFF_FACTOR:
1258 case AL_REFERENCE_DISTANCE:
1259 case AL_CONE_INNER_ANGLE:
1260 case AL_CONE_OUTER_ANGLE:
1261 case AL_SEC_OFFSET:
1262 case AL_SAMPLE_OFFSET:
1263 case AL_BYTE_OFFSET:
1264 case AL_DOPPLER_FACTOR:
1265 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1266 *values = (ALint)dvals[0];
1267 return err;
1269 case AL_SAMPLE_RW_OFFSETS_SOFT:
1270 case AL_BYTE_RW_OFFSETS_SOFT:
1271 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1273 values[0] = (ALint)dvals[0];
1274 values[1] = (ALint)dvals[1];
1276 return err;
1278 case AL_POSITION:
1279 case AL_VELOCITY:
1280 case AL_DIRECTION:
1281 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1283 values[0] = (ALint)dvals[0];
1284 values[1] = (ALint)dvals[1];
1285 values[2] = (ALint)dvals[2];
1287 return err;
1289 case AL_ORIENTATION:
1290 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1292 values[0] = (ALint)dvals[0];
1293 values[1] = (ALint)dvals[1];
1294 values[2] = (ALint)dvals[2];
1295 values[3] = (ALint)dvals[3];
1296 values[4] = (ALint)dvals[4];
1297 values[5] = (ALint)dvals[5];
1299 return err;
1301 case siSampleOffsetLatencySOFT:
1302 /* i64 only */
1303 break;
1305 case siDirectFilter:
1306 case siAuxSendFilter:
1307 /* ??? */
1308 break;
1311 ERR("Unexpected property: 0x%04x\n", prop);
1312 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1315 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values)
1317 ALdouble dvals[6];
1318 ALint ivals[3];
1319 ALboolean err;
1321 switch(prop)
1323 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1324 LockContext(Context);
1325 ReadLock(&Source->queue_lock);
1326 values[0] = GetSourceOffset(Source);
1327 ReadUnlock(&Source->queue_lock);
1328 values[1] = ALCdevice_GetLatency(Context->Device);
1329 UnlockContext(Context);
1330 return AL_TRUE;
1332 case AL_MAX_DISTANCE:
1333 case AL_ROLLOFF_FACTOR:
1334 case AL_REFERENCE_DISTANCE:
1335 case AL_CONE_INNER_ANGLE:
1336 case AL_CONE_OUTER_ANGLE:
1337 case AL_SEC_OFFSET:
1338 case AL_SAMPLE_OFFSET:
1339 case AL_BYTE_OFFSET:
1340 case AL_DOPPLER_FACTOR:
1341 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1342 *values = (ALint64)dvals[0];
1343 return err;
1345 case AL_SAMPLE_RW_OFFSETS_SOFT:
1346 case AL_BYTE_RW_OFFSETS_SOFT:
1347 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1349 values[0] = (ALint64)dvals[0];
1350 values[1] = (ALint64)dvals[1];
1352 return err;
1354 case AL_POSITION:
1355 case AL_VELOCITY:
1356 case AL_DIRECTION:
1357 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1359 values[0] = (ALint64)dvals[0];
1360 values[1] = (ALint64)dvals[1];
1361 values[2] = (ALint64)dvals[2];
1363 return err;
1365 case AL_ORIENTATION:
1366 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1368 values[0] = (ALint64)dvals[0];
1369 values[1] = (ALint64)dvals[1];
1370 values[2] = (ALint64)dvals[2];
1371 values[3] = (ALint64)dvals[3];
1372 values[4] = (ALint64)dvals[4];
1373 values[5] = (ALint64)dvals[5];
1375 return err;
1377 case AL_SOURCE_RELATIVE:
1378 case AL_LOOPING:
1379 case AL_SOURCE_STATE:
1380 case AL_BUFFERS_QUEUED:
1381 case AL_BUFFERS_PROCESSED:
1382 case siByteLength:
1383 case siSampleLength:
1384 case AL_SOURCE_TYPE:
1385 case AL_DIRECT_FILTER_GAINHF_AUTO:
1386 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1387 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1388 case AL_DIRECT_CHANNELS_SOFT:
1389 case AL_DISTANCE_MODEL:
1390 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1391 *values = ivals[0];
1392 return err;
1394 case siBuffer:
1395 case siDirectFilter:
1396 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1397 *values = (ALuint)ivals[0];
1398 return err;
1400 case siAuxSendFilter:
1401 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1403 values[0] = (ALuint)ivals[0];
1404 values[1] = (ALuint)ivals[1];
1405 values[2] = (ALuint)ivals[2];
1407 return err;
1410 ERR("Unexpected property: 0x%04x\n", prop);
1411 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1415 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1417 ALCcontext *context;
1418 ALsizei cur = 0;
1419 ALenum err;
1421 context = GetContextRef();
1422 if(!context) return;
1424 if(!(n >= 0))
1425 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1426 for(cur = 0;cur < n;cur++)
1428 ALsource *source = al_calloc(16, sizeof(ALsource));
1429 if(!source)
1431 alDeleteSources(cur, sources);
1432 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1434 InitSourceParams(source);
1436 err = NewThunkEntry(&source->id);
1437 if(err == AL_NO_ERROR)
1438 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1439 if(err != AL_NO_ERROR)
1441 FreeThunkEntry(source->id);
1442 memset(source, 0, sizeof(ALsource));
1443 al_free(source);
1445 alDeleteSources(cur, sources);
1446 SET_ERROR_AND_GOTO(context, err, done);
1449 sources[cur] = source->id;
1452 done:
1453 ALCcontext_DecRef(context);
1457 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1459 ALCcontext *context;
1460 ALbufferlistitem *BufferList;
1461 ALsource *Source;
1462 ALsizei i, j;
1464 context = GetContextRef();
1465 if(!context) return;
1467 if(!(n >= 0))
1468 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1470 /* Check that all Sources are valid */
1471 for(i = 0;i < n;i++)
1473 if(LookupSource(context, sources[i]) == NULL)
1474 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1476 for(i = 0;i < n;i++)
1478 ALvoice *voice, *voice_end;
1480 if((Source=RemoveSource(context, sources[i])) == NULL)
1481 continue;
1482 FreeThunkEntry(Source->id);
1484 LockContext(context);
1485 voice = context->Voices;
1486 voice_end = voice + context->VoiceCount;
1487 while(voice != voice_end)
1489 ALsource *old = Source;
1490 if(COMPARE_EXCHANGE(&voice->Source, &old, NULL))
1491 break;
1492 voice++;
1494 UnlockContext(context);
1496 BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, NULL);
1497 while(BufferList != NULL)
1499 ALbufferlistitem *next = BufferList->next;
1500 if(BufferList->buffer != NULL)
1501 DecrementRef(&BufferList->buffer->ref);
1502 free(BufferList);
1503 BufferList = next;
1506 for(j = 0;j < MAX_SENDS;++j)
1508 if(Source->Send[j].Slot)
1509 DecrementRef(&Source->Send[j].Slot->ref);
1510 Source->Send[j].Slot = NULL;
1513 memset(Source, 0, sizeof(*Source));
1514 al_free(Source);
1517 done:
1518 ALCcontext_DecRef(context);
1522 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1524 ALCcontext *context;
1525 ALboolean ret;
1527 context = GetContextRef();
1528 if(!context) return AL_FALSE;
1530 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1532 ALCcontext_DecRef(context);
1534 return ret;
1538 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1540 ALCcontext *Context;
1541 ALsource *Source;
1543 Context = GetContextRef();
1544 if(!Context) return;
1546 if((Source=LookupSource(Context, source)) == NULL)
1547 alSetError(Context, AL_INVALID_NAME);
1548 else if(!(FloatValsByProp(param) == 1))
1549 alSetError(Context, AL_INVALID_ENUM);
1550 else
1551 SetSourcefv(Source, Context, param, &value);
1553 ALCcontext_DecRef(Context);
1556 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1558 ALCcontext *Context;
1559 ALsource *Source;
1561 Context = GetContextRef();
1562 if(!Context) return;
1564 if((Source=LookupSource(Context, source)) == NULL)
1565 alSetError(Context, AL_INVALID_NAME);
1566 else if(!(FloatValsByProp(param) == 3))
1567 alSetError(Context, AL_INVALID_ENUM);
1568 else
1570 ALfloat fvals[3] = { value1, value2, value3 };
1571 SetSourcefv(Source, Context, param, fvals);
1574 ALCcontext_DecRef(Context);
1577 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1579 ALCcontext *Context;
1580 ALsource *Source;
1582 Context = GetContextRef();
1583 if(!Context) return;
1585 if((Source=LookupSource(Context, source)) == NULL)
1586 alSetError(Context, AL_INVALID_NAME);
1587 else if(!values)
1588 alSetError(Context, AL_INVALID_VALUE);
1589 else if(!(FloatValsByProp(param) > 0))
1590 alSetError(Context, AL_INVALID_ENUM);
1591 else
1592 SetSourcefv(Source, Context, param, values);
1594 ALCcontext_DecRef(Context);
1598 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1600 ALCcontext *Context;
1601 ALsource *Source;
1603 Context = GetContextRef();
1604 if(!Context) return;
1606 if((Source=LookupSource(Context, source)) == NULL)
1607 alSetError(Context, AL_INVALID_NAME);
1608 else if(!(DoubleValsByProp(param) == 1))
1609 alSetError(Context, AL_INVALID_ENUM);
1610 else
1612 ALfloat fval = (ALfloat)value;
1613 SetSourcefv(Source, Context, param, &fval);
1616 ALCcontext_DecRef(Context);
1619 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1621 ALCcontext *Context;
1622 ALsource *Source;
1624 Context = GetContextRef();
1625 if(!Context) return;
1627 if((Source=LookupSource(Context, source)) == NULL)
1628 alSetError(Context, AL_INVALID_NAME);
1629 else if(!(DoubleValsByProp(param) == 3))
1630 alSetError(Context, AL_INVALID_ENUM);
1631 else
1633 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1634 SetSourcefv(Source, Context, param, fvals);
1637 ALCcontext_DecRef(Context);
1640 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1642 ALCcontext *Context;
1643 ALsource *Source;
1644 ALint count;
1646 Context = GetContextRef();
1647 if(!Context) return;
1649 if((Source=LookupSource(Context, source)) == NULL)
1650 alSetError(Context, AL_INVALID_NAME);
1651 else if(!values)
1652 alSetError(Context, AL_INVALID_VALUE);
1653 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 3))
1654 alSetError(Context, AL_INVALID_ENUM);
1655 else
1657 ALfloat fvals[3];
1658 ALint i;
1660 for(i = 0;i < count;i++)
1661 fvals[i] = (ALfloat)values[i];
1662 SetSourcefv(Source, Context, param, fvals);
1665 ALCcontext_DecRef(Context);
1669 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1671 ALCcontext *Context;
1672 ALsource *Source;
1674 Context = GetContextRef();
1675 if(!Context) return;
1677 if((Source=LookupSource(Context, source)) == NULL)
1678 alSetError(Context, AL_INVALID_NAME);
1679 else if(!(IntValsByProp(param) == 1))
1680 alSetError(Context, AL_INVALID_ENUM);
1681 else
1682 SetSourceiv(Source, Context, param, &value);
1684 ALCcontext_DecRef(Context);
1687 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1689 ALCcontext *Context;
1690 ALsource *Source;
1692 Context = GetContextRef();
1693 if(!Context) return;
1695 if((Source=LookupSource(Context, source)) == NULL)
1696 alSetError(Context, AL_INVALID_NAME);
1697 else if(!(IntValsByProp(param) == 3))
1698 alSetError(Context, AL_INVALID_ENUM);
1699 else
1701 ALint ivals[3] = { value1, value2, value3 };
1702 SetSourceiv(Source, Context, param, ivals);
1705 ALCcontext_DecRef(Context);
1708 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1710 ALCcontext *Context;
1711 ALsource *Source;
1713 Context = GetContextRef();
1714 if(!Context) return;
1716 if((Source=LookupSource(Context, source)) == NULL)
1717 alSetError(Context, AL_INVALID_NAME);
1718 else if(!values)
1719 alSetError(Context, AL_INVALID_VALUE);
1720 else if(!(IntValsByProp(param) > 0))
1721 alSetError(Context, AL_INVALID_ENUM);
1722 else
1723 SetSourceiv(Source, Context, param, values);
1725 ALCcontext_DecRef(Context);
1729 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1731 ALCcontext *Context;
1732 ALsource *Source;
1734 Context = GetContextRef();
1735 if(!Context) return;
1737 if((Source=LookupSource(Context, source)) == NULL)
1738 alSetError(Context, AL_INVALID_NAME);
1739 else if(!(Int64ValsByProp(param) == 1))
1740 alSetError(Context, AL_INVALID_ENUM);
1741 else
1742 SetSourcei64v(Source, Context, param, &value);
1744 ALCcontext_DecRef(Context);
1747 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1749 ALCcontext *Context;
1750 ALsource *Source;
1752 Context = GetContextRef();
1753 if(!Context) return;
1755 if((Source=LookupSource(Context, source)) == NULL)
1756 alSetError(Context, AL_INVALID_NAME);
1757 else if(!(Int64ValsByProp(param) == 3))
1758 alSetError(Context, AL_INVALID_ENUM);
1759 else
1761 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1762 SetSourcei64v(Source, Context, param, i64vals);
1765 ALCcontext_DecRef(Context);
1768 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1770 ALCcontext *Context;
1771 ALsource *Source;
1773 Context = GetContextRef();
1774 if(!Context) return;
1776 if((Source=LookupSource(Context, source)) == NULL)
1777 alSetError(Context, AL_INVALID_NAME);
1778 else if(!values)
1779 alSetError(Context, AL_INVALID_VALUE);
1780 else if(!(Int64ValsByProp(param) > 0))
1781 alSetError(Context, AL_INVALID_ENUM);
1782 else
1783 SetSourcei64v(Source, Context, param, values);
1785 ALCcontext_DecRef(Context);
1789 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1791 ALCcontext *Context;
1792 ALsource *Source;
1794 Context = GetContextRef();
1795 if(!Context) return;
1797 if((Source=LookupSource(Context, source)) == NULL)
1798 alSetError(Context, AL_INVALID_NAME);
1799 else if(!value)
1800 alSetError(Context, AL_INVALID_VALUE);
1801 else if(!(FloatValsByProp(param) == 1))
1802 alSetError(Context, AL_INVALID_ENUM);
1803 else
1805 ALdouble dval;
1806 if(GetSourcedv(Source, Context, param, &dval))
1807 *value = (ALfloat)dval;
1810 ALCcontext_DecRef(Context);
1814 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1816 ALCcontext *Context;
1817 ALsource *Source;
1819 Context = GetContextRef();
1820 if(!Context) return;
1822 if((Source=LookupSource(Context, source)) == NULL)
1823 alSetError(Context, AL_INVALID_NAME);
1824 else if(!(value1 && value2 && value3))
1825 alSetError(Context, AL_INVALID_VALUE);
1826 else if(!(FloatValsByProp(param) == 3))
1827 alSetError(Context, AL_INVALID_ENUM);
1828 else
1830 ALdouble dvals[3];
1831 if(GetSourcedv(Source, Context, param, dvals))
1833 *value1 = (ALfloat)dvals[0];
1834 *value2 = (ALfloat)dvals[1];
1835 *value3 = (ALfloat)dvals[2];
1839 ALCcontext_DecRef(Context);
1843 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1845 ALCcontext *Context;
1846 ALsource *Source;
1847 ALint count;
1849 Context = GetContextRef();
1850 if(!Context) return;
1852 if((Source=LookupSource(Context, source)) == NULL)
1853 alSetError(Context, AL_INVALID_NAME);
1854 else if(!values)
1855 alSetError(Context, AL_INVALID_VALUE);
1856 else if(!((count=FloatValsByProp(param)) > 0 && count <= 3))
1857 alSetError(Context, AL_INVALID_ENUM);
1858 else
1860 ALdouble dvals[3];
1861 if(GetSourcedv(Source, Context, param, dvals))
1863 ALint i;
1864 for(i = 0;i < count;i++)
1865 values[i] = (ALfloat)dvals[i];
1869 ALCcontext_DecRef(Context);
1873 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1875 ALCcontext *Context;
1876 ALsource *Source;
1878 Context = GetContextRef();
1879 if(!Context) return;
1881 if((Source=LookupSource(Context, source)) == NULL)
1882 alSetError(Context, AL_INVALID_NAME);
1883 else if(!value)
1884 alSetError(Context, AL_INVALID_VALUE);
1885 else if(!(DoubleValsByProp(param) == 1))
1886 alSetError(Context, AL_INVALID_ENUM);
1887 else
1888 GetSourcedv(Source, Context, param, value);
1890 ALCcontext_DecRef(Context);
1893 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1895 ALCcontext *Context;
1896 ALsource *Source;
1898 Context = GetContextRef();
1899 if(!Context) return;
1901 if((Source=LookupSource(Context, source)) == NULL)
1902 alSetError(Context, AL_INVALID_NAME);
1903 else if(!(value1 && value2 && value3))
1904 alSetError(Context, AL_INVALID_VALUE);
1905 else if(!(DoubleValsByProp(param) == 3))
1906 alSetError(Context, AL_INVALID_ENUM);
1907 else
1909 ALdouble dvals[3];
1910 if(GetSourcedv(Source, Context, param, dvals))
1912 *value1 = dvals[0];
1913 *value2 = dvals[1];
1914 *value3 = dvals[2];
1918 ALCcontext_DecRef(Context);
1921 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1923 ALCcontext *Context;
1924 ALsource *Source;
1926 Context = GetContextRef();
1927 if(!Context) return;
1929 if((Source=LookupSource(Context, source)) == NULL)
1930 alSetError(Context, AL_INVALID_NAME);
1931 else if(!values)
1932 alSetError(Context, AL_INVALID_VALUE);
1933 else if(!(DoubleValsByProp(param) > 0))
1934 alSetError(Context, AL_INVALID_ENUM);
1935 else
1936 GetSourcedv(Source, Context, param, values);
1938 ALCcontext_DecRef(Context);
1942 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1944 ALCcontext *Context;
1945 ALsource *Source;
1947 Context = GetContextRef();
1948 if(!Context) return;
1950 if((Source=LookupSource(Context, source)) == NULL)
1951 alSetError(Context, AL_INVALID_NAME);
1952 else if(!value)
1953 alSetError(Context, AL_INVALID_VALUE);
1954 else if(!(IntValsByProp(param) == 1))
1955 alSetError(Context, AL_INVALID_ENUM);
1956 else
1957 GetSourceiv(Source, Context, param, value);
1959 ALCcontext_DecRef(Context);
1963 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
1965 ALCcontext *Context;
1966 ALsource *Source;
1968 Context = GetContextRef();
1969 if(!Context) return;
1971 if((Source=LookupSource(Context, source)) == NULL)
1972 alSetError(Context, AL_INVALID_NAME);
1973 else if(!(value1 && value2 && value3))
1974 alSetError(Context, AL_INVALID_VALUE);
1975 else if(!(IntValsByProp(param) == 3))
1976 alSetError(Context, AL_INVALID_ENUM);
1977 else
1979 ALint ivals[3];
1980 if(GetSourceiv(Source, Context, param, ivals))
1982 *value1 = ivals[0];
1983 *value2 = ivals[1];
1984 *value3 = ivals[2];
1988 ALCcontext_DecRef(Context);
1992 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
1994 ALCcontext *Context;
1995 ALsource *Source;
1997 Context = GetContextRef();
1998 if(!Context) return;
2000 if((Source=LookupSource(Context, source)) == NULL)
2001 alSetError(Context, AL_INVALID_NAME);
2002 else if(!values)
2003 alSetError(Context, AL_INVALID_VALUE);
2004 else if(!(IntValsByProp(param) > 0))
2005 alSetError(Context, AL_INVALID_ENUM);
2006 else
2007 GetSourceiv(Source, Context, param, values);
2009 ALCcontext_DecRef(Context);
2013 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2015 ALCcontext *Context;
2016 ALsource *Source;
2018 Context = GetContextRef();
2019 if(!Context) return;
2021 if((Source=LookupSource(Context, source)) == NULL)
2022 alSetError(Context, AL_INVALID_NAME);
2023 else if(!value)
2024 alSetError(Context, AL_INVALID_VALUE);
2025 else if(!(Int64ValsByProp(param) == 1))
2026 alSetError(Context, AL_INVALID_ENUM);
2027 else
2028 GetSourcei64v(Source, Context, param, value);
2030 ALCcontext_DecRef(Context);
2033 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2035 ALCcontext *Context;
2036 ALsource *Source;
2038 Context = GetContextRef();
2039 if(!Context) return;
2041 if((Source=LookupSource(Context, source)) == NULL)
2042 alSetError(Context, AL_INVALID_NAME);
2043 else if(!(value1 && value2 && value3))
2044 alSetError(Context, AL_INVALID_VALUE);
2045 else if(!(Int64ValsByProp(param) == 3))
2046 alSetError(Context, AL_INVALID_ENUM);
2047 else
2049 ALint64 i64vals[3];
2050 if(GetSourcei64v(Source, Context, param, i64vals))
2052 *value1 = i64vals[0];
2053 *value2 = i64vals[1];
2054 *value3 = i64vals[2];
2058 ALCcontext_DecRef(Context);
2061 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2063 ALCcontext *Context;
2064 ALsource *Source;
2066 Context = GetContextRef();
2067 if(!Context) return;
2069 if((Source=LookupSource(Context, source)) == NULL)
2070 alSetError(Context, AL_INVALID_NAME);
2071 else if(!values)
2072 alSetError(Context, AL_INVALID_VALUE);
2073 else if(!(Int64ValsByProp(param) > 0))
2074 alSetError(Context, AL_INVALID_ENUM);
2075 else
2076 GetSourcei64v(Source, Context, param, values);
2078 ALCcontext_DecRef(Context);
2082 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2084 alSourcePlayv(1, &source);
2086 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2088 ALCcontext *context;
2089 ALsource *source;
2090 ALsizei i;
2092 context = GetContextRef();
2093 if(!context) return;
2095 if(!(n >= 0))
2096 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2097 for(i = 0;i < n;i++)
2099 if(!LookupSource(context, sources[i]))
2100 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2103 LockContext(context);
2104 while(n > context->MaxVoices-context->VoiceCount)
2106 ALvoice *temp = NULL;
2107 ALsizei newcount;
2109 newcount = context->MaxVoices << 1;
2110 if(newcount > 0)
2111 temp = realloc(context->Voices, newcount * sizeof(context->Voices[0]));
2112 if(!temp)
2114 UnlockContext(context);
2115 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2117 memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0]));
2119 context->Voices = temp;
2120 context->MaxVoices = newcount;
2123 for(i = 0;i < n;i++)
2125 source = LookupSource(context, sources[i]);
2126 if(context->DeferUpdates) source->new_state = AL_PLAYING;
2127 else SetSourceState(source, context, AL_PLAYING);
2129 UnlockContext(context);
2131 done:
2132 ALCcontext_DecRef(context);
2135 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2137 alSourcePausev(1, &source);
2139 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2141 ALCcontext *context;
2142 ALsource *source;
2143 ALsizei i;
2145 context = GetContextRef();
2146 if(!context) return;
2148 if(!(n >= 0))
2149 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2150 for(i = 0;i < n;i++)
2152 if(!LookupSource(context, sources[i]))
2153 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2156 LockContext(context);
2157 for(i = 0;i < n;i++)
2159 source = LookupSource(context, sources[i]);
2160 if(context->DeferUpdates) source->new_state = AL_PAUSED;
2161 else SetSourceState(source, context, AL_PAUSED);
2163 UnlockContext(context);
2165 done:
2166 ALCcontext_DecRef(context);
2169 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2171 alSourceStopv(1, &source);
2173 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2175 ALCcontext *context;
2176 ALsource *source;
2177 ALsizei i;
2179 context = GetContextRef();
2180 if(!context) return;
2182 if(!(n >= 0))
2183 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2184 for(i = 0;i < n;i++)
2186 if(!LookupSource(context, sources[i]))
2187 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2190 LockContext(context);
2191 for(i = 0;i < n;i++)
2193 source = LookupSource(context, sources[i]);
2194 source->new_state = AL_NONE;
2195 SetSourceState(source, context, AL_STOPPED);
2197 UnlockContext(context);
2199 done:
2200 ALCcontext_DecRef(context);
2203 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2205 alSourceRewindv(1, &source);
2207 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2209 ALCcontext *context;
2210 ALsource *source;
2211 ALsizei i;
2213 context = GetContextRef();
2214 if(!context) return;
2216 if(!(n >= 0))
2217 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2218 for(i = 0;i < n;i++)
2220 if(!LookupSource(context, sources[i]))
2221 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2224 LockContext(context);
2225 for(i = 0;i < n;i++)
2227 source = LookupSource(context, sources[i]);
2228 source->new_state = AL_NONE;
2229 SetSourceState(source, context, AL_INITIAL);
2231 UnlockContext(context);
2233 done:
2234 ALCcontext_DecRef(context);
2238 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2240 ALCdevice *device;
2241 ALCcontext *context;
2242 ALsource *source;
2243 ALsizei i;
2244 ALbufferlistitem *BufferListStart;
2245 ALbufferlistitem *BufferList;
2246 ALbuffer *BufferFmt = NULL;
2248 if(nb == 0)
2249 return;
2251 context = GetContextRef();
2252 if(!context) return;
2254 device = context->Device;
2256 if(!(nb >= 0))
2257 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2258 if((source=LookupSource(context, src)) == NULL)
2259 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2261 WriteLock(&source->queue_lock);
2262 if(source->SourceType == AL_STATIC)
2264 WriteUnlock(&source->queue_lock);
2265 /* Can't queue on a Static Source */
2266 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2269 /* Check for a valid Buffer, for its frequency and format */
2270 BufferList = ATOMIC_LOAD(&source->queue);
2271 while(BufferList)
2273 if(BufferList->buffer)
2275 BufferFmt = BufferList->buffer;
2276 break;
2278 BufferList = BufferList->next;
2281 BufferListStart = NULL;
2282 BufferList = NULL;
2283 for(i = 0;i < nb;i++)
2285 ALbuffer *buffer = NULL;
2286 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2288 WriteUnlock(&source->queue_lock);
2289 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2292 if(!BufferListStart)
2294 BufferListStart = malloc(sizeof(ALbufferlistitem));
2295 BufferListStart->buffer = buffer;
2296 BufferListStart->next = NULL;
2297 BufferListStart->prev = NULL;
2298 BufferList = BufferListStart;
2300 else
2302 BufferList->next = malloc(sizeof(ALbufferlistitem));
2303 BufferList->next->buffer = buffer;
2304 BufferList->next->next = NULL;
2305 BufferList->next->prev = BufferList;
2306 BufferList = BufferList->next;
2308 if(!buffer) continue;
2310 /* Hold a read lock on each buffer being queued while checking all
2311 * provided buffers. This is done so other threads don't see an extra
2312 * reference on some buffers if this operation ends up failing. */
2313 ReadLock(&buffer->lock);
2314 IncrementRef(&buffer->ref);
2316 if(BufferFmt == NULL)
2318 BufferFmt = buffer;
2320 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2321 source->SampleSize = BytesFromFmt(buffer->FmtType);
2323 else if(BufferFmt->Frequency != buffer->Frequency ||
2324 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2325 BufferFmt->OriginalType != buffer->OriginalType)
2327 WriteUnlock(&source->queue_lock);
2328 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2330 buffer_error:
2331 /* A buffer failed (invalid ID or format), so unlock and release
2332 * each buffer we had. */
2333 while(BufferList != NULL)
2335 ALbufferlistitem *prev = BufferList->prev;
2336 if((buffer=BufferList->buffer) != NULL)
2338 DecrementRef(&buffer->ref);
2339 ReadUnlock(&buffer->lock);
2341 free(BufferList);
2342 BufferList = prev;
2344 goto done;
2347 /* All buffers good, unlock them now. */
2348 while(BufferList != NULL)
2350 ALbuffer *buffer = BufferList->buffer;
2351 if(buffer) ReadUnlock(&buffer->lock);
2352 BufferList = BufferList->prev;
2355 /* Source is now streaming */
2356 source->SourceType = AL_STREAMING;
2358 BufferList = NULL;
2359 if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
2361 /* Queue head is not NULL, append to the end of the queue */
2362 while(BufferList->next != NULL)
2363 BufferList = BufferList->next;
2365 BufferListStart->prev = BufferList;
2366 BufferList->next = BufferListStart;
2368 BufferList = NULL;
2369 ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
2370 WriteUnlock(&source->queue_lock);
2372 done:
2373 ALCcontext_DecRef(context);
2376 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2378 ALCcontext *context;
2379 ALsource *source;
2380 ALbufferlistitem *NewHead;
2381 ALbufferlistitem *OldHead;
2382 ALbufferlistitem *Current;
2383 ALsizei i;
2385 if(nb == 0)
2386 return;
2388 context = GetContextRef();
2389 if(!context) return;
2391 if(!(nb >= 0))
2392 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2394 if((source=LookupSource(context, src)) == NULL)
2395 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2397 WriteLock(&source->queue_lock);
2398 /* Find the new buffer queue head */
2399 NewHead = ATOMIC_LOAD(&source->queue);
2400 Current = ATOMIC_LOAD(&source->current_buffer);
2401 for(i = 0;i < nb && NewHead;i++)
2403 if(NewHead == Current)
2404 break;
2405 NewHead = NewHead->next;
2407 if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
2409 WriteUnlock(&source->queue_lock);
2410 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2411 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2414 /* Swap it, and cut the new head from the old. */
2415 OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NewHead);
2416 if(NewHead)
2418 ALCdevice *device = context->Device;
2419 ALbufferlistitem *OldTail = NewHead->prev;
2420 uint count;
2422 /* Cut the new head's link back to the old body. The mixer is robust
2423 * enough to handle the link back going away. Once the active mix (if
2424 * any) is complete, it's safe to finish cutting the old tail from the
2425 * new head. */
2426 NewHead->prev = NULL;
2427 if(((count=ReadRef(&device->MixCount))&1) != 0)
2429 while(count == ReadRef(&device->MixCount))
2430 althrd_yield();
2432 OldTail->next = NULL;
2434 WriteUnlock(&source->queue_lock);
2436 while(OldHead != NULL)
2438 ALbufferlistitem *next = OldHead->next;
2439 ALbuffer *buffer = OldHead->buffer;
2441 if(!buffer)
2442 *(buffers++) = 0;
2443 else
2445 *(buffers++) = buffer->id;
2446 DecrementRef(&buffer->ref);
2449 free(OldHead);
2450 OldHead = next;
2453 done:
2454 ALCcontext_DecRef(context);
2458 static ALvoid InitSourceParams(ALsource *Source)
2460 ALuint i;
2462 RWLockInit(&Source->queue_lock);
2464 Source->InnerAngle = 360.0f;
2465 Source->OuterAngle = 360.0f;
2466 Source->Pitch = 1.0f;
2467 Source->Position[0] = 0.0f;
2468 Source->Position[1] = 0.0f;
2469 Source->Position[2] = 0.0f;
2470 Source->Velocity[0] = 0.0f;
2471 Source->Velocity[1] = 0.0f;
2472 Source->Velocity[2] = 0.0f;
2473 Source->Direction[0] = 0.0f;
2474 Source->Direction[1] = 0.0f;
2475 Source->Direction[2] = 0.0f;
2476 Source->Orientation[0][0] = 0.0f;
2477 Source->Orientation[0][1] = 0.0f;
2478 Source->Orientation[0][2] = -1.0f;
2479 Source->Orientation[1][0] = 0.0f;
2480 Source->Orientation[1][1] = 1.0f;
2481 Source->Orientation[1][2] = 0.0f;
2482 Source->RefDistance = 1.0f;
2483 Source->MaxDistance = FLT_MAX;
2484 Source->RollOffFactor = 1.0f;
2485 Source->Looping = AL_FALSE;
2486 Source->Gain = 1.0f;
2487 Source->MinGain = 0.0f;
2488 Source->MaxGain = 1.0f;
2489 Source->OuterGain = 0.0f;
2490 Source->OuterGainHF = 1.0f;
2492 Source->DryGainHFAuto = AL_TRUE;
2493 Source->WetGainAuto = AL_TRUE;
2494 Source->WetGainHFAuto = AL_TRUE;
2495 Source->AirAbsorptionFactor = 0.0f;
2496 Source->RoomRolloffFactor = 0.0f;
2497 Source->DopplerFactor = 1.0f;
2498 Source->DirectChannels = AL_FALSE;
2500 Source->Radius = 0.0f;
2502 Source->DistanceModel = DefaultDistanceModel;
2504 Source->Resampler = DefaultResampler;
2506 Source->state = AL_INITIAL;
2507 Source->new_state = AL_NONE;
2508 Source->SourceType = AL_UNDETERMINED;
2509 Source->Offset = -1.0;
2511 ATOMIC_INIT(&Source->queue, NULL);
2512 ATOMIC_INIT(&Source->current_buffer, NULL);
2514 Source->Direct.Gain = 1.0f;
2515 Source->Direct.GainHF = 1.0f;
2516 Source->Direct.HFReference = LOWPASSFREQREF;
2517 Source->Direct.GainLF = 1.0f;
2518 Source->Direct.LFReference = HIGHPASSFREQREF;
2519 for(i = 0;i < MAX_SENDS;i++)
2521 Source->Send[i].Gain = 1.0f;
2522 Source->Send[i].GainHF = 1.0f;
2523 Source->Send[i].HFReference = LOWPASSFREQREF;
2524 Source->Send[i].GainLF = 1.0f;
2525 Source->Send[i].LFReference = HIGHPASSFREQREF;
2528 ATOMIC_INIT(&Source->NeedsUpdate, AL_TRUE);
2532 /* SetSourceState
2534 * Sets the source's new play state given its current state.
2536 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2538 ReadLock(&Source->queue_lock);
2539 if(state == AL_PLAYING)
2541 ALCdevice *device = Context->Device;
2542 ALbufferlistitem *BufferList;
2543 ALvoice *voice = NULL;
2544 ALsizei i;
2546 /* Check that there is a queue containing at least one valid, non zero
2547 * length Buffer. */
2548 BufferList = ATOMIC_LOAD(&Source->queue);
2549 while(BufferList)
2551 ALbuffer *buffer;
2552 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2553 break;
2554 BufferList = BufferList->next;
2557 if(Source->state != AL_PAUSED)
2559 Source->state = AL_PLAYING;
2560 Source->position = 0;
2561 Source->position_fraction = 0;
2562 ATOMIC_STORE(&Source->current_buffer, BufferList);
2564 else
2565 Source->state = AL_PLAYING;
2567 // Check if an Offset has been set
2568 if(Source->Offset >= 0.0)
2569 ApplyOffset(Source);
2571 /* If there's nothing to play, or device is disconnected, go right to
2572 * stopped */
2573 if(!BufferList || !device->Connected)
2574 goto do_stop;
2576 /* Make sure this source isn't already active, while looking for an
2577 * unused active source slot to put it in. */
2578 for(i = 0;i < Context->VoiceCount;i++)
2580 ALsource *old = Source;
2581 if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL))
2583 if(voice == NULL)
2585 voice = &Context->Voices[i];
2586 voice->Source = Source;
2588 break;
2590 old = NULL;
2591 if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source))
2592 voice = &Context->Voices[i];
2594 if(voice == NULL)
2596 voice = &Context->Voices[Context->VoiceCount++];
2597 voice->Source = Source;
2600 voice->Direct.Moving = AL_FALSE;
2601 voice->Direct.Counter = 0;
2602 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
2604 ALsizei j;
2605 for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
2606 voice->Direct.Hrtf.State[i].History[j] = 0.0f;
2607 for(j = 0;j < HRIR_LENGTH;j++)
2609 voice->Direct.Hrtf.State[i].Values[j][0] = 0.0f;
2610 voice->Direct.Hrtf.State[i].Values[j][1] = 0.0f;
2613 for(i = 0;i < (ALsizei)device->NumAuxSends;i++)
2615 voice->Send[i].Moving = AL_FALSE;
2616 voice->Send[i].Counter = 0;
2619 if(BufferList->buffer->FmtChannels == FmtMono)
2620 voice->Update = CalcSourceParams;
2621 else
2622 voice->Update = CalcNonAttnSourceParams;
2624 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
2626 else if(state == AL_PAUSED)
2628 if(Source->state == AL_PLAYING)
2629 Source->state = AL_PAUSED;
2631 else if(state == AL_STOPPED)
2633 do_stop:
2634 if(Source->state != AL_INITIAL)
2636 Source->state = AL_STOPPED;
2637 ATOMIC_STORE(&Source->current_buffer, NULL);
2639 Source->Offset = -1.0;
2641 else if(state == AL_INITIAL)
2643 if(Source->state != AL_INITIAL)
2645 Source->state = AL_INITIAL;
2646 Source->position = 0;
2647 Source->position_fraction = 0;
2648 ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue));
2650 Source->Offset = -1.0;
2652 ReadUnlock(&Source->queue_lock);
2655 /* GetSourceOffset
2657 * Gets the current read offset for the given Source, in 32.32 fixed-point
2658 * samples. The offset is relative to the start of the queue (not the start of
2659 * the current buffer).
2661 static ALint64 GetSourceOffset(const ALsource *Source)
2663 const ALbufferlistitem *BufferList;
2664 const ALbufferlistitem *Current;
2665 ALuint64 readPos;
2667 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2668 return 0;
2670 /* NOTE: This is the offset into the *current* buffer, so add the length of
2671 * any played buffers */
2672 readPos = (ALuint64)Source->position << 32;
2673 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2674 BufferList = ATOMIC_LOAD(&Source->queue);
2675 Current = ATOMIC_LOAD(&Source->current_buffer);
2676 while(BufferList && BufferList != Current)
2678 if(BufferList->buffer)
2679 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2680 BufferList = BufferList->next;
2683 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
2686 /* GetSourceSecOffset
2688 * Gets the current read offset for the given Source, in seconds. The offset is
2689 * relative to the start of the queue (not the start of the current buffer).
2691 static ALdouble GetSourceSecOffset(const ALsource *Source)
2693 const ALbufferlistitem *BufferList;
2694 const ALbufferlistitem *Current;
2695 const ALbuffer *Buffer = NULL;
2696 ALuint64 readPos;
2698 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2699 return 0.0;
2701 /* NOTE: This is the offset into the *current* buffer, so add the length of
2702 * any played buffers */
2703 readPos = (ALuint64)Source->position << FRACTIONBITS;
2704 readPos |= (ALuint64)Source->position_fraction;
2705 BufferList = ATOMIC_LOAD(&Source->queue);
2706 Current = ATOMIC_LOAD(&Source->current_buffer);
2707 while(BufferList && BufferList != Current)
2709 const ALbuffer *buffer = BufferList->buffer;
2710 if(buffer != NULL)
2712 if(!Buffer) Buffer = buffer;
2713 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
2715 BufferList = BufferList->next;
2718 while(BufferList && !Buffer)
2720 Buffer = BufferList->buffer;
2721 BufferList = BufferList->next;
2723 assert(Buffer != NULL);
2725 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2728 /* GetSourceOffsets
2730 * Gets the current read and write offsets for the given Source, in the
2731 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2732 * the start of the queue (not the start of the current buffer).
2734 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2736 const ALbufferlistitem *BufferList;
2737 const ALbufferlistitem *Current;
2738 const ALbuffer *Buffer = NULL;
2739 ALboolean readFin = AL_FALSE;
2740 ALuint readPos, writePos;
2741 ALuint totalBufferLen;
2743 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2745 offset[0] = 0.0;
2746 offset[1] = 0.0;
2747 return;
2750 if(updateLen > 0.0 && updateLen < 0.015)
2751 updateLen = 0.015;
2753 /* NOTE: This is the offset into the *current* buffer, so add the length of
2754 * any played buffers */
2755 totalBufferLen = 0;
2756 readPos = Source->position;
2757 BufferList = ATOMIC_LOAD(&Source->queue);
2758 Current = ATOMIC_LOAD(&Source->current_buffer);
2759 while(BufferList != NULL)
2761 const ALbuffer *buffer;
2762 readFin = readFin || (BufferList == Current);
2763 if((buffer=BufferList->buffer) != NULL)
2765 if(!Buffer) Buffer = buffer;
2766 totalBufferLen += buffer->SampleLen;
2767 if(!readFin) readPos += buffer->SampleLen;
2769 BufferList = BufferList->next;
2771 assert(Buffer != NULL);
2773 if(Source->state == AL_PLAYING)
2774 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
2775 else
2776 writePos = readPos;
2778 if(Source->Looping)
2780 readPos %= totalBufferLen;
2781 writePos %= totalBufferLen;
2783 else
2785 /* Wrap positions back to 0 */
2786 if(readPos >= totalBufferLen)
2787 readPos = 0;
2788 if(writePos >= totalBufferLen)
2789 writePos = 0;
2792 switch(name)
2794 case AL_SEC_OFFSET:
2795 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2796 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2797 break;
2799 case AL_SAMPLE_OFFSET:
2800 case AL_SAMPLE_RW_OFFSETS_SOFT:
2801 offset[0] = (ALdouble)readPos;
2802 offset[1] = (ALdouble)writePos;
2803 break;
2805 case AL_BYTE_OFFSET:
2806 case AL_BYTE_RW_OFFSETS_SOFT:
2807 if(Buffer->OriginalType == UserFmtIMA4)
2809 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2810 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2811 ALuint FrameBlockSize = Buffer->OriginalAlign;
2813 /* Round down to nearest ADPCM block */
2814 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2815 if(Source->state != AL_PLAYING)
2816 offset[1] = offset[0];
2817 else
2819 /* Round up to nearest ADPCM block */
2820 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2821 FrameBlockSize * BlockSize);
2824 else if(Buffer->OriginalType == UserFmtMSADPCM)
2826 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2827 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2828 ALuint FrameBlockSize = Buffer->OriginalAlign;
2830 /* Round down to nearest ADPCM block */
2831 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2832 if(Source->state != AL_PLAYING)
2833 offset[1] = offset[0];
2834 else
2836 /* Round up to nearest ADPCM block */
2837 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2838 FrameBlockSize * BlockSize);
2841 else
2843 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2844 offset[0] = (ALdouble)(readPos * FrameSize);
2845 offset[1] = (ALdouble)(writePos * FrameSize);
2847 break;
2852 /* ApplyOffset
2854 * Apply the stored playback offset to the Source. This function will update
2855 * the number of buffers "played" given the stored offset.
2857 ALboolean ApplyOffset(ALsource *Source)
2859 ALbufferlistitem *BufferList;
2860 const ALbuffer *Buffer;
2861 ALint bufferLen, totalBufferLen;
2862 ALint offset;
2864 /* Get sample frame offset */
2865 offset = GetSampleOffset(Source);
2866 if(offset == -1)
2867 return AL_FALSE;
2869 totalBufferLen = 0;
2870 BufferList = ATOMIC_LOAD(&Source->queue);
2871 while(BufferList && totalBufferLen <= offset)
2873 Buffer = BufferList->buffer;
2874 bufferLen = Buffer ? Buffer->SampleLen : 0;
2876 if(bufferLen > offset-totalBufferLen)
2878 /* Offset is in this buffer */
2879 ATOMIC_STORE(&Source->current_buffer, BufferList);
2881 Source->position = offset - totalBufferLen;
2882 Source->position_fraction = 0;
2883 return AL_TRUE;
2886 totalBufferLen += bufferLen;
2888 BufferList = BufferList->next;
2891 /* Offset is out of range of the queue */
2892 return AL_FALSE;
2896 /* GetSampleOffset
2898 * Returns the sample offset into the Source's queue (from the Sample, Byte or
2899 * Second offset supplied by the application). This takes into account the fact
2900 * that the buffer format may have been modifed since.
2902 static ALint GetSampleOffset(ALsource *Source)
2904 const ALbuffer *Buffer = NULL;
2905 const ALbufferlistitem *BufferList;
2906 ALint Offset = -1;
2908 /* Find the first valid Buffer in the Queue */
2909 BufferList = ATOMIC_LOAD(&Source->queue);
2910 while(BufferList)
2912 if(BufferList->buffer)
2914 Buffer = BufferList->buffer;
2915 break;
2917 BufferList = BufferList->next;
2920 if(!Buffer)
2922 Source->Offset = -1.0;
2923 return -1;
2926 switch(Source->OffsetType)
2928 case AL_BYTE_OFFSET:
2929 /* Determine the ByteOffset (and ensure it is block aligned) */
2930 Offset = (ALint)Source->Offset;
2931 if(Buffer->OriginalType == UserFmtIMA4)
2933 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2934 Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2935 Offset *= Buffer->OriginalAlign;
2937 else if(Buffer->OriginalType == UserFmtMSADPCM)
2939 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2940 Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2941 Offset *= Buffer->OriginalAlign;
2943 else
2944 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2945 break;
2947 case AL_SAMPLE_OFFSET:
2948 Offset = (ALint)Source->Offset;
2949 break;
2951 case AL_SEC_OFFSET:
2952 Offset = (ALint)(Source->Offset * Buffer->Frequency);
2953 break;
2955 Source->Offset = -1.0;
2957 return Offset;
2961 /* ReleaseALSources
2963 * Destroys all sources in the source map.
2965 ALvoid ReleaseALSources(ALCcontext *Context)
2967 ALbufferlistitem *item;
2968 ALsizei pos;
2969 ALuint j;
2970 for(pos = 0;pos < Context->SourceMap.size;pos++)
2972 ALsource *temp = Context->SourceMap.array[pos].value;
2973 Context->SourceMap.array[pos].value = NULL;
2975 item = ATOMIC_EXCHANGE(ALbufferlistitem*, &temp->queue, NULL);
2976 while(item != NULL)
2978 ALbufferlistitem *next = item->next;
2979 if(item->buffer != NULL)
2980 DecrementRef(&item->buffer->ref);
2981 free(item);
2982 item = next;
2985 for(j = 0;j < MAX_SENDS;++j)
2987 if(temp->Send[j].Slot)
2988 DecrementRef(&temp->Send[j].Slot->ref);
2989 temp->Send[j].Slot = NULL;
2992 FreeThunkEntry(temp->id);
2993 memset(temp, 0, sizeof(*temp));
2994 al_free(temp);