Avoid aliasing an int array
[openal-soft.git] / OpenAL32 / alSource.c
blob3da891bc46303e9e038308b5fa8dcb6598dab18e
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <math.h>
25 #include <float.h>
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alMain.h"
30 #include "alError.h"
31 #include "alSource.h"
32 #include "alBuffer.h"
33 #include "alThunk.h"
34 #include "alAuxEffectSlot.h"
36 #include "threads.h"
39 enum Resampler DefaultResampler = LinearResampler;
40 const ALsizei ResamplerPadding[ResamplerMax] = {
41 0, /* Point */
42 1, /* Linear */
43 2, /* Cubic */
45 const ALsizei ResamplerPrePadding[ResamplerMax] = {
46 0, /* Point */
47 0, /* Linear */
48 1, /* Cubic */
52 extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
53 extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
55 static ALvoid InitSourceParams(ALsource *Source);
56 static ALint64 GetSourceOffset(const ALsource *Source);
57 static ALdouble GetSourceSecOffset(const ALsource *Source);
58 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
59 static ALint GetSampleOffset(ALsource *Source);
61 typedef enum SrcFloatProp {
62 sfPitch = AL_PITCH,
63 sfGain = AL_GAIN,
64 sfMinGain = AL_MIN_GAIN,
65 sfMaxGain = AL_MAX_GAIN,
66 sfMaxDistance = AL_MAX_DISTANCE,
67 sfRolloffFactor = AL_ROLLOFF_FACTOR,
68 sfDopplerFactor = AL_DOPPLER_FACTOR,
69 sfConeOuterGain = AL_CONE_OUTER_GAIN,
70 sfSecOffset = AL_SEC_OFFSET,
71 sfSampleOffset = AL_SAMPLE_OFFSET,
72 sfByteOffset = AL_BYTE_OFFSET,
73 sfConeInnerAngle = AL_CONE_INNER_ANGLE,
74 sfConeOuterAngle = AL_CONE_OUTER_ANGLE,
75 sfRefDistance = AL_REFERENCE_DISTANCE,
77 sfPosition = AL_POSITION,
78 sfVelocity = AL_VELOCITY,
79 sfDirection = AL_DIRECTION,
81 sfSourceRelative = AL_SOURCE_RELATIVE,
82 sfLooping = AL_LOOPING,
83 sfBuffer = AL_BUFFER,
84 sfSourceState = AL_SOURCE_STATE,
85 sfBuffersQueued = AL_BUFFERS_QUEUED,
86 sfBuffersProcessed = AL_BUFFERS_PROCESSED,
87 sfSourceType = AL_SOURCE_TYPE,
89 /* ALC_EXT_EFX */
90 sfConeOuterGainHF = AL_CONE_OUTER_GAINHF,
91 sfAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
92 sfRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
93 sfDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
94 sfAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
95 sfAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
97 /* AL_SOFT_direct_channels */
98 sfDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
100 /* AL_EXT_source_distance_model */
101 sfDistanceModel = AL_DISTANCE_MODEL,
103 sfSecLength = AL_SEC_LENGTH_SOFT,
105 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
106 sfSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
107 sfByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
109 /* AL_SOFT_source_latency */
110 sfSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
111 } SrcFloatProp;
113 typedef enum SrcIntProp {
114 siMaxDistance = AL_MAX_DISTANCE,
115 siRolloffFactor = AL_ROLLOFF_FACTOR,
116 siRefDistance = AL_REFERENCE_DISTANCE,
117 siSourceRelative = AL_SOURCE_RELATIVE,
118 siConeInnerAngle = AL_CONE_INNER_ANGLE,
119 siConeOuterAngle = AL_CONE_OUTER_ANGLE,
120 siLooping = AL_LOOPING,
121 siBuffer = AL_BUFFER,
122 siSourceState = AL_SOURCE_STATE,
123 siBuffersQueued = AL_BUFFERS_QUEUED,
124 siBuffersProcessed = AL_BUFFERS_PROCESSED,
125 siSourceType = AL_SOURCE_TYPE,
126 siSecOffset = AL_SEC_OFFSET,
127 siSampleOffset = AL_SAMPLE_OFFSET,
128 siByteOffset = AL_BYTE_OFFSET,
129 siDopplerFactor = AL_DOPPLER_FACTOR,
130 siPosition = AL_POSITION,
131 siVelocity = AL_VELOCITY,
132 siDirection = AL_DIRECTION,
134 /* ALC_EXT_EFX */
135 siDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
136 siAuxSendFilterGainAutio = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
137 siAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
138 siDirectFilter = AL_DIRECT_FILTER,
139 siAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
141 /* AL_SOFT_direct_channels */
142 siDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
144 /* AL_EXT_source_distance_model */
145 siDistanceModel = AL_DISTANCE_MODEL,
147 siByteLength = AL_BYTE_LENGTH_SOFT,
148 siSampleLength = AL_SAMPLE_LENGTH_SOFT,
150 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
151 siSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
152 siByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
154 /* AL_SOFT_source_latency */
155 siSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
156 } SrcIntProp;
158 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values);
159 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values);
160 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values);
162 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values);
163 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values);
164 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values);
166 static ALint FloatValsByProp(ALenum prop)
168 if(prop != (ALenum)((SrcFloatProp)prop))
169 return 0;
170 switch((SrcFloatProp)prop)
172 case sfPitch:
173 case sfGain:
174 case sfMinGain:
175 case sfMaxGain:
176 case sfMaxDistance:
177 case sfRolloffFactor:
178 case sfDopplerFactor:
179 case sfConeOuterGain:
180 case sfSecOffset:
181 case sfSampleOffset:
182 case sfByteOffset:
183 case sfConeInnerAngle:
184 case sfConeOuterAngle:
185 case sfRefDistance:
186 case sfConeOuterGainHF:
187 case sfAirAbsorptionFactor:
188 case sfRoomRolloffFactor:
189 case sfDirectFilterGainHFAuto:
190 case sfAuxSendFilterGainAuto:
191 case sfAuxSendFilterGainHFAuto:
192 case sfDirectChannelsSOFT:
193 case sfDistanceModel:
194 case sfSourceRelative:
195 case sfLooping:
196 case sfBuffer:
197 case sfSourceState:
198 case sfBuffersQueued:
199 case sfBuffersProcessed:
200 case sfSourceType:
201 case sfSecLength:
202 return 1;
204 case sfSampleRWOffsetsSOFT:
205 case sfByteRWOffsetsSOFT:
206 return 2;
208 case sfPosition:
209 case sfVelocity:
210 case sfDirection:
211 return 3;
213 case sfSecOffsetLatencySOFT:
214 break; /* Double only */
216 return 0;
218 static ALint DoubleValsByProp(ALenum prop)
220 if(prop != (ALenum)((SrcFloatProp)prop))
221 return 0;
222 switch((SrcFloatProp)prop)
224 case sfPitch:
225 case sfGain:
226 case sfMinGain:
227 case sfMaxGain:
228 case sfMaxDistance:
229 case sfRolloffFactor:
230 case sfDopplerFactor:
231 case sfConeOuterGain:
232 case sfSecOffset:
233 case sfSampleOffset:
234 case sfByteOffset:
235 case sfConeInnerAngle:
236 case sfConeOuterAngle:
237 case sfRefDistance:
238 case sfConeOuterGainHF:
239 case sfAirAbsorptionFactor:
240 case sfRoomRolloffFactor:
241 case sfDirectFilterGainHFAuto:
242 case sfAuxSendFilterGainAuto:
243 case sfAuxSendFilterGainHFAuto:
244 case sfDirectChannelsSOFT:
245 case sfDistanceModel:
246 case sfSourceRelative:
247 case sfLooping:
248 case sfBuffer:
249 case sfSourceState:
250 case sfBuffersQueued:
251 case sfBuffersProcessed:
252 case sfSourceType:
253 case sfSecLength:
254 return 1;
256 case sfSampleRWOffsetsSOFT:
257 case sfByteRWOffsetsSOFT:
258 case sfSecOffsetLatencySOFT:
259 return 2;
261 case sfPosition:
262 case sfVelocity:
263 case sfDirection:
264 return 3;
266 return 0;
269 static ALint IntValsByProp(ALenum prop)
271 if(prop != (ALenum)((SrcIntProp)prop))
272 return 0;
273 switch((SrcIntProp)prop)
275 case siMaxDistance:
276 case siRolloffFactor:
277 case siRefDistance:
278 case siSourceRelative:
279 case siConeInnerAngle:
280 case siConeOuterAngle:
281 case siLooping:
282 case siBuffer:
283 case siSourceState:
284 case siBuffersQueued:
285 case siBuffersProcessed:
286 case siSourceType:
287 case siSecOffset:
288 case siSampleOffset:
289 case siByteOffset:
290 case siDopplerFactor:
291 case siDirectFilterGainHFAuto:
292 case siAuxSendFilterGainAutio:
293 case siAuxSendFilterGainHFAuto:
294 case siDirectFilter:
295 case siDirectChannelsSOFT:
296 case siDistanceModel:
297 case siByteLength:
298 case siSampleLength:
299 return 1;
301 case siSampleRWOffsetsSOFT:
302 case siByteRWOffsetsSOFT:
303 return 2;
305 case siPosition:
306 case siVelocity:
307 case siDirection:
308 case siAuxSendFilter:
309 return 3;
311 case siSampleOffsetLatencySOFT:
312 break; /* i64 only */
314 return 0;
316 static ALint Int64ValsByProp(ALenum prop)
318 if(prop != (ALenum)((SrcIntProp)prop))
319 return 0;
320 switch((SrcIntProp)prop)
322 case siMaxDistance:
323 case siRolloffFactor:
324 case siRefDistance:
325 case siSourceRelative:
326 case siConeInnerAngle:
327 case siConeOuterAngle:
328 case siLooping:
329 case siBuffer:
330 case siSourceState:
331 case siBuffersQueued:
332 case siBuffersProcessed:
333 case siSourceType:
334 case siSecOffset:
335 case siSampleOffset:
336 case siByteOffset:
337 case siDopplerFactor:
338 case siDirectFilterGainHFAuto:
339 case siAuxSendFilterGainAutio:
340 case siAuxSendFilterGainHFAuto:
341 case siDirectFilter:
342 case siDirectChannelsSOFT:
343 case siDistanceModel:
344 case siByteLength:
345 case siSampleLength:
346 return 1;
348 case siSampleRWOffsetsSOFT:
349 case siByteRWOffsetsSOFT:
350 case siSampleOffsetLatencySOFT:
351 return 2;
353 case siPosition:
354 case siVelocity:
355 case siDirection:
356 case siAuxSendFilter:
357 return 3;
359 return 0;
363 #define CHECKVAL(x) do { \
364 if(!(x)) \
365 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
366 } while(0)
368 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values)
370 ALint ival;
372 switch(prop)
374 case AL_PITCH:
375 CHECKVAL(*values >= 0.0f);
377 Source->Pitch = *values;
378 Source->NeedsUpdate = AL_TRUE;
379 return AL_TRUE;
381 case AL_CONE_INNER_ANGLE:
382 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
384 Source->InnerAngle = *values;
385 Source->NeedsUpdate = AL_TRUE;
386 return AL_TRUE;
388 case AL_CONE_OUTER_ANGLE:
389 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
391 Source->OuterAngle = *values;
392 Source->NeedsUpdate = AL_TRUE;
393 return AL_TRUE;
395 case AL_GAIN:
396 CHECKVAL(*values >= 0.0f);
398 Source->Gain = *values;
399 Source->NeedsUpdate = AL_TRUE;
400 return AL_TRUE;
402 case AL_MAX_DISTANCE:
403 CHECKVAL(*values >= 0.0f);
405 Source->MaxDistance = *values;
406 Source->NeedsUpdate = AL_TRUE;
407 return AL_TRUE;
409 case AL_ROLLOFF_FACTOR:
410 CHECKVAL(*values >= 0.0f);
412 Source->RollOffFactor = *values;
413 Source->NeedsUpdate = AL_TRUE;
414 return AL_TRUE;
416 case AL_REFERENCE_DISTANCE:
417 CHECKVAL(*values >= 0.0f);
419 Source->RefDistance = *values;
420 Source->NeedsUpdate = AL_TRUE;
421 return AL_TRUE;
423 case AL_MIN_GAIN:
424 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
426 Source->MinGain = *values;
427 Source->NeedsUpdate = AL_TRUE;
428 return AL_TRUE;
430 case AL_MAX_GAIN:
431 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
433 Source->MaxGain = *values;
434 Source->NeedsUpdate = AL_TRUE;
435 return AL_TRUE;
437 case AL_CONE_OUTER_GAIN:
438 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
440 Source->OuterGain = *values;
441 Source->NeedsUpdate = AL_TRUE;
442 return AL_TRUE;
444 case AL_CONE_OUTER_GAINHF:
445 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
447 Source->OuterGainHF = *values;
448 Source->NeedsUpdate = AL_TRUE;
449 return AL_TRUE;
451 case AL_AIR_ABSORPTION_FACTOR:
452 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
454 Source->AirAbsorptionFactor = *values;
455 Source->NeedsUpdate = AL_TRUE;
456 return AL_TRUE;
458 case AL_ROOM_ROLLOFF_FACTOR:
459 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
461 Source->RoomRolloffFactor = *values;
462 Source->NeedsUpdate = AL_TRUE;
463 return AL_TRUE;
465 case AL_DOPPLER_FACTOR:
466 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
468 Source->DopplerFactor = *values;
469 Source->NeedsUpdate = AL_TRUE;
470 return AL_TRUE;
472 case AL_SEC_OFFSET:
473 case AL_SAMPLE_OFFSET:
474 case AL_BYTE_OFFSET:
475 CHECKVAL(*values >= 0.0f);
477 LockContext(Context);
478 Source->OffsetType = prop;
479 Source->Offset = *values;
481 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
482 !Context->DeferUpdates)
484 if(ApplyOffset(Source) == AL_FALSE)
486 UnlockContext(Context);
487 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
490 UnlockContext(Context);
491 return AL_TRUE;
494 case sfSecLength:
495 case AL_SEC_OFFSET_LATENCY_SOFT:
496 /* Query only */
497 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
500 case AL_POSITION:
501 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
503 LockContext(Context);
504 Source->Position[0] = values[0];
505 Source->Position[1] = values[1];
506 Source->Position[2] = values[2];
507 UnlockContext(Context);
508 Source->NeedsUpdate = AL_TRUE;
509 return AL_TRUE;
511 case AL_VELOCITY:
512 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
514 LockContext(Context);
515 Source->Velocity[0] = values[0];
516 Source->Velocity[1] = values[1];
517 Source->Velocity[2] = values[2];
518 UnlockContext(Context);
519 Source->NeedsUpdate = AL_TRUE;
520 return AL_TRUE;
522 case AL_DIRECTION:
523 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
525 LockContext(Context);
526 Source->Orientation[0] = values[0];
527 Source->Orientation[1] = values[1];
528 Source->Orientation[2] = values[2];
529 UnlockContext(Context);
530 Source->NeedsUpdate = AL_TRUE;
531 return AL_TRUE;
534 case sfSampleRWOffsetsSOFT:
535 case sfByteRWOffsetsSOFT:
536 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
539 case sfSourceRelative:
540 case sfLooping:
541 case sfSourceState:
542 case sfSourceType:
543 case sfDistanceModel:
544 case sfDirectFilterGainHFAuto:
545 case sfAuxSendFilterGainAuto:
546 case sfAuxSendFilterGainHFAuto:
547 case sfDirectChannelsSOFT:
548 ival = (ALint)values[0];
549 return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival);
551 case sfBuffer:
552 case sfBuffersQueued:
553 case sfBuffersProcessed:
554 ival = (ALint)((ALuint)values[0]);
555 return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival);
558 ERR("Unexpected property: 0x%04x\n", prop);
559 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
562 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values)
564 ALCdevice *device = Context->Device;
565 ALbuffer *buffer = NULL;
566 ALfilter *filter = NULL;
567 ALeffectslot *slot = NULL;
568 ALbufferlistitem *oldlist;
569 ALfloat fvals[3];
571 switch(prop)
573 case AL_SOURCE_RELATIVE:
574 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
576 Source->HeadRelative = (ALboolean)*values;
577 Source->NeedsUpdate = AL_TRUE;
578 return AL_TRUE;
580 case AL_LOOPING:
581 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
583 Source->Looping = (ALboolean)*values;
584 return AL_TRUE;
586 case AL_BUFFER:
587 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
589 WriteLock(&Source->queue_lock);
590 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
592 WriteUnlock(&Source->queue_lock);
593 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
596 if(buffer != NULL)
598 ALbufferlistitem *BufferListItem;
600 /* Add the selected buffer to a one-item queue */
601 BufferListItem = malloc(sizeof(ALbufferlistitem));
602 BufferListItem->buffer = buffer;
603 BufferListItem->next = NULL;
604 BufferListItem->prev = NULL;
605 IncrementRef(&buffer->ref);
607 /* Source is now Static */
608 Source->SourceType = AL_STATIC;
609 oldlist = ExchangePtr((XchgPtr*)&Source->queue, BufferListItem);
611 ReadLock(&buffer->lock);
612 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
613 Source->SampleSize = BytesFromFmt(buffer->FmtType);
614 ReadUnlock(&buffer->lock);
616 else
618 /* Source is now Undetermined */
619 Source->SourceType = AL_UNDETERMINED;
620 oldlist = ExchangePtr((XchgPtr*)&Source->queue, NULL);
622 Source->current_buffer = Source->queue;
623 WriteUnlock(&Source->queue_lock);
625 /* Delete all elements in the previous queue */
626 while(oldlist != NULL)
628 ALbufferlistitem *temp = oldlist;
629 oldlist = temp->next;
631 if(temp->buffer)
632 DecrementRef(&temp->buffer->ref);
633 free(temp);
635 return AL_TRUE;
637 case siSourceState:
638 case siSourceType:
639 case siBuffersQueued:
640 case siBuffersProcessed:
641 /* Query only */
642 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
644 case AL_SEC_OFFSET:
645 case AL_SAMPLE_OFFSET:
646 case AL_BYTE_OFFSET:
647 CHECKVAL(*values >= 0);
649 LockContext(Context);
650 Source->OffsetType = prop;
651 Source->Offset = *values;
653 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
654 !Context->DeferUpdates)
656 if(ApplyOffset(Source) == AL_FALSE)
658 UnlockContext(Context);
659 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
662 UnlockContext(Context);
663 return AL_TRUE;
666 case siByteLength:
667 case siSampleLength:
668 case siSampleRWOffsetsSOFT:
669 case siByteRWOffsetsSOFT:
670 /* Query only */
671 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
674 case AL_DIRECT_FILTER:
675 CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
677 LockContext(Context);
678 if(!filter)
680 Source->Direct.Gain = 1.0f;
681 Source->Direct.GainHF = 1.0f;
682 Source->Direct.HFReference = LOWPASSFREQREF;
683 Source->Direct.GainLF = 1.0f;
684 Source->Direct.LFReference = HIGHPASSFREQREF;
686 else
688 Source->Direct.Gain = filter->Gain;
689 Source->Direct.GainHF = filter->GainHF;
690 Source->Direct.HFReference = filter->HFReference;
691 Source->Direct.GainLF = filter->GainLF;
692 Source->Direct.LFReference = filter->LFReference;
694 UnlockContext(Context);
695 Source->NeedsUpdate = AL_TRUE;
696 return AL_TRUE;
698 case AL_DIRECT_FILTER_GAINHF_AUTO:
699 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
701 Source->DryGainHFAuto = *values;
702 Source->NeedsUpdate = AL_TRUE;
703 return AL_TRUE;
705 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
706 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
708 Source->WetGainAuto = *values;
709 Source->NeedsUpdate = AL_TRUE;
710 return AL_TRUE;
712 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
713 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
715 Source->WetGainHFAuto = *values;
716 Source->NeedsUpdate = AL_TRUE;
717 return AL_TRUE;
719 case AL_DIRECT_CHANNELS_SOFT:
720 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
722 Source->DirectChannels = *values;
723 Source->NeedsUpdate = AL_TRUE;
724 return AL_TRUE;
726 case AL_DISTANCE_MODEL:
727 CHECKVAL(*values == AL_NONE ||
728 *values == AL_INVERSE_DISTANCE ||
729 *values == AL_INVERSE_DISTANCE_CLAMPED ||
730 *values == AL_LINEAR_DISTANCE ||
731 *values == AL_LINEAR_DISTANCE_CLAMPED ||
732 *values == AL_EXPONENT_DISTANCE ||
733 *values == AL_EXPONENT_DISTANCE_CLAMPED);
735 Source->DistanceModel = *values;
736 if(Context->SourceDistanceModel)
737 Source->NeedsUpdate = AL_TRUE;
738 return AL_TRUE;
741 case AL_AUXILIARY_SEND_FILTER:
742 LockContext(Context);
743 if(!((ALuint)values[1] < device->NumAuxSends &&
744 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
745 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
747 UnlockContext(Context);
748 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
751 /* Add refcount on the new slot, and release the previous slot */
752 if(slot) IncrementRef(&slot->ref);
753 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
754 if(slot) DecrementRef(&slot->ref);
756 if(!filter)
758 /* Disable filter */
759 Source->Send[values[1]].Gain = 1.0f;
760 Source->Send[values[1]].GainHF = 1.0f;
761 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
762 Source->Send[values[1]].GainLF = 1.0f;
763 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
765 else
767 Source->Send[values[1]].Gain = filter->Gain;
768 Source->Send[values[1]].GainHF = filter->GainHF;
769 Source->Send[values[1]].HFReference = filter->HFReference;
770 Source->Send[values[1]].GainLF = filter->GainLF;
771 Source->Send[values[1]].LFReference = filter->LFReference;
773 Source->NeedsUpdate = AL_TRUE;
774 UnlockContext(Context);
775 return AL_TRUE;
778 case AL_MAX_DISTANCE:
779 case AL_ROLLOFF_FACTOR:
780 case AL_CONE_INNER_ANGLE:
781 case AL_CONE_OUTER_ANGLE:
782 case AL_REFERENCE_DISTANCE:
783 case siDopplerFactor:
784 fvals[0] = (ALfloat)*values;
785 return SetSourcefv(Source, Context, (int)prop, fvals);
787 case AL_POSITION:
788 case AL_VELOCITY:
789 case AL_DIRECTION:
790 fvals[0] = (ALfloat)values[0];
791 fvals[1] = (ALfloat)values[1];
792 fvals[2] = (ALfloat)values[2];
793 return SetSourcefv(Source, Context, (int)prop, fvals);
795 case siSampleOffsetLatencySOFT:
796 /* i64 only */
797 break;
800 ERR("Unexpected property: 0x%04x\n", prop);
801 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
804 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values)
806 ALfloat fvals[3];
807 ALint ivals[3];
809 switch(prop)
811 case siSampleRWOffsetsSOFT:
812 case siByteRWOffsetsSOFT:
813 case siSampleOffsetLatencySOFT:
814 /* Query only */
815 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
818 /* 1x int */
819 case AL_SOURCE_RELATIVE:
820 case AL_LOOPING:
821 case AL_SOURCE_STATE:
822 case AL_BYTE_OFFSET:
823 case AL_SAMPLE_OFFSET:
824 case siByteLength:
825 case siSampleLength:
826 case siSourceType:
827 case siBuffersQueued:
828 case siBuffersProcessed:
829 case AL_DIRECT_FILTER_GAINHF_AUTO:
830 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
831 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
832 case AL_DIRECT_CHANNELS_SOFT:
833 case AL_DISTANCE_MODEL:
834 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
836 ivals[0] = (ALint)*values;
837 return SetSourceiv(Source, Context, (int)prop, ivals);
839 /* 1x uint */
840 case AL_BUFFER:
841 case AL_DIRECT_FILTER:
842 CHECKVAL(*values <= UINT_MAX && *values >= 0);
844 ivals[0] = (ALuint)*values;
845 return SetSourceiv(Source, Context, (int)prop, ivals);
847 /* 3x uint */
848 case AL_AUXILIARY_SEND_FILTER:
849 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
850 values[1] <= UINT_MAX && values[1] >= 0 &&
851 values[2] <= UINT_MAX && values[2] >= 0);
853 ivals[0] = (ALuint)values[0];
854 ivals[1] = (ALuint)values[1];
855 ivals[2] = (ALuint)values[2];
856 return SetSourceiv(Source, Context, (int)prop, ivals);
858 /* 1x float */
859 case AL_MAX_DISTANCE:
860 case AL_ROLLOFF_FACTOR:
861 case AL_CONE_INNER_ANGLE:
862 case AL_CONE_OUTER_ANGLE:
863 case AL_REFERENCE_DISTANCE:
864 case AL_SEC_OFFSET:
865 case siDopplerFactor:
866 fvals[0] = (ALfloat)*values;
867 return SetSourcefv(Source, Context, (int)prop, fvals);
869 /* 3x float */
870 case AL_POSITION:
871 case AL_VELOCITY:
872 case AL_DIRECTION:
873 fvals[0] = (ALfloat)values[0];
874 fvals[1] = (ALfloat)values[1];
875 fvals[2] = (ALfloat)values[2];
876 return SetSourcefv(Source, Context, (int)prop, fvals);
879 ERR("Unexpected property: 0x%04x\n", prop);
880 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
883 #undef CHECKVAL
886 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values)
888 ALbufferlistitem *BufferList;
889 ALdouble offsets[2];
890 ALdouble updateLen;
891 ALint ivals[3];
892 ALboolean err;
894 switch(prop)
896 case AL_GAIN:
897 *values = Source->Gain;
898 return AL_TRUE;
900 case AL_PITCH:
901 *values = Source->Pitch;
902 return AL_TRUE;
904 case AL_MAX_DISTANCE:
905 *values = Source->MaxDistance;
906 return AL_TRUE;
908 case AL_ROLLOFF_FACTOR:
909 *values = Source->RollOffFactor;
910 return AL_TRUE;
912 case AL_REFERENCE_DISTANCE:
913 *values = Source->RefDistance;
914 return AL_TRUE;
916 case AL_CONE_INNER_ANGLE:
917 *values = Source->InnerAngle;
918 return AL_TRUE;
920 case AL_CONE_OUTER_ANGLE:
921 *values = Source->OuterAngle;
922 return AL_TRUE;
924 case AL_MIN_GAIN:
925 *values = Source->MinGain;
926 return AL_TRUE;
928 case AL_MAX_GAIN:
929 *values = Source->MaxGain;
930 return AL_TRUE;
932 case AL_CONE_OUTER_GAIN:
933 *values = Source->OuterGain;
934 return AL_TRUE;
936 case AL_SEC_OFFSET:
937 case AL_SAMPLE_OFFSET:
938 case AL_BYTE_OFFSET:
939 ReadLock(&Source->queue_lock);
940 LockContext(Context);
941 GetSourceOffsets(Source, prop, offsets, 0.0);
942 UnlockContext(Context);
943 ReadUnlock(&Source->queue_lock);
944 *values = offsets[0];
945 return AL_TRUE;
947 case AL_CONE_OUTER_GAINHF:
948 *values = Source->OuterGainHF;
949 return AL_TRUE;
951 case AL_AIR_ABSORPTION_FACTOR:
952 *values = Source->AirAbsorptionFactor;
953 return AL_TRUE;
955 case AL_ROOM_ROLLOFF_FACTOR:
956 *values = Source->RoomRolloffFactor;
957 return AL_TRUE;
959 case AL_DOPPLER_FACTOR:
960 *values = Source->DopplerFactor;
961 return AL_TRUE;
963 case sfSecLength:
964 ReadLock(&Source->queue_lock);
965 if(!(BufferList=Source->queue))
966 *values = 0;
967 else
969 ALint length = 0;
970 ALsizei freq = 1;
971 do {
972 ALbuffer *buffer = BufferList->buffer;
973 if(buffer && buffer->SampleLen > 0)
975 freq = buffer->Frequency;
976 length += buffer->SampleLen;
978 } while((BufferList=BufferList->next) != NULL);
979 *values = (ALdouble)length / (ALdouble)freq;
981 ReadUnlock(&Source->queue_lock);
982 return AL_TRUE;
984 case AL_SAMPLE_RW_OFFSETS_SOFT:
985 case AL_BYTE_RW_OFFSETS_SOFT:
986 ReadLock(&Source->queue_lock);
987 LockContext(Context);
988 updateLen = (ALdouble)Context->Device->UpdateSize /
989 Context->Device->Frequency;
990 GetSourceOffsets(Source, prop, values, updateLen);
991 UnlockContext(Context);
992 ReadUnlock(&Source->queue_lock);
993 return AL_TRUE;
995 case AL_SEC_OFFSET_LATENCY_SOFT:
996 ReadLock(&Source->queue_lock);
997 LockContext(Context);
998 values[0] = GetSourceSecOffset(Source);
999 values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) /
1000 1000000000.0;
1001 UnlockContext(Context);
1002 ReadUnlock(&Source->queue_lock);
1003 return AL_TRUE;
1005 case AL_POSITION:
1006 LockContext(Context);
1007 values[0] = Source->Position[0];
1008 values[1] = Source->Position[1];
1009 values[2] = Source->Position[2];
1010 UnlockContext(Context);
1011 return AL_TRUE;
1013 case AL_VELOCITY:
1014 LockContext(Context);
1015 values[0] = Source->Velocity[0];
1016 values[1] = Source->Velocity[1];
1017 values[2] = Source->Velocity[2];
1018 UnlockContext(Context);
1019 return AL_TRUE;
1021 case AL_DIRECTION:
1022 LockContext(Context);
1023 values[0] = Source->Orientation[0];
1024 values[1] = Source->Orientation[1];
1025 values[2] = Source->Orientation[2];
1026 UnlockContext(Context);
1027 return AL_TRUE;
1029 case AL_SOURCE_RELATIVE:
1030 case AL_LOOPING:
1031 case AL_BUFFER:
1032 case AL_SOURCE_STATE:
1033 case AL_BUFFERS_QUEUED:
1034 case AL_BUFFERS_PROCESSED:
1035 case AL_SOURCE_TYPE:
1036 case AL_DIRECT_FILTER_GAINHF_AUTO:
1037 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1038 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1039 case AL_DIRECT_CHANNELS_SOFT:
1040 case AL_DISTANCE_MODEL:
1041 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1042 *values = (ALdouble)ivals[0];
1043 return err;
1046 ERR("Unexpected property: 0x%04x\n", prop);
1047 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1050 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values)
1052 ALbufferlistitem *BufferList;
1053 ALdouble dvals[3];
1054 ALboolean err;
1056 switch(prop)
1058 case AL_SOURCE_RELATIVE:
1059 *values = Source->HeadRelative;
1060 return AL_TRUE;
1062 case AL_LOOPING:
1063 *values = Source->Looping;
1064 return AL_TRUE;
1066 case AL_BUFFER:
1067 ReadLock(&Source->queue_lock);
1068 BufferList = (Source->SourceType == AL_STATIC) ? Source->queue :
1069 Source->current_buffer;
1070 *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1071 ReadUnlock(&Source->queue_lock);
1072 return AL_TRUE;
1074 case AL_SOURCE_STATE:
1075 *values = Source->state;
1076 return AL_TRUE;
1078 case siByteLength:
1079 ReadLock(&Source->queue_lock);
1080 if(!(BufferList=Source->queue))
1081 *values = 0;
1082 else
1084 ALint length = 0;
1085 do {
1086 ALbuffer *buffer = BufferList->buffer;
1087 if(buffer && buffer->SampleLen > 0)
1089 ALuint byte_align, sample_align;
1090 if(buffer->OriginalType == UserFmtIMA4)
1092 ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1093 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1094 sample_align = buffer->OriginalAlign;
1096 else if(buffer->OriginalType == UserFmtMSADPCM)
1098 ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1099 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1100 sample_align = buffer->OriginalAlign;
1102 else
1104 ALsizei align = buffer->OriginalAlign;
1105 byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1106 sample_align = buffer->OriginalAlign;
1109 length += buffer->SampleLen / sample_align * byte_align;
1111 } while((BufferList=BufferList->next) != NULL);
1112 *values = length;
1114 ReadUnlock(&Source->queue_lock);
1115 return AL_TRUE;
1117 case siSampleLength:
1118 ReadLock(&Source->queue_lock);
1119 if(!(BufferList=Source->queue))
1120 *values = 0;
1121 else
1123 ALint length = 0;
1124 do {
1125 ALbuffer *buffer = BufferList->buffer;
1126 if(buffer) length += buffer->SampleLen;
1127 } while((BufferList=BufferList->next) != NULL);
1128 *values = length;
1130 ReadUnlock(&Source->queue_lock);
1131 return AL_TRUE;
1133 case AL_BUFFERS_QUEUED:
1134 ReadLock(&Source->queue_lock);
1135 if(!(BufferList=Source->queue))
1136 *values = 0;
1137 else
1139 ALsizei count = 0;
1140 do {
1141 ++count;
1142 } while((BufferList=BufferList->next) != NULL);
1143 *values = count;
1145 ReadUnlock(&Source->queue_lock);
1146 return AL_TRUE;
1148 case AL_BUFFERS_PROCESSED:
1149 ReadLock(&Source->queue_lock);
1150 if(Source->Looping || Source->SourceType != AL_STREAMING)
1152 /* Buffers on a looping source are in a perpetual state of
1153 * PENDING, so don't report any as PROCESSED */
1154 *values = 0;
1156 else
1158 const ALbufferlistitem *BufferList = Source->queue;
1159 ALsizei played = 0;
1160 while(BufferList && BufferList != Source->current_buffer)
1162 played++;
1163 BufferList = BufferList->next;
1165 *values = played;
1167 ReadUnlock(&Source->queue_lock);
1168 return AL_TRUE;
1170 case AL_SOURCE_TYPE:
1171 *values = Source->SourceType;
1172 return AL_TRUE;
1174 case AL_DIRECT_FILTER_GAINHF_AUTO:
1175 *values = Source->DryGainHFAuto;
1176 return AL_TRUE;
1178 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1179 *values = Source->WetGainAuto;
1180 return AL_TRUE;
1182 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1183 *values = Source->WetGainHFAuto;
1184 return AL_TRUE;
1186 case AL_DIRECT_CHANNELS_SOFT:
1187 *values = Source->DirectChannels;
1188 return AL_TRUE;
1190 case AL_DISTANCE_MODEL:
1191 *values = Source->DistanceModel;
1192 return AL_TRUE;
1194 case AL_MAX_DISTANCE:
1195 case AL_ROLLOFF_FACTOR:
1196 case AL_REFERENCE_DISTANCE:
1197 case AL_CONE_INNER_ANGLE:
1198 case AL_CONE_OUTER_ANGLE:
1199 case AL_SEC_OFFSET:
1200 case AL_SAMPLE_OFFSET:
1201 case AL_BYTE_OFFSET:
1202 case AL_DOPPLER_FACTOR:
1203 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1204 *values = (ALint)dvals[0];
1205 return err;
1207 case AL_SAMPLE_RW_OFFSETS_SOFT:
1208 case AL_BYTE_RW_OFFSETS_SOFT:
1209 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1211 values[0] = (ALint)dvals[0];
1212 values[1] = (ALint)dvals[1];
1214 return err;
1216 case AL_POSITION:
1217 case AL_VELOCITY:
1218 case AL_DIRECTION:
1219 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1221 values[0] = (ALint)dvals[0];
1222 values[1] = (ALint)dvals[1];
1223 values[2] = (ALint)dvals[2];
1225 return err;
1227 case siSampleOffsetLatencySOFT:
1228 /* i64 only */
1229 break;
1231 case siDirectFilter:
1232 case siAuxSendFilter:
1233 /* ??? */
1234 break;
1237 ERR("Unexpected property: 0x%04x\n", prop);
1238 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1241 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values)
1243 ALdouble dvals[3];
1244 ALint ivals[3];
1245 ALboolean err;
1247 switch(prop)
1249 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1250 ReadLock(&Source->queue_lock);
1251 LockContext(Context);
1252 values[0] = GetSourceOffset(Source);
1253 values[1] = ALCdevice_GetLatency(Context->Device);
1254 UnlockContext(Context);
1255 ReadUnlock(&Source->queue_lock);
1256 return AL_TRUE;
1258 case AL_MAX_DISTANCE:
1259 case AL_ROLLOFF_FACTOR:
1260 case AL_REFERENCE_DISTANCE:
1261 case AL_CONE_INNER_ANGLE:
1262 case AL_CONE_OUTER_ANGLE:
1263 case AL_SEC_OFFSET:
1264 case AL_SAMPLE_OFFSET:
1265 case AL_BYTE_OFFSET:
1266 case AL_DOPPLER_FACTOR:
1267 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1268 *values = (ALint64)dvals[0];
1269 return err;
1271 case AL_SAMPLE_RW_OFFSETS_SOFT:
1272 case AL_BYTE_RW_OFFSETS_SOFT:
1273 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1275 values[0] = (ALint64)dvals[0];
1276 values[1] = (ALint64)dvals[1];
1278 return err;
1280 case AL_POSITION:
1281 case AL_VELOCITY:
1282 case AL_DIRECTION:
1283 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1285 values[0] = (ALint64)dvals[0];
1286 values[1] = (ALint64)dvals[1];
1287 values[2] = (ALint64)dvals[2];
1289 return err;
1291 case AL_SOURCE_RELATIVE:
1292 case AL_LOOPING:
1293 case AL_SOURCE_STATE:
1294 case AL_BUFFERS_QUEUED:
1295 case AL_BUFFERS_PROCESSED:
1296 case siByteLength:
1297 case siSampleLength:
1298 case AL_SOURCE_TYPE:
1299 case AL_DIRECT_FILTER_GAINHF_AUTO:
1300 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1301 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1302 case AL_DIRECT_CHANNELS_SOFT:
1303 case AL_DISTANCE_MODEL:
1304 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1305 *values = ivals[0];
1306 return err;
1308 case siBuffer:
1309 case siDirectFilter:
1310 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1311 *values = (ALuint)ivals[0];
1312 return err;
1314 case siAuxSendFilter:
1315 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1317 values[0] = (ALuint)ivals[0];
1318 values[1] = (ALuint)ivals[1];
1319 values[2] = (ALuint)ivals[2];
1321 return err;
1324 ERR("Unexpected property: 0x%04x\n", prop);
1325 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1329 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1331 ALCcontext *context;
1332 ALsizei cur = 0;
1333 ALenum err;
1335 context = GetContextRef();
1336 if(!context) return;
1338 if(!(n >= 0))
1339 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1340 for(cur = 0;cur < n;cur++)
1342 ALsource *source = al_calloc(16, sizeof(ALsource));
1343 if(!source)
1345 alDeleteSources(cur, sources);
1346 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1348 InitSourceParams(source);
1350 err = NewThunkEntry(&source->id);
1351 if(err == AL_NO_ERROR)
1352 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1353 if(err != AL_NO_ERROR)
1355 FreeThunkEntry(source->id);
1356 memset(source, 0, sizeof(ALsource));
1357 al_free(source);
1359 alDeleteSources(cur, sources);
1360 SET_ERROR_AND_GOTO(context, err, done);
1363 sources[cur] = source->id;
1366 done:
1367 ALCcontext_DecRef(context);
1371 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1373 ALCcontext *context;
1374 ALbufferlistitem *BufferList;
1375 ALsource *Source;
1376 ALsizei i, j;
1378 context = GetContextRef();
1379 if(!context) return;
1381 if(!(n >= 0))
1382 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1384 /* Check that all Sources are valid */
1385 for(i = 0;i < n;i++)
1387 if(LookupSource(context, sources[i]) == NULL)
1388 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1390 for(i = 0;i < n;i++)
1392 ALactivesource **srclist, **srclistend;
1394 if((Source=RemoveSource(context, sources[i])) == NULL)
1395 continue;
1396 FreeThunkEntry(Source->id);
1398 LockContext(context);
1399 srclist = context->ActiveSources;
1400 srclistend = srclist + context->ActiveSourceCount;
1401 while(srclist != srclistend)
1403 if((*srclist)->Source == Source)
1405 ALactivesource *temp = *(--srclistend);
1406 *srclistend = *srclist;
1407 *srclist = temp;
1408 --(context->ActiveSourceCount);
1409 break;
1411 srclist++;
1413 UnlockContext(context);
1415 while(Source->queue != NULL)
1417 BufferList = Source->queue;
1418 Source->queue = BufferList->next;
1420 if(BufferList->buffer != NULL)
1421 DecrementRef(&BufferList->buffer->ref);
1422 free(BufferList);
1425 for(j = 0;j < MAX_SENDS;++j)
1427 if(Source->Send[j].Slot)
1428 DecrementRef(&Source->Send[j].Slot->ref);
1429 Source->Send[j].Slot = NULL;
1432 memset(Source, 0, sizeof(*Source));
1433 al_free(Source);
1436 done:
1437 ALCcontext_DecRef(context);
1441 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1443 ALCcontext *context;
1444 ALboolean ret;
1446 context = GetContextRef();
1447 if(!context) return AL_FALSE;
1449 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1451 ALCcontext_DecRef(context);
1453 return ret;
1457 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1459 ALCcontext *Context;
1460 ALsource *Source;
1462 Context = GetContextRef();
1463 if(!Context) return;
1465 if((Source=LookupSource(Context, source)) == NULL)
1466 alSetError(Context, AL_INVALID_NAME);
1467 else if(!(FloatValsByProp(param) == 1))
1468 alSetError(Context, AL_INVALID_ENUM);
1469 else
1470 SetSourcefv(Source, Context, param, &value);
1472 ALCcontext_DecRef(Context);
1475 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1477 ALCcontext *Context;
1478 ALsource *Source;
1480 Context = GetContextRef();
1481 if(!Context) return;
1483 if((Source=LookupSource(Context, source)) == NULL)
1484 alSetError(Context, AL_INVALID_NAME);
1485 else if(!(FloatValsByProp(param) == 3))
1486 alSetError(Context, AL_INVALID_ENUM);
1487 else
1489 ALfloat fvals[3] = { value1, value2, value3 };
1490 SetSourcefv(Source, Context, param, fvals);
1493 ALCcontext_DecRef(Context);
1496 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1498 ALCcontext *Context;
1499 ALsource *Source;
1501 Context = GetContextRef();
1502 if(!Context) return;
1504 if((Source=LookupSource(Context, source)) == NULL)
1505 alSetError(Context, AL_INVALID_NAME);
1506 else if(!values)
1507 alSetError(Context, AL_INVALID_VALUE);
1508 else if(!(FloatValsByProp(param) > 0))
1509 alSetError(Context, AL_INVALID_ENUM);
1510 else
1511 SetSourcefv(Source, Context, param, values);
1513 ALCcontext_DecRef(Context);
1517 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1519 ALCcontext *Context;
1520 ALsource *Source;
1522 Context = GetContextRef();
1523 if(!Context) return;
1525 if((Source=LookupSource(Context, source)) == NULL)
1526 alSetError(Context, AL_INVALID_NAME);
1527 else if(!(DoubleValsByProp(param) == 1))
1528 alSetError(Context, AL_INVALID_ENUM);
1529 else
1531 ALfloat fval = (ALfloat)value;
1532 SetSourcefv(Source, Context, param, &fval);
1535 ALCcontext_DecRef(Context);
1538 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1540 ALCcontext *Context;
1541 ALsource *Source;
1543 Context = GetContextRef();
1544 if(!Context) return;
1546 if((Source=LookupSource(Context, source)) == NULL)
1547 alSetError(Context, AL_INVALID_NAME);
1548 else if(!(DoubleValsByProp(param) == 3))
1549 alSetError(Context, AL_INVALID_ENUM);
1550 else
1552 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1553 SetSourcefv(Source, Context, param, fvals);
1556 ALCcontext_DecRef(Context);
1559 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1561 ALCcontext *Context;
1562 ALsource *Source;
1563 ALint count;
1565 Context = GetContextRef();
1566 if(!Context) return;
1568 if((Source=LookupSource(Context, source)) == NULL)
1569 alSetError(Context, AL_INVALID_NAME);
1570 else if(!values)
1571 alSetError(Context, AL_INVALID_VALUE);
1572 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 3))
1573 alSetError(Context, AL_INVALID_ENUM);
1574 else
1576 ALfloat fvals[3];
1577 ALint i;
1579 for(i = 0;i < count;i++)
1580 fvals[i] = (ALfloat)values[i];
1581 SetSourcefv(Source, Context, param, fvals);
1584 ALCcontext_DecRef(Context);
1588 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1590 ALCcontext *Context;
1591 ALsource *Source;
1593 Context = GetContextRef();
1594 if(!Context) return;
1596 if((Source=LookupSource(Context, source)) == NULL)
1597 alSetError(Context, AL_INVALID_NAME);
1598 else if(!(IntValsByProp(param) == 1))
1599 alSetError(Context, AL_INVALID_ENUM);
1600 else
1601 SetSourceiv(Source, Context, param, &value);
1603 ALCcontext_DecRef(Context);
1606 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1608 ALCcontext *Context;
1609 ALsource *Source;
1611 Context = GetContextRef();
1612 if(!Context) return;
1614 if((Source=LookupSource(Context, source)) == NULL)
1615 alSetError(Context, AL_INVALID_NAME);
1616 else if(!(IntValsByProp(param) == 3))
1617 alSetError(Context, AL_INVALID_ENUM);
1618 else
1620 ALint ivals[3] = { value1, value2, value3 };
1621 SetSourceiv(Source, Context, param, ivals);
1624 ALCcontext_DecRef(Context);
1627 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1629 ALCcontext *Context;
1630 ALsource *Source;
1632 Context = GetContextRef();
1633 if(!Context) return;
1635 if((Source=LookupSource(Context, source)) == NULL)
1636 alSetError(Context, AL_INVALID_NAME);
1637 else if(!values)
1638 alSetError(Context, AL_INVALID_VALUE);
1639 else if(!(IntValsByProp(param) > 0))
1640 alSetError(Context, AL_INVALID_ENUM);
1641 else
1642 SetSourceiv(Source, Context, param, values);
1644 ALCcontext_DecRef(Context);
1648 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1650 ALCcontext *Context;
1651 ALsource *Source;
1653 Context = GetContextRef();
1654 if(!Context) return;
1656 if((Source=LookupSource(Context, source)) == NULL)
1657 alSetError(Context, AL_INVALID_NAME);
1658 else if(!(Int64ValsByProp(param) == 1))
1659 alSetError(Context, AL_INVALID_ENUM);
1660 else
1661 SetSourcei64v(Source, Context, param, &value);
1663 ALCcontext_DecRef(Context);
1666 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1668 ALCcontext *Context;
1669 ALsource *Source;
1671 Context = GetContextRef();
1672 if(!Context) return;
1674 if((Source=LookupSource(Context, source)) == NULL)
1675 alSetError(Context, AL_INVALID_NAME);
1676 else if(!(Int64ValsByProp(param) == 3))
1677 alSetError(Context, AL_INVALID_ENUM);
1678 else
1680 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1681 SetSourcei64v(Source, Context, param, i64vals);
1684 ALCcontext_DecRef(Context);
1687 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1689 ALCcontext *Context;
1690 ALsource *Source;
1692 Context = GetContextRef();
1693 if(!Context) return;
1695 if((Source=LookupSource(Context, source)) == NULL)
1696 alSetError(Context, AL_INVALID_NAME);
1697 else if(!values)
1698 alSetError(Context, AL_INVALID_VALUE);
1699 else if(!(Int64ValsByProp(param) > 0))
1700 alSetError(Context, AL_INVALID_ENUM);
1701 else
1702 SetSourcei64v(Source, Context, param, values);
1704 ALCcontext_DecRef(Context);
1708 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1710 ALCcontext *Context;
1711 ALsource *Source;
1713 Context = GetContextRef();
1714 if(!Context) return;
1716 if((Source=LookupSource(Context, source)) == NULL)
1717 alSetError(Context, AL_INVALID_NAME);
1718 else if(!value)
1719 alSetError(Context, AL_INVALID_VALUE);
1720 else if(!(FloatValsByProp(param) == 1))
1721 alSetError(Context, AL_INVALID_ENUM);
1722 else
1724 ALdouble dval;
1725 if(GetSourcedv(Source, Context, param, &dval))
1726 *value = (ALfloat)dval;
1729 ALCcontext_DecRef(Context);
1733 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1735 ALCcontext *Context;
1736 ALsource *Source;
1738 Context = GetContextRef();
1739 if(!Context) return;
1741 if((Source=LookupSource(Context, source)) == NULL)
1742 alSetError(Context, AL_INVALID_NAME);
1743 else if(!(value1 && value2 && value3))
1744 alSetError(Context, AL_INVALID_VALUE);
1745 else if(!(FloatValsByProp(param) == 3))
1746 alSetError(Context, AL_INVALID_ENUM);
1747 else
1749 ALdouble dvals[3];
1750 if(GetSourcedv(Source, Context, param, dvals))
1752 *value1 = (ALfloat)dvals[0];
1753 *value2 = (ALfloat)dvals[1];
1754 *value3 = (ALfloat)dvals[2];
1758 ALCcontext_DecRef(Context);
1762 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1764 ALCcontext *Context;
1765 ALsource *Source;
1766 ALint count;
1768 Context = GetContextRef();
1769 if(!Context) return;
1771 if((Source=LookupSource(Context, source)) == NULL)
1772 alSetError(Context, AL_INVALID_NAME);
1773 else if(!values)
1774 alSetError(Context, AL_INVALID_VALUE);
1775 else if(!((count=FloatValsByProp(param)) > 0 && count <= 3))
1776 alSetError(Context, AL_INVALID_ENUM);
1777 else
1779 ALdouble dvals[3];
1780 if(GetSourcedv(Source, Context, param, dvals))
1782 ALint i;
1783 for(i = 0;i < count;i++)
1784 values[i] = (ALfloat)dvals[i];
1788 ALCcontext_DecRef(Context);
1792 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1794 ALCcontext *Context;
1795 ALsource *Source;
1797 Context = GetContextRef();
1798 if(!Context) return;
1800 if((Source=LookupSource(Context, source)) == NULL)
1801 alSetError(Context, AL_INVALID_NAME);
1802 else if(!value)
1803 alSetError(Context, AL_INVALID_VALUE);
1804 else if(!(DoubleValsByProp(param) == 1))
1805 alSetError(Context, AL_INVALID_ENUM);
1806 else
1807 GetSourcedv(Source, Context, param, value);
1809 ALCcontext_DecRef(Context);
1812 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1814 ALCcontext *Context;
1815 ALsource *Source;
1817 Context = GetContextRef();
1818 if(!Context) return;
1820 if((Source=LookupSource(Context, source)) == NULL)
1821 alSetError(Context, AL_INVALID_NAME);
1822 else if(!(value1 && value2 && value3))
1823 alSetError(Context, AL_INVALID_VALUE);
1824 else if(!(DoubleValsByProp(param) == 3))
1825 alSetError(Context, AL_INVALID_ENUM);
1826 else
1828 ALdouble dvals[3];
1829 if(GetSourcedv(Source, Context, param, dvals))
1831 *value1 = dvals[0];
1832 *value2 = dvals[1];
1833 *value3 = dvals[2];
1837 ALCcontext_DecRef(Context);
1840 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1842 ALCcontext *Context;
1843 ALsource *Source;
1845 Context = GetContextRef();
1846 if(!Context) return;
1848 if((Source=LookupSource(Context, source)) == NULL)
1849 alSetError(Context, AL_INVALID_NAME);
1850 else if(!values)
1851 alSetError(Context, AL_INVALID_VALUE);
1852 else if(!(DoubleValsByProp(param) > 0))
1853 alSetError(Context, AL_INVALID_ENUM);
1854 else
1855 GetSourcedv(Source, Context, param, values);
1857 ALCcontext_DecRef(Context);
1861 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1863 ALCcontext *Context;
1864 ALsource *Source;
1866 Context = GetContextRef();
1867 if(!Context) return;
1869 if((Source=LookupSource(Context, source)) == NULL)
1870 alSetError(Context, AL_INVALID_NAME);
1871 else if(!value)
1872 alSetError(Context, AL_INVALID_VALUE);
1873 else if(!(IntValsByProp(param) == 1))
1874 alSetError(Context, AL_INVALID_ENUM);
1875 else
1876 GetSourceiv(Source, Context, param, value);
1878 ALCcontext_DecRef(Context);
1882 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
1884 ALCcontext *Context;
1885 ALsource *Source;
1887 Context = GetContextRef();
1888 if(!Context) return;
1890 if((Source=LookupSource(Context, source)) == NULL)
1891 alSetError(Context, AL_INVALID_NAME);
1892 else if(!(value1 && value2 && value3))
1893 alSetError(Context, AL_INVALID_VALUE);
1894 else if(!(IntValsByProp(param) == 3))
1895 alSetError(Context, AL_INVALID_ENUM);
1896 else
1898 ALint ivals[3];
1899 if(GetSourceiv(Source, Context, param, ivals))
1901 *value1 = ivals[0];
1902 *value2 = ivals[1];
1903 *value3 = ivals[2];
1907 ALCcontext_DecRef(Context);
1911 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
1913 ALCcontext *Context;
1914 ALsource *Source;
1916 Context = GetContextRef();
1917 if(!Context) return;
1919 if((Source=LookupSource(Context, source)) == NULL)
1920 alSetError(Context, AL_INVALID_NAME);
1921 else if(!values)
1922 alSetError(Context, AL_INVALID_VALUE);
1923 else if(!(IntValsByProp(param) > 0))
1924 alSetError(Context, AL_INVALID_ENUM);
1925 else
1926 GetSourceiv(Source, Context, param, values);
1928 ALCcontext_DecRef(Context);
1932 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
1934 ALCcontext *Context;
1935 ALsource *Source;
1937 Context = GetContextRef();
1938 if(!Context) return;
1940 if((Source=LookupSource(Context, source)) == NULL)
1941 alSetError(Context, AL_INVALID_NAME);
1942 else if(!value)
1943 alSetError(Context, AL_INVALID_VALUE);
1944 else if(!(Int64ValsByProp(param) == 1))
1945 alSetError(Context, AL_INVALID_ENUM);
1946 else
1947 GetSourcei64v(Source, Context, param, value);
1949 ALCcontext_DecRef(Context);
1952 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
1954 ALCcontext *Context;
1955 ALsource *Source;
1957 Context = GetContextRef();
1958 if(!Context) return;
1960 if((Source=LookupSource(Context, source)) == NULL)
1961 alSetError(Context, AL_INVALID_NAME);
1962 else if(!(value1 && value2 && value3))
1963 alSetError(Context, AL_INVALID_VALUE);
1964 else if(!(Int64ValsByProp(param) == 3))
1965 alSetError(Context, AL_INVALID_ENUM);
1966 else
1968 ALint64 i64vals[3];
1969 if(GetSourcei64v(Source, Context, param, i64vals))
1971 *value1 = i64vals[0];
1972 *value2 = i64vals[1];
1973 *value3 = i64vals[2];
1977 ALCcontext_DecRef(Context);
1980 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
1982 ALCcontext *Context;
1983 ALsource *Source;
1985 Context = GetContextRef();
1986 if(!Context) return;
1988 if((Source=LookupSource(Context, source)) == NULL)
1989 alSetError(Context, AL_INVALID_NAME);
1990 else if(!values)
1991 alSetError(Context, AL_INVALID_VALUE);
1992 else if(!(Int64ValsByProp(param) > 0))
1993 alSetError(Context, AL_INVALID_ENUM);
1994 else
1995 GetSourcei64v(Source, Context, param, values);
1997 ALCcontext_DecRef(Context);
2001 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2003 alSourcePlayv(1, &source);
2005 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2007 ALCcontext *context;
2008 ALsource *source;
2009 ALsizei i;
2011 context = GetContextRef();
2012 if(!context) return;
2014 if(!(n >= 0))
2015 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2016 for(i = 0;i < n;i++)
2018 if(!LookupSource(context, sources[i]))
2019 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2022 LockContext(context);
2023 while(n > context->MaxActiveSources-context->ActiveSourceCount)
2025 ALactivesource **temp = NULL;
2026 ALsizei newcount;
2028 newcount = context->MaxActiveSources << 1;
2029 if(newcount > 0)
2030 temp = realloc(context->ActiveSources,
2031 newcount * sizeof(context->ActiveSources[0]));
2032 if(!temp)
2034 UnlockContext(context);
2035 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2037 for(i = context->MaxActiveSources;i < newcount;i++)
2038 temp[i] = NULL;
2040 context->ActiveSources = temp;
2041 context->MaxActiveSources = newcount;
2044 for(i = 0;i < n;i++)
2046 source = LookupSource(context, sources[i]);
2047 if(context->DeferUpdates) source->new_state = AL_PLAYING;
2048 else SetSourceState(source, context, AL_PLAYING);
2050 UnlockContext(context);
2052 done:
2053 ALCcontext_DecRef(context);
2056 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2058 alSourcePausev(1, &source);
2060 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2062 ALCcontext *context;
2063 ALsource *source;
2064 ALsizei i;
2066 context = GetContextRef();
2067 if(!context) return;
2069 if(!(n >= 0))
2070 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2071 for(i = 0;i < n;i++)
2073 if(!LookupSource(context, sources[i]))
2074 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2077 LockContext(context);
2078 for(i = 0;i < n;i++)
2080 source = LookupSource(context, sources[i]);
2081 if(context->DeferUpdates) source->new_state = AL_PAUSED;
2082 else SetSourceState(source, context, AL_PAUSED);
2084 UnlockContext(context);
2086 done:
2087 ALCcontext_DecRef(context);
2090 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2092 alSourceStopv(1, &source);
2094 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2096 ALCcontext *context;
2097 ALsource *source;
2098 ALsizei i;
2100 context = GetContextRef();
2101 if(!context) return;
2103 if(!(n >= 0))
2104 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2105 for(i = 0;i < n;i++)
2107 if(!LookupSource(context, sources[i]))
2108 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2111 LockContext(context);
2112 for(i = 0;i < n;i++)
2114 source = LookupSource(context, sources[i]);
2115 source->new_state = AL_NONE;
2116 SetSourceState(source, context, AL_STOPPED);
2118 UnlockContext(context);
2120 done:
2121 ALCcontext_DecRef(context);
2124 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2126 alSourceRewindv(1, &source);
2128 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2130 ALCcontext *context;
2131 ALsource *source;
2132 ALsizei i;
2134 context = GetContextRef();
2135 if(!context) return;
2137 if(!(n >= 0))
2138 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2139 for(i = 0;i < n;i++)
2141 if(!LookupSource(context, sources[i]))
2142 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2145 LockContext(context);
2146 for(i = 0;i < n;i++)
2148 source = LookupSource(context, sources[i]);
2149 source->new_state = AL_NONE;
2150 SetSourceState(source, context, AL_INITIAL);
2152 UnlockContext(context);
2154 done:
2155 ALCcontext_DecRef(context);
2159 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2161 ALCdevice *device;
2162 ALCcontext *context;
2163 ALsource *source;
2164 ALsizei i;
2165 ALbufferlistitem *BufferListStart;
2166 ALbufferlistitem *BufferList;
2167 ALbuffer *BufferFmt = NULL;
2169 if(nb == 0)
2170 return;
2172 context = GetContextRef();
2173 if(!context) return;
2175 device = context->Device;
2177 if(!(nb >= 0))
2178 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2179 if((source=LookupSource(context, src)) == NULL)
2180 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2182 WriteLock(&source->queue_lock);
2183 if(source->SourceType == AL_STATIC)
2185 WriteUnlock(&source->queue_lock);
2186 /* Can't queue on a Static Source */
2187 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2190 /* Check for a valid Buffer, for its frequency and format */
2191 BufferList = source->queue;
2192 while(BufferList)
2194 if(BufferList->buffer)
2196 BufferFmt = BufferList->buffer;
2197 break;
2199 BufferList = BufferList->next;
2202 BufferListStart = NULL;
2203 BufferList = NULL;
2204 for(i = 0;i < nb;i++)
2206 ALbuffer *buffer = NULL;
2207 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2209 WriteUnlock(&source->queue_lock);
2210 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2213 if(!BufferListStart)
2215 BufferListStart = malloc(sizeof(ALbufferlistitem));
2216 BufferListStart->buffer = buffer;
2217 BufferListStart->next = NULL;
2218 BufferListStart->prev = NULL;
2219 BufferList = BufferListStart;
2221 else
2223 BufferList->next = malloc(sizeof(ALbufferlistitem));
2224 BufferList->next->buffer = buffer;
2225 BufferList->next->next = NULL;
2226 BufferList->next->prev = BufferList;
2227 BufferList = BufferList->next;
2229 if(!buffer) continue;
2231 /* Hold a read lock on each buffer being queued while checking all
2232 * provided buffers. This is done so other threads don't see an extra
2233 * reference on some buffers if this operation ends up failing. */
2234 ReadLock(&buffer->lock);
2235 IncrementRef(&buffer->ref);
2237 if(BufferFmt == NULL)
2239 BufferFmt = buffer;
2241 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2242 source->SampleSize = BytesFromFmt(buffer->FmtType);
2244 else if(BufferFmt->Frequency != buffer->Frequency ||
2245 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2246 BufferFmt->OriginalType != buffer->OriginalType)
2248 WriteUnlock(&source->queue_lock);
2249 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2251 buffer_error:
2252 /* A buffer failed (invalid ID or format), so unlock and release
2253 * each buffer we had. */
2254 while(BufferList != NULL)
2256 ALbufferlistitem *prev = BufferList->prev;
2257 if((buffer=BufferList->buffer) != NULL)
2259 DecrementRef(&buffer->ref);
2260 ReadUnlock(&buffer->lock);
2262 free(BufferList);
2263 BufferList = prev;
2265 goto done;
2268 /* All buffers good, unlock them now. */
2269 while(BufferList != NULL)
2271 ALbuffer *buffer = BufferList->buffer;
2272 if(buffer) ReadUnlock(&buffer->lock);
2273 BufferList = BufferList->prev;
2276 /* Source is now streaming */
2277 source->SourceType = AL_STREAMING;
2279 if((BufferList=CompExchangePtr((XchgPtr*)&source->queue, NULL, BufferListStart)) != NULL)
2281 /* Queue head is not NULL, append to the end of the queue */
2282 while(BufferList->next != NULL)
2283 BufferList = BufferList->next;
2285 BufferListStart->prev = BufferList;
2286 BufferList->next = BufferListStart;
2288 CompExchangePtr((XchgPtr*)&source->current_buffer, NULL, BufferListStart);
2289 WriteUnlock(&source->queue_lock);
2291 done:
2292 ALCcontext_DecRef(context);
2295 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2297 ALCcontext *context;
2298 ALsource *source;
2299 ALbufferlistitem *BufferList;
2300 ALbufferlistitem *OldHead;
2301 ALsizei i;
2303 if(nb == 0)
2304 return;
2306 context = GetContextRef();
2307 if(!context) return;
2309 if(!(nb >= 0))
2310 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2312 if((source=LookupSource(context, src)) == NULL)
2313 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2315 WriteLock(&source->queue_lock);
2316 /* Find the new buffer queue head */
2317 BufferList = source->queue;
2318 for(i = 0;i < nb && BufferList;i++)
2320 if(BufferList == source->current_buffer)
2321 break;
2322 BufferList = BufferList->next;
2324 if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
2326 WriteUnlock(&source->queue_lock);
2327 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2328 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2331 /* Swap it, and cut the new head from the old. */
2332 OldHead = ExchangePtr((XchgPtr*)&source->queue, BufferList);
2333 if(BufferList)
2335 ALCdevice *device = context->Device;
2336 uint count;
2338 /* Cut the new head's link back to the old body. The mixer is robust
2339 * enough to handle the link back going away. Once the active mix (if
2340 * any) is complete, it's safe to finish cutting the old tail from the
2341 * new head. */
2342 BufferList = ExchangePtr((XchgPtr*)&BufferList->prev, NULL);
2343 if(((count=ReadRef(&device->MixCount))&1) != 0)
2345 while(count == ReadRef(&device->MixCount))
2346 althrd_yield();
2348 BufferList->next = NULL;
2350 WriteUnlock(&source->queue_lock);
2352 while(OldHead != NULL)
2354 ALbufferlistitem *next = OldHead->next;
2355 ALbuffer *buffer = OldHead->buffer;
2357 if(!buffer)
2358 *(buffers++) = 0;
2359 else
2361 *(buffers++) = buffer->id;
2362 DecrementRef(&buffer->ref);
2365 free(OldHead);
2366 OldHead = next;
2369 done:
2370 ALCcontext_DecRef(context);
2374 static ALvoid InitSourceParams(ALsource *Source)
2376 ALuint i;
2378 RWLockInit(&Source->queue_lock);
2380 Source->InnerAngle = 360.0f;
2381 Source->OuterAngle = 360.0f;
2382 Source->Pitch = 1.0f;
2383 Source->Position[0] = 0.0f;
2384 Source->Position[1] = 0.0f;
2385 Source->Position[2] = 0.0f;
2386 Source->Orientation[0] = 0.0f;
2387 Source->Orientation[1] = 0.0f;
2388 Source->Orientation[2] = 0.0f;
2389 Source->Velocity[0] = 0.0f;
2390 Source->Velocity[1] = 0.0f;
2391 Source->Velocity[2] = 0.0f;
2392 Source->RefDistance = 1.0f;
2393 Source->MaxDistance = FLT_MAX;
2394 Source->RollOffFactor = 1.0f;
2395 Source->Looping = AL_FALSE;
2396 Source->Gain = 1.0f;
2397 Source->MinGain = 0.0f;
2398 Source->MaxGain = 1.0f;
2399 Source->OuterGain = 0.0f;
2400 Source->OuterGainHF = 1.0f;
2402 Source->DryGainHFAuto = AL_TRUE;
2403 Source->WetGainAuto = AL_TRUE;
2404 Source->WetGainHFAuto = AL_TRUE;
2405 Source->AirAbsorptionFactor = 0.0f;
2406 Source->RoomRolloffFactor = 0.0f;
2407 Source->DopplerFactor = 1.0f;
2408 Source->DirectChannels = AL_FALSE;
2410 Source->DistanceModel = DefaultDistanceModel;
2412 Source->Resampler = DefaultResampler;
2414 Source->state = AL_INITIAL;
2415 Source->new_state = AL_NONE;
2416 Source->SourceType = AL_UNDETERMINED;
2417 Source->Offset = -1.0;
2419 Source->queue = NULL;
2420 Source->current_buffer = NULL;
2422 Source->Direct.Gain = 1.0f;
2423 Source->Direct.GainHF = 1.0f;
2424 Source->Direct.HFReference = LOWPASSFREQREF;
2425 Source->Direct.GainLF = 1.0f;
2426 Source->Direct.LFReference = HIGHPASSFREQREF;
2427 for(i = 0;i < MAX_SENDS;i++)
2429 Source->Send[i].Gain = 1.0f;
2430 Source->Send[i].GainHF = 1.0f;
2431 Source->Send[i].HFReference = LOWPASSFREQREF;
2432 Source->Send[i].GainLF = 1.0f;
2433 Source->Send[i].LFReference = HIGHPASSFREQREF;
2436 Source->NeedsUpdate = AL_TRUE;
2440 /* SetSourceState
2442 * Sets the source's new play state given its current state.
2444 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2446 ReadLock(&Source->queue_lock);
2447 if(state == AL_PLAYING)
2449 ALCdevice *device = Context->Device;
2450 ALbufferlistitem *BufferList;
2451 ALactivesource *src = NULL;
2452 ALsizei j, k;
2454 /* Check that there is a queue containing at least one valid, non zero
2455 * length Buffer. */
2456 BufferList = Source->queue;
2457 while(BufferList)
2459 ALbuffer *buffer;
2460 if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2461 break;
2462 BufferList = BufferList->next;
2465 if(Source->state != AL_PAUSED)
2467 Source->state = AL_PLAYING;
2468 Source->position = 0;
2469 Source->position_fraction = 0;
2470 Source->current_buffer = BufferList;
2472 else
2473 Source->state = AL_PLAYING;
2475 // Check if an Offset has been set
2476 if(Source->Offset >= 0.0)
2477 ApplyOffset(Source);
2479 /* If there's nothing to play, or device is disconnected, go right to
2480 * stopped */
2481 if(!BufferList || !device->Connected)
2482 goto do_stop;
2484 for(j = 0;j < Context->ActiveSourceCount;j++)
2486 if(Context->ActiveSources[j]->Source == Source)
2488 src = Context->ActiveSources[j];
2489 break;
2492 if(src == NULL)
2494 src = Context->ActiveSources[Context->ActiveSourceCount];
2495 if(src == NULL)
2497 src = al_malloc(16, sizeof(src[0]));
2498 Context->ActiveSources[Context->ActiveSourceCount] = src;
2500 memset(src, 0, sizeof(*src));
2502 src->Source = Source;
2503 if(BufferList->buffer->FmtChannels == FmtMono)
2504 src->Update = CalcSourceParams;
2505 else
2506 src->Update = CalcNonAttnSourceParams;
2507 Context->ActiveSourceCount++;
2509 else
2511 ALuint i;
2513 src->Direct.Moving = AL_FALSE;
2514 src->Direct.Counter = 0;
2515 for(j = 0;j < MAX_INPUT_CHANNELS;j++)
2517 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
2518 src->Direct.Mix.Hrtf.State[j].History[k] = 0.0f;
2519 for(k = 0;k < HRIR_LENGTH;k++)
2521 src->Direct.Mix.Hrtf.State[j].Values[k][0] = 0.0f;
2522 src->Direct.Mix.Hrtf.State[j].Values[k][1] = 0.0f;
2525 for(i = 0;i < device->NumAuxSends;i++)
2527 src->Send[i].Counter = 0;
2528 src->Send[i].Moving = AL_FALSE;
2531 Source->NeedsUpdate = AL_TRUE;
2533 else if(state == AL_PAUSED)
2535 if(Source->state == AL_PLAYING)
2536 Source->state = AL_PAUSED;
2538 else if(state == AL_STOPPED)
2540 do_stop:
2541 if(Source->state != AL_INITIAL)
2543 Source->state = AL_STOPPED;
2544 Source->current_buffer = NULL;
2546 Source->Offset = -1.0;
2548 else if(state == AL_INITIAL)
2550 if(Source->state != AL_INITIAL)
2552 Source->state = AL_INITIAL;
2553 Source->position = 0;
2554 Source->position_fraction = 0;
2555 Source->current_buffer = Source->queue;
2557 Source->Offset = -1.0;
2559 ReadUnlock(&Source->queue_lock);
2562 /* GetSourceOffset
2564 * Gets the current read offset for the given Source, in 32.32 fixed-point
2565 * samples. The offset is relative to the start of the queue (not the start of
2566 * the current buffer).
2568 static ALint64 GetSourceOffset(const ALsource *Source)
2570 const ALbufferlistitem *BufferList;
2571 ALuint64 readPos;
2573 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2574 return 0;
2576 /* NOTE: This is the offset into the *current* buffer, so add the length of
2577 * any played buffers */
2578 readPos = (ALuint64)Source->position << 32;
2579 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2580 BufferList = Source->queue;
2581 while(BufferList && BufferList != Source->current_buffer)
2583 if(BufferList->buffer)
2584 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2585 BufferList = BufferList->next;
2588 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
2591 /* GetSourceSecOffset
2593 * Gets the current read offset for the given Source, in seconds. The offset is
2594 * relative to the start of the queue (not the start of the current buffer).
2596 static ALdouble GetSourceSecOffset(const ALsource *Source)
2598 const ALbufferlistitem *BufferList;
2599 const ALbuffer *Buffer = NULL;
2600 ALuint64 readPos;
2602 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2603 return 0.0;
2605 /* NOTE: This is the offset into the *current* buffer, so add the length of
2606 * any played buffers */
2607 readPos = (ALuint64)Source->position << FRACTIONBITS;
2608 readPos |= (ALuint64)Source->position_fraction;
2609 BufferList = Source->queue;
2610 while(BufferList && BufferList != Source->current_buffer)
2612 const ALbuffer *buffer = BufferList->buffer;
2613 if(buffer != NULL)
2615 if(!Buffer) Buffer = buffer;
2616 readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
2618 BufferList = BufferList->next;
2621 while(BufferList && !Buffer)
2623 Buffer = BufferList->buffer;
2624 BufferList = BufferList->next;
2626 assert(Buffer != NULL);
2628 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2631 /* GetSourceOffsets
2633 * Gets the current read and write offsets for the given Source, in the
2634 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2635 * the start of the queue (not the start of the current buffer).
2637 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2639 const ALbufferlistitem *BufferList;
2640 const ALbuffer *Buffer = NULL;
2641 ALboolean readFin = AL_FALSE;
2642 ALuint readPos, writePos;
2643 ALuint totalBufferLen;
2645 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2647 offset[0] = 0.0;
2648 offset[1] = 0.0;
2649 return;
2652 if(updateLen > 0.0 && updateLen < 0.015)
2653 updateLen = 0.015;
2655 /* NOTE: This is the offset into the *current* buffer, so add the length of
2656 * any played buffers */
2657 totalBufferLen = 0;
2658 readPos = Source->position;
2659 BufferList = Source->queue;
2660 while(BufferList != NULL)
2662 const ALbuffer *buffer;
2663 readFin = readFin || (BufferList == Source->current_buffer);
2664 if((buffer=BufferList->buffer) != NULL)
2666 if(!Buffer) Buffer = buffer;
2667 totalBufferLen += buffer->SampleLen;
2668 if(!readFin) readPos += buffer->SampleLen;
2670 BufferList = BufferList->next;
2672 assert(Buffer != NULL);
2674 if(Source->state == AL_PLAYING)
2675 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
2676 else
2677 writePos = readPos;
2679 if(Source->Looping)
2681 readPos %= totalBufferLen;
2682 writePos %= totalBufferLen;
2684 else
2686 /* Wrap positions back to 0 */
2687 if(readPos >= totalBufferLen)
2688 readPos = 0;
2689 if(writePos >= totalBufferLen)
2690 writePos = 0;
2693 switch(name)
2695 case AL_SEC_OFFSET:
2696 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2697 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2698 break;
2700 case AL_SAMPLE_OFFSET:
2701 case AL_SAMPLE_RW_OFFSETS_SOFT:
2702 offset[0] = (ALdouble)readPos;
2703 offset[1] = (ALdouble)writePos;
2704 break;
2706 case AL_BYTE_OFFSET:
2707 case AL_BYTE_RW_OFFSETS_SOFT:
2708 if(Buffer->OriginalType == UserFmtIMA4)
2710 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2711 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2712 ALuint FrameBlockSize = Buffer->OriginalAlign;
2714 /* Round down to nearest ADPCM block */
2715 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2716 if(Source->state != AL_PLAYING)
2717 offset[1] = offset[0];
2718 else
2720 /* Round up to nearest ADPCM block */
2721 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2722 FrameBlockSize * BlockSize);
2725 else if(Buffer->OriginalType == UserFmtMSADPCM)
2727 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2728 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2729 ALuint FrameBlockSize = Buffer->OriginalAlign;
2731 /* Round down to nearest ADPCM block */
2732 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2733 if(Source->state != AL_PLAYING)
2734 offset[1] = offset[0];
2735 else
2737 /* Round up to nearest ADPCM block */
2738 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2739 FrameBlockSize * BlockSize);
2742 else
2744 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2745 offset[0] = (ALdouble)(readPos * FrameSize);
2746 offset[1] = (ALdouble)(writePos * FrameSize);
2748 break;
2753 /* ApplyOffset
2755 * Apply the stored playback offset to the Source. This function will update
2756 * the number of buffers "played" given the stored offset.
2758 ALboolean ApplyOffset(ALsource *Source)
2760 ALbufferlistitem *BufferList;
2761 const ALbuffer *Buffer;
2762 ALint bufferLen, totalBufferLen;
2763 ALint offset;
2765 /* Get sample frame offset */
2766 offset = GetSampleOffset(Source);
2767 if(offset == -1)
2768 return AL_FALSE;
2770 totalBufferLen = 0;
2771 BufferList = Source->queue;
2772 while(BufferList && totalBufferLen <= offset)
2774 Buffer = BufferList->buffer;
2775 bufferLen = Buffer ? Buffer->SampleLen : 0;
2777 if(bufferLen > offset-totalBufferLen)
2779 /* Offset is in this buffer */
2780 Source->current_buffer = BufferList;
2782 Source->position = offset - totalBufferLen;
2783 Source->position_fraction = 0;
2784 return AL_TRUE;
2787 totalBufferLen += bufferLen;
2789 BufferList = BufferList->next;
2792 /* Offset is out of range of the queue */
2793 return AL_FALSE;
2797 /* GetSampleOffset
2799 * Returns the sample offset into the Source's queue (from the Sample, Byte or
2800 * Second offset supplied by the application). This takes into account the fact
2801 * that the buffer format may have been modifed since.
2803 static ALint GetSampleOffset(ALsource *Source)
2805 const ALbuffer *Buffer = NULL;
2806 const ALbufferlistitem *BufferList;
2807 ALint Offset = -1;
2809 /* Find the first valid Buffer in the Queue */
2810 BufferList = Source->queue;
2811 while(BufferList)
2813 if(BufferList->buffer)
2815 Buffer = BufferList->buffer;
2816 break;
2818 BufferList = BufferList->next;
2821 if(!Buffer)
2823 Source->Offset = -1.0;
2824 return -1;
2827 switch(Source->OffsetType)
2829 case AL_BYTE_OFFSET:
2830 /* Determine the ByteOffset (and ensure it is block aligned) */
2831 Offset = (ALint)Source->Offset;
2832 if(Buffer->OriginalType == UserFmtIMA4)
2834 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2835 Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2836 Offset *= Buffer->OriginalAlign;
2838 else if(Buffer->OriginalType == UserFmtMSADPCM)
2840 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2841 Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2842 Offset *= Buffer->OriginalAlign;
2844 else
2845 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2846 break;
2848 case AL_SAMPLE_OFFSET:
2849 Offset = (ALint)Source->Offset;
2850 break;
2852 case AL_SEC_OFFSET:
2853 Offset = (ALint)(Source->Offset * Buffer->Frequency);
2854 break;
2856 Source->Offset = -1.0;
2858 return Offset;
2862 /* ReleaseALSources
2864 * Destroys all sources in the source map.
2866 ALvoid ReleaseALSources(ALCcontext *Context)
2868 ALsizei pos;
2869 ALuint j;
2870 for(pos = 0;pos < Context->SourceMap.size;pos++)
2872 ALsource *temp = Context->SourceMap.array[pos].value;
2873 Context->SourceMap.array[pos].value = NULL;
2875 while(temp->queue != NULL)
2877 ALbufferlistitem *BufferList = temp->queue;
2878 temp->queue = BufferList->next;
2880 if(BufferList->buffer != NULL)
2881 DecrementRef(&BufferList->buffer->ref);
2882 free(BufferList);
2885 for(j = 0;j < MAX_SENDS;++j)
2887 if(temp->Send[j].Slot)
2888 DecrementRef(&temp->Send[j].Slot->ref);
2889 temp->Send[j].Slot = NULL;
2892 FreeThunkEntry(temp->id);
2893 memset(temp, 0, sizeof(*temp));
2894 al_free(temp);