Use a helper to count the number of int(64) values for a property
[openal-soft.git] / OpenAL32 / alSource.c
blob2079f1926bd9d6fcd50f598b237b2c1ca17e24f7
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 static ALvoid InitSourceParams(ALsource *Source);
51 static ALint64 GetSourceOffset(const ALsource *Source);
52 static ALdouble GetSourceSecOffset(const ALsource *Source);
53 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
54 static ALint GetSampleOffset(ALsource *Source);
56 typedef enum SrcFloatProp {
57 sfPitch = AL_PITCH,
58 sfGain = AL_GAIN,
59 sfMinGain = AL_MIN_GAIN,
60 sfMaxGain = AL_MAX_GAIN,
61 sfMaxDistance = AL_MAX_DISTANCE,
62 sfRolloffFactor = AL_ROLLOFF_FACTOR,
63 sfDopplerFactor = AL_DOPPLER_FACTOR,
64 sfConeOuterGain = AL_CONE_OUTER_GAIN,
65 sfSecOffset = AL_SEC_OFFSET,
66 sfSampleOffset = AL_SAMPLE_OFFSET,
67 sfByteOffset = AL_BYTE_OFFSET,
68 sfConeInnerAngle = AL_CONE_INNER_ANGLE,
69 sfConeOuterAngle = AL_CONE_OUTER_ANGLE,
70 sfRefDistance = AL_REFERENCE_DISTANCE,
72 sfPosition = AL_POSITION,
73 sfVelocity = AL_VELOCITY,
74 sfDirection = AL_DIRECTION,
76 sfSourceRelative = AL_SOURCE_RELATIVE,
77 sfLooping = AL_LOOPING,
78 sfBuffer = AL_BUFFER,
79 sfSourceState = AL_SOURCE_STATE,
80 sfBuffersQueued = AL_BUFFERS_QUEUED,
81 sfBuffersProcessed = AL_BUFFERS_PROCESSED,
82 sfSourceType = AL_SOURCE_TYPE,
84 /* ALC_EXT_EFX */
85 sfConeOuterGainHF = AL_CONE_OUTER_GAINHF,
86 sfAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
87 sfRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
88 sfDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
89 sfAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
90 sfAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
92 /* AL_SOFT_direct_channels */
93 sfDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
95 /* AL_EXT_source_distance_model */
96 sfDistanceModel = AL_DISTANCE_MODEL,
98 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
99 sfSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
100 sfByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
102 /* AL_SOFT_source_latency */
103 sfSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
104 } SrcFloatProp;
106 typedef enum SrcIntProp {
107 siMaxDistance = AL_MAX_DISTANCE,
108 siRolloffFactor = AL_ROLLOFF_FACTOR,
109 siRefDistance = AL_REFERENCE_DISTANCE,
110 siSourceRelative = AL_SOURCE_RELATIVE,
111 siConeInnerAngle = AL_CONE_INNER_ANGLE,
112 siConeOuterAngle = AL_CONE_OUTER_ANGLE,
113 siLooping = AL_LOOPING,
114 siBuffer = AL_BUFFER,
115 siSourceState = AL_SOURCE_STATE,
116 siBuffersQueued = AL_BUFFERS_QUEUED,
117 siBuffersProcessed = AL_BUFFERS_PROCESSED,
118 siSourceType = AL_SOURCE_TYPE,
119 siSecOffset = AL_SEC_OFFSET,
120 siSampleOffset = AL_SAMPLE_OFFSET,
121 siByteOffset = AL_BYTE_OFFSET,
122 siDopplerFactor = AL_DOPPLER_FACTOR,
123 siPosition = AL_POSITION,
124 siVelocity = AL_VELOCITY,
125 siDirection = AL_DIRECTION,
127 /* ALC_EXT_EFX */
128 siDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
129 siAuxSendFilterGainAutio = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
130 siAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
131 siDirectFilter = AL_DIRECT_FILTER,
132 siAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
134 /* AL_SOFT_direct_channels */
135 siDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
137 /* AL_EXT_source_distance_model */
138 siDistanceModel = AL_DISTANCE_MODEL,
140 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
141 siSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
142 siByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
144 /* AL_SOFT_source_latency */
145 siSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
146 } SrcIntProp;
148 static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values);
149 static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values);
150 static ALenum SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values);
152 static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values);
153 static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values);
154 static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values);
157 static ALint IntValsByProp(ALenum prop)
159 if(prop != (ALenum)((SrcIntProp)prop))
160 return 0;
161 switch((SrcIntProp)prop)
163 case siMaxDistance:
164 case siRolloffFactor:
165 case siRefDistance:
166 case siSourceRelative:
167 case siConeInnerAngle:
168 case siConeOuterAngle:
169 case siLooping:
170 case siBuffer:
171 case siSourceState:
172 case siBuffersQueued:
173 case siBuffersProcessed:
174 case siSourceType:
175 case siSecOffset:
176 case siSampleOffset:
177 case siByteOffset:
178 case siDopplerFactor:
179 case siDirectFilterGainHFAuto:
180 case siAuxSendFilterGainAutio:
181 case siAuxSendFilterGainHFAuto:
182 case siDirectFilter:
183 case siDirectChannelsSOFT:
184 case siDistanceModel:
185 return 1;
187 case siSampleRWOffsetsSOFT:
188 case siByteRWOffsetsSOFT:
189 return 2;
191 case siPosition:
192 case siVelocity:
193 case siDirection:
194 case siAuxSendFilter:
195 return 3;
197 case siSampleOffsetLatencySOFT:
198 break; /* i64 only */
200 return 0;
202 static ALint Int64ValsByProp(ALenum prop)
204 if(prop != (ALenum)((SrcIntProp)prop))
205 return 0;
206 switch((SrcIntProp)prop)
208 case siMaxDistance:
209 case siRolloffFactor:
210 case siRefDistance:
211 case siSourceRelative:
212 case siConeInnerAngle:
213 case siConeOuterAngle:
214 case siLooping:
215 case siBuffer:
216 case siSourceState:
217 case siBuffersQueued:
218 case siBuffersProcessed:
219 case siSourceType:
220 case siSecOffset:
221 case siSampleOffset:
222 case siByteOffset:
223 case siDopplerFactor:
224 case siDirectFilterGainHFAuto:
225 case siAuxSendFilterGainAutio:
226 case siAuxSendFilterGainHFAuto:
227 case siDirectFilter:
228 case siDirectChannelsSOFT:
229 case siDistanceModel:
230 return 1;
232 case siSampleRWOffsetsSOFT:
233 case siByteRWOffsetsSOFT:
234 case siSampleOffsetLatencySOFT:
235 return 2;
237 case siPosition:
238 case siVelocity:
239 case siDirection:
240 case siAuxSendFilter:
241 return 3;
243 return 0;
247 #define RETERR(x) do { \
248 alSetError(Context, (x)); \
249 return (x); \
250 } while(0)
252 #define CHECKVAL(x) do { \
253 if(!(x)) \
254 RETERR(AL_INVALID_VALUE); \
255 } while(0)
257 static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values)
259 ALint ival;
261 switch(prop)
263 case AL_PITCH:
264 CHECKVAL(*values >= 0.0f);
266 Source->Pitch = *values;
267 Source->NeedsUpdate = AL_TRUE;
268 return AL_NO_ERROR;
270 case AL_CONE_INNER_ANGLE:
271 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
273 Source->InnerAngle = *values;
274 Source->NeedsUpdate = AL_TRUE;
275 return AL_NO_ERROR;
277 case AL_CONE_OUTER_ANGLE:
278 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
280 Source->OuterAngle = *values;
281 Source->NeedsUpdate = AL_TRUE;
282 return AL_NO_ERROR;
284 case AL_GAIN:
285 CHECKVAL(*values >= 0.0f);
287 Source->Gain = *values;
288 Source->NeedsUpdate = AL_TRUE;
289 return AL_NO_ERROR;
291 case AL_MAX_DISTANCE:
292 CHECKVAL(*values >= 0.0f);
294 Source->MaxDistance = *values;
295 Source->NeedsUpdate = AL_TRUE;
296 return AL_NO_ERROR;
298 case AL_ROLLOFF_FACTOR:
299 CHECKVAL(*values >= 0.0f);
301 Source->RollOffFactor = *values;
302 Source->NeedsUpdate = AL_TRUE;
303 return AL_NO_ERROR;
305 case AL_REFERENCE_DISTANCE:
306 CHECKVAL(*values >= 0.0f);
308 Source->RefDistance = *values;
309 Source->NeedsUpdate = AL_TRUE;
310 return AL_NO_ERROR;
312 case AL_MIN_GAIN:
313 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
315 Source->MinGain = *values;
316 Source->NeedsUpdate = AL_TRUE;
317 return AL_NO_ERROR;
319 case AL_MAX_GAIN:
320 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
322 Source->MaxGain = *values;
323 Source->NeedsUpdate = AL_TRUE;
324 return AL_NO_ERROR;
326 case AL_CONE_OUTER_GAIN:
327 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
329 Source->OuterGain = *values;
330 Source->NeedsUpdate = AL_TRUE;
331 return AL_NO_ERROR;
333 case AL_CONE_OUTER_GAINHF:
334 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
336 Source->OuterGainHF = *values;
337 Source->NeedsUpdate = AL_TRUE;
338 return AL_NO_ERROR;
340 case AL_AIR_ABSORPTION_FACTOR:
341 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
343 Source->AirAbsorptionFactor = *values;
344 Source->NeedsUpdate = AL_TRUE;
345 return AL_NO_ERROR;
347 case AL_ROOM_ROLLOFF_FACTOR:
348 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
350 Source->RoomRolloffFactor = *values;
351 Source->NeedsUpdate = AL_TRUE;
352 return AL_NO_ERROR;
354 case AL_DOPPLER_FACTOR:
355 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
357 Source->DopplerFactor = *values;
358 Source->NeedsUpdate = AL_TRUE;
359 return AL_NO_ERROR;
361 case AL_SEC_OFFSET:
362 case AL_SAMPLE_OFFSET:
363 case AL_BYTE_OFFSET:
364 CHECKVAL(*values >= 0.0f);
366 LockContext(Context);
367 Source->OffsetType = prop;
368 Source->Offset = *values;
370 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
371 !Context->DeferUpdates)
373 if(ApplyOffset(Source) == AL_FALSE)
375 UnlockContext(Context);
376 RETERR(AL_INVALID_VALUE);
379 UnlockContext(Context);
380 return AL_NO_ERROR;
383 case AL_SEC_OFFSET_LATENCY_SOFT:
384 /* Query only */
385 RETERR(AL_INVALID_OPERATION);
388 case AL_POSITION:
389 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
391 LockContext(Context);
392 Source->Position[0] = values[0];
393 Source->Position[1] = values[1];
394 Source->Position[2] = values[2];
395 UnlockContext(Context);
396 Source->NeedsUpdate = AL_TRUE;
397 return AL_NO_ERROR;
399 case AL_VELOCITY:
400 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
402 LockContext(Context);
403 Source->Velocity[0] = values[0];
404 Source->Velocity[1] = values[1];
405 Source->Velocity[2] = values[2];
406 UnlockContext(Context);
407 Source->NeedsUpdate = AL_TRUE;
408 return AL_NO_ERROR;
410 case AL_DIRECTION:
411 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
413 LockContext(Context);
414 Source->Orientation[0] = values[0];
415 Source->Orientation[1] = values[1];
416 Source->Orientation[2] = values[2];
417 UnlockContext(Context);
418 Source->NeedsUpdate = AL_TRUE;
419 return AL_NO_ERROR;
422 case sfSampleRWOffsetsSOFT:
423 case sfByteRWOffsetsSOFT:
424 RETERR(AL_INVALID_OPERATION);
427 case sfSourceRelative:
428 case sfLooping:
429 case sfSourceState:
430 case sfSourceType:
431 case sfDistanceModel:
432 case sfDirectFilterGainHFAuto:
433 case sfAuxSendFilterGainAuto:
434 case sfAuxSendFilterGainHFAuto:
435 case sfDirectChannelsSOFT:
436 ival = (ALint)values[0];
437 return SetSourceiv(Source, Context, prop, &ival);
439 case sfBuffer:
440 case sfBuffersQueued:
441 case sfBuffersProcessed:
442 ival = (ALint)((ALuint)values[0]);
443 return SetSourceiv(Source, Context, prop, &ival);
446 ERR("Unexpected property: 0x%04x\n", prop);
447 RETERR(AL_INVALID_ENUM);
450 static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values)
452 ALCdevice *device = Context->Device;
453 ALbuffer *buffer = NULL;
454 ALfilter *filter = NULL;
455 ALeffectslot *slot = NULL;
456 ALbufferlistitem *oldlist;
457 ALfloat fvals[3];
459 switch(prop)
461 case AL_SOURCE_RELATIVE:
462 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
464 Source->HeadRelative = (ALboolean)*values;
465 Source->NeedsUpdate = AL_TRUE;
466 return AL_NO_ERROR;
468 case AL_LOOPING:
469 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
471 Source->Looping = (ALboolean)*values;
472 return AL_NO_ERROR;
474 case AL_BUFFER:
475 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
477 LockContext(Context);
478 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
480 UnlockContext(Context);
481 RETERR(AL_INVALID_OPERATION);
484 Source->BuffersInQueue = 0;
485 Source->BuffersPlayed = 0;
487 if(buffer != NULL)
489 ALbufferlistitem *BufferListItem;
491 /* Source is now Static */
492 Source->SourceType = AL_STATIC;
494 /* Add the selected buffer to a one-item queue */
495 BufferListItem = malloc(sizeof(ALbufferlistitem));
496 BufferListItem->buffer = buffer;
497 BufferListItem->next = NULL;
498 BufferListItem->prev = NULL;
499 IncrementRef(&buffer->ref);
501 oldlist = ExchangePtr((XchgPtr*)&Source->queue, BufferListItem);
502 Source->BuffersInQueue = 1;
504 ReadLock(&buffer->lock);
505 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
506 Source->SampleSize = BytesFromFmt(buffer->FmtType);
507 ReadUnlock(&buffer->lock);
508 if(buffer->FmtChannels == FmtMono)
509 Source->Update = CalcSourceParams;
510 else
511 Source->Update = CalcNonAttnSourceParams;
512 Source->NeedsUpdate = AL_TRUE;
514 else
516 /* Source is now Undetermined */
517 Source->SourceType = AL_UNDETERMINED;
518 oldlist = ExchangePtr((XchgPtr*)&Source->queue, NULL);
521 /* Delete all elements in the previous queue */
522 while(oldlist != NULL)
524 ALbufferlistitem *temp = oldlist;
525 oldlist = temp->next;
527 if(temp->buffer)
528 DecrementRef(&temp->buffer->ref);
529 free(temp);
531 UnlockContext(Context);
532 return AL_NO_ERROR;
534 case siSourceState:
535 case siSourceType:
536 case siBuffersQueued:
537 case siBuffersProcessed:
538 /* Query only */
539 RETERR(AL_INVALID_OPERATION);
541 case AL_SEC_OFFSET:
542 case AL_SAMPLE_OFFSET:
543 case AL_BYTE_OFFSET:
544 CHECKVAL(*values >= 0);
546 LockContext(Context);
547 Source->OffsetType = prop;
548 Source->Offset = *values;
550 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
551 !Context->DeferUpdates)
553 if(ApplyOffset(Source) == AL_FALSE)
555 UnlockContext(Context);
556 RETERR(AL_INVALID_VALUE);
559 UnlockContext(Context);
560 return AL_NO_ERROR;
563 case siSampleRWOffsetsSOFT:
564 case siByteRWOffsetsSOFT:
565 case siSampleOffsetLatencySOFT:
566 /* Query only */
567 RETERR(AL_INVALID_OPERATION);
570 case AL_DIRECT_FILTER:
571 CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
573 LockContext(Context);
574 if(!filter)
576 Source->DirectGain = 1.0f;
577 Source->DirectGainHF = 1.0f;
579 else
581 Source->DirectGain = filter->Gain;
582 Source->DirectGainHF = filter->GainHF;
584 UnlockContext(Context);
585 Source->NeedsUpdate = AL_TRUE;
586 return AL_NO_ERROR;
588 case AL_DIRECT_FILTER_GAINHF_AUTO:
589 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
591 Source->DryGainHFAuto = *values;
592 Source->NeedsUpdate = AL_TRUE;
593 return AL_NO_ERROR;
595 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
596 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
598 Source->WetGainAuto = *values;
599 Source->NeedsUpdate = AL_TRUE;
600 return AL_NO_ERROR;
602 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
603 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
605 Source->WetGainHFAuto = *values;
606 Source->NeedsUpdate = AL_TRUE;
607 return AL_NO_ERROR;
609 case AL_DIRECT_CHANNELS_SOFT:
610 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
612 Source->DirectChannels = *values;
613 Source->NeedsUpdate = AL_TRUE;
614 return AL_NO_ERROR;
616 case AL_DISTANCE_MODEL:
617 CHECKVAL(*values == AL_NONE ||
618 *values == AL_INVERSE_DISTANCE ||
619 *values == AL_INVERSE_DISTANCE_CLAMPED ||
620 *values == AL_LINEAR_DISTANCE ||
621 *values == AL_LINEAR_DISTANCE_CLAMPED ||
622 *values == AL_EXPONENT_DISTANCE ||
623 *values == AL_EXPONENT_DISTANCE_CLAMPED);
625 Source->DistanceModel = *values;
626 if(Context->SourceDistanceModel)
627 Source->NeedsUpdate = AL_TRUE;
628 return AL_NO_ERROR;
631 case AL_AUXILIARY_SEND_FILTER:
632 LockContext(Context);
633 if(!((ALuint)values[1] < device->NumAuxSends &&
634 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
635 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
637 UnlockContext(Context);
638 RETERR(AL_INVALID_VALUE);
641 /* Add refcount on the new slot, and release the previous slot */
642 if(slot) IncrementRef(&slot->ref);
643 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
644 if(slot) DecrementRef(&slot->ref);
646 if(!filter)
648 /* Disable filter */
649 Source->Send[values[1]].Gain = 1.0f;
650 Source->Send[values[1]].GainHF = 1.0f;
652 else
654 Source->Send[values[1]].Gain = filter->Gain;
655 Source->Send[values[1]].GainHF = filter->GainHF;
657 Source->NeedsUpdate = AL_TRUE;
658 UnlockContext(Context);
659 return AL_NO_ERROR;
662 case AL_MAX_DISTANCE:
663 case AL_ROLLOFF_FACTOR:
664 case AL_CONE_INNER_ANGLE:
665 case AL_CONE_OUTER_ANGLE:
666 case AL_REFERENCE_DISTANCE:
667 case siDopplerFactor:
668 fvals[0] = (ALfloat)*values;
669 return SetSourcefv(Source, Context, (int)prop, fvals);
671 case AL_POSITION:
672 case AL_VELOCITY:
673 case AL_DIRECTION:
674 fvals[0] = (ALfloat)values[0];
675 fvals[1] = (ALfloat)values[1];
676 fvals[2] = (ALfloat)values[2];
677 return SetSourcefv(Source, Context, (int)prop, fvals);
680 ERR("Unexpected property: 0x%04x\n", prop);
681 RETERR(AL_INVALID_ENUM);
684 static ALenum SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values)
686 ALfloat fvals[3];
687 ALint ivals[3];
689 switch(prop)
691 case siSampleRWOffsetsSOFT:
692 case siByteRWOffsetsSOFT:
693 case siSampleOffsetLatencySOFT:
694 /* Query only */
695 RETERR(AL_INVALID_OPERATION);
698 /* 1x int */
699 case AL_SOURCE_RELATIVE:
700 case AL_LOOPING:
701 case AL_SOURCE_STATE:
702 case AL_BYTE_OFFSET:
703 case AL_SAMPLE_OFFSET:
704 case siSourceType:
705 case siBuffersQueued:
706 case siBuffersProcessed:
707 case AL_DIRECT_FILTER_GAINHF_AUTO:
708 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
709 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
710 case AL_DIRECT_CHANNELS_SOFT:
711 case AL_DISTANCE_MODEL:
712 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
714 ivals[0] = (ALint)*values;
715 return SetSourceiv(Source, Context, (int)prop, ivals);
717 /* 1x uint */
718 case AL_BUFFER:
719 case AL_DIRECT_FILTER:
720 CHECKVAL(*values <= UINT_MAX && *values >= 0);
722 ivals[0] = (ALuint)*values;
723 return SetSourceiv(Source, Context, (int)prop, ivals);
725 /* 3x uint */
726 case AL_AUXILIARY_SEND_FILTER:
727 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
728 values[1] <= UINT_MAX && values[1] >= 0 &&
729 values[2] <= UINT_MAX && values[2] >= 0);
731 ivals[0] = (ALuint)values[0];
732 ivals[1] = (ALuint)values[1];
733 ivals[2] = (ALuint)values[2];
734 return SetSourceiv(Source, Context, (int)prop, ivals);
736 /* 1x float */
737 case AL_MAX_DISTANCE:
738 case AL_ROLLOFF_FACTOR:
739 case AL_CONE_INNER_ANGLE:
740 case AL_CONE_OUTER_ANGLE:
741 case AL_REFERENCE_DISTANCE:
742 case AL_SEC_OFFSET:
743 case siDopplerFactor:
744 fvals[0] = (ALfloat)*values;
745 return SetSourcefv(Source, Context, (int)prop, fvals);
747 /* 3x float */
748 case AL_POSITION:
749 case AL_VELOCITY:
750 case AL_DIRECTION:
751 fvals[0] = (ALfloat)values[0];
752 fvals[1] = (ALfloat)values[1];
753 fvals[2] = (ALfloat)values[2];
754 return SetSourcefv(Source, Context, (int)prop, fvals);
757 ERR("Unexpected property: 0x%04x\n", prop);
758 RETERR(AL_INVALID_ENUM);
761 #undef CHECKVAL
764 static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values)
766 ALdouble offsets[2];
767 ALdouble updateLen;
768 ALint ivals[3];
769 ALenum err;
771 switch(prop)
773 case AL_GAIN:
774 *values = Source->Gain;
775 return AL_NO_ERROR;
777 case AL_PITCH:
778 *values = Source->Pitch;
779 return AL_NO_ERROR;
781 case AL_MAX_DISTANCE:
782 *values = Source->MaxDistance;
783 return AL_NO_ERROR;
785 case AL_ROLLOFF_FACTOR:
786 *values = Source->RollOffFactor;
787 return AL_NO_ERROR;
789 case AL_REFERENCE_DISTANCE:
790 *values = Source->RefDistance;
791 return AL_NO_ERROR;
793 case AL_CONE_INNER_ANGLE:
794 *values = Source->InnerAngle;
795 return AL_NO_ERROR;
797 case AL_CONE_OUTER_ANGLE:
798 *values = Source->OuterAngle;
799 return AL_NO_ERROR;
801 case AL_MIN_GAIN:
802 *values = Source->MinGain;
803 return AL_NO_ERROR;
805 case AL_MAX_GAIN:
806 *values = Source->MaxGain;
807 return AL_NO_ERROR;
809 case AL_CONE_OUTER_GAIN:
810 *values = Source->OuterGain;
811 return AL_NO_ERROR;
813 case AL_SEC_OFFSET:
814 case AL_SAMPLE_OFFSET:
815 case AL_BYTE_OFFSET:
816 LockContext(Context);
817 updateLen = (ALdouble)Context->Device->UpdateSize /
818 Context->Device->Frequency;
819 GetSourceOffsets(Source, prop, offsets, updateLen);
820 UnlockContext(Context);
821 *values = offsets[0];
822 return AL_NO_ERROR;
824 case AL_CONE_OUTER_GAINHF:
825 *values = Source->OuterGainHF;
826 return AL_NO_ERROR;
828 case AL_AIR_ABSORPTION_FACTOR:
829 *values = Source->AirAbsorptionFactor;
830 return AL_NO_ERROR;
832 case AL_ROOM_ROLLOFF_FACTOR:
833 *values = Source->RoomRolloffFactor;
834 return AL_NO_ERROR;
836 case AL_DOPPLER_FACTOR:
837 *values = Source->DopplerFactor;
838 return AL_NO_ERROR;
840 case AL_SAMPLE_RW_OFFSETS_SOFT:
841 case AL_BYTE_RW_OFFSETS_SOFT:
842 LockContext(Context);
843 updateLen = (ALdouble)Context->Device->UpdateSize /
844 Context->Device->Frequency;
845 GetSourceOffsets(Source, prop, values, updateLen);
846 UnlockContext(Context);
847 return AL_NO_ERROR;
849 case AL_SEC_OFFSET_LATENCY_SOFT:
850 LockContext(Context);
851 values[0] = GetSourceSecOffset(Source);
852 values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) /
853 1000000000.0;
854 UnlockContext(Context);
855 return AL_NO_ERROR;
857 case AL_POSITION:
858 LockContext(Context);
859 values[0] = Source->Position[0];
860 values[1] = Source->Position[1];
861 values[2] = Source->Position[2];
862 UnlockContext(Context);
863 return AL_NO_ERROR;
865 case AL_VELOCITY:
866 LockContext(Context);
867 values[0] = Source->Velocity[0];
868 values[1] = Source->Velocity[1];
869 values[2] = Source->Velocity[2];
870 UnlockContext(Context);
871 return AL_NO_ERROR;
873 case AL_DIRECTION:
874 LockContext(Context);
875 values[0] = Source->Orientation[0];
876 values[1] = Source->Orientation[1];
877 values[2] = Source->Orientation[2];
878 UnlockContext(Context);
879 return AL_NO_ERROR;
881 case AL_SOURCE_RELATIVE:
882 case AL_LOOPING:
883 case AL_BUFFER:
884 case AL_SOURCE_STATE:
885 case AL_BUFFERS_QUEUED:
886 case AL_BUFFERS_PROCESSED:
887 case AL_SOURCE_TYPE:
888 case AL_DIRECT_FILTER_GAINHF_AUTO:
889 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
890 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
891 case AL_DIRECT_CHANNELS_SOFT:
892 case AL_DISTANCE_MODEL:
893 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) == AL_NO_ERROR)
894 *values = (ALdouble)ivals[0];
895 return err;
898 ERR("Unexpected property: 0x%04x\n", prop);
899 RETERR(AL_INVALID_ENUM);
902 static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values)
904 ALbufferlistitem *BufferList;
905 ALdouble dvals[3];
906 ALenum err;
908 switch(prop)
910 case AL_SOURCE_RELATIVE:
911 *values = Source->HeadRelative;
912 return AL_NO_ERROR;
914 case AL_LOOPING:
915 *values = Source->Looping;
916 return AL_NO_ERROR;
918 case AL_BUFFER:
919 LockContext(Context);
920 BufferList = Source->queue;
921 if(Source->SourceType != AL_STATIC)
923 ALuint i = Source->BuffersPlayed;
924 while(i > 0)
926 BufferList = BufferList->next;
927 i--;
930 *values = ((BufferList && BufferList->buffer) ?
931 BufferList->buffer->id : 0);
932 UnlockContext(Context);
933 return AL_NO_ERROR;
935 case AL_SOURCE_STATE:
936 *values = Source->state;
937 return AL_NO_ERROR;
939 case AL_BUFFERS_QUEUED:
940 *values = Source->BuffersInQueue;
941 return AL_NO_ERROR;
943 case AL_BUFFERS_PROCESSED:
944 LockContext(Context);
945 if(Source->Looping || Source->SourceType != AL_STREAMING)
947 /* Buffers on a looping source are in a perpetual state of
948 * PENDING, so don't report any as PROCESSED */
949 *values = 0;
951 else
952 *values = Source->BuffersPlayed;
953 UnlockContext(Context);
954 return AL_NO_ERROR;
956 case AL_SOURCE_TYPE:
957 *values = Source->SourceType;
958 return AL_NO_ERROR;
960 case AL_DIRECT_FILTER_GAINHF_AUTO:
961 *values = Source->DryGainHFAuto;
962 return AL_NO_ERROR;
964 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
965 *values = Source->WetGainAuto;
966 return AL_NO_ERROR;
968 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
969 *values = Source->WetGainHFAuto;
970 return AL_NO_ERROR;
972 case AL_DIRECT_CHANNELS_SOFT:
973 *values = Source->DirectChannels;
974 return AL_NO_ERROR;
976 case AL_DISTANCE_MODEL:
977 *values = Source->DistanceModel;
978 return AL_NO_ERROR;
980 case AL_MAX_DISTANCE:
981 case AL_ROLLOFF_FACTOR:
982 case AL_REFERENCE_DISTANCE:
983 case AL_CONE_INNER_ANGLE:
984 case AL_CONE_OUTER_ANGLE:
985 case AL_SEC_OFFSET:
986 case AL_SAMPLE_OFFSET:
987 case AL_BYTE_OFFSET:
988 case AL_DOPPLER_FACTOR:
989 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
990 *values = (ALint)dvals[0];
991 return err;
993 case AL_SAMPLE_RW_OFFSETS_SOFT:
994 case AL_BYTE_RW_OFFSETS_SOFT:
995 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
997 values[0] = (ALint)dvals[0];
998 values[1] = (ALint)dvals[1];
1000 return err;
1002 case AL_POSITION:
1003 case AL_VELOCITY:
1004 case AL_DIRECTION:
1005 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
1007 values[0] = (ALint)dvals[0];
1008 values[1] = (ALint)dvals[1];
1009 values[2] = (ALint)dvals[2];
1011 return err;
1013 case siSampleOffsetLatencySOFT:
1014 /* i64 only */
1015 break;
1017 case siDirectFilter:
1018 case siAuxSendFilter:
1019 /* ??? */
1020 break;
1023 ERR("Unexpected property: 0x%04x\n", prop);
1024 RETERR(AL_INVALID_ENUM);
1027 static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values)
1029 ALdouble dvals[3];
1030 ALint ivals[3];
1031 ALenum err;
1033 switch(prop)
1035 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1036 LockContext(Context);
1037 values[0] = GetSourceOffset(Source);
1038 values[1] = ALCdevice_GetLatency(Context->Device);
1039 UnlockContext(Context);
1040 return AL_NO_ERROR;
1042 case AL_MAX_DISTANCE:
1043 case AL_ROLLOFF_FACTOR:
1044 case AL_REFERENCE_DISTANCE:
1045 case AL_CONE_INNER_ANGLE:
1046 case AL_CONE_OUTER_ANGLE:
1047 case AL_SEC_OFFSET:
1048 case AL_SAMPLE_OFFSET:
1049 case AL_BYTE_OFFSET:
1050 case AL_DOPPLER_FACTOR:
1051 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
1052 *values = (ALint64)dvals[0];
1053 return err;
1055 case AL_SAMPLE_RW_OFFSETS_SOFT:
1056 case AL_BYTE_RW_OFFSETS_SOFT:
1057 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
1059 values[0] = (ALint64)dvals[0];
1060 values[1] = (ALint64)dvals[1];
1062 return err;
1064 case AL_POSITION:
1065 case AL_VELOCITY:
1066 case AL_DIRECTION:
1067 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
1069 values[0] = (ALint64)dvals[0];
1070 values[1] = (ALint64)dvals[1];
1071 values[2] = (ALint64)dvals[2];
1073 return err;
1075 case AL_SOURCE_RELATIVE:
1076 case AL_LOOPING:
1077 case AL_BUFFER:
1078 case AL_SOURCE_STATE:
1079 case AL_BUFFERS_QUEUED:
1080 case AL_BUFFERS_PROCESSED:
1081 case AL_SOURCE_TYPE:
1082 case AL_DIRECT_FILTER_GAINHF_AUTO:
1083 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1084 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1085 case AL_DIRECT_CHANNELS_SOFT:
1086 case AL_DISTANCE_MODEL:
1087 case siDirectFilter:
1088 case siAuxSendFilter:
1089 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) == AL_NO_ERROR)
1090 *values = ivals[0];
1091 return err;
1094 ERR("Unexpected property: 0x%04x\n", prop);
1095 RETERR(AL_INVALID_ENUM);
1098 #undef RETERR
1101 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1103 ALCcontext *Context;
1104 ALsizei cur = 0;
1106 Context = GetContextRef();
1107 if(!Context) return;
1109 al_try
1111 ALenum err;
1113 CHECK_VALUE(Context, n >= 0);
1114 for(cur = 0;cur < n;cur++)
1116 ALsource *source = al_calloc(16, sizeof(ALsource));
1117 if(!source)
1118 al_throwerr(Context, AL_OUT_OF_MEMORY);
1119 InitSourceParams(source);
1121 err = NewThunkEntry(&source->id);
1122 if(err == AL_NO_ERROR)
1123 err = InsertUIntMapEntry(&Context->SourceMap, source->id, source);
1124 if(err != AL_NO_ERROR)
1126 FreeThunkEntry(source->id);
1127 memset(source, 0, sizeof(ALsource));
1128 al_free(source);
1130 al_throwerr(Context, err);
1133 sources[cur] = source->id;
1136 al_catchany()
1138 if(cur > 0)
1139 alDeleteSources(cur, sources);
1141 al_endtry;
1143 ALCcontext_DecRef(Context);
1147 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1149 ALCcontext *Context;
1151 Context = GetContextRef();
1152 if(!Context) return;
1154 al_try
1156 ALbufferlistitem *BufferList;
1157 ALsource *Source;
1158 ALsizei i, j;
1160 CHECK_VALUE(Context, n >= 0);
1162 /* Check that all Sources are valid */
1163 for(i = 0;i < n;i++)
1165 if(LookupSource(Context, sources[i]) == NULL)
1166 al_throwerr(Context, AL_INVALID_NAME);
1169 for(i = 0;i < n;i++)
1171 ALsource **srclist, **srclistend;
1173 if((Source=RemoveSource(Context, sources[i])) == NULL)
1174 continue;
1175 FreeThunkEntry(Source->id);
1177 LockContext(Context);
1178 srclist = Context->ActiveSources;
1179 srclistend = srclist + Context->ActiveSourceCount;
1180 while(srclist != srclistend)
1182 if(*srclist == Source)
1184 Context->ActiveSourceCount--;
1185 *srclist = *(--srclistend);
1186 break;
1188 srclist++;
1190 UnlockContext(Context);
1192 while(Source->queue != NULL)
1194 BufferList = Source->queue;
1195 Source->queue = BufferList->next;
1197 if(BufferList->buffer != NULL)
1198 DecrementRef(&BufferList->buffer->ref);
1199 free(BufferList);
1202 for(j = 0;j < MAX_SENDS;++j)
1204 if(Source->Send[j].Slot)
1205 DecrementRef(&Source->Send[j].Slot->ref);
1206 Source->Send[j].Slot = NULL;
1209 memset(Source, 0, sizeof(*Source));
1210 al_free(Source);
1213 al_endtry;
1215 ALCcontext_DecRef(Context);
1219 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1221 ALCcontext *Context;
1222 ALboolean result;
1224 Context = GetContextRef();
1225 if(!Context) return AL_FALSE;
1227 result = (LookupSource(Context, source) ? AL_TRUE : AL_FALSE);
1229 ALCcontext_DecRef(Context);
1231 return result;
1235 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1237 ALCcontext *Context;
1238 ALsource *Source;
1240 Context = GetContextRef();
1241 if(!Context) return;
1243 if((Source=LookupSource(Context, source)) == NULL)
1244 alSetError(Context, AL_INVALID_NAME);
1245 else switch(param)
1247 case AL_PITCH:
1248 case AL_CONE_INNER_ANGLE:
1249 case AL_CONE_OUTER_ANGLE:
1250 case AL_GAIN:
1251 case AL_MAX_DISTANCE:
1252 case AL_ROLLOFF_FACTOR:
1253 case AL_REFERENCE_DISTANCE:
1254 case AL_MIN_GAIN:
1255 case AL_MAX_GAIN:
1256 case AL_CONE_OUTER_GAIN:
1257 case AL_CONE_OUTER_GAINHF:
1258 case AL_AIR_ABSORPTION_FACTOR:
1259 case AL_ROOM_ROLLOFF_FACTOR:
1260 case AL_DOPPLER_FACTOR:
1261 case AL_SEC_OFFSET:
1262 case AL_SAMPLE_OFFSET:
1263 case AL_BYTE_OFFSET:
1264 SetSourcefv(Source, Context, param, &value);
1265 break;
1267 default:
1268 alSetError(Context, AL_INVALID_ENUM);
1271 ALCcontext_DecRef(Context);
1274 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1276 ALCcontext *Context;
1277 ALsource *Source;
1278 ALfloat fvals[3];
1280 Context = GetContextRef();
1281 if(!Context) return;
1283 if((Source=LookupSource(Context, source)) == NULL)
1284 alSetError(Context, AL_INVALID_NAME);
1285 else switch(param)
1287 case AL_POSITION:
1288 case AL_VELOCITY:
1289 case AL_DIRECTION:
1290 fvals[0] = value1;
1291 fvals[1] = value2;
1292 fvals[2] = value3;
1293 SetSourcefv(Source, Context, param, fvals);
1294 break;
1296 default:
1297 alSetError(Context, AL_INVALID_ENUM);
1300 ALCcontext_DecRef(Context);
1303 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1305 ALCcontext *Context;
1306 ALsource *Source;
1308 Context = GetContextRef();
1309 if(!Context) return;
1311 if((Source=LookupSource(Context, source)) == NULL)
1312 alSetError(Context, AL_INVALID_NAME);
1313 else if(!values)
1314 alSetError(Context, AL_INVALID_VALUE);
1315 else switch(param)
1317 case AL_PITCH:
1318 case AL_CONE_INNER_ANGLE:
1319 case AL_CONE_OUTER_ANGLE:
1320 case AL_GAIN:
1321 case AL_MAX_DISTANCE:
1322 case AL_ROLLOFF_FACTOR:
1323 case AL_REFERENCE_DISTANCE:
1324 case AL_MIN_GAIN:
1325 case AL_MAX_GAIN:
1326 case AL_CONE_OUTER_GAIN:
1327 case AL_CONE_OUTER_GAINHF:
1328 case AL_SEC_OFFSET:
1329 case AL_SAMPLE_OFFSET:
1330 case AL_BYTE_OFFSET:
1331 case AL_AIR_ABSORPTION_FACTOR:
1332 case AL_ROOM_ROLLOFF_FACTOR:
1334 case AL_POSITION:
1335 case AL_VELOCITY:
1336 case AL_DIRECTION:
1337 SetSourcefv(Source, Context, param, values);
1338 break;
1340 default:
1341 alSetError(Context, AL_INVALID_ENUM);
1344 ALCcontext_DecRef(Context);
1348 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1350 ALCcontext *Context;
1351 ALsource *Source;
1352 ALfloat fval;
1354 Context = GetContextRef();
1355 if(!Context) return;
1357 if((Source=LookupSource(Context, source)) == NULL)
1358 alSetError(Context, AL_INVALID_NAME);
1359 else switch(param)
1361 case AL_PITCH:
1362 case AL_CONE_INNER_ANGLE:
1363 case AL_CONE_OUTER_ANGLE:
1364 case AL_GAIN:
1365 case AL_MAX_DISTANCE:
1366 case AL_ROLLOFF_FACTOR:
1367 case AL_REFERENCE_DISTANCE:
1368 case AL_MIN_GAIN:
1369 case AL_MAX_GAIN:
1370 case AL_CONE_OUTER_GAIN:
1371 case AL_CONE_OUTER_GAINHF:
1372 case AL_AIR_ABSORPTION_FACTOR:
1373 case AL_ROOM_ROLLOFF_FACTOR:
1374 case AL_DOPPLER_FACTOR:
1375 case AL_SEC_OFFSET:
1376 case AL_SAMPLE_OFFSET:
1377 case AL_BYTE_OFFSET:
1378 fval = (ALfloat)value;
1379 SetSourcefv(Source, Context, param, &fval);
1380 break;
1382 default:
1383 alSetError(Context, AL_INVALID_ENUM);
1386 ALCcontext_DecRef(Context);
1389 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1391 ALCcontext *Context;
1392 ALsource *Source;
1393 ALfloat fvals[3];
1395 Context = GetContextRef();
1396 if(!Context) return;
1398 if((Source=LookupSource(Context, source)) == NULL)
1399 alSetError(Context, AL_INVALID_NAME);
1400 else switch(param)
1402 case AL_POSITION:
1403 case AL_VELOCITY:
1404 case AL_DIRECTION:
1405 fvals[0] = (ALfloat)value1;
1406 fvals[1] = (ALfloat)value2;
1407 fvals[2] = (ALfloat)value3;
1408 SetSourcefv(Source, Context, param, fvals);
1409 break;
1411 default:
1412 alSetError(Context, AL_INVALID_ENUM);
1415 ALCcontext_DecRef(Context);
1418 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1420 ALCcontext *Context;
1421 ALsource *Source;
1422 ALfloat fvals[3];
1424 Context = GetContextRef();
1425 if(!Context) return;
1427 if((Source=LookupSource(Context, source)) == NULL)
1428 alSetError(Context, AL_INVALID_NAME);
1429 else if(!values)
1430 alSetError(Context, AL_INVALID_VALUE);
1431 else switch(param)
1433 case AL_PITCH:
1434 case AL_CONE_INNER_ANGLE:
1435 case AL_CONE_OUTER_ANGLE:
1436 case AL_GAIN:
1437 case AL_MAX_DISTANCE:
1438 case AL_ROLLOFF_FACTOR:
1439 case AL_REFERENCE_DISTANCE:
1440 case AL_MIN_GAIN:
1441 case AL_MAX_GAIN:
1442 case AL_CONE_OUTER_GAIN:
1443 case AL_CONE_OUTER_GAINHF:
1444 case AL_SEC_OFFSET:
1445 case AL_SAMPLE_OFFSET:
1446 case AL_BYTE_OFFSET:
1447 case AL_AIR_ABSORPTION_FACTOR:
1448 case AL_ROOM_ROLLOFF_FACTOR:
1449 fvals[0] = (ALfloat)values[0];
1450 SetSourcefv(Source, Context, param, fvals);
1451 break;
1453 case AL_SEC_OFFSET_LATENCY_SOFT:
1454 fvals[0] = (ALfloat)values[0];
1455 fvals[1] = (ALfloat)values[1];
1456 SetSourcefv(Source, Context, param, fvals);
1457 break;
1459 case AL_POSITION:
1460 case AL_VELOCITY:
1461 case AL_DIRECTION:
1462 fvals[0] = (ALfloat)values[0];
1463 fvals[1] = (ALfloat)values[1];
1464 fvals[2] = (ALfloat)values[2];
1465 SetSourcefv(Source, Context, param, fvals);
1466 break;
1468 default:
1469 alSetError(Context, AL_INVALID_ENUM);
1472 ALCcontext_DecRef(Context);
1476 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1478 ALCcontext *Context;
1479 ALsource *Source;
1481 Context = GetContextRef();
1482 if(!Context) return;
1484 if((Source=LookupSource(Context, source)) == NULL)
1485 alSetError(Context, AL_INVALID_NAME);
1486 else if(!(IntValsByProp(param) == 1))
1487 alSetError(Context, AL_INVALID_ENUM);
1488 else
1489 SetSourceiv(Source, Context, param, &value);
1491 ALCcontext_DecRef(Context);
1494 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1496 ALCcontext *Context;
1497 ALsource *Source;
1499 Context = GetContextRef();
1500 if(!Context) return;
1502 if((Source=LookupSource(Context, source)) == NULL)
1503 alSetError(Context, AL_INVALID_NAME);
1504 else if(!(IntValsByProp(param) == 3))
1505 alSetError(Context, AL_INVALID_ENUM);
1506 else
1508 ALint ivals[3] = { value1, value2, value3 };
1509 SetSourceiv(Source, Context, param, ivals);
1512 ALCcontext_DecRef(Context);
1515 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1517 ALCcontext *Context;
1518 ALsource *Source;
1520 Context = GetContextRef();
1521 if(!Context) return;
1523 if((Source=LookupSource(Context, source)) == NULL)
1524 alSetError(Context, AL_INVALID_NAME);
1525 else if(!values)
1526 alSetError(Context, AL_INVALID_VALUE);
1527 else if(!(IntValsByProp(param) > 0))
1528 alSetError(Context, AL_INVALID_ENUM);
1529 else
1530 SetSourceiv(Source, Context, param, values);
1532 ALCcontext_DecRef(Context);
1536 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1538 ALCcontext *Context;
1539 ALsource *Source;
1541 Context = GetContextRef();
1542 if(!Context) return;
1544 if((Source=LookupSource(Context, source)) == NULL)
1545 alSetError(Context, AL_INVALID_NAME);
1546 else if(!(Int64ValsByProp(param) == 1))
1547 alSetError(Context, AL_INVALID_ENUM);
1548 else
1549 SetSourcei64v(Source, Context, param, &value);
1551 ALCcontext_DecRef(Context);
1554 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1556 ALCcontext *Context;
1557 ALsource *Source;
1559 Context = GetContextRef();
1560 if(!Context) return;
1562 if((Source=LookupSource(Context, source)) == NULL)
1563 alSetError(Context, AL_INVALID_NAME);
1564 else if(!(Int64ValsByProp(param) == 3))
1565 alSetError(Context, AL_INVALID_ENUM);
1566 else
1568 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1569 SetSourcei64v(Source, Context, param, i64vals);
1572 ALCcontext_DecRef(Context);
1575 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1577 ALCcontext *Context;
1578 ALsource *Source;
1580 Context = GetContextRef();
1581 if(!Context) return;
1583 if((Source=LookupSource(Context, source)) == NULL)
1584 alSetError(Context, AL_INVALID_NAME);
1585 else if(!values)
1586 alSetError(Context, AL_INVALID_VALUE);
1587 else if(!(Int64ValsByProp(param) > 0))
1588 alSetError(Context, AL_INVALID_ENUM);
1589 else
1590 SetSourcei64v(Source, Context, param, values);
1592 ALCcontext_DecRef(Context);
1596 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1598 ALCcontext *Context;
1599 ALsource *Source;
1600 ALdouble dval;
1602 Context = GetContextRef();
1603 if(!Context) return;
1605 if((Source=LookupSource(Context, source)) == NULL)
1606 alSetError(Context, AL_INVALID_NAME);
1607 else if(!value)
1608 alSetError(Context, AL_INVALID_VALUE);
1609 else switch(param)
1611 case AL_PITCH:
1612 case AL_GAIN:
1613 case AL_MIN_GAIN:
1614 case AL_MAX_GAIN:
1615 case AL_MAX_DISTANCE:
1616 case AL_ROLLOFF_FACTOR:
1617 case AL_CONE_OUTER_GAIN:
1618 case AL_CONE_OUTER_GAINHF:
1619 case AL_SEC_OFFSET:
1620 case AL_SAMPLE_OFFSET:
1621 case AL_BYTE_OFFSET:
1622 case AL_CONE_INNER_ANGLE:
1623 case AL_CONE_OUTER_ANGLE:
1624 case AL_REFERENCE_DISTANCE:
1625 case AL_AIR_ABSORPTION_FACTOR:
1626 case AL_ROOM_ROLLOFF_FACTOR:
1627 case AL_DOPPLER_FACTOR:
1628 if(GetSourcedv(Source, Context, param, &dval) == AL_NO_ERROR)
1629 *value = (ALfloat)dval;
1630 break;
1632 default:
1633 alSetError(Context, AL_INVALID_ENUM);
1636 ALCcontext_DecRef(Context);
1640 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1642 ALCcontext *Context;
1643 ALsource *Source;
1644 ALdouble dvals[3];
1646 Context = GetContextRef();
1647 if(!Context) return;
1649 if((Source=LookupSource(Context, source)) == NULL)
1650 alSetError(Context, AL_INVALID_NAME);
1651 else if(!(value1 && value2 && value3))
1652 alSetError(Context, AL_INVALID_VALUE);
1653 else switch(param)
1655 case AL_POSITION:
1656 case AL_VELOCITY:
1657 case AL_DIRECTION:
1658 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1660 *value1 = (ALfloat)dvals[0];
1661 *value2 = (ALfloat)dvals[1];
1662 *value3 = (ALfloat)dvals[2];
1664 break;
1666 default:
1667 alSetError(Context, AL_INVALID_ENUM);
1670 ALCcontext_DecRef(Context);
1674 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1676 ALCcontext *Context;
1677 ALsource *Source;
1678 ALdouble dvals[2];
1680 switch(param)
1682 case AL_PITCH:
1683 case AL_GAIN:
1684 case AL_MIN_GAIN:
1685 case AL_MAX_GAIN:
1686 case AL_MAX_DISTANCE:
1687 case AL_ROLLOFF_FACTOR:
1688 case AL_DOPPLER_FACTOR:
1689 case AL_CONE_OUTER_GAIN:
1690 case AL_SEC_OFFSET:
1691 case AL_SAMPLE_OFFSET:
1692 case AL_BYTE_OFFSET:
1693 case AL_CONE_INNER_ANGLE:
1694 case AL_CONE_OUTER_ANGLE:
1695 case AL_REFERENCE_DISTANCE:
1696 case AL_CONE_OUTER_GAINHF:
1697 case AL_AIR_ABSORPTION_FACTOR:
1698 case AL_ROOM_ROLLOFF_FACTOR:
1699 alGetSourcef(source, param, values);
1700 return;
1702 case AL_POSITION:
1703 case AL_VELOCITY:
1704 case AL_DIRECTION:
1705 alGetSource3f(source, param, values+0, values+1, values+2);
1706 return;
1709 Context = GetContextRef();
1710 if(!Context) return;
1712 if((Source=LookupSource(Context, source)) == NULL)
1713 alSetError(Context, AL_INVALID_NAME);
1714 else if(!values)
1715 alSetError(Context, AL_INVALID_VALUE);
1716 else switch(param)
1718 case AL_SAMPLE_RW_OFFSETS_SOFT:
1719 case AL_BYTE_RW_OFFSETS_SOFT:
1720 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1722 values[0] = (ALfloat)dvals[0];
1723 values[1] = (ALfloat)dvals[1];
1725 break;
1727 default:
1728 alSetError(Context, AL_INVALID_ENUM);
1731 ALCcontext_DecRef(Context);
1735 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1737 ALCcontext *Context;
1738 ALsource *Source;
1740 Context = GetContextRef();
1741 if(!Context) return;
1743 if((Source=LookupSource(Context, source)) == NULL)
1744 alSetError(Context, AL_INVALID_NAME);
1745 else if(!value)
1746 alSetError(Context, AL_INVALID_VALUE);
1747 else switch(param)
1749 case AL_PITCH:
1750 case AL_GAIN:
1751 case AL_MIN_GAIN:
1752 case AL_MAX_GAIN:
1753 case AL_MAX_DISTANCE:
1754 case AL_ROLLOFF_FACTOR:
1755 case AL_CONE_OUTER_GAIN:
1756 case AL_CONE_OUTER_GAINHF:
1757 case AL_SEC_OFFSET:
1758 case AL_SAMPLE_OFFSET:
1759 case AL_BYTE_OFFSET:
1760 case AL_CONE_INNER_ANGLE:
1761 case AL_CONE_OUTER_ANGLE:
1762 case AL_REFERENCE_DISTANCE:
1763 case AL_AIR_ABSORPTION_FACTOR:
1764 case AL_ROOM_ROLLOFF_FACTOR:
1765 case AL_DOPPLER_FACTOR:
1766 GetSourcedv(Source, Context, param, value);
1767 break;
1769 default:
1770 alSetError(Context, AL_INVALID_ENUM);
1773 ALCcontext_DecRef(Context);
1776 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1778 ALCcontext *Context;
1779 ALsource *Source;
1780 ALdouble dvals[3];
1782 Context = GetContextRef();
1783 if(!Context) return;
1785 if((Source=LookupSource(Context, source)) == NULL)
1786 alSetError(Context, AL_INVALID_NAME);
1787 else if(!(value1 && value2 && value3))
1788 alSetError(Context, AL_INVALID_VALUE);
1789 else switch(param)
1791 case AL_POSITION:
1792 case AL_VELOCITY:
1793 case AL_DIRECTION:
1794 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1796 *value1 = dvals[0];
1797 *value2 = dvals[1];
1798 *value3 = dvals[2];
1800 break;
1802 default:
1803 alSetError(Context, AL_INVALID_ENUM);
1806 ALCcontext_DecRef(Context);
1809 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1811 ALCcontext *Context;
1812 ALsource *Source;
1814 Context = GetContextRef();
1815 if(!Context) return;
1817 if((Source=LookupSource(Context, source)) == NULL)
1818 alSetError(Context, AL_INVALID_NAME);
1819 else if(!values)
1820 alSetError(Context, AL_INVALID_VALUE);
1821 else switch(param)
1823 case AL_PITCH:
1824 case AL_GAIN:
1825 case AL_MIN_GAIN:
1826 case AL_MAX_GAIN:
1827 case AL_MAX_DISTANCE:
1828 case AL_ROLLOFF_FACTOR:
1829 case AL_DOPPLER_FACTOR:
1830 case AL_CONE_OUTER_GAIN:
1831 case AL_SEC_OFFSET:
1832 case AL_SAMPLE_OFFSET:
1833 case AL_BYTE_OFFSET:
1834 case AL_CONE_INNER_ANGLE:
1835 case AL_CONE_OUTER_ANGLE:
1836 case AL_REFERENCE_DISTANCE:
1837 case AL_CONE_OUTER_GAINHF:
1838 case AL_AIR_ABSORPTION_FACTOR:
1839 case AL_ROOM_ROLLOFF_FACTOR:
1841 case AL_SAMPLE_RW_OFFSETS_SOFT:
1842 case AL_BYTE_RW_OFFSETS_SOFT:
1843 case AL_SEC_OFFSET_LATENCY_SOFT:
1845 case AL_POSITION:
1846 case AL_VELOCITY:
1847 case AL_DIRECTION:
1848 GetSourcedv(Source, Context, param, values);
1849 break;
1851 default:
1852 alSetError(Context, AL_INVALID_ENUM);
1855 ALCcontext_DecRef(Context);
1859 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1861 ALCcontext *Context;
1862 ALsource *Source;
1864 Context = GetContextRef();
1865 if(!Context) return;
1867 if((Source=LookupSource(Context, source)) == NULL)
1868 alSetError(Context, AL_INVALID_NAME);
1869 else if(!value)
1870 alSetError(Context, AL_INVALID_VALUE);
1871 else if(!(IntValsByProp(param) == 1))
1872 alSetError(Context, AL_INVALID_ENUM);
1873 else
1874 GetSourceiv(Source, Context, param, value);
1876 ALCcontext_DecRef(Context);
1880 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
1882 ALCcontext *Context;
1883 ALsource *Source;
1885 Context = GetContextRef();
1886 if(!Context) return;
1888 if((Source=LookupSource(Context, source)) == NULL)
1889 alSetError(Context, AL_INVALID_NAME);
1890 else if(!(value1 && value2 && value3))
1891 alSetError(Context, AL_INVALID_VALUE);
1892 else if(!(IntValsByProp(param) == 3))
1893 alSetError(Context, AL_INVALID_ENUM);
1894 else
1896 ALint ivals[3];
1897 if(GetSourceiv(Source, Context, param, ivals) == AL_NO_ERROR)
1899 *value1 = ivals[0];
1900 *value2 = ivals[1];
1901 *value3 = ivals[2];
1905 ALCcontext_DecRef(Context);
1909 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
1911 ALCcontext *Context;
1912 ALsource *Source;
1914 Context = GetContextRef();
1915 if(!Context) return;
1917 if((Source=LookupSource(Context, source)) == NULL)
1918 alSetError(Context, AL_INVALID_NAME);
1919 else if(!values)
1920 alSetError(Context, AL_INVALID_VALUE);
1921 else if(!(IntValsByProp(param) > 0))
1922 alSetError(Context, AL_INVALID_ENUM);
1923 else
1924 GetSourceiv(Source, Context, param, values);
1926 ALCcontext_DecRef(Context);
1930 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
1932 ALCcontext *Context;
1933 ALsource *Source;
1935 Context = GetContextRef();
1936 if(!Context) return;
1938 if((Source=LookupSource(Context, source)) == NULL)
1939 alSetError(Context, AL_INVALID_NAME);
1940 else if(!value)
1941 alSetError(Context, AL_INVALID_VALUE);
1942 else if(!(Int64ValsByProp(param) == 1))
1943 alSetError(Context, AL_INVALID_ENUM);
1944 else
1945 GetSourcei64v(Source, Context, param, value);
1947 ALCcontext_DecRef(Context);
1950 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
1952 ALCcontext *Context;
1953 ALsource *Source;
1955 Context = GetContextRef();
1956 if(!Context) return;
1958 if((Source=LookupSource(Context, source)) == NULL)
1959 alSetError(Context, AL_INVALID_NAME);
1960 else if(!(value1 && value2 && value3))
1961 alSetError(Context, AL_INVALID_VALUE);
1962 else if(!(Int64ValsByProp(param) == 3))
1963 alSetError(Context, AL_INVALID_ENUM);
1964 else
1966 ALint64 i64vals[3];
1967 if(GetSourcei64v(Source, Context, param, i64vals) == AL_NO_ERROR)
1969 *value1 = i64vals[0];
1970 *value2 = i64vals[1];
1971 *value3 = i64vals[2];
1975 ALCcontext_DecRef(Context);
1978 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
1980 ALCcontext *Context;
1981 ALsource *Source;
1983 Context = GetContextRef();
1984 if(!Context) return;
1986 if((Source=LookupSource(Context, source)) == NULL)
1987 alSetError(Context, AL_INVALID_NAME);
1988 else if(!values)
1989 alSetError(Context, AL_INVALID_VALUE);
1990 else if(!(Int64ValsByProp(param) > 0))
1991 alSetError(Context, AL_INVALID_ENUM);
1992 else
1993 GetSourcei64v(Source, Context, param, values);
1995 ALCcontext_DecRef(Context);
1999 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2001 alSourcePlayv(1, &source);
2003 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2005 ALCcontext *Context;
2006 ALsource *Source;
2007 ALsizei i;
2009 Context = GetContextRef();
2010 if(!Context) return;
2012 al_try
2014 CHECK_VALUE(Context, n >= 0);
2015 for(i = 0;i < n;i++)
2017 if(!LookupSource(Context, sources[i]))
2018 al_throwerr(Context, AL_INVALID_NAME);
2021 LockContext(Context);
2022 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
2024 void *temp = NULL;
2025 ALsizei newcount;
2027 newcount = Context->MaxActiveSources << 1;
2028 if(newcount > 0)
2029 temp = realloc(Context->ActiveSources,
2030 sizeof(*Context->ActiveSources) * newcount);
2031 if(!temp)
2033 UnlockContext(Context);
2034 al_throwerr(Context, AL_OUT_OF_MEMORY);
2037 Context->ActiveSources = temp;
2038 Context->MaxActiveSources = newcount;
2041 for(i = 0;i < n;i++)
2043 Source = LookupSource(Context, sources[i]);
2044 if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
2045 else SetSourceState(Source, Context, AL_PLAYING);
2047 UnlockContext(Context);
2049 al_endtry;
2051 ALCcontext_DecRef(Context);
2054 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2056 alSourcePausev(1, &source);
2058 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2060 ALCcontext *Context;
2061 ALsource *Source;
2062 ALsizei i;
2064 Context = GetContextRef();
2065 if(!Context) return;
2067 al_try
2069 CHECK_VALUE(Context, n >= 0);
2070 for(i = 0;i < n;i++)
2072 if(!LookupSource(Context, sources[i]))
2073 al_throwerr(Context, AL_INVALID_NAME);
2076 LockContext(Context);
2077 for(i = 0;i < n;i++)
2079 Source = LookupSource(Context, sources[i]);
2080 if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
2081 else SetSourceState(Source, Context, AL_PAUSED);
2083 UnlockContext(Context);
2085 al_endtry;
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 al_try
2105 CHECK_VALUE(Context, n >= 0);
2106 for(i = 0;i < n;i++)
2108 if(!LookupSource(Context, sources[i]))
2109 al_throwerr(Context, AL_INVALID_NAME);
2112 LockContext(Context);
2113 for(i = 0;i < n;i++)
2115 Source = LookupSource(Context, sources[i]);
2116 Source->new_state = AL_NONE;
2117 SetSourceState(Source, Context, AL_STOPPED);
2119 UnlockContext(Context);
2121 al_endtry;
2123 ALCcontext_DecRef(Context);
2126 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2128 alSourceRewindv(1, &source);
2130 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2132 ALCcontext *Context;
2133 ALsource *Source;
2134 ALsizei i;
2136 Context = GetContextRef();
2137 if(!Context) return;
2139 al_try
2141 CHECK_VALUE(Context, n >= 0);
2142 for(i = 0;i < n;i++)
2144 if(!LookupSource(Context, sources[i]))
2145 al_throwerr(Context, AL_INVALID_NAME);
2148 LockContext(Context);
2149 for(i = 0;i < n;i++)
2151 Source = LookupSource(Context, sources[i]);
2152 Source->new_state = AL_NONE;
2153 SetSourceState(Source, Context, AL_INITIAL);
2155 UnlockContext(Context);
2157 al_endtry;
2159 ALCcontext_DecRef(Context);
2163 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers)
2165 ALCcontext *Context;
2166 ALsource *Source;
2167 ALsizei i;
2168 ALbufferlistitem *BufferListStart = NULL;
2169 ALbufferlistitem *BufferList;
2170 ALbuffer *BufferFmt;
2172 if(nb == 0)
2173 return;
2175 Context = GetContextRef();
2176 if(!Context) return;
2178 al_try
2180 ALCdevice *device = Context->Device;
2182 CHECK_VALUE(Context, nb >= 0);
2184 if((Source=LookupSource(Context, source)) == NULL)
2185 al_throwerr(Context, AL_INVALID_NAME);
2187 LockContext(Context);
2188 if(Source->SourceType == AL_STATIC)
2190 UnlockContext(Context);
2191 /* Can't queue on a Static Source */
2192 al_throwerr(Context, AL_INVALID_OPERATION);
2195 BufferFmt = NULL;
2197 /* Check for a valid Buffer, for its frequency and format */
2198 BufferList = Source->queue;
2199 while(BufferList)
2201 if(BufferList->buffer)
2203 BufferFmt = BufferList->buffer;
2204 break;
2206 BufferList = BufferList->next;
2209 for(i = 0;i < nb;i++)
2211 ALbuffer *buffer = NULL;
2212 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2214 UnlockContext(Context);
2215 al_throwerr(Context, AL_INVALID_NAME);
2218 if(!BufferListStart)
2220 BufferListStart = malloc(sizeof(ALbufferlistitem));
2221 BufferListStart->buffer = buffer;
2222 BufferListStart->next = NULL;
2223 BufferListStart->prev = NULL;
2224 BufferList = BufferListStart;
2226 else
2228 BufferList->next = malloc(sizeof(ALbufferlistitem));
2229 BufferList->next->buffer = buffer;
2230 BufferList->next->next = NULL;
2231 BufferList->next->prev = BufferList;
2232 BufferList = BufferList->next;
2234 if(!buffer) continue;
2235 IncrementRef(&buffer->ref);
2237 ReadLock(&buffer->lock);
2238 if(BufferFmt == NULL)
2240 BufferFmt = buffer;
2242 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2243 Source->SampleSize = BytesFromFmt(buffer->FmtType);
2244 if(buffer->FmtChannels == FmtMono)
2245 Source->Update = CalcSourceParams;
2246 else
2247 Source->Update = CalcNonAttnSourceParams;
2249 Source->NeedsUpdate = AL_TRUE;
2251 else if(BufferFmt->Frequency != buffer->Frequency ||
2252 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2253 BufferFmt->OriginalType != buffer->OriginalType)
2255 ReadUnlock(&buffer->lock);
2256 UnlockContext(Context);
2257 al_throwerr(Context, AL_INVALID_OPERATION);
2259 ReadUnlock(&buffer->lock);
2262 /* Source is now streaming */
2263 Source->SourceType = AL_STREAMING;
2265 if(Source->queue == NULL)
2266 Source->queue = BufferListStart;
2267 else
2269 /* Append to the end of the queue */
2270 BufferList = Source->queue;
2271 while(BufferList->next != NULL)
2272 BufferList = BufferList->next;
2274 BufferListStart->prev = BufferList;
2275 BufferList->next = BufferListStart;
2278 Source->BuffersInQueue += nb;
2280 UnlockContext(Context);
2282 al_catchany()
2284 while(BufferListStart)
2286 BufferList = BufferListStart;
2287 BufferListStart = BufferList->next;
2289 if(BufferList->buffer)
2290 DecrementRef(&BufferList->buffer->ref);
2291 free(BufferList);
2294 al_endtry;
2296 ALCcontext_DecRef(Context);
2299 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers)
2301 ALCcontext *Context;
2302 ALsource *Source;
2303 ALsizei i;
2304 ALbufferlistitem *BufferList;
2306 if(nb == 0)
2307 return;
2309 Context = GetContextRef();
2310 if(!Context) return;
2312 al_try
2314 CHECK_VALUE(Context, nb >= 0);
2316 if((Source=LookupSource(Context, source)) == NULL)
2317 al_throwerr(Context, AL_INVALID_NAME);
2319 LockContext(Context);
2320 if(Source->Looping || Source->SourceType != AL_STREAMING ||
2321 (ALuint)nb > Source->BuffersPlayed)
2323 UnlockContext(Context);
2324 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2325 al_throwerr(Context, AL_INVALID_VALUE);
2328 for(i = 0;i < nb;i++)
2330 BufferList = Source->queue;
2331 Source->queue = BufferList->next;
2332 Source->BuffersInQueue--;
2333 Source->BuffersPlayed--;
2335 if(BufferList->buffer)
2337 buffers[i] = BufferList->buffer->id;
2338 DecrementRef(&BufferList->buffer->ref);
2340 else
2341 buffers[i] = 0;
2343 free(BufferList);
2345 if(Source->queue)
2346 Source->queue->prev = NULL;
2347 UnlockContext(Context);
2349 al_endtry;
2351 ALCcontext_DecRef(Context);
2355 static ALvoid InitSourceParams(ALsource *Source)
2357 ALuint i;
2359 Source->InnerAngle = 360.0f;
2360 Source->OuterAngle = 360.0f;
2361 Source->Pitch = 1.0f;
2362 Source->Position[0] = 0.0f;
2363 Source->Position[1] = 0.0f;
2364 Source->Position[2] = 0.0f;
2365 Source->Orientation[0] = 0.0f;
2366 Source->Orientation[1] = 0.0f;
2367 Source->Orientation[2] = 0.0f;
2368 Source->Velocity[0] = 0.0f;
2369 Source->Velocity[1] = 0.0f;
2370 Source->Velocity[2] = 0.0f;
2371 Source->RefDistance = 1.0f;
2372 Source->MaxDistance = FLT_MAX;
2373 Source->RollOffFactor = 1.0f;
2374 Source->Looping = AL_FALSE;
2375 Source->Gain = 1.0f;
2376 Source->MinGain = 0.0f;
2377 Source->MaxGain = 1.0f;
2378 Source->OuterGain = 0.0f;
2379 Source->OuterGainHF = 1.0f;
2381 Source->DryGainHFAuto = AL_TRUE;
2382 Source->WetGainAuto = AL_TRUE;
2383 Source->WetGainHFAuto = AL_TRUE;
2384 Source->AirAbsorptionFactor = 0.0f;
2385 Source->RoomRolloffFactor = 0.0f;
2386 Source->DopplerFactor = 1.0f;
2387 Source->DirectChannels = AL_FALSE;
2389 Source->DistanceModel = DefaultDistanceModel;
2391 Source->Resampler = DefaultResampler;
2393 Source->state = AL_INITIAL;
2394 Source->new_state = AL_NONE;
2395 Source->SourceType = AL_UNDETERMINED;
2396 Source->Offset = -1.0;
2398 Source->DirectGain = 1.0f;
2399 Source->DirectGainHF = 1.0f;
2400 for(i = 0;i < MAX_SENDS;i++)
2402 Source->Send[i].Gain = 1.0f;
2403 Source->Send[i].GainHF = 1.0f;
2406 Source->NeedsUpdate = AL_TRUE;
2408 Source->Hrtf.Moving = AL_FALSE;
2409 Source->Hrtf.Counter = 0;
2413 /* SetSourceState
2415 * Sets the source's new play state given its current state.
2417 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2419 if(state == AL_PLAYING)
2421 ALbufferlistitem *BufferList;
2422 ALsizei j, k;
2424 /* Check that there is a queue containing at least one valid, non zero
2425 * length Buffer. */
2426 BufferList = Source->queue;
2427 while(BufferList)
2429 if(BufferList->buffer != NULL && BufferList->buffer->SampleLen)
2430 break;
2431 BufferList = BufferList->next;
2434 if(Source->state != AL_PLAYING)
2436 for(j = 0;j < MaxChannels;j++)
2438 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
2439 Source->Hrtf.History[j][k] = 0.0f;
2440 for(k = 0;k < HRIR_LENGTH;k++)
2442 Source->Hrtf.Values[j][k][0] = 0.0f;
2443 Source->Hrtf.Values[j][k][1] = 0.0f;
2448 if(Source->state != AL_PAUSED)
2450 Source->state = AL_PLAYING;
2451 Source->position = 0;
2452 Source->position_fraction = 0;
2453 Source->BuffersPlayed = 0;
2455 else
2456 Source->state = AL_PLAYING;
2458 // Check if an Offset has been set
2459 if(Source->Offset >= 0.0)
2460 ApplyOffset(Source);
2462 /* If there's nothing to play, or device is disconnected, go right to
2463 * stopped */
2464 if(!BufferList || !Context->Device->Connected)
2466 SetSourceState(Source, Context, AL_STOPPED);
2467 return;
2470 for(j = 0;j < Context->ActiveSourceCount;j++)
2472 if(Context->ActiveSources[j] == Source)
2473 break;
2475 if(j == Context->ActiveSourceCount)
2476 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
2478 else if(state == AL_PAUSED)
2480 if(Source->state == AL_PLAYING)
2482 Source->state = AL_PAUSED;
2483 Source->Hrtf.Moving = AL_FALSE;
2484 Source->Hrtf.Counter = 0;
2487 else if(state == AL_STOPPED)
2489 if(Source->state != AL_INITIAL)
2491 Source->state = AL_STOPPED;
2492 Source->BuffersPlayed = Source->BuffersInQueue;
2493 Source->Hrtf.Moving = AL_FALSE;
2494 Source->Hrtf.Counter = 0;
2496 Source->Offset = -1.0;
2498 else if(state == AL_INITIAL)
2500 if(Source->state != AL_INITIAL)
2502 Source->state = AL_INITIAL;
2503 Source->position = 0;
2504 Source->position_fraction = 0;
2505 Source->BuffersPlayed = 0;
2506 Source->Hrtf.Moving = AL_FALSE;
2507 Source->Hrtf.Counter = 0;
2509 Source->Offset = -1.0;
2513 /* GetSourceOffset
2515 * Gets the current read offset for the given Source, in 32.32 fixed-point
2516 * samples. The offset is relative to the start of the queue (not the start of
2517 * the current buffer).
2519 static ALint64 GetSourceOffset(const ALsource *Source)
2521 const ALbufferlistitem *BufferList;
2522 ALuint64 readPos;
2523 ALuint i;
2525 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2526 return 0;
2528 /* NOTE: This is the offset into the *current* buffer, so add the length of
2529 * any played buffers */
2530 readPos = (ALuint64)Source->position << 32;
2531 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2532 BufferList = Source->queue;
2533 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2535 if(BufferList->buffer)
2536 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2537 BufferList = BufferList->next;
2540 return (ALint64)minu64(readPos, MAKEU64(0x7fffffff,0xffffffff));
2543 /* GetSourceSecOffset
2545 * Gets the current read offset for the given Source, in seconds. The offset is
2546 * relative to the start of the queue (not the start of the current buffer).
2548 static ALdouble GetSourceSecOffset(const ALsource *Source)
2550 const ALbufferlistitem *BufferList;
2551 const ALbuffer *Buffer = NULL;
2552 ALuint64 readPos;
2553 ALuint i;
2555 BufferList = Source->queue;
2556 while(BufferList)
2558 if(BufferList->buffer)
2560 Buffer = BufferList->buffer;
2561 break;
2563 BufferList = BufferList->next;
2566 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2567 return 0.0;
2569 /* NOTE: This is the offset into the *current* buffer, so add the length of
2570 * any played buffers */
2571 readPos = (ALuint64)Source->position << FRACTIONBITS;
2572 readPos |= (ALuint64)Source->position_fraction;
2573 BufferList = Source->queue;
2574 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2576 if(BufferList->buffer)
2577 readPos += (ALuint64)BufferList->buffer->SampleLen << FRACTIONBITS;
2578 BufferList = BufferList->next;
2581 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2584 /* GetSourceOffsets
2586 * Gets the current read and write offsets for the given Source, in the
2587 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2588 * the start of the queue (not the start of the current buffer).
2590 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2592 const ALbufferlistitem *BufferList;
2593 const ALbuffer *Buffer = NULL;
2594 ALuint readPos, writePos;
2595 ALuint totalBufferLen;
2596 ALuint i;
2598 // Find the first valid Buffer in the Queue
2599 BufferList = Source->queue;
2600 while(BufferList)
2602 if(BufferList->buffer)
2604 Buffer = BufferList->buffer;
2605 break;
2607 BufferList = BufferList->next;
2610 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2612 offset[0] = 0.0;
2613 offset[1] = 0.0;
2614 return;
2617 if(updateLen > 0.0 && updateLen < 0.015)
2618 updateLen = 0.015;
2620 /* NOTE: This is the offset into the *current* buffer, so add the length of
2621 * any played buffers */
2622 readPos = Source->position;
2623 totalBufferLen = 0;
2624 BufferList = Source->queue;
2625 for(i = 0;BufferList;i++)
2627 if(BufferList->buffer)
2629 if(i < Source->BuffersPlayed)
2630 readPos += BufferList->buffer->SampleLen;
2631 totalBufferLen += BufferList->buffer->SampleLen;
2633 BufferList = BufferList->next;
2635 if(Source->state == AL_PLAYING)
2636 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
2637 else
2638 writePos = readPos;
2640 if(Source->Looping)
2642 readPos %= totalBufferLen;
2643 writePos %= totalBufferLen;
2645 else
2647 /* Wrap positions back to 0 */
2648 if(readPos >= totalBufferLen)
2649 readPos = 0;
2650 if(writePos >= totalBufferLen)
2651 writePos = 0;
2654 switch(name)
2656 case AL_SEC_OFFSET:
2657 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2658 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2659 break;
2661 case AL_SAMPLE_OFFSET:
2662 case AL_SAMPLE_RW_OFFSETS_SOFT:
2663 offset[0] = (ALdouble)readPos;
2664 offset[1] = (ALdouble)writePos;
2665 break;
2667 case AL_BYTE_OFFSET:
2668 case AL_BYTE_RW_OFFSETS_SOFT:
2669 if(Buffer->OriginalType == UserFmtIMA4)
2671 ALuint BlockSize = 36 * ChannelsFromFmt(Buffer->FmtChannels);
2672 ALuint FrameBlockSize = 65;
2674 /* Round down to nearest ADPCM block */
2675 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2676 if(Source->state != AL_PLAYING)
2677 offset[1] = offset[0];
2678 else
2680 /* Round up to nearest ADPCM block */
2681 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2682 FrameBlockSize * BlockSize);
2685 else
2687 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2688 offset[0] = (ALdouble)(readPos * FrameSize);
2689 offset[1] = (ALdouble)(writePos * FrameSize);
2691 break;
2696 /* ApplyOffset
2698 * Apply the stored playback offset to the Source. This function will update
2699 * the number of buffers "played" given the stored offset.
2701 ALboolean ApplyOffset(ALsource *Source)
2703 const ALbufferlistitem *BufferList;
2704 const ALbuffer *Buffer;
2705 ALint bufferLen, totalBufferLen;
2706 ALint buffersPlayed;
2707 ALint offset;
2709 /* Get sample frame offset */
2710 offset = GetSampleOffset(Source);
2711 if(offset == -1)
2712 return AL_FALSE;
2714 buffersPlayed = 0;
2715 totalBufferLen = 0;
2717 BufferList = Source->queue;
2718 while(BufferList)
2720 Buffer = BufferList->buffer;
2721 bufferLen = Buffer ? Buffer->SampleLen : 0;
2723 if(bufferLen <= offset-totalBufferLen)
2725 /* Offset is past this buffer so increment to the next buffer */
2726 buffersPlayed++;
2728 else if(totalBufferLen <= offset)
2730 /* Offset is in this buffer */
2731 Source->BuffersPlayed = buffersPlayed;
2733 Source->position = offset - totalBufferLen;
2734 Source->position_fraction = 0;
2735 return AL_TRUE;
2738 totalBufferLen += bufferLen;
2740 BufferList = BufferList->next;
2743 /* Offset is out of range of the queue */
2744 return AL_FALSE;
2748 /* GetSampleOffset
2750 * Returns the sample offset into the Source's queue (from the Sample, Byte or
2751 * Second offset supplied by the application). This takes into account the fact
2752 * that the buffer format may have been modifed since.
2754 static ALint GetSampleOffset(ALsource *Source)
2756 const ALbuffer *Buffer = NULL;
2757 const ALbufferlistitem *BufferList;
2758 ALint Offset = -1;
2760 /* Find the first valid Buffer in the Queue */
2761 BufferList = Source->queue;
2762 while(BufferList)
2764 if(BufferList->buffer)
2766 Buffer = BufferList->buffer;
2767 break;
2769 BufferList = BufferList->next;
2772 if(!Buffer)
2774 Source->Offset = -1.0;
2775 return -1;
2778 switch(Source->OffsetType)
2780 case AL_BYTE_OFFSET:
2781 /* Determine the ByteOffset (and ensure it is block aligned) */
2782 Offset = (ALint)Source->Offset;
2783 if(Buffer->OriginalType == UserFmtIMA4)
2785 Offset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
2786 Offset *= 65;
2788 else
2789 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2790 break;
2792 case AL_SAMPLE_OFFSET:
2793 Offset = (ALint)Source->Offset;
2794 break;
2796 case AL_SEC_OFFSET:
2797 Offset = (ALint)(Source->Offset * Buffer->Frequency);
2798 break;
2800 Source->Offset = -1.0;
2802 return Offset;
2806 /* ReleaseALSources
2808 * Destroys all sources in the source map.
2810 ALvoid ReleaseALSources(ALCcontext *Context)
2812 ALsizei pos;
2813 ALuint j;
2814 for(pos = 0;pos < Context->SourceMap.size;pos++)
2816 ALsource *temp = Context->SourceMap.array[pos].value;
2817 Context->SourceMap.array[pos].value = NULL;
2819 while(temp->queue != NULL)
2821 ALbufferlistitem *BufferList = temp->queue;
2822 temp->queue = BufferList->next;
2824 if(BufferList->buffer != NULL)
2825 DecrementRef(&BufferList->buffer->ref);
2826 free(BufferList);
2829 for(j = 0;j < MAX_SENDS;++j)
2831 if(temp->Send[j].Slot)
2832 DecrementRef(&temp->Send[j].Slot->ref);
2833 temp->Send[j].Slot = NULL;
2836 FreeThunkEntry(temp->id);
2837 memset(temp, 0, sizeof(*temp));
2838 al_free(temp);