Use gettimeofday if clock_gettime isn't available
[openal-soft.git] / OpenAL32 / alSource.c
blob1a1d696f5f3aeb9267e58fe58b0fd24221daf706
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"
37 enum Resampler DefaultResampler = LinearResampler;
38 const ALsizei ResamplerPadding[ResamplerMax] = {
39 0, /* Point */
40 1, /* Linear */
41 2, /* Cubic */
43 const ALsizei ResamplerPrePadding[ResamplerMax] = {
44 0, /* Point */
45 0, /* Linear */
46 1, /* Cubic */
50 extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
51 extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
53 static ALvoid InitSourceParams(ALsource *Source);
54 static ALint64 GetSourceOffset(const ALsource *Source);
55 static ALdouble GetSourceSecOffset(const ALsource *Source);
56 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
57 static ALint GetSampleOffset(ALsource *Source);
59 typedef enum SrcFloatProp {
60 sfPitch = AL_PITCH,
61 sfGain = AL_GAIN,
62 sfMinGain = AL_MIN_GAIN,
63 sfMaxGain = AL_MAX_GAIN,
64 sfMaxDistance = AL_MAX_DISTANCE,
65 sfRolloffFactor = AL_ROLLOFF_FACTOR,
66 sfDopplerFactor = AL_DOPPLER_FACTOR,
67 sfConeOuterGain = AL_CONE_OUTER_GAIN,
68 sfSecOffset = AL_SEC_OFFSET,
69 sfSampleOffset = AL_SAMPLE_OFFSET,
70 sfByteOffset = AL_BYTE_OFFSET,
71 sfConeInnerAngle = AL_CONE_INNER_ANGLE,
72 sfConeOuterAngle = AL_CONE_OUTER_ANGLE,
73 sfRefDistance = AL_REFERENCE_DISTANCE,
75 sfPosition = AL_POSITION,
76 sfVelocity = AL_VELOCITY,
77 sfDirection = AL_DIRECTION,
79 sfSourceRelative = AL_SOURCE_RELATIVE,
80 sfLooping = AL_LOOPING,
81 sfBuffer = AL_BUFFER,
82 sfSourceState = AL_SOURCE_STATE,
83 sfBuffersQueued = AL_BUFFERS_QUEUED,
84 sfBuffersProcessed = AL_BUFFERS_PROCESSED,
85 sfSourceType = AL_SOURCE_TYPE,
87 /* ALC_EXT_EFX */
88 sfConeOuterGainHF = AL_CONE_OUTER_GAINHF,
89 sfAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
90 sfRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
91 sfDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
92 sfAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
93 sfAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
95 /* AL_SOFT_direct_channels */
96 sfDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
98 /* AL_EXT_source_distance_model */
99 sfDistanceModel = AL_DISTANCE_MODEL,
101 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
102 sfSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
103 sfByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
105 /* AL_SOFT_source_latency */
106 sfSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
107 } SrcFloatProp;
109 typedef enum SrcIntProp {
110 siMaxDistance = AL_MAX_DISTANCE,
111 siRolloffFactor = AL_ROLLOFF_FACTOR,
112 siRefDistance = AL_REFERENCE_DISTANCE,
113 siSourceRelative = AL_SOURCE_RELATIVE,
114 siConeInnerAngle = AL_CONE_INNER_ANGLE,
115 siConeOuterAngle = AL_CONE_OUTER_ANGLE,
116 siLooping = AL_LOOPING,
117 siBuffer = AL_BUFFER,
118 siSourceState = AL_SOURCE_STATE,
119 siBuffersQueued = AL_BUFFERS_QUEUED,
120 siBuffersProcessed = AL_BUFFERS_PROCESSED,
121 siSourceType = AL_SOURCE_TYPE,
122 siSecOffset = AL_SEC_OFFSET,
123 siSampleOffset = AL_SAMPLE_OFFSET,
124 siByteOffset = AL_BYTE_OFFSET,
125 siDopplerFactor = AL_DOPPLER_FACTOR,
126 siPosition = AL_POSITION,
127 siVelocity = AL_VELOCITY,
128 siDirection = AL_DIRECTION,
130 /* ALC_EXT_EFX */
131 siDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
132 siAuxSendFilterGainAutio = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
133 siAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
134 siDirectFilter = AL_DIRECT_FILTER,
135 siAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
137 /* AL_SOFT_direct_channels */
138 siDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
140 /* AL_EXT_source_distance_model */
141 siDistanceModel = AL_DISTANCE_MODEL,
143 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
144 siSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
145 siByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
147 /* AL_SOFT_source_latency */
148 siSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
149 } SrcIntProp;
151 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values);
152 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values);
153 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values);
155 static ALboolean GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values);
156 static ALboolean GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values);
157 static ALboolean GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values);
159 static ALint FloatValsByProp(ALenum prop)
161 if(prop != (ALenum)((SrcFloatProp)prop))
162 return 0;
163 switch((SrcFloatProp)prop)
165 case sfPitch:
166 case sfGain:
167 case sfMinGain:
168 case sfMaxGain:
169 case sfMaxDistance:
170 case sfRolloffFactor:
171 case sfDopplerFactor:
172 case sfConeOuterGain:
173 case sfSecOffset:
174 case sfSampleOffset:
175 case sfByteOffset:
176 case sfConeInnerAngle:
177 case sfConeOuterAngle:
178 case sfRefDistance:
179 case sfConeOuterGainHF:
180 case sfAirAbsorptionFactor:
181 case sfRoomRolloffFactor:
182 case sfDirectFilterGainHFAuto:
183 case sfAuxSendFilterGainAuto:
184 case sfAuxSendFilterGainHFAuto:
185 case sfDirectChannelsSOFT:
186 case sfDistanceModel:
187 case sfSourceRelative:
188 case sfLooping:
189 case sfBuffer:
190 case sfSourceState:
191 case sfBuffersQueued:
192 case sfBuffersProcessed:
193 case sfSourceType:
194 return 1;
196 case sfSampleRWOffsetsSOFT:
197 case sfByteRWOffsetsSOFT:
198 return 2;
200 case sfPosition:
201 case sfVelocity:
202 case sfDirection:
203 return 3;
205 case sfSecOffsetLatencySOFT:
206 break; /* Double only */
208 return 0;
210 static ALint DoubleValsByProp(ALenum prop)
212 if(prop != (ALenum)((SrcFloatProp)prop))
213 return 0;
214 switch((SrcFloatProp)prop)
216 case sfPitch:
217 case sfGain:
218 case sfMinGain:
219 case sfMaxGain:
220 case sfMaxDistance:
221 case sfRolloffFactor:
222 case sfDopplerFactor:
223 case sfConeOuterGain:
224 case sfSecOffset:
225 case sfSampleOffset:
226 case sfByteOffset:
227 case sfConeInnerAngle:
228 case sfConeOuterAngle:
229 case sfRefDistance:
230 case sfConeOuterGainHF:
231 case sfAirAbsorptionFactor:
232 case sfRoomRolloffFactor:
233 case sfDirectFilterGainHFAuto:
234 case sfAuxSendFilterGainAuto:
235 case sfAuxSendFilterGainHFAuto:
236 case sfDirectChannelsSOFT:
237 case sfDistanceModel:
238 case sfSourceRelative:
239 case sfLooping:
240 case sfBuffer:
241 case sfSourceState:
242 case sfBuffersQueued:
243 case sfBuffersProcessed:
244 case sfSourceType:
245 return 1;
247 case sfSampleRWOffsetsSOFT:
248 case sfByteRWOffsetsSOFT:
249 case sfSecOffsetLatencySOFT:
250 return 2;
252 case sfPosition:
253 case sfVelocity:
254 case sfDirection:
255 return 3;
257 return 0;
260 static ALint IntValsByProp(ALenum prop)
262 if(prop != (ALenum)((SrcIntProp)prop))
263 return 0;
264 switch((SrcIntProp)prop)
266 case siMaxDistance:
267 case siRolloffFactor:
268 case siRefDistance:
269 case siSourceRelative:
270 case siConeInnerAngle:
271 case siConeOuterAngle:
272 case siLooping:
273 case siBuffer:
274 case siSourceState:
275 case siBuffersQueued:
276 case siBuffersProcessed:
277 case siSourceType:
278 case siSecOffset:
279 case siSampleOffset:
280 case siByteOffset:
281 case siDopplerFactor:
282 case siDirectFilterGainHFAuto:
283 case siAuxSendFilterGainAutio:
284 case siAuxSendFilterGainHFAuto:
285 case siDirectFilter:
286 case siDirectChannelsSOFT:
287 case siDistanceModel:
288 return 1;
290 case siSampleRWOffsetsSOFT:
291 case siByteRWOffsetsSOFT:
292 return 2;
294 case siPosition:
295 case siVelocity:
296 case siDirection:
297 case siAuxSendFilter:
298 return 3;
300 case siSampleOffsetLatencySOFT:
301 break; /* i64 only */
303 return 0;
305 static ALint Int64ValsByProp(ALenum prop)
307 if(prop != (ALenum)((SrcIntProp)prop))
308 return 0;
309 switch((SrcIntProp)prop)
311 case siMaxDistance:
312 case siRolloffFactor:
313 case siRefDistance:
314 case siSourceRelative:
315 case siConeInnerAngle:
316 case siConeOuterAngle:
317 case siLooping:
318 case siBuffer:
319 case siSourceState:
320 case siBuffersQueued:
321 case siBuffersProcessed:
322 case siSourceType:
323 case siSecOffset:
324 case siSampleOffset:
325 case siByteOffset:
326 case siDopplerFactor:
327 case siDirectFilterGainHFAuto:
328 case siAuxSendFilterGainAutio:
329 case siAuxSendFilterGainHFAuto:
330 case siDirectFilter:
331 case siDirectChannelsSOFT:
332 case siDistanceModel:
333 return 1;
335 case siSampleRWOffsetsSOFT:
336 case siByteRWOffsetsSOFT:
337 case siSampleOffsetLatencySOFT:
338 return 2;
340 case siPosition:
341 case siVelocity:
342 case siDirection:
343 case siAuxSendFilter:
344 return 3;
346 return 0;
350 #define CHECKVAL(x) do { \
351 if(!(x)) \
352 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
353 } while(0)
355 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values)
357 ALint ival;
359 switch(prop)
361 case AL_PITCH:
362 CHECKVAL(*values >= 0.0f);
364 Source->Pitch = *values;
365 Source->NeedsUpdate = AL_TRUE;
366 return AL_TRUE;
368 case AL_CONE_INNER_ANGLE:
369 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
371 Source->InnerAngle = *values;
372 Source->NeedsUpdate = AL_TRUE;
373 return AL_TRUE;
375 case AL_CONE_OUTER_ANGLE:
376 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
378 Source->OuterAngle = *values;
379 Source->NeedsUpdate = AL_TRUE;
380 return AL_TRUE;
382 case AL_GAIN:
383 CHECKVAL(*values >= 0.0f);
385 Source->Gain = *values;
386 Source->NeedsUpdate = AL_TRUE;
387 return AL_TRUE;
389 case AL_MAX_DISTANCE:
390 CHECKVAL(*values >= 0.0f);
392 Source->MaxDistance = *values;
393 Source->NeedsUpdate = AL_TRUE;
394 return AL_TRUE;
396 case AL_ROLLOFF_FACTOR:
397 CHECKVAL(*values >= 0.0f);
399 Source->RollOffFactor = *values;
400 Source->NeedsUpdate = AL_TRUE;
401 return AL_TRUE;
403 case AL_REFERENCE_DISTANCE:
404 CHECKVAL(*values >= 0.0f);
406 Source->RefDistance = *values;
407 Source->NeedsUpdate = AL_TRUE;
408 return AL_TRUE;
410 case AL_MIN_GAIN:
411 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
413 Source->MinGain = *values;
414 Source->NeedsUpdate = AL_TRUE;
415 return AL_TRUE;
417 case AL_MAX_GAIN:
418 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
420 Source->MaxGain = *values;
421 Source->NeedsUpdate = AL_TRUE;
422 return AL_TRUE;
424 case AL_CONE_OUTER_GAIN:
425 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
427 Source->OuterGain = *values;
428 Source->NeedsUpdate = AL_TRUE;
429 return AL_TRUE;
431 case AL_CONE_OUTER_GAINHF:
432 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
434 Source->OuterGainHF = *values;
435 Source->NeedsUpdate = AL_TRUE;
436 return AL_TRUE;
438 case AL_AIR_ABSORPTION_FACTOR:
439 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
441 Source->AirAbsorptionFactor = *values;
442 Source->NeedsUpdate = AL_TRUE;
443 return AL_TRUE;
445 case AL_ROOM_ROLLOFF_FACTOR:
446 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
448 Source->RoomRolloffFactor = *values;
449 Source->NeedsUpdate = AL_TRUE;
450 return AL_TRUE;
452 case AL_DOPPLER_FACTOR:
453 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
455 Source->DopplerFactor = *values;
456 Source->NeedsUpdate = AL_TRUE;
457 return AL_TRUE;
459 case AL_SEC_OFFSET:
460 case AL_SAMPLE_OFFSET:
461 case AL_BYTE_OFFSET:
462 CHECKVAL(*values >= 0.0f);
464 LockContext(Context);
465 Source->OffsetType = prop;
466 Source->Offset = *values;
468 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
469 !Context->DeferUpdates)
471 if(ApplyOffset(Source) == AL_FALSE)
473 UnlockContext(Context);
474 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
477 UnlockContext(Context);
478 return AL_TRUE;
481 case AL_SEC_OFFSET_LATENCY_SOFT:
482 /* Query only */
483 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
486 case AL_POSITION:
487 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
489 LockContext(Context);
490 Source->Position[0] = values[0];
491 Source->Position[1] = values[1];
492 Source->Position[2] = values[2];
493 UnlockContext(Context);
494 Source->NeedsUpdate = AL_TRUE;
495 return AL_TRUE;
497 case AL_VELOCITY:
498 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
500 LockContext(Context);
501 Source->Velocity[0] = values[0];
502 Source->Velocity[1] = values[1];
503 Source->Velocity[2] = values[2];
504 UnlockContext(Context);
505 Source->NeedsUpdate = AL_TRUE;
506 return AL_TRUE;
508 case AL_DIRECTION:
509 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
511 LockContext(Context);
512 Source->Orientation[0] = values[0];
513 Source->Orientation[1] = values[1];
514 Source->Orientation[2] = values[2];
515 UnlockContext(Context);
516 Source->NeedsUpdate = AL_TRUE;
517 return AL_TRUE;
520 case sfSampleRWOffsetsSOFT:
521 case sfByteRWOffsetsSOFT:
522 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
525 case sfSourceRelative:
526 case sfLooping:
527 case sfSourceState:
528 case sfSourceType:
529 case sfDistanceModel:
530 case sfDirectFilterGainHFAuto:
531 case sfAuxSendFilterGainAuto:
532 case sfAuxSendFilterGainHFAuto:
533 case sfDirectChannelsSOFT:
534 ival = (ALint)values[0];
535 return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival);
537 case sfBuffer:
538 case sfBuffersQueued:
539 case sfBuffersProcessed:
540 ival = (ALint)((ALuint)values[0]);
541 return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival);
544 ERR("Unexpected property: 0x%04x\n", prop);
545 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
548 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values)
550 ALCdevice *device = Context->Device;
551 ALbuffer *buffer = NULL;
552 ALfilter *filter = NULL;
553 ALeffectslot *slot = NULL;
554 ALbufferlistitem *oldlist;
555 ALfloat fvals[3];
557 switch(prop)
559 case AL_SOURCE_RELATIVE:
560 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
562 Source->HeadRelative = (ALboolean)*values;
563 Source->NeedsUpdate = AL_TRUE;
564 return AL_TRUE;
566 case AL_LOOPING:
567 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
569 Source->Looping = (ALboolean)*values;
570 return AL_TRUE;
572 case AL_BUFFER:
573 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
575 LockContext(Context);
576 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
578 UnlockContext(Context);
579 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
582 Source->BuffersInQueue = 0;
583 Source->BuffersPlayed = 0;
585 if(buffer != NULL)
587 ALbufferlistitem *BufferListItem;
589 /* Source is now Static */
590 Source->SourceType = AL_STATIC;
592 /* Add the selected buffer to a one-item queue */
593 BufferListItem = malloc(sizeof(ALbufferlistitem));
594 BufferListItem->buffer = buffer;
595 BufferListItem->next = NULL;
596 BufferListItem->prev = NULL;
597 IncrementRef(&buffer->ref);
599 oldlist = ExchangePtr((XchgPtr*)&Source->queue, BufferListItem);
600 Source->BuffersInQueue = 1;
602 ReadLock(&buffer->lock);
603 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
604 Source->SampleSize = BytesFromFmt(buffer->FmtType);
605 ReadUnlock(&buffer->lock);
607 else
609 /* Source is now Undetermined */
610 Source->SourceType = AL_UNDETERMINED;
611 oldlist = ExchangePtr((XchgPtr*)&Source->queue, NULL);
614 /* Delete all elements in the previous queue */
615 while(oldlist != NULL)
617 ALbufferlistitem *temp = oldlist;
618 oldlist = temp->next;
620 if(temp->buffer)
621 DecrementRef(&temp->buffer->ref);
622 free(temp);
624 UnlockContext(Context);
625 return AL_TRUE;
627 case siSourceState:
628 case siSourceType:
629 case siBuffersQueued:
630 case siBuffersProcessed:
631 /* Query only */
632 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
634 case AL_SEC_OFFSET:
635 case AL_SAMPLE_OFFSET:
636 case AL_BYTE_OFFSET:
637 CHECKVAL(*values >= 0);
639 LockContext(Context);
640 Source->OffsetType = prop;
641 Source->Offset = *values;
643 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
644 !Context->DeferUpdates)
646 if(ApplyOffset(Source) == AL_FALSE)
648 UnlockContext(Context);
649 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
652 UnlockContext(Context);
653 return AL_TRUE;
656 case siSampleRWOffsetsSOFT:
657 case siByteRWOffsetsSOFT:
658 /* Query only */
659 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
662 case AL_DIRECT_FILTER:
663 CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
665 LockContext(Context);
666 if(!filter)
668 Source->DirectGain = 1.0f;
669 Source->DirectGainHF = 1.0f;
671 else
673 Source->DirectGain = filter->Gain;
674 Source->DirectGainHF = filter->GainHF;
676 UnlockContext(Context);
677 Source->NeedsUpdate = AL_TRUE;
678 return AL_TRUE;
680 case AL_DIRECT_FILTER_GAINHF_AUTO:
681 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
683 Source->DryGainHFAuto = *values;
684 Source->NeedsUpdate = AL_TRUE;
685 return AL_TRUE;
687 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
688 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
690 Source->WetGainAuto = *values;
691 Source->NeedsUpdate = AL_TRUE;
692 return AL_TRUE;
694 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
695 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
697 Source->WetGainHFAuto = *values;
698 Source->NeedsUpdate = AL_TRUE;
699 return AL_TRUE;
701 case AL_DIRECT_CHANNELS_SOFT:
702 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
704 Source->DirectChannels = *values;
705 Source->NeedsUpdate = AL_TRUE;
706 return AL_TRUE;
708 case AL_DISTANCE_MODEL:
709 CHECKVAL(*values == AL_NONE ||
710 *values == AL_INVERSE_DISTANCE ||
711 *values == AL_INVERSE_DISTANCE_CLAMPED ||
712 *values == AL_LINEAR_DISTANCE ||
713 *values == AL_LINEAR_DISTANCE_CLAMPED ||
714 *values == AL_EXPONENT_DISTANCE ||
715 *values == AL_EXPONENT_DISTANCE_CLAMPED);
717 Source->DistanceModel = *values;
718 if(Context->SourceDistanceModel)
719 Source->NeedsUpdate = AL_TRUE;
720 return AL_TRUE;
723 case AL_AUXILIARY_SEND_FILTER:
724 LockContext(Context);
725 if(!((ALuint)values[1] < device->NumAuxSends &&
726 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
727 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
729 UnlockContext(Context);
730 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
733 /* Add refcount on the new slot, and release the previous slot */
734 if(slot) IncrementRef(&slot->ref);
735 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
736 if(slot) DecrementRef(&slot->ref);
738 if(!filter)
740 /* Disable filter */
741 Source->Send[values[1]].Gain = 1.0f;
742 Source->Send[values[1]].GainHF = 1.0f;
744 else
746 Source->Send[values[1]].Gain = filter->Gain;
747 Source->Send[values[1]].GainHF = filter->GainHF;
749 Source->NeedsUpdate = AL_TRUE;
750 UnlockContext(Context);
751 return AL_TRUE;
754 case AL_MAX_DISTANCE:
755 case AL_ROLLOFF_FACTOR:
756 case AL_CONE_INNER_ANGLE:
757 case AL_CONE_OUTER_ANGLE:
758 case AL_REFERENCE_DISTANCE:
759 case siDopplerFactor:
760 fvals[0] = (ALfloat)*values;
761 return SetSourcefv(Source, Context, (int)prop, fvals);
763 case AL_POSITION:
764 case AL_VELOCITY:
765 case AL_DIRECTION:
766 fvals[0] = (ALfloat)values[0];
767 fvals[1] = (ALfloat)values[1];
768 fvals[2] = (ALfloat)values[2];
769 return SetSourcefv(Source, Context, (int)prop, fvals);
771 case siSampleOffsetLatencySOFT:
772 /* i64 only */
773 break;
776 ERR("Unexpected property: 0x%04x\n", prop);
777 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
780 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values)
782 ALfloat fvals[3];
783 ALint ivals[3];
785 switch(prop)
787 case siSampleRWOffsetsSOFT:
788 case siByteRWOffsetsSOFT:
789 case siSampleOffsetLatencySOFT:
790 /* Query only */
791 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
794 /* 1x int */
795 case AL_SOURCE_RELATIVE:
796 case AL_LOOPING:
797 case AL_SOURCE_STATE:
798 case AL_BYTE_OFFSET:
799 case AL_SAMPLE_OFFSET:
800 case siSourceType:
801 case siBuffersQueued:
802 case siBuffersProcessed:
803 case AL_DIRECT_FILTER_GAINHF_AUTO:
804 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
805 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
806 case AL_DIRECT_CHANNELS_SOFT:
807 case AL_DISTANCE_MODEL:
808 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
810 ivals[0] = (ALint)*values;
811 return SetSourceiv(Source, Context, (int)prop, ivals);
813 /* 1x uint */
814 case AL_BUFFER:
815 case AL_DIRECT_FILTER:
816 CHECKVAL(*values <= UINT_MAX && *values >= 0);
818 ivals[0] = (ALuint)*values;
819 return SetSourceiv(Source, Context, (int)prop, ivals);
821 /* 3x uint */
822 case AL_AUXILIARY_SEND_FILTER:
823 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
824 values[1] <= UINT_MAX && values[1] >= 0 &&
825 values[2] <= UINT_MAX && values[2] >= 0);
827 ivals[0] = (ALuint)values[0];
828 ivals[1] = (ALuint)values[1];
829 ivals[2] = (ALuint)values[2];
830 return SetSourceiv(Source, Context, (int)prop, ivals);
832 /* 1x float */
833 case AL_MAX_DISTANCE:
834 case AL_ROLLOFF_FACTOR:
835 case AL_CONE_INNER_ANGLE:
836 case AL_CONE_OUTER_ANGLE:
837 case AL_REFERENCE_DISTANCE:
838 case AL_SEC_OFFSET:
839 case siDopplerFactor:
840 fvals[0] = (ALfloat)*values;
841 return SetSourcefv(Source, Context, (int)prop, fvals);
843 /* 3x float */
844 case AL_POSITION:
845 case AL_VELOCITY:
846 case AL_DIRECTION:
847 fvals[0] = (ALfloat)values[0];
848 fvals[1] = (ALfloat)values[1];
849 fvals[2] = (ALfloat)values[2];
850 return SetSourcefv(Source, Context, (int)prop, fvals);
853 ERR("Unexpected property: 0x%04x\n", prop);
854 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
857 #undef CHECKVAL
860 static ALboolean GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values)
862 ALdouble offsets[2];
863 ALdouble updateLen;
864 ALint ivals[3];
865 ALboolean err;
867 switch(prop)
869 case AL_GAIN:
870 *values = Source->Gain;
871 return AL_TRUE;
873 case AL_PITCH:
874 *values = Source->Pitch;
875 return AL_TRUE;
877 case AL_MAX_DISTANCE:
878 *values = Source->MaxDistance;
879 return AL_TRUE;
881 case AL_ROLLOFF_FACTOR:
882 *values = Source->RollOffFactor;
883 return AL_TRUE;
885 case AL_REFERENCE_DISTANCE:
886 *values = Source->RefDistance;
887 return AL_TRUE;
889 case AL_CONE_INNER_ANGLE:
890 *values = Source->InnerAngle;
891 return AL_TRUE;
893 case AL_CONE_OUTER_ANGLE:
894 *values = Source->OuterAngle;
895 return AL_TRUE;
897 case AL_MIN_GAIN:
898 *values = Source->MinGain;
899 return AL_TRUE;
901 case AL_MAX_GAIN:
902 *values = Source->MaxGain;
903 return AL_TRUE;
905 case AL_CONE_OUTER_GAIN:
906 *values = Source->OuterGain;
907 return AL_TRUE;
909 case AL_SEC_OFFSET:
910 case AL_SAMPLE_OFFSET:
911 case AL_BYTE_OFFSET:
912 LockContext(Context);
913 updateLen = (ALdouble)Context->Device->UpdateSize /
914 Context->Device->Frequency;
915 GetSourceOffsets(Source, prop, offsets, updateLen);
916 UnlockContext(Context);
917 *values = offsets[0];
918 return AL_TRUE;
920 case AL_CONE_OUTER_GAINHF:
921 *values = Source->OuterGainHF;
922 return AL_TRUE;
924 case AL_AIR_ABSORPTION_FACTOR:
925 *values = Source->AirAbsorptionFactor;
926 return AL_TRUE;
928 case AL_ROOM_ROLLOFF_FACTOR:
929 *values = Source->RoomRolloffFactor;
930 return AL_TRUE;
932 case AL_DOPPLER_FACTOR:
933 *values = Source->DopplerFactor;
934 return AL_TRUE;
936 case AL_SAMPLE_RW_OFFSETS_SOFT:
937 case AL_BYTE_RW_OFFSETS_SOFT:
938 LockContext(Context);
939 updateLen = (ALdouble)Context->Device->UpdateSize /
940 Context->Device->Frequency;
941 GetSourceOffsets(Source, prop, values, updateLen);
942 UnlockContext(Context);
943 return AL_TRUE;
945 case AL_SEC_OFFSET_LATENCY_SOFT:
946 LockContext(Context);
947 values[0] = GetSourceSecOffset(Source);
948 values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) /
949 1000000000.0;
950 UnlockContext(Context);
951 return AL_TRUE;
953 case AL_POSITION:
954 LockContext(Context);
955 values[0] = Source->Position[0];
956 values[1] = Source->Position[1];
957 values[2] = Source->Position[2];
958 UnlockContext(Context);
959 return AL_TRUE;
961 case AL_VELOCITY:
962 LockContext(Context);
963 values[0] = Source->Velocity[0];
964 values[1] = Source->Velocity[1];
965 values[2] = Source->Velocity[2];
966 UnlockContext(Context);
967 return AL_TRUE;
969 case AL_DIRECTION:
970 LockContext(Context);
971 values[0] = Source->Orientation[0];
972 values[1] = Source->Orientation[1];
973 values[2] = Source->Orientation[2];
974 UnlockContext(Context);
975 return AL_TRUE;
977 case AL_SOURCE_RELATIVE:
978 case AL_LOOPING:
979 case AL_BUFFER:
980 case AL_SOURCE_STATE:
981 case AL_BUFFERS_QUEUED:
982 case AL_BUFFERS_PROCESSED:
983 case AL_SOURCE_TYPE:
984 case AL_DIRECT_FILTER_GAINHF_AUTO:
985 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
986 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
987 case AL_DIRECT_CHANNELS_SOFT:
988 case AL_DISTANCE_MODEL:
989 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
990 *values = (ALdouble)ivals[0];
991 return err;
994 ERR("Unexpected property: 0x%04x\n", prop);
995 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
998 static ALboolean GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values)
1000 ALbufferlistitem *BufferList;
1001 ALdouble dvals[3];
1002 ALboolean err;
1004 switch(prop)
1006 case AL_SOURCE_RELATIVE:
1007 *values = Source->HeadRelative;
1008 return AL_TRUE;
1010 case AL_LOOPING:
1011 *values = Source->Looping;
1012 return AL_TRUE;
1014 case AL_BUFFER:
1015 LockContext(Context);
1016 BufferList = Source->queue;
1017 if(Source->SourceType != AL_STATIC)
1019 ALuint i = Source->BuffersPlayed;
1020 while(i > 0)
1022 BufferList = BufferList->next;
1023 i--;
1026 *values = ((BufferList && BufferList->buffer) ?
1027 BufferList->buffer->id : 0);
1028 UnlockContext(Context);
1029 return AL_TRUE;
1031 case AL_SOURCE_STATE:
1032 *values = Source->state;
1033 return AL_TRUE;
1035 case AL_BUFFERS_QUEUED:
1036 *values = Source->BuffersInQueue;
1037 return AL_TRUE;
1039 case AL_BUFFERS_PROCESSED:
1040 LockContext(Context);
1041 if(Source->Looping || Source->SourceType != AL_STREAMING)
1043 /* Buffers on a looping source are in a perpetual state of
1044 * PENDING, so don't report any as PROCESSED */
1045 *values = 0;
1047 else
1048 *values = Source->BuffersPlayed;
1049 UnlockContext(Context);
1050 return AL_TRUE;
1052 case AL_SOURCE_TYPE:
1053 *values = Source->SourceType;
1054 return AL_TRUE;
1056 case AL_DIRECT_FILTER_GAINHF_AUTO:
1057 *values = Source->DryGainHFAuto;
1058 return AL_TRUE;
1060 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1061 *values = Source->WetGainAuto;
1062 return AL_TRUE;
1064 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1065 *values = Source->WetGainHFAuto;
1066 return AL_TRUE;
1068 case AL_DIRECT_CHANNELS_SOFT:
1069 *values = Source->DirectChannels;
1070 return AL_TRUE;
1072 case AL_DISTANCE_MODEL:
1073 *values = Source->DistanceModel;
1074 return AL_TRUE;
1076 case AL_MAX_DISTANCE:
1077 case AL_ROLLOFF_FACTOR:
1078 case AL_REFERENCE_DISTANCE:
1079 case AL_CONE_INNER_ANGLE:
1080 case AL_CONE_OUTER_ANGLE:
1081 case AL_SEC_OFFSET:
1082 case AL_SAMPLE_OFFSET:
1083 case AL_BYTE_OFFSET:
1084 case AL_DOPPLER_FACTOR:
1085 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1086 *values = (ALint)dvals[0];
1087 return err;
1089 case AL_SAMPLE_RW_OFFSETS_SOFT:
1090 case AL_BYTE_RW_OFFSETS_SOFT:
1091 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1093 values[0] = (ALint)dvals[0];
1094 values[1] = (ALint)dvals[1];
1096 return err;
1098 case AL_POSITION:
1099 case AL_VELOCITY:
1100 case AL_DIRECTION:
1101 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1103 values[0] = (ALint)dvals[0];
1104 values[1] = (ALint)dvals[1];
1105 values[2] = (ALint)dvals[2];
1107 return err;
1109 case siSampleOffsetLatencySOFT:
1110 /* i64 only */
1111 break;
1113 case siDirectFilter:
1114 case siAuxSendFilter:
1115 /* ??? */
1116 break;
1119 ERR("Unexpected property: 0x%04x\n", prop);
1120 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1123 static ALboolean GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values)
1125 ALdouble dvals[3];
1126 ALint ivals[3];
1127 ALboolean err;
1129 switch(prop)
1131 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1132 LockContext(Context);
1133 values[0] = GetSourceOffset(Source);
1134 values[1] = ALCdevice_GetLatency(Context->Device);
1135 UnlockContext(Context);
1136 return AL_TRUE;
1138 case AL_MAX_DISTANCE:
1139 case AL_ROLLOFF_FACTOR:
1140 case AL_REFERENCE_DISTANCE:
1141 case AL_CONE_INNER_ANGLE:
1142 case AL_CONE_OUTER_ANGLE:
1143 case AL_SEC_OFFSET:
1144 case AL_SAMPLE_OFFSET:
1145 case AL_BYTE_OFFSET:
1146 case AL_DOPPLER_FACTOR:
1147 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1148 *values = (ALint64)dvals[0];
1149 return err;
1151 case AL_SAMPLE_RW_OFFSETS_SOFT:
1152 case AL_BYTE_RW_OFFSETS_SOFT:
1153 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1155 values[0] = (ALint64)dvals[0];
1156 values[1] = (ALint64)dvals[1];
1158 return err;
1160 case AL_POSITION:
1161 case AL_VELOCITY:
1162 case AL_DIRECTION:
1163 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
1165 values[0] = (ALint64)dvals[0];
1166 values[1] = (ALint64)dvals[1];
1167 values[2] = (ALint64)dvals[2];
1169 return err;
1171 case AL_SOURCE_RELATIVE:
1172 case AL_LOOPING:
1173 case AL_SOURCE_STATE:
1174 case AL_BUFFERS_QUEUED:
1175 case AL_BUFFERS_PROCESSED:
1176 case AL_SOURCE_TYPE:
1177 case AL_DIRECT_FILTER_GAINHF_AUTO:
1178 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1179 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1180 case AL_DIRECT_CHANNELS_SOFT:
1181 case AL_DISTANCE_MODEL:
1182 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1183 *values = ivals[0];
1184 return err;
1186 case siBuffer:
1187 case siDirectFilter:
1188 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1189 *values = ((ALuint*)ivals)[0];
1190 return err;
1192 case siAuxSendFilter:
1193 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1195 values[0] = ((ALuint*)ivals)[0];
1196 values[1] = ((ALuint*)ivals)[1];
1197 values[2] = ((ALuint*)ivals)[2];
1199 return err;
1202 ERR("Unexpected property: 0x%04x\n", prop);
1203 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1207 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1209 ALCcontext *context;
1210 ALsizei cur = 0;
1211 ALenum err;
1213 context = GetContextRef();
1214 if(!context) return;
1216 if(!(n >= 0))
1217 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1218 for(cur = 0;cur < n;cur++)
1220 ALsource *source = al_calloc(16, sizeof(ALsource));
1221 if(!source)
1223 alDeleteSources(cur, sources);
1224 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1226 InitSourceParams(source);
1228 err = NewThunkEntry(&source->id);
1229 if(err == AL_NO_ERROR)
1230 err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1231 if(err != AL_NO_ERROR)
1233 FreeThunkEntry(source->id);
1234 memset(source, 0, sizeof(ALsource));
1235 al_free(source);
1237 alDeleteSources(cur, sources);
1238 SET_ERROR_AND_GOTO(context, err, done);
1241 sources[cur] = source->id;
1244 done:
1245 ALCcontext_DecRef(context);
1249 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1251 ALCcontext *context;
1252 ALbufferlistitem *BufferList;
1253 ALsource *Source;
1254 ALsizei i, j;
1256 context = GetContextRef();
1257 if(!context) return;
1259 if(!(n >= 0))
1260 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1262 /* Check that all Sources are valid */
1263 for(i = 0;i < n;i++)
1265 if(LookupSource(context, sources[i]) == NULL)
1266 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1268 for(i = 0;i < n;i++)
1270 ALactivesource **srclist, **srclistend;
1272 if((Source=RemoveSource(context, sources[i])) == NULL)
1273 continue;
1274 FreeThunkEntry(Source->id);
1276 LockContext(context);
1277 srclist = context->ActiveSources;
1278 srclistend = srclist + context->ActiveSourceCount;
1279 while(srclist != srclistend)
1281 if((*srclist)->Source == Source)
1283 ALactivesource *temp = *(--srclistend);
1284 *srclistend = *srclist;
1285 *srclist = temp;
1286 --(context->ActiveSourceCount);
1287 break;
1289 srclist++;
1291 UnlockContext(context);
1293 while(Source->queue != NULL)
1295 BufferList = Source->queue;
1296 Source->queue = BufferList->next;
1298 if(BufferList->buffer != NULL)
1299 DecrementRef(&BufferList->buffer->ref);
1300 free(BufferList);
1303 for(j = 0;j < MAX_SENDS;++j)
1305 if(Source->Send[j].Slot)
1306 DecrementRef(&Source->Send[j].Slot->ref);
1307 Source->Send[j].Slot = NULL;
1310 memset(Source, 0, sizeof(*Source));
1311 al_free(Source);
1314 done:
1315 ALCcontext_DecRef(context);
1319 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1321 ALCcontext *context;
1322 ALboolean ret;
1324 context = GetContextRef();
1325 if(!context) return AL_FALSE;
1327 ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1329 ALCcontext_DecRef(context);
1331 return ret;
1335 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1337 ALCcontext *Context;
1338 ALsource *Source;
1340 Context = GetContextRef();
1341 if(!Context) return;
1343 if((Source=LookupSource(Context, source)) == NULL)
1344 alSetError(Context, AL_INVALID_NAME);
1345 else if(!(FloatValsByProp(param) == 1))
1346 alSetError(Context, AL_INVALID_ENUM);
1347 else
1348 SetSourcefv(Source, Context, param, &value);
1350 ALCcontext_DecRef(Context);
1353 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1355 ALCcontext *Context;
1356 ALsource *Source;
1358 Context = GetContextRef();
1359 if(!Context) return;
1361 if((Source=LookupSource(Context, source)) == NULL)
1362 alSetError(Context, AL_INVALID_NAME);
1363 else if(!(FloatValsByProp(param) == 3))
1364 alSetError(Context, AL_INVALID_ENUM);
1365 else
1367 ALfloat fvals[3] = { value1, value2, value3 };
1368 SetSourcefv(Source, Context, param, fvals);
1371 ALCcontext_DecRef(Context);
1374 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1376 ALCcontext *Context;
1377 ALsource *Source;
1379 Context = GetContextRef();
1380 if(!Context) return;
1382 if((Source=LookupSource(Context, source)) == NULL)
1383 alSetError(Context, AL_INVALID_NAME);
1384 else if(!values)
1385 alSetError(Context, AL_INVALID_VALUE);
1386 else if(!(FloatValsByProp(param) > 0))
1387 alSetError(Context, AL_INVALID_ENUM);
1388 else
1389 SetSourcefv(Source, Context, param, values);
1391 ALCcontext_DecRef(Context);
1395 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1397 ALCcontext *Context;
1398 ALsource *Source;
1400 Context = GetContextRef();
1401 if(!Context) return;
1403 if((Source=LookupSource(Context, source)) == NULL)
1404 alSetError(Context, AL_INVALID_NAME);
1405 else if(!(DoubleValsByProp(param) == 1))
1406 alSetError(Context, AL_INVALID_ENUM);
1407 else
1409 ALfloat fval = (ALfloat)value;
1410 SetSourcefv(Source, Context, param, &fval);
1413 ALCcontext_DecRef(Context);
1416 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1418 ALCcontext *Context;
1419 ALsource *Source;
1421 Context = GetContextRef();
1422 if(!Context) return;
1424 if((Source=LookupSource(Context, source)) == NULL)
1425 alSetError(Context, AL_INVALID_NAME);
1426 else if(!(DoubleValsByProp(param) == 3))
1427 alSetError(Context, AL_INVALID_ENUM);
1428 else
1430 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1431 SetSourcefv(Source, Context, param, fvals);
1434 ALCcontext_DecRef(Context);
1437 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1439 ALCcontext *Context;
1440 ALsource *Source;
1441 ALint count;
1443 Context = GetContextRef();
1444 if(!Context) return;
1446 if((Source=LookupSource(Context, source)) == NULL)
1447 alSetError(Context, AL_INVALID_NAME);
1448 else if(!values)
1449 alSetError(Context, AL_INVALID_VALUE);
1450 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 3))
1451 alSetError(Context, AL_INVALID_ENUM);
1452 else
1454 ALfloat fvals[3];
1455 ALint i;
1457 for(i = 0;i < count;i++)
1458 fvals[i] = (ALfloat)values[i];
1459 SetSourcefv(Source, Context, param, fvals);
1462 ALCcontext_DecRef(Context);
1466 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1468 ALCcontext *Context;
1469 ALsource *Source;
1471 Context = GetContextRef();
1472 if(!Context) return;
1474 if((Source=LookupSource(Context, source)) == NULL)
1475 alSetError(Context, AL_INVALID_NAME);
1476 else if(!(IntValsByProp(param) == 1))
1477 alSetError(Context, AL_INVALID_ENUM);
1478 else
1479 SetSourceiv(Source, Context, param, &value);
1481 ALCcontext_DecRef(Context);
1484 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1486 ALCcontext *Context;
1487 ALsource *Source;
1489 Context = GetContextRef();
1490 if(!Context) return;
1492 if((Source=LookupSource(Context, source)) == NULL)
1493 alSetError(Context, AL_INVALID_NAME);
1494 else if(!(IntValsByProp(param) == 3))
1495 alSetError(Context, AL_INVALID_ENUM);
1496 else
1498 ALint ivals[3] = { value1, value2, value3 };
1499 SetSourceiv(Source, Context, param, ivals);
1502 ALCcontext_DecRef(Context);
1505 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1507 ALCcontext *Context;
1508 ALsource *Source;
1510 Context = GetContextRef();
1511 if(!Context) return;
1513 if((Source=LookupSource(Context, source)) == NULL)
1514 alSetError(Context, AL_INVALID_NAME);
1515 else if(!values)
1516 alSetError(Context, AL_INVALID_VALUE);
1517 else if(!(IntValsByProp(param) > 0))
1518 alSetError(Context, AL_INVALID_ENUM);
1519 else
1520 SetSourceiv(Source, Context, param, values);
1522 ALCcontext_DecRef(Context);
1526 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1528 ALCcontext *Context;
1529 ALsource *Source;
1531 Context = GetContextRef();
1532 if(!Context) return;
1534 if((Source=LookupSource(Context, source)) == NULL)
1535 alSetError(Context, AL_INVALID_NAME);
1536 else if(!(Int64ValsByProp(param) == 1))
1537 alSetError(Context, AL_INVALID_ENUM);
1538 else
1539 SetSourcei64v(Source, Context, param, &value);
1541 ALCcontext_DecRef(Context);
1544 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1546 ALCcontext *Context;
1547 ALsource *Source;
1549 Context = GetContextRef();
1550 if(!Context) return;
1552 if((Source=LookupSource(Context, source)) == NULL)
1553 alSetError(Context, AL_INVALID_NAME);
1554 else if(!(Int64ValsByProp(param) == 3))
1555 alSetError(Context, AL_INVALID_ENUM);
1556 else
1558 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1559 SetSourcei64v(Source, Context, param, i64vals);
1562 ALCcontext_DecRef(Context);
1565 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1567 ALCcontext *Context;
1568 ALsource *Source;
1570 Context = GetContextRef();
1571 if(!Context) return;
1573 if((Source=LookupSource(Context, source)) == NULL)
1574 alSetError(Context, AL_INVALID_NAME);
1575 else if(!values)
1576 alSetError(Context, AL_INVALID_VALUE);
1577 else if(!(Int64ValsByProp(param) > 0))
1578 alSetError(Context, AL_INVALID_ENUM);
1579 else
1580 SetSourcei64v(Source, Context, param, values);
1582 ALCcontext_DecRef(Context);
1586 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1588 ALCcontext *Context;
1589 ALsource *Source;
1591 Context = GetContextRef();
1592 if(!Context) return;
1594 if((Source=LookupSource(Context, source)) == NULL)
1595 alSetError(Context, AL_INVALID_NAME);
1596 else if(!value)
1597 alSetError(Context, AL_INVALID_VALUE);
1598 else if(!(FloatValsByProp(param) == 1))
1599 alSetError(Context, AL_INVALID_ENUM);
1600 else
1602 ALdouble dval;
1603 if(GetSourcedv(Source, Context, param, &dval))
1604 *value = (ALfloat)dval;
1607 ALCcontext_DecRef(Context);
1611 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1613 ALCcontext *Context;
1614 ALsource *Source;
1616 Context = GetContextRef();
1617 if(!Context) return;
1619 if((Source=LookupSource(Context, source)) == NULL)
1620 alSetError(Context, AL_INVALID_NAME);
1621 else if(!(value1 && value2 && value3))
1622 alSetError(Context, AL_INVALID_VALUE);
1623 else if(!(FloatValsByProp(param) == 3))
1624 alSetError(Context, AL_INVALID_ENUM);
1625 else
1627 ALdouble dvals[3];
1628 if(GetSourcedv(Source, Context, param, dvals))
1630 *value1 = (ALfloat)dvals[0];
1631 *value2 = (ALfloat)dvals[1];
1632 *value3 = (ALfloat)dvals[2];
1636 ALCcontext_DecRef(Context);
1640 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *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=FloatValsByProp(param)) > 0 && count <= 3))
1654 alSetError(Context, AL_INVALID_ENUM);
1655 else
1657 ALdouble dvals[3];
1658 if(GetSourcedv(Source, Context, param, dvals))
1660 ALint i;
1661 for(i = 0;i < count;i++)
1662 values[i] = (ALfloat)dvals[i];
1666 ALCcontext_DecRef(Context);
1670 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1672 ALCcontext *Context;
1673 ALsource *Source;
1675 Context = GetContextRef();
1676 if(!Context) return;
1678 if((Source=LookupSource(Context, source)) == NULL)
1679 alSetError(Context, AL_INVALID_NAME);
1680 else if(!value)
1681 alSetError(Context, AL_INVALID_VALUE);
1682 else if(!(DoubleValsByProp(param) == 1))
1683 alSetError(Context, AL_INVALID_ENUM);
1684 else
1685 GetSourcedv(Source, Context, param, value);
1687 ALCcontext_DecRef(Context);
1690 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1692 ALCcontext *Context;
1693 ALsource *Source;
1695 Context = GetContextRef();
1696 if(!Context) return;
1698 if((Source=LookupSource(Context, source)) == NULL)
1699 alSetError(Context, AL_INVALID_NAME);
1700 else if(!(value1 && value2 && value3))
1701 alSetError(Context, AL_INVALID_VALUE);
1702 else if(!(DoubleValsByProp(param) == 3))
1703 alSetError(Context, AL_INVALID_ENUM);
1704 else
1706 ALdouble dvals[3];
1707 if(GetSourcedv(Source, Context, param, dvals))
1709 *value1 = dvals[0];
1710 *value2 = dvals[1];
1711 *value3 = dvals[2];
1715 ALCcontext_DecRef(Context);
1718 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1720 ALCcontext *Context;
1721 ALsource *Source;
1723 Context = GetContextRef();
1724 if(!Context) return;
1726 if((Source=LookupSource(Context, source)) == NULL)
1727 alSetError(Context, AL_INVALID_NAME);
1728 else if(!values)
1729 alSetError(Context, AL_INVALID_VALUE);
1730 else if(!(DoubleValsByProp(param) > 0))
1731 alSetError(Context, AL_INVALID_ENUM);
1732 else
1733 GetSourcedv(Source, Context, param, values);
1735 ALCcontext_DecRef(Context);
1739 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1741 ALCcontext *Context;
1742 ALsource *Source;
1744 Context = GetContextRef();
1745 if(!Context) return;
1747 if((Source=LookupSource(Context, source)) == NULL)
1748 alSetError(Context, AL_INVALID_NAME);
1749 else if(!value)
1750 alSetError(Context, AL_INVALID_VALUE);
1751 else if(!(IntValsByProp(param) == 1))
1752 alSetError(Context, AL_INVALID_ENUM);
1753 else
1754 GetSourceiv(Source, Context, param, value);
1756 ALCcontext_DecRef(Context);
1760 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
1762 ALCcontext *Context;
1763 ALsource *Source;
1765 Context = GetContextRef();
1766 if(!Context) return;
1768 if((Source=LookupSource(Context, source)) == NULL)
1769 alSetError(Context, AL_INVALID_NAME);
1770 else if(!(value1 && value2 && value3))
1771 alSetError(Context, AL_INVALID_VALUE);
1772 else if(!(IntValsByProp(param) == 3))
1773 alSetError(Context, AL_INVALID_ENUM);
1774 else
1776 ALint ivals[3];
1777 if(GetSourceiv(Source, Context, param, ivals))
1779 *value1 = ivals[0];
1780 *value2 = ivals[1];
1781 *value3 = ivals[2];
1785 ALCcontext_DecRef(Context);
1789 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
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(!values)
1800 alSetError(Context, AL_INVALID_VALUE);
1801 else if(!(IntValsByProp(param) > 0))
1802 alSetError(Context, AL_INVALID_ENUM);
1803 else
1804 GetSourceiv(Source, Context, param, values);
1806 ALCcontext_DecRef(Context);
1810 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
1812 ALCcontext *Context;
1813 ALsource *Source;
1815 Context = GetContextRef();
1816 if(!Context) return;
1818 if((Source=LookupSource(Context, source)) == NULL)
1819 alSetError(Context, AL_INVALID_NAME);
1820 else if(!value)
1821 alSetError(Context, AL_INVALID_VALUE);
1822 else if(!(Int64ValsByProp(param) == 1))
1823 alSetError(Context, AL_INVALID_ENUM);
1824 else
1825 GetSourcei64v(Source, Context, param, value);
1827 ALCcontext_DecRef(Context);
1830 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
1832 ALCcontext *Context;
1833 ALsource *Source;
1835 Context = GetContextRef();
1836 if(!Context) return;
1838 if((Source=LookupSource(Context, source)) == NULL)
1839 alSetError(Context, AL_INVALID_NAME);
1840 else if(!(value1 && value2 && value3))
1841 alSetError(Context, AL_INVALID_VALUE);
1842 else if(!(Int64ValsByProp(param) == 3))
1843 alSetError(Context, AL_INVALID_ENUM);
1844 else
1846 ALint64 i64vals[3];
1847 if(GetSourcei64v(Source, Context, param, i64vals))
1849 *value1 = i64vals[0];
1850 *value2 = i64vals[1];
1851 *value3 = i64vals[2];
1855 ALCcontext_DecRef(Context);
1858 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
1860 ALCcontext *Context;
1861 ALsource *Source;
1863 Context = GetContextRef();
1864 if(!Context) return;
1866 if((Source=LookupSource(Context, source)) == NULL)
1867 alSetError(Context, AL_INVALID_NAME);
1868 else if(!values)
1869 alSetError(Context, AL_INVALID_VALUE);
1870 else if(!(Int64ValsByProp(param) > 0))
1871 alSetError(Context, AL_INVALID_ENUM);
1872 else
1873 GetSourcei64v(Source, Context, param, values);
1875 ALCcontext_DecRef(Context);
1879 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1881 alSourcePlayv(1, &source);
1883 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1885 ALCcontext *context;
1886 ALsource *source;
1887 ALsizei i;
1889 context = GetContextRef();
1890 if(!context) return;
1892 if(!(n >= 0))
1893 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1894 for(i = 0;i < n;i++)
1896 if(!LookupSource(context, sources[i]))
1897 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1900 LockContext(context);
1901 while(n > context->MaxActiveSources-context->ActiveSourceCount)
1903 ALactivesource **temp = NULL;
1904 ALsizei newcount;
1906 newcount = context->MaxActiveSources << 1;
1907 if(newcount > 0)
1908 temp = realloc(context->ActiveSources,
1909 newcount * sizeof(context->ActiveSources[0]));
1910 if(!temp)
1912 UnlockContext(context);
1913 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1915 for(i = context->MaxActiveSources;i < newcount;i++)
1916 temp[i] = NULL;
1918 context->ActiveSources = temp;
1919 context->MaxActiveSources = newcount;
1922 for(i = 0;i < n;i++)
1924 source = LookupSource(context, sources[i]);
1925 if(context->DeferUpdates) source->new_state = AL_PLAYING;
1926 else SetSourceState(source, context, AL_PLAYING);
1928 UnlockContext(context);
1930 done:
1931 ALCcontext_DecRef(context);
1934 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1936 alSourcePausev(1, &source);
1938 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1940 ALCcontext *context;
1941 ALsource *source;
1942 ALsizei i;
1944 context = GetContextRef();
1945 if(!context) return;
1947 if(!(n >= 0))
1948 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1949 for(i = 0;i < n;i++)
1951 if(!LookupSource(context, sources[i]))
1952 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1955 LockContext(context);
1956 for(i = 0;i < n;i++)
1958 source = LookupSource(context, sources[i]);
1959 if(context->DeferUpdates) source->new_state = AL_PAUSED;
1960 else SetSourceState(source, context, AL_PAUSED);
1962 UnlockContext(context);
1964 done:
1965 ALCcontext_DecRef(context);
1968 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1970 alSourceStopv(1, &source);
1972 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1974 ALCcontext *context;
1975 ALsource *source;
1976 ALsizei i;
1978 context = GetContextRef();
1979 if(!context) return;
1981 if(!(n >= 0))
1982 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1983 for(i = 0;i < n;i++)
1985 if(!LookupSource(context, sources[i]))
1986 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1989 LockContext(context);
1990 for(i = 0;i < n;i++)
1992 source = LookupSource(context, sources[i]);
1993 source->new_state = AL_NONE;
1994 SetSourceState(source, context, AL_STOPPED);
1996 UnlockContext(context);
1998 done:
1999 ALCcontext_DecRef(context);
2002 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2004 alSourceRewindv(1, &source);
2006 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2008 ALCcontext *context;
2009 ALsource *source;
2010 ALsizei i;
2012 context = GetContextRef();
2013 if(!context) return;
2015 if(!(n >= 0))
2016 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2017 for(i = 0;i < n;i++)
2019 if(!LookupSource(context, sources[i]))
2020 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2023 LockContext(context);
2024 for(i = 0;i < n;i++)
2026 source = LookupSource(context, sources[i]);
2027 source->new_state = AL_NONE;
2028 SetSourceState(source, context, AL_INITIAL);
2030 UnlockContext(context);
2032 done:
2033 ALCcontext_DecRef(context);
2037 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2039 ALCdevice *device;
2040 ALCcontext *context;
2041 ALsource *source;
2042 ALsizei i;
2043 ALbufferlistitem *BufferListStart = NULL;
2044 ALbufferlistitem *BufferList;
2045 ALbuffer *BufferFmt = NULL;
2047 if(nb == 0)
2048 return;
2050 context = GetContextRef();
2051 if(!context) return;
2053 device = context->Device;
2055 if(!(nb >= 0))
2056 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2057 if((source=LookupSource(context, src)) == NULL)
2058 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2060 LockContext(context);
2061 if(source->SourceType == AL_STATIC)
2063 UnlockContext(context);
2064 /* Can't queue on a Static Source */
2065 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2068 /* Check for a valid Buffer, for its frequency and format */
2069 BufferList = source->queue;
2070 while(BufferList)
2072 if(BufferList->buffer)
2074 BufferFmt = BufferList->buffer;
2075 break;
2077 BufferList = BufferList->next;
2080 for(i = 0;i < nb;i++)
2082 ALbuffer *buffer = NULL;
2083 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2085 UnlockContext(context);
2086 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2089 if(!BufferListStart)
2091 BufferListStart = malloc(sizeof(ALbufferlistitem));
2092 BufferListStart->buffer = buffer;
2093 BufferListStart->next = NULL;
2094 BufferListStart->prev = NULL;
2095 BufferList = BufferListStart;
2097 else
2099 BufferList->next = malloc(sizeof(ALbufferlistitem));
2100 BufferList->next->buffer = buffer;
2101 BufferList->next->next = NULL;
2102 BufferList->next->prev = BufferList;
2103 BufferList = BufferList->next;
2105 if(!buffer) continue;
2106 IncrementRef(&buffer->ref);
2108 ReadLock(&buffer->lock);
2109 if(BufferFmt == NULL)
2111 BufferFmt = buffer;
2113 source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2114 source->SampleSize = BytesFromFmt(buffer->FmtType);
2116 else if(BufferFmt->Frequency != buffer->Frequency ||
2117 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2118 BufferFmt->OriginalType != buffer->OriginalType)
2120 ReadUnlock(&buffer->lock);
2121 UnlockContext(context);
2122 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2124 ReadUnlock(&buffer->lock);
2127 /* Source is now streaming */
2128 source->SourceType = AL_STREAMING;
2130 if(source->queue == NULL)
2131 source->queue = BufferListStart;
2132 else
2134 /* Append to the end of the queue */
2135 BufferList = source->queue;
2136 while(BufferList->next != NULL)
2137 BufferList = BufferList->next;
2139 BufferListStart->prev = BufferList;
2140 BufferList->next = BufferListStart;
2142 BufferListStart = NULL;
2144 source->BuffersInQueue += nb;
2146 UnlockContext(context);
2148 done:
2149 while(BufferListStart)
2151 BufferList = BufferListStart;
2152 BufferListStart = BufferList->next;
2154 if(BufferList->buffer)
2155 DecrementRef(&BufferList->buffer->ref);
2156 free(BufferList);
2159 ALCcontext_DecRef(context);
2162 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2164 ALCcontext *context;
2165 ALsource *source;
2166 ALsizei i;
2167 ALbufferlistitem *BufferList;
2169 if(nb == 0)
2170 return;
2172 context = GetContextRef();
2173 if(!context) return;
2175 if(!(nb >= 0))
2176 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2178 if((source=LookupSource(context, src)) == NULL)
2179 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2181 LockContext(context);
2182 if(source->Looping || source->SourceType != AL_STREAMING ||
2183 (ALuint)nb > source->BuffersPlayed)
2185 UnlockContext(context);
2186 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2187 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2190 for(i = 0;i < nb;i++)
2192 BufferList = source->queue;
2193 source->queue = BufferList->next;
2194 source->BuffersInQueue--;
2195 source->BuffersPlayed--;
2197 if(BufferList->buffer)
2199 buffers[i] = BufferList->buffer->id;
2200 DecrementRef(&BufferList->buffer->ref);
2202 else
2203 buffers[i] = 0;
2205 free(BufferList);
2207 if(source->queue)
2208 source->queue->prev = NULL;
2209 UnlockContext(context);
2211 done:
2212 ALCcontext_DecRef(context);
2216 static ALvoid InitSourceParams(ALsource *Source)
2218 ALuint i;
2220 Source->InnerAngle = 360.0f;
2221 Source->OuterAngle = 360.0f;
2222 Source->Pitch = 1.0f;
2223 Source->Position[0] = 0.0f;
2224 Source->Position[1] = 0.0f;
2225 Source->Position[2] = 0.0f;
2226 Source->Orientation[0] = 0.0f;
2227 Source->Orientation[1] = 0.0f;
2228 Source->Orientation[2] = 0.0f;
2229 Source->Velocity[0] = 0.0f;
2230 Source->Velocity[1] = 0.0f;
2231 Source->Velocity[2] = 0.0f;
2232 Source->RefDistance = 1.0f;
2233 Source->MaxDistance = FLT_MAX;
2234 Source->RollOffFactor = 1.0f;
2235 Source->Looping = AL_FALSE;
2236 Source->Gain = 1.0f;
2237 Source->MinGain = 0.0f;
2238 Source->MaxGain = 1.0f;
2239 Source->OuterGain = 0.0f;
2240 Source->OuterGainHF = 1.0f;
2242 Source->DryGainHFAuto = AL_TRUE;
2243 Source->WetGainAuto = AL_TRUE;
2244 Source->WetGainHFAuto = AL_TRUE;
2245 Source->AirAbsorptionFactor = 0.0f;
2246 Source->RoomRolloffFactor = 0.0f;
2247 Source->DopplerFactor = 1.0f;
2248 Source->DirectChannels = AL_FALSE;
2250 Source->DistanceModel = DefaultDistanceModel;
2252 Source->Resampler = DefaultResampler;
2254 Source->state = AL_INITIAL;
2255 Source->new_state = AL_NONE;
2256 Source->SourceType = AL_UNDETERMINED;
2257 Source->Offset = -1.0;
2259 Source->DirectGain = 1.0f;
2260 Source->DirectGainHF = 1.0f;
2261 for(i = 0;i < MAX_SENDS;i++)
2263 Source->Send[i].Gain = 1.0f;
2264 Source->Send[i].GainHF = 1.0f;
2267 Source->NeedsUpdate = AL_TRUE;
2271 /* SetSourceState
2273 * Sets the source's new play state given its current state.
2275 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2277 if(state == AL_PLAYING)
2279 ALCdevice *device = Context->Device;
2280 ALbufferlistitem *BufferList;
2281 ALactivesource *src = NULL;
2282 ALsizei j, k;
2284 /* Check that there is a queue containing at least one valid, non zero
2285 * length Buffer. */
2286 BufferList = Source->queue;
2287 while(BufferList)
2289 if(BufferList->buffer != NULL && BufferList->buffer->SampleLen)
2290 break;
2291 BufferList = BufferList->next;
2294 if(Source->state != AL_PAUSED)
2296 Source->state = AL_PLAYING;
2297 Source->position = 0;
2298 Source->position_fraction = 0;
2299 Source->BuffersPlayed = 0;
2301 else
2302 Source->state = AL_PLAYING;
2304 // Check if an Offset has been set
2305 if(Source->Offset >= 0.0)
2306 ApplyOffset(Source);
2308 /* If there's nothing to play, or device is disconnected, go right to
2309 * stopped */
2310 if(!BufferList || !device->Connected)
2312 SetSourceState(Source, Context, AL_STOPPED);
2313 return;
2316 for(j = 0;j < Context->ActiveSourceCount;j++)
2318 if(Context->ActiveSources[j]->Source == Source)
2320 src = Context->ActiveSources[j];
2321 break;
2324 if(src == NULL)
2326 src = Context->ActiveSources[Context->ActiveSourceCount];
2327 if(src == NULL)
2329 src = al_malloc(16, sizeof(src[0]));
2330 Context->ActiveSources[Context->ActiveSourceCount] = src;
2332 memset(src, 0, sizeof(*src));
2334 src->Source = Source;
2335 if(BufferList->buffer->FmtChannels == FmtMono)
2336 src->Update = CalcSourceParams;
2337 else
2338 src->Update = CalcNonAttnSourceParams;
2339 Context->ActiveSourceCount++;
2341 else
2343 ALuint i;
2345 src->Direct.Moving = AL_FALSE;
2346 src->Direct.Counter = 0;
2347 for(j = 0;j < MAX_INPUT_CHANNELS;j++)
2349 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
2350 src->Direct.Mix.Hrtf.State[j].History[k] = 0.0f;
2351 for(k = 0;k < HRIR_LENGTH;k++)
2353 src->Direct.Mix.Hrtf.State[j].Values[k][0] = 0.0f;
2354 src->Direct.Mix.Hrtf.State[j].Values[k][1] = 0.0f;
2357 for(i = 0;i < device->NumAuxSends;i++)
2359 src->Send[i].Counter = 0;
2360 src->Send[i].Moving = AL_FALSE;
2363 Source->NeedsUpdate = AL_TRUE;
2365 else if(state == AL_PAUSED)
2367 if(Source->state == AL_PLAYING)
2368 Source->state = AL_PAUSED;
2370 else if(state == AL_STOPPED)
2372 if(Source->state != AL_INITIAL)
2374 Source->state = AL_STOPPED;
2375 Source->BuffersPlayed = Source->BuffersInQueue;
2377 Source->Offset = -1.0;
2379 else if(state == AL_INITIAL)
2381 if(Source->state != AL_INITIAL)
2383 Source->state = AL_INITIAL;
2384 Source->position = 0;
2385 Source->position_fraction = 0;
2386 Source->BuffersPlayed = 0;
2388 Source->Offset = -1.0;
2392 /* GetSourceOffset
2394 * Gets the current read offset for the given Source, in 32.32 fixed-point
2395 * samples. The offset is relative to the start of the queue (not the start of
2396 * the current buffer).
2398 static ALint64 GetSourceOffset(const ALsource *Source)
2400 const ALbufferlistitem *BufferList;
2401 ALuint64 readPos;
2402 ALuint i;
2404 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2405 return 0;
2407 /* NOTE: This is the offset into the *current* buffer, so add the length of
2408 * any played buffers */
2409 readPos = (ALuint64)Source->position << 32;
2410 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2411 BufferList = Source->queue;
2412 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2414 if(BufferList->buffer)
2415 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2416 BufferList = BufferList->next;
2419 return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
2422 /* GetSourceSecOffset
2424 * Gets the current read offset for the given Source, in seconds. The offset is
2425 * relative to the start of the queue (not the start of the current buffer).
2427 static ALdouble GetSourceSecOffset(const ALsource *Source)
2429 const ALbufferlistitem *BufferList;
2430 const ALbuffer *Buffer = NULL;
2431 ALuint64 readPos;
2432 ALuint i;
2434 BufferList = Source->queue;
2435 while(BufferList)
2437 if(BufferList->buffer)
2439 Buffer = BufferList->buffer;
2440 break;
2442 BufferList = BufferList->next;
2445 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2446 return 0.0;
2448 /* NOTE: This is the offset into the *current* buffer, so add the length of
2449 * any played buffers */
2450 readPos = (ALuint64)Source->position << FRACTIONBITS;
2451 readPos |= (ALuint64)Source->position_fraction;
2452 BufferList = Source->queue;
2453 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2455 if(BufferList->buffer)
2456 readPos += (ALuint64)BufferList->buffer->SampleLen << FRACTIONBITS;
2457 BufferList = BufferList->next;
2460 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2463 /* GetSourceOffsets
2465 * Gets the current read and write offsets for the given Source, in the
2466 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2467 * the start of the queue (not the start of the current buffer).
2469 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2471 const ALbufferlistitem *BufferList;
2472 const ALbuffer *Buffer = NULL;
2473 ALuint readPos, writePos;
2474 ALuint totalBufferLen;
2475 ALuint i;
2477 // Find the first valid Buffer in the Queue
2478 BufferList = Source->queue;
2479 while(BufferList)
2481 if(BufferList->buffer)
2483 Buffer = BufferList->buffer;
2484 break;
2486 BufferList = BufferList->next;
2489 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2491 offset[0] = 0.0;
2492 offset[1] = 0.0;
2493 return;
2496 if(updateLen > 0.0 && updateLen < 0.015)
2497 updateLen = 0.015;
2499 /* NOTE: This is the offset into the *current* buffer, so add the length of
2500 * any played buffers */
2501 readPos = Source->position;
2502 totalBufferLen = 0;
2503 BufferList = Source->queue;
2504 for(i = 0;BufferList;i++)
2506 if(BufferList->buffer)
2508 if(i < Source->BuffersPlayed)
2509 readPos += BufferList->buffer->SampleLen;
2510 totalBufferLen += BufferList->buffer->SampleLen;
2512 BufferList = BufferList->next;
2514 if(Source->state == AL_PLAYING)
2515 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
2516 else
2517 writePos = readPos;
2519 if(Source->Looping)
2521 readPos %= totalBufferLen;
2522 writePos %= totalBufferLen;
2524 else
2526 /* Wrap positions back to 0 */
2527 if(readPos >= totalBufferLen)
2528 readPos = 0;
2529 if(writePos >= totalBufferLen)
2530 writePos = 0;
2533 switch(name)
2535 case AL_SEC_OFFSET:
2536 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2537 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2538 break;
2540 case AL_SAMPLE_OFFSET:
2541 case AL_SAMPLE_RW_OFFSETS_SOFT:
2542 offset[0] = (ALdouble)readPos;
2543 offset[1] = (ALdouble)writePos;
2544 break;
2546 case AL_BYTE_OFFSET:
2547 case AL_BYTE_RW_OFFSETS_SOFT:
2548 if(Buffer->OriginalType == UserFmtIMA4)
2550 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2551 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2552 ALuint FrameBlockSize = Buffer->OriginalAlign;
2554 /* Round down to nearest ADPCM block */
2555 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2556 if(Source->state != AL_PLAYING)
2557 offset[1] = offset[0];
2558 else
2560 /* Round up to nearest ADPCM block */
2561 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2562 FrameBlockSize * BlockSize);
2565 else if(Buffer->OriginalType == UserFmtMSADPCM)
2567 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2568 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2569 ALuint FrameBlockSize = Buffer->OriginalAlign;
2571 /* Round down to nearest ADPCM block */
2572 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2573 if(Source->state != AL_PLAYING)
2574 offset[1] = offset[0];
2575 else
2577 /* Round up to nearest ADPCM block */
2578 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2579 FrameBlockSize * BlockSize);
2582 else
2584 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2585 offset[0] = (ALdouble)(readPos * FrameSize);
2586 offset[1] = (ALdouble)(writePos * FrameSize);
2588 break;
2593 /* ApplyOffset
2595 * Apply the stored playback offset to the Source. This function will update
2596 * the number of buffers "played" given the stored offset.
2598 ALboolean ApplyOffset(ALsource *Source)
2600 const ALbufferlistitem *BufferList;
2601 const ALbuffer *Buffer;
2602 ALint bufferLen, totalBufferLen;
2603 ALint buffersPlayed;
2604 ALint offset;
2606 /* Get sample frame offset */
2607 offset = GetSampleOffset(Source);
2608 if(offset == -1)
2609 return AL_FALSE;
2611 buffersPlayed = 0;
2612 totalBufferLen = 0;
2614 BufferList = Source->queue;
2615 while(BufferList)
2617 Buffer = BufferList->buffer;
2618 bufferLen = Buffer ? Buffer->SampleLen : 0;
2620 if(bufferLen <= offset-totalBufferLen)
2622 /* Offset is past this buffer so increment to the next buffer */
2623 buffersPlayed++;
2625 else if(totalBufferLen <= offset)
2627 /* Offset is in this buffer */
2628 Source->BuffersPlayed = buffersPlayed;
2630 Source->position = offset - totalBufferLen;
2631 Source->position_fraction = 0;
2632 return AL_TRUE;
2635 totalBufferLen += bufferLen;
2637 BufferList = BufferList->next;
2640 /* Offset is out of range of the queue */
2641 return AL_FALSE;
2645 /* GetSampleOffset
2647 * Returns the sample offset into the Source's queue (from the Sample, Byte or
2648 * Second offset supplied by the application). This takes into account the fact
2649 * that the buffer format may have been modifed since.
2651 static ALint GetSampleOffset(ALsource *Source)
2653 const ALbuffer *Buffer = NULL;
2654 const ALbufferlistitem *BufferList;
2655 ALint Offset = -1;
2657 /* Find the first valid Buffer in the Queue */
2658 BufferList = Source->queue;
2659 while(BufferList)
2661 if(BufferList->buffer)
2663 Buffer = BufferList->buffer;
2664 break;
2666 BufferList = BufferList->next;
2669 if(!Buffer)
2671 Source->Offset = -1.0;
2672 return -1;
2675 switch(Source->OffsetType)
2677 case AL_BYTE_OFFSET:
2678 /* Determine the ByteOffset (and ensure it is block aligned) */
2679 Offset = (ALint)Source->Offset;
2680 if(Buffer->OriginalType == UserFmtIMA4)
2682 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2683 Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2684 Offset *= Buffer->OriginalAlign;
2686 else if(Buffer->OriginalType == UserFmtMSADPCM)
2688 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2689 Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
2690 Offset *= Buffer->OriginalAlign;
2692 else
2693 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2694 break;
2696 case AL_SAMPLE_OFFSET:
2697 Offset = (ALint)Source->Offset;
2698 break;
2700 case AL_SEC_OFFSET:
2701 Offset = (ALint)(Source->Offset * Buffer->Frequency);
2702 break;
2704 Source->Offset = -1.0;
2706 return Offset;
2710 /* ReleaseALSources
2712 * Destroys all sources in the source map.
2714 ALvoid ReleaseALSources(ALCcontext *Context)
2716 ALsizei pos;
2717 ALuint j;
2718 for(pos = 0;pos < Context->SourceMap.size;pos++)
2720 ALsource *temp = Context->SourceMap.array[pos].value;
2721 Context->SourceMap.array[pos].value = NULL;
2723 while(temp->queue != NULL)
2725 ALbufferlistitem *BufferList = temp->queue;
2726 temp->queue = BufferList->next;
2728 if(BufferList->buffer != NULL)
2729 DecrementRef(&BufferList->buffer->ref);
2730 free(BufferList);
2733 for(j = 0;j < MAX_SENDS;++j)
2735 if(temp->Send[j].Slot)
2736 DecrementRef(&temp->Send[j].Slot->ref);
2737 temp->Send[j].Slot = NULL;
2740 FreeThunkEntry(temp->id);
2741 memset(temp, 0, sizeof(*temp));
2742 al_free(temp);