Avoid recreating the DSound primary buffer
[openal-soft.git] / OpenAL32 / alSource.c
blobdace22d64d7aa94b2391b448f3426e1d0e22bca9
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 static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, ALenum name, const ALfloat *values);
57 static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, ALenum name, const ALint *values);
58 static ALenum SetSourcei64v(ALsource *Source, ALCcontext *Context, ALenum name, const ALint64SOFT *values);
60 static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, ALenum name, ALdouble *values);
61 static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, ALenum name, ALint *values);
62 static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, ALenum name, ALint64 *values);
65 #define RETERR(x) do { \
66 alSetError(Context, (x)); \
67 return (x); \
68 } while(0)
70 #define CHECKVAL(x) do { \
71 if(!(x)) \
72 RETERR(AL_INVALID_VALUE); \
73 } while(0)
75 static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, ALenum name, const ALfloat *values)
77 switch(name)
79 case AL_PITCH:
80 CHECKVAL(*values >= 0.0f);
82 Source->Pitch = *values;
83 Source->NeedsUpdate = AL_TRUE;
84 break;
86 case AL_CONE_INNER_ANGLE:
87 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
89 Source->InnerAngle = *values;
90 Source->NeedsUpdate = AL_TRUE;
91 break;
93 case AL_CONE_OUTER_ANGLE:
94 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
96 Source->OuterAngle = *values;
97 Source->NeedsUpdate = AL_TRUE;
98 break;
100 case AL_GAIN:
101 CHECKVAL(*values >= 0.0f);
103 Source->Gain = *values;
104 Source->NeedsUpdate = AL_TRUE;
105 break;
107 case AL_MAX_DISTANCE:
108 CHECKVAL(*values >= 0.0f);
110 Source->MaxDistance = *values;
111 Source->NeedsUpdate = AL_TRUE;
112 break;
114 case AL_ROLLOFF_FACTOR:
115 CHECKVAL(*values >= 0.0f);
117 Source->RollOffFactor = *values;
118 Source->NeedsUpdate = AL_TRUE;
119 break;
121 case AL_REFERENCE_DISTANCE:
122 CHECKVAL(*values >= 0.0f);
124 Source->RefDistance = *values;
125 Source->NeedsUpdate = AL_TRUE;
126 break;
128 case AL_MIN_GAIN:
129 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
131 Source->MinGain = *values;
132 Source->NeedsUpdate = AL_TRUE;
133 break;
135 case AL_MAX_GAIN:
136 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
138 Source->MaxGain = *values;
139 Source->NeedsUpdate = AL_TRUE;
140 break;
142 case AL_CONE_OUTER_GAIN:
143 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
145 Source->OuterGain = *values;
146 Source->NeedsUpdate = AL_TRUE;
147 break;
149 case AL_CONE_OUTER_GAINHF:
150 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
152 Source->OuterGainHF = *values;
153 Source->NeedsUpdate = AL_TRUE;
154 break;
156 case AL_AIR_ABSORPTION_FACTOR:
157 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
159 Source->AirAbsorptionFactor = *values;
160 Source->NeedsUpdate = AL_TRUE;
161 break;
163 case AL_ROOM_ROLLOFF_FACTOR:
164 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
166 Source->RoomRolloffFactor = *values;
167 Source->NeedsUpdate = AL_TRUE;
168 break;
170 case AL_DOPPLER_FACTOR:
171 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
173 Source->DopplerFactor = *values;
174 Source->NeedsUpdate = AL_TRUE;
175 break;
177 case AL_SEC_OFFSET:
178 case AL_SAMPLE_OFFSET:
179 case AL_BYTE_OFFSET:
180 CHECKVAL(*values >= 0.0f);
182 LockContext(Context);
183 Source->OffsetType = name;
184 Source->Offset = *values;
186 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
187 !Context->DeferUpdates)
189 if(ApplyOffset(Source) == AL_FALSE)
191 UnlockContext(Context);
192 RETERR(AL_INVALID_VALUE);
195 UnlockContext(Context);
196 break;
199 case AL_SEC_OFFSET_LATENCY_SOFT:
200 /* Query only */
201 RETERR(AL_INVALID_OPERATION);
204 case AL_POSITION:
205 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
207 LockContext(Context);
208 Source->Position[0] = values[0];
209 Source->Position[1] = values[1];
210 Source->Position[2] = values[2];
211 UnlockContext(Context);
212 Source->NeedsUpdate = AL_TRUE;
213 break;
215 case AL_VELOCITY:
216 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
218 LockContext(Context);
219 Source->Velocity[0] = values[0];
220 Source->Velocity[1] = values[1];
221 Source->Velocity[2] = values[2];
222 UnlockContext(Context);
223 Source->NeedsUpdate = AL_TRUE;
224 break;
226 case AL_DIRECTION:
227 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
229 LockContext(Context);
230 Source->Orientation[0] = values[0];
231 Source->Orientation[1] = values[1];
232 Source->Orientation[2] = values[2];
233 UnlockContext(Context);
234 Source->NeedsUpdate = AL_TRUE;
235 break;
237 default:
238 RETERR(AL_INVALID_ENUM);
241 return AL_NO_ERROR;
244 static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, ALenum name, const ALint *values)
246 ALCdevice *device = Context->Device;
247 ALbuffer *buffer = NULL;
248 ALfilter *filter = NULL;
249 ALeffectslot *slot = NULL;
250 ALbufferlistitem *oldlist;
251 ALfloat fvals[3];
252 ALenum err;
254 switch(name)
256 case AL_SOURCE_RELATIVE:
257 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
259 Source->HeadRelative = (ALboolean)*values;
260 Source->NeedsUpdate = AL_TRUE;
261 break;
263 case AL_LOOPING:
264 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
266 Source->Looping = (ALboolean)*values;
267 break;
269 case AL_BUFFER:
270 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
272 LockContext(Context);
273 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
275 UnlockContext(Context);
276 RETERR(AL_INVALID_OPERATION);
279 Source->BuffersInQueue = 0;
280 Source->BuffersPlayed = 0;
282 if(buffer != NULL)
284 ALbufferlistitem *BufferListItem;
286 /* Source is now Static */
287 Source->SourceType = AL_STATIC;
289 /* Add the selected buffer to a one-item queue */
290 BufferListItem = malloc(sizeof(ALbufferlistitem));
291 BufferListItem->buffer = buffer;
292 BufferListItem->next = NULL;
293 BufferListItem->prev = NULL;
294 IncrementRef(&buffer->ref);
296 oldlist = ExchangePtr((XchgPtr*)&Source->queue, BufferListItem);
297 Source->BuffersInQueue = 1;
299 ReadLock(&buffer->lock);
300 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
301 Source->SampleSize = BytesFromFmt(buffer->FmtType);
302 ReadUnlock(&buffer->lock);
303 if(buffer->FmtChannels == FmtMono)
304 Source->Update = CalcSourceParams;
305 else
306 Source->Update = CalcNonAttnSourceParams;
307 Source->NeedsUpdate = AL_TRUE;
309 else
311 /* Source is now Undetermined */
312 Source->SourceType = AL_UNDETERMINED;
313 oldlist = ExchangePtr((XchgPtr*)&Source->queue, NULL);
316 /* Delete all elements in the previous queue */
317 while(oldlist != NULL)
319 ALbufferlistitem *temp = oldlist;
320 oldlist = temp->next;
322 if(temp->buffer)
323 DecrementRef(&temp->buffer->ref);
324 free(temp);
326 UnlockContext(Context);
327 break;
329 case AL_SOURCE_STATE:
330 /* Query only */
331 RETERR(AL_INVALID_OPERATION);
333 case AL_SEC_OFFSET:
334 case AL_SAMPLE_OFFSET:
335 case AL_BYTE_OFFSET:
336 CHECKVAL(*values >= 0);
338 LockContext(Context);
339 Source->OffsetType = name;
340 Source->Offset = *values;
342 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
343 !Context->DeferUpdates)
345 if(ApplyOffset(Source) == AL_FALSE)
347 UnlockContext(Context);
348 RETERR(AL_INVALID_VALUE);
351 UnlockContext(Context);
352 break;
354 case AL_DIRECT_FILTER:
355 CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
357 LockContext(Context);
358 if(!filter)
360 Source->DirectGain = 1.0f;
361 Source->DirectGainHF = 1.0f;
363 else
365 Source->DirectGain = filter->Gain;
366 Source->DirectGainHF = filter->GainHF;
368 UnlockContext(Context);
369 Source->NeedsUpdate = AL_TRUE;
370 break;
372 case AL_DIRECT_FILTER_GAINHF_AUTO:
373 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
375 Source->DryGainHFAuto = *values;
376 Source->NeedsUpdate = AL_TRUE;
377 break;
379 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
380 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
382 Source->WetGainAuto = *values;
383 Source->NeedsUpdate = AL_TRUE;
384 break;
386 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
387 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
389 Source->WetGainHFAuto = *values;
390 Source->NeedsUpdate = AL_TRUE;
391 break;
393 case AL_DIRECT_CHANNELS_SOFT:
394 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
396 Source->DirectChannels = *values;
397 Source->NeedsUpdate = AL_TRUE;
398 break;
400 case AL_DISTANCE_MODEL:
401 CHECKVAL(*values == AL_NONE ||
402 *values == AL_INVERSE_DISTANCE ||
403 *values == AL_INVERSE_DISTANCE_CLAMPED ||
404 *values == AL_LINEAR_DISTANCE ||
405 *values == AL_LINEAR_DISTANCE_CLAMPED ||
406 *values == AL_EXPONENT_DISTANCE ||
407 *values == AL_EXPONENT_DISTANCE_CLAMPED);
409 Source->DistanceModel = *values;
410 if(Context->SourceDistanceModel)
411 Source->NeedsUpdate = AL_TRUE;
412 break;
415 case AL_AUXILIARY_SEND_FILTER:
416 LockContext(Context);
417 if(!((ALuint)values[1] < device->NumAuxSends &&
418 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
419 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
421 UnlockContext(Context);
422 RETERR(AL_INVALID_VALUE);
425 /* Add refcount on the new slot, and release the previous slot */
426 if(slot) IncrementRef(&slot->ref);
427 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
428 if(slot) DecrementRef(&slot->ref);
430 if(!filter)
432 /* Disable filter */
433 Source->Send[values[1]].Gain = 1.0f;
434 Source->Send[values[1]].GainHF = 1.0f;
436 else
438 Source->Send[values[1]].Gain = filter->Gain;
439 Source->Send[values[1]].GainHF = filter->GainHF;
441 Source->NeedsUpdate = AL_TRUE;
442 UnlockContext(Context);
443 break;
446 case AL_MAX_DISTANCE:
447 case AL_ROLLOFF_FACTOR:
448 case AL_CONE_INNER_ANGLE:
449 case AL_CONE_OUTER_ANGLE:
450 case AL_REFERENCE_DISTANCE:
451 fvals[0] = (ALfloat)*values;
452 if((err=SetSourcefv(Source, Context, name, fvals)) != AL_NO_ERROR)
453 return err;
454 break;
456 case AL_POSITION:
457 case AL_VELOCITY:
458 case AL_DIRECTION:
459 fvals[0] = (ALfloat)values[0];
460 fvals[1] = (ALfloat)values[1];
461 fvals[2] = (ALfloat)values[2];
462 if((err=SetSourcefv(Source, Context, name, fvals)) != AL_NO_ERROR)
463 return err;
464 break;
466 default:
467 RETERR(AL_INVALID_ENUM);
470 return AL_NO_ERROR;
473 static ALenum SetSourcei64v(ALsource *Source, ALCcontext *Context, ALenum name, const ALint64SOFT *values)
475 ALfloat fvals[3];
476 ALint ivals[3];
477 ALenum err;
479 switch(name)
481 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
482 /* Query only */
483 RETERR(AL_INVALID_OPERATION);
486 /* 1x int */
487 case AL_SOURCE_RELATIVE:
488 case AL_LOOPING:
489 case AL_SOURCE_STATE:
490 case AL_BYTE_OFFSET:
491 case AL_SAMPLE_OFFSET:
492 case AL_DIRECT_FILTER_GAINHF_AUTO:
493 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
494 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
495 case AL_DIRECT_CHANNELS_SOFT:
496 case AL_DISTANCE_MODEL:
497 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
499 ivals[0] = (ALint)*values;
500 if((err=SetSourceiv(Source, Context, name, ivals)))
501 return err;
502 break;
504 /* 1x uint */
505 case AL_BUFFER:
506 case AL_DIRECT_FILTER:
507 CHECKVAL(*values <= UINT_MAX && *values >= 0);
509 ivals[0] = (ALuint)*values;
510 if((err=SetSourceiv(Source, Context, name, ivals)))
511 return err;
512 break;
514 /* 3x uint */
515 case AL_AUXILIARY_SEND_FILTER:
516 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
517 values[1] <= UINT_MAX && values[1] >= 0 &&
518 values[2] <= UINT_MAX && values[2] >= 0);
520 ivals[0] = (ALuint)values[0];
521 ivals[1] = (ALuint)values[1];
522 ivals[2] = (ALuint)values[2];
523 if((err=SetSourceiv(Source, Context, name, ivals)))
524 return err;
525 break;
527 /* 1x float */
528 case AL_MAX_DISTANCE:
529 case AL_ROLLOFF_FACTOR:
530 case AL_CONE_INNER_ANGLE:
531 case AL_CONE_OUTER_ANGLE:
532 case AL_REFERENCE_DISTANCE:
533 case AL_SEC_OFFSET:
534 fvals[0] = (ALfloat)*values;
535 if((err=SetSourcefv(Source, Context, name, fvals)) != AL_NO_ERROR)
536 return err;
537 break;
539 /* 3x float */
540 case AL_POSITION:
541 case AL_VELOCITY:
542 case AL_DIRECTION:
543 fvals[0] = (ALfloat)values[0];
544 fvals[1] = (ALfloat)values[1];
545 fvals[2] = (ALfloat)values[2];
546 if((err=SetSourcefv(Source, Context, name, fvals)) != AL_NO_ERROR)
547 return err;
548 break;
550 default:
551 RETERR(AL_INVALID_ENUM);
554 return AL_NO_ERROR;
557 #undef CHECKVAL
560 static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, ALenum name, ALdouble *values)
562 ALdouble offsets[2];
563 ALdouble updateLen;
564 ALint ivals[3];
565 ALenum err;
567 switch(name)
569 case AL_PITCH:
570 *values = Source->Pitch;
571 break;
573 case AL_MAX_DISTANCE:
574 *values = Source->MaxDistance;
575 break;
577 case AL_ROLLOFF_FACTOR:
578 *values = Source->RollOffFactor;
579 break;
581 case AL_REFERENCE_DISTANCE:
582 *values = Source->RefDistance;
583 break;
585 case AL_CONE_INNER_ANGLE:
586 *values = Source->InnerAngle;
587 break;
589 case AL_CONE_OUTER_ANGLE:
590 *values = Source->OuterAngle;
591 break;
593 case AL_MIN_GAIN:
594 *values = Source->MinGain;
595 break;
597 case AL_MAX_GAIN:
598 *values = Source->MaxGain;
599 break;
601 case AL_CONE_OUTER_GAIN:
602 *values = Source->OuterGain;
603 break;
605 case AL_SEC_OFFSET:
606 case AL_SAMPLE_OFFSET:
607 case AL_BYTE_OFFSET:
608 LockContext(Context);
609 updateLen = (ALdouble)Context->Device->UpdateSize /
610 Context->Device->Frequency;
611 GetSourceOffsets(Source, name, offsets, updateLen);
612 UnlockContext(Context);
613 *values = offsets[0];
614 break;
616 case AL_CONE_OUTER_GAINHF:
617 *values = Source->OuterGainHF;
618 break;
620 case AL_AIR_ABSORPTION_FACTOR:
621 *values = Source->AirAbsorptionFactor;
622 break;
624 case AL_ROOM_ROLLOFF_FACTOR:
625 *values = Source->RoomRolloffFactor;
626 break;
628 case AL_DOPPLER_FACTOR:
629 *values = Source->DopplerFactor;
630 break;
632 case AL_SAMPLE_RW_OFFSETS_SOFT:
633 case AL_BYTE_RW_OFFSETS_SOFT:
634 LockContext(Context);
635 updateLen = (ALdouble)Context->Device->UpdateSize /
636 Context->Device->Frequency;
637 GetSourceOffsets(Source, name, values, updateLen);
638 UnlockContext(Context);
639 break;
641 case AL_SEC_OFFSET_LATENCY_SOFT:
642 LockContext(Context);
643 values[0] = GetSourceSecOffset(Source);
644 values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) /
645 1000000000.0;
646 UnlockContext(Context);
647 break;
649 case AL_POSITION:
650 LockContext(Context);
651 values[0] = Source->Position[0];
652 values[1] = Source->Position[1];
653 values[2] = Source->Position[2];
654 UnlockContext(Context);
655 break;
657 case AL_VELOCITY:
658 LockContext(Context);
659 values[0] = Source->Velocity[0];
660 values[1] = Source->Velocity[1];
661 values[2] = Source->Velocity[2];
662 UnlockContext(Context);
663 break;
665 case AL_DIRECTION:
666 LockContext(Context);
667 values[0] = Source->Orientation[0];
668 values[1] = Source->Orientation[1];
669 values[2] = Source->Orientation[2];
670 UnlockContext(Context);
671 break;
673 case AL_SOURCE_RELATIVE:
674 case AL_LOOPING:
675 case AL_BUFFER:
676 case AL_SOURCE_STATE:
677 case AL_BUFFERS_QUEUED:
678 case AL_BUFFERS_PROCESSED:
679 case AL_SOURCE_TYPE:
680 case AL_DIRECT_FILTER_GAINHF_AUTO:
681 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
682 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
683 case AL_DIRECT_CHANNELS_SOFT:
684 case AL_DISTANCE_MODEL:
685 if((err=GetSourceiv(Source, Context, name, ivals)) != AL_NO_ERROR)
686 return err;
687 *values = (ALdouble)ivals[0];
688 break;
690 default:
691 RETERR(AL_INVALID_ENUM);
694 return AL_NO_ERROR;
697 static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, ALenum name, ALint *values)
699 ALbufferlistitem *BufferList;
700 ALdouble dvals[3];
701 ALenum err;
703 switch(name)
705 case AL_SOURCE_RELATIVE:
706 *values = Source->HeadRelative;
707 break;
709 case AL_LOOPING:
710 *values = Source->Looping;
711 break;
713 case AL_BUFFER:
714 LockContext(Context);
715 BufferList = Source->queue;
716 if(Source->SourceType != AL_STATIC)
718 ALuint i = Source->BuffersPlayed;
719 while(i > 0)
721 BufferList = BufferList->next;
722 i--;
725 *values = ((BufferList && BufferList->buffer) ?
726 BufferList->buffer->id : 0);
727 UnlockContext(Context);
728 break;
730 case AL_SOURCE_STATE:
731 *values = Source->state;
732 break;
734 case AL_BUFFERS_QUEUED:
735 *values = Source->BuffersInQueue;
736 break;
738 case AL_BUFFERS_PROCESSED:
739 LockContext(Context);
740 if(Source->Looping || Source->SourceType != AL_STREAMING)
742 /* Buffers on a looping source are in a perpetual state of
743 * PENDING, so don't report any as PROCESSED */
744 *values = 0;
746 else
747 *values = Source->BuffersPlayed;
748 UnlockContext(Context);
749 break;
751 case AL_SOURCE_TYPE:
752 *values = Source->SourceType;
753 break;
755 case AL_DIRECT_FILTER_GAINHF_AUTO:
756 *values = Source->DryGainHFAuto;
757 break;
759 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
760 *values = Source->WetGainAuto;
761 break;
763 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
764 *values = Source->WetGainHFAuto;
765 break;
767 case AL_DIRECT_CHANNELS_SOFT:
768 *values = Source->DirectChannels;
769 break;
771 case AL_DISTANCE_MODEL:
772 *values = Source->DistanceModel;
773 break;
775 case AL_MAX_DISTANCE:
776 case AL_ROLLOFF_FACTOR:
777 case AL_REFERENCE_DISTANCE:
778 case AL_CONE_INNER_ANGLE:
779 case AL_CONE_OUTER_ANGLE:
780 case AL_SEC_OFFSET:
781 case AL_SAMPLE_OFFSET:
782 case AL_BYTE_OFFSET:
783 case AL_DOPPLER_FACTOR:
784 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
785 return err;
786 *values = (ALint)dvals[0];
787 break;
789 case AL_SAMPLE_RW_OFFSETS_SOFT:
790 case AL_BYTE_RW_OFFSETS_SOFT:
791 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
792 return err;
793 values[0] = (ALint)dvals[0];
794 values[1] = (ALint)dvals[1];
795 break;
797 case AL_POSITION:
798 case AL_VELOCITY:
799 case AL_DIRECTION:
800 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
801 return err;
802 values[0] = (ALint)dvals[0];
803 values[1] = (ALint)dvals[1];
804 values[2] = (ALint)dvals[2];
805 break;
807 default:
808 RETERR(AL_INVALID_ENUM);
811 return AL_NO_ERROR;
814 static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, ALenum name, ALint64 *values)
816 ALdouble dvals[3];
817 ALint ivals[3];
818 ALenum err;
820 switch(name)
822 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
823 LockContext(Context);
824 values[0] = GetSourceOffset(Source);
825 values[1] = ALCdevice_GetLatency(Context->Device);
826 UnlockContext(Context);
827 break;
829 case AL_MAX_DISTANCE:
830 case AL_ROLLOFF_FACTOR:
831 case AL_REFERENCE_DISTANCE:
832 case AL_CONE_INNER_ANGLE:
833 case AL_CONE_OUTER_ANGLE:
834 case AL_SEC_OFFSET:
835 case AL_SAMPLE_OFFSET:
836 case AL_BYTE_OFFSET:
837 case AL_DOPPLER_FACTOR:
838 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
839 return err;
840 *values = (ALint64)dvals[0];
841 break;
843 case AL_SAMPLE_RW_OFFSETS_SOFT:
844 case AL_BYTE_RW_OFFSETS_SOFT:
845 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
846 return err;
847 values[0] = (ALint64)dvals[0];
848 values[1] = (ALint64)dvals[1];
849 break;
851 case AL_POSITION:
852 case AL_VELOCITY:
853 case AL_DIRECTION:
854 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
855 return err;
856 values[0] = (ALint64)dvals[0];
857 values[1] = (ALint64)dvals[1];
858 values[2] = (ALint64)dvals[2];
859 break;
861 case AL_SOURCE_RELATIVE:
862 case AL_LOOPING:
863 case AL_BUFFER:
864 case AL_SOURCE_STATE:
865 case AL_BUFFERS_QUEUED:
866 case AL_BUFFERS_PROCESSED:
867 case AL_SOURCE_TYPE:
868 case AL_DIRECT_FILTER_GAINHF_AUTO:
869 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
870 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
871 case AL_DIRECT_CHANNELS_SOFT:
872 case AL_DISTANCE_MODEL:
873 if((err=GetSourceiv(Source, Context, name, ivals)) != AL_NO_ERROR)
874 return err;
875 *values = ivals[0];
876 break;
878 default:
879 RETERR(AL_INVALID_ENUM);
882 return AL_NO_ERROR;
885 #undef RETERR
888 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
890 ALCcontext *Context;
891 ALsizei cur = 0;
893 Context = GetContextRef();
894 if(!Context) return;
896 al_try
898 ALenum err;
900 CHECK_VALUE(Context, n >= 0);
901 for(cur = 0;cur < n;cur++)
903 ALsource *source = al_calloc(16, sizeof(ALsource));
904 if(!source)
905 al_throwerr(Context, AL_OUT_OF_MEMORY);
906 InitSourceParams(source);
908 err = NewThunkEntry(&source->id);
909 if(err == AL_NO_ERROR)
910 err = InsertUIntMapEntry(&Context->SourceMap, source->id, source);
911 if(err != AL_NO_ERROR)
913 FreeThunkEntry(source->id);
914 memset(source, 0, sizeof(ALsource));
915 al_free(source);
917 al_throwerr(Context, err);
920 sources[cur] = source->id;
923 al_catchany()
925 if(cur > 0)
926 alDeleteSources(cur, sources);
928 al_endtry;
930 ALCcontext_DecRef(Context);
934 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
936 ALCcontext *Context;
938 Context = GetContextRef();
939 if(!Context) return;
941 al_try
943 ALbufferlistitem *BufferList;
944 ALsource *Source;
945 ALsizei i, j;
947 CHECK_VALUE(Context, n >= 0);
949 /* Check that all Sources are valid */
950 for(i = 0;i < n;i++)
952 if(LookupSource(Context, sources[i]) == NULL)
953 al_throwerr(Context, AL_INVALID_NAME);
956 for(i = 0;i < n;i++)
958 ALsource **srclist, **srclistend;
960 if((Source=RemoveSource(Context, sources[i])) == NULL)
961 continue;
962 FreeThunkEntry(Source->id);
964 LockContext(Context);
965 srclist = Context->ActiveSources;
966 srclistend = srclist + Context->ActiveSourceCount;
967 while(srclist != srclistend)
969 if(*srclist == Source)
971 Context->ActiveSourceCount--;
972 *srclist = *(--srclistend);
973 break;
975 srclist++;
977 UnlockContext(Context);
979 while(Source->queue != NULL)
981 BufferList = Source->queue;
982 Source->queue = BufferList->next;
984 if(BufferList->buffer != NULL)
985 DecrementRef(&BufferList->buffer->ref);
986 free(BufferList);
989 for(j = 0;j < MAX_SENDS;++j)
991 if(Source->Send[j].Slot)
992 DecrementRef(&Source->Send[j].Slot->ref);
993 Source->Send[j].Slot = NULL;
996 memset(Source, 0, sizeof(*Source));
997 al_free(Source);
1000 al_endtry;
1002 ALCcontext_DecRef(Context);
1006 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1008 ALCcontext *Context;
1009 ALboolean result;
1011 Context = GetContextRef();
1012 if(!Context) return AL_FALSE;
1014 result = (LookupSource(Context, source) ? AL_TRUE : AL_FALSE);
1016 ALCcontext_DecRef(Context);
1018 return result;
1022 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1024 ALCcontext *Context;
1025 ALsource *Source;
1027 Context = GetContextRef();
1028 if(!Context) return;
1030 if((Source=LookupSource(Context, source)) == NULL)
1031 alSetError(Context, AL_INVALID_NAME);
1032 else switch(param)
1034 case AL_PITCH:
1035 case AL_CONE_INNER_ANGLE:
1036 case AL_CONE_OUTER_ANGLE:
1037 case AL_GAIN:
1038 case AL_MAX_DISTANCE:
1039 case AL_ROLLOFF_FACTOR:
1040 case AL_REFERENCE_DISTANCE:
1041 case AL_MIN_GAIN:
1042 case AL_MAX_GAIN:
1043 case AL_CONE_OUTER_GAIN:
1044 case AL_CONE_OUTER_GAINHF:
1045 case AL_AIR_ABSORPTION_FACTOR:
1046 case AL_ROOM_ROLLOFF_FACTOR:
1047 case AL_DOPPLER_FACTOR:
1048 case AL_SEC_OFFSET:
1049 case AL_SAMPLE_OFFSET:
1050 case AL_BYTE_OFFSET:
1051 SetSourcefv(Source, Context, param, &value);
1052 break;
1054 default:
1055 alSetError(Context, AL_INVALID_ENUM);
1058 ALCcontext_DecRef(Context);
1061 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1063 ALCcontext *Context;
1064 ALsource *Source;
1065 ALfloat fvals[3];
1067 Context = GetContextRef();
1068 if(!Context) return;
1070 if((Source=LookupSource(Context, source)) == NULL)
1071 alSetError(Context, AL_INVALID_NAME);
1072 else switch(param)
1074 case AL_POSITION:
1075 case AL_VELOCITY:
1076 case AL_DIRECTION:
1077 fvals[0] = value1;
1078 fvals[1] = value2;
1079 fvals[2] = value3;
1080 SetSourcefv(Source, Context, param, fvals);
1081 break;
1083 default:
1084 alSetError(Context, AL_INVALID_ENUM);
1087 ALCcontext_DecRef(Context);
1090 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1092 ALCcontext *Context;
1093 ALsource *Source;
1095 Context = GetContextRef();
1096 if(!Context) return;
1098 if((Source=LookupSource(Context, source)) == NULL)
1099 alSetError(Context, AL_INVALID_NAME);
1100 else if(!values)
1101 alSetError(Context, AL_INVALID_VALUE);
1102 else switch(param)
1104 case AL_PITCH:
1105 case AL_CONE_INNER_ANGLE:
1106 case AL_CONE_OUTER_ANGLE:
1107 case AL_GAIN:
1108 case AL_MAX_DISTANCE:
1109 case AL_ROLLOFF_FACTOR:
1110 case AL_REFERENCE_DISTANCE:
1111 case AL_MIN_GAIN:
1112 case AL_MAX_GAIN:
1113 case AL_CONE_OUTER_GAIN:
1114 case AL_CONE_OUTER_GAINHF:
1115 case AL_SEC_OFFSET:
1116 case AL_SAMPLE_OFFSET:
1117 case AL_BYTE_OFFSET:
1118 case AL_AIR_ABSORPTION_FACTOR:
1119 case AL_ROOM_ROLLOFF_FACTOR:
1121 case AL_POSITION:
1122 case AL_VELOCITY:
1123 case AL_DIRECTION:
1124 SetSourcefv(Source, Context, param, values);
1125 break;
1127 default:
1128 alSetError(Context, AL_INVALID_ENUM);
1131 ALCcontext_DecRef(Context);
1135 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1137 ALCcontext *Context;
1138 ALsource *Source;
1139 ALfloat fval;
1141 Context = GetContextRef();
1142 if(!Context) return;
1144 if((Source=LookupSource(Context, source)) == NULL)
1145 alSetError(Context, AL_INVALID_NAME);
1146 else switch(param)
1148 case AL_PITCH:
1149 case AL_CONE_INNER_ANGLE:
1150 case AL_CONE_OUTER_ANGLE:
1151 case AL_GAIN:
1152 case AL_MAX_DISTANCE:
1153 case AL_ROLLOFF_FACTOR:
1154 case AL_REFERENCE_DISTANCE:
1155 case AL_MIN_GAIN:
1156 case AL_MAX_GAIN:
1157 case AL_CONE_OUTER_GAIN:
1158 case AL_CONE_OUTER_GAINHF:
1159 case AL_AIR_ABSORPTION_FACTOR:
1160 case AL_ROOM_ROLLOFF_FACTOR:
1161 case AL_DOPPLER_FACTOR:
1162 case AL_SEC_OFFSET:
1163 case AL_SAMPLE_OFFSET:
1164 case AL_BYTE_OFFSET:
1165 fval = (ALfloat)value;
1166 SetSourcefv(Source, Context, param, &fval);
1167 break;
1169 default:
1170 alSetError(Context, AL_INVALID_ENUM);
1173 ALCcontext_DecRef(Context);
1176 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1178 ALCcontext *Context;
1179 ALsource *Source;
1180 ALfloat fvals[3];
1182 Context = GetContextRef();
1183 if(!Context) return;
1185 if((Source=LookupSource(Context, source)) == NULL)
1186 alSetError(Context, AL_INVALID_NAME);
1187 else switch(param)
1189 case AL_POSITION:
1190 case AL_VELOCITY:
1191 case AL_DIRECTION:
1192 fvals[0] = (ALfloat)value1;
1193 fvals[1] = (ALfloat)value2;
1194 fvals[2] = (ALfloat)value3;
1195 SetSourcefv(Source, Context, param, fvals);
1196 break;
1198 default:
1199 alSetError(Context, AL_INVALID_ENUM);
1202 ALCcontext_DecRef(Context);
1205 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1207 ALCcontext *Context;
1208 ALsource *Source;
1209 ALfloat fvals[3];
1211 Context = GetContextRef();
1212 if(!Context) return;
1214 if((Source=LookupSource(Context, source)) == NULL)
1215 alSetError(Context, AL_INVALID_NAME);
1216 else if(!values)
1217 alSetError(Context, AL_INVALID_VALUE);
1218 else switch(param)
1220 case AL_PITCH:
1221 case AL_CONE_INNER_ANGLE:
1222 case AL_CONE_OUTER_ANGLE:
1223 case AL_GAIN:
1224 case AL_MAX_DISTANCE:
1225 case AL_ROLLOFF_FACTOR:
1226 case AL_REFERENCE_DISTANCE:
1227 case AL_MIN_GAIN:
1228 case AL_MAX_GAIN:
1229 case AL_CONE_OUTER_GAIN:
1230 case AL_CONE_OUTER_GAINHF:
1231 case AL_SEC_OFFSET:
1232 case AL_SAMPLE_OFFSET:
1233 case AL_BYTE_OFFSET:
1234 case AL_AIR_ABSORPTION_FACTOR:
1235 case AL_ROOM_ROLLOFF_FACTOR:
1236 fvals[0] = (ALfloat)values[0];
1237 SetSourcefv(Source, Context, param, fvals);
1238 break;
1240 case AL_SEC_OFFSET_LATENCY_SOFT:
1241 fvals[0] = (ALfloat)values[0];
1242 fvals[1] = (ALfloat)values[1];
1243 SetSourcefv(Source, Context, param, fvals);
1244 break;
1246 case AL_POSITION:
1247 case AL_VELOCITY:
1248 case AL_DIRECTION:
1249 fvals[0] = (ALfloat)values[0];
1250 fvals[1] = (ALfloat)values[1];
1251 fvals[2] = (ALfloat)values[2];
1252 SetSourcefv(Source, Context, param, fvals);
1253 break;
1255 default:
1256 alSetError(Context, AL_INVALID_ENUM);
1259 ALCcontext_DecRef(Context);
1263 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1265 ALCcontext *Context;
1266 ALsource *Source;
1268 Context = GetContextRef();
1269 if(!Context) return;
1271 if((Source=LookupSource(Context, source)) == NULL)
1272 alSetError(Context, AL_INVALID_NAME);
1273 else switch(param)
1275 case AL_MAX_DISTANCE:
1276 case AL_ROLLOFF_FACTOR:
1277 case AL_CONE_INNER_ANGLE:
1278 case AL_CONE_OUTER_ANGLE:
1279 case AL_REFERENCE_DISTANCE:
1280 case AL_SOURCE_RELATIVE:
1281 case AL_LOOPING:
1282 case AL_BUFFER:
1283 case AL_SOURCE_STATE:
1284 case AL_SEC_OFFSET:
1285 case AL_SAMPLE_OFFSET:
1286 case AL_BYTE_OFFSET:
1287 case AL_DIRECT_FILTER:
1288 case AL_DIRECT_FILTER_GAINHF_AUTO:
1289 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1290 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1291 case AL_DIRECT_CHANNELS_SOFT:
1292 case AL_DISTANCE_MODEL:
1293 SetSourceiv(Source, Context, param, &value);
1294 break;
1296 default:
1297 alSetError(Context, AL_INVALID_ENUM);
1300 ALCcontext_DecRef(Context);
1303 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1305 ALCcontext *Context;
1306 ALsource *Source;
1307 ALint ivals[3];
1309 Context = GetContextRef();
1310 if(!Context) return;
1312 if((Source=LookupSource(Context, source)) == NULL)
1313 alSetError(Context, AL_INVALID_NAME);
1314 else switch(param)
1316 case AL_POSITION:
1317 case AL_VELOCITY:
1318 case AL_DIRECTION:
1319 case AL_AUXILIARY_SEND_FILTER:
1320 ivals[0] = value1;
1321 ivals[1] = value2;
1322 ivals[2] = value3;
1323 SetSourceiv(Source, Context, param, ivals);
1324 break;
1326 default:
1327 alSetError(Context, AL_INVALID_ENUM);
1330 ALCcontext_DecRef(Context);
1333 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1335 ALCcontext *Context;
1336 ALsource *Source;
1338 Context = GetContextRef();
1339 if(!Context) return;
1341 if((Source=LookupSource(Context, source)) == NULL)
1342 alSetError(Context, AL_INVALID_NAME);
1343 else if(!values)
1344 alSetError(Context, AL_INVALID_VALUE);
1345 else switch(param)
1347 case AL_SOURCE_RELATIVE:
1348 case AL_CONE_INNER_ANGLE:
1349 case AL_CONE_OUTER_ANGLE:
1350 case AL_LOOPING:
1351 case AL_BUFFER:
1352 case AL_SOURCE_STATE:
1353 case AL_SEC_OFFSET:
1354 case AL_SAMPLE_OFFSET:
1355 case AL_BYTE_OFFSET:
1356 case AL_MAX_DISTANCE:
1357 case AL_ROLLOFF_FACTOR:
1358 case AL_REFERENCE_DISTANCE:
1359 case AL_DIRECT_FILTER:
1360 case AL_DIRECT_FILTER_GAINHF_AUTO:
1361 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1362 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1363 case AL_DISTANCE_MODEL:
1364 case AL_DIRECT_CHANNELS_SOFT:
1366 case AL_POSITION:
1367 case AL_VELOCITY:
1368 case AL_DIRECTION:
1369 case AL_AUXILIARY_SEND_FILTER:
1370 SetSourceiv(Source, Context, param, values);
1371 break;
1373 default:
1374 alSetError(Context, AL_INVALID_ENUM);
1377 ALCcontext_DecRef(Context);
1381 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1383 ALCcontext *Context;
1384 ALsource *Source;
1386 Context = GetContextRef();
1387 if(!Context) return;
1389 if((Source=LookupSource(Context, source)) == NULL)
1390 alSetError(Context, AL_INVALID_NAME);
1391 else switch(param)
1393 case AL_MAX_DISTANCE:
1394 case AL_ROLLOFF_FACTOR:
1395 case AL_CONE_INNER_ANGLE:
1396 case AL_CONE_OUTER_ANGLE:
1397 case AL_REFERENCE_DISTANCE:
1398 case AL_SOURCE_RELATIVE:
1399 case AL_LOOPING:
1400 case AL_SOURCE_STATE:
1401 case AL_SEC_OFFSET:
1402 case AL_SAMPLE_OFFSET:
1403 case AL_BYTE_OFFSET:
1404 case AL_DIRECT_FILTER_GAINHF_AUTO:
1405 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1406 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1407 case AL_DIRECT_CHANNELS_SOFT:
1408 case AL_DISTANCE_MODEL:
1409 case AL_BUFFER:
1410 case AL_DIRECT_FILTER:
1411 SetSourcei64v(Source, Context, param, &value);
1412 break;
1414 default:
1415 alSetError(Context, AL_INVALID_ENUM);
1418 ALCcontext_DecRef(Context);
1421 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1423 ALCcontext *Context;
1424 ALsource *Source;
1425 ALint64SOFT i64vals[3];
1427 Context = GetContextRef();
1428 if(!Context) return;
1430 if((Source=LookupSource(Context, source)) == NULL)
1431 alSetError(Context, AL_INVALID_NAME);
1432 else switch(param)
1434 case AL_POSITION:
1435 case AL_VELOCITY:
1436 case AL_DIRECTION:
1437 case AL_AUXILIARY_SEND_FILTER:
1438 i64vals[0] = value1;
1439 i64vals[1] = value2;
1440 i64vals[2] = value3;
1441 SetSourcei64v(Source, Context, param, i64vals);
1442 break;
1444 default:
1445 alSetError(Context, AL_INVALID_ENUM);
1448 ALCcontext_DecRef(Context);
1451 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1453 ALCcontext *Context;
1454 ALsource *Source;
1456 Context = GetContextRef();
1457 if(!Context) return;
1459 if((Source=LookupSource(Context, source)) == NULL)
1460 alSetError(Context, AL_INVALID_NAME);
1461 else if(!values)
1462 alSetError(Context, AL_INVALID_VALUE);
1463 else switch(param)
1465 case AL_SOURCE_RELATIVE:
1466 case AL_CONE_INNER_ANGLE:
1467 case AL_CONE_OUTER_ANGLE:
1468 case AL_LOOPING:
1469 case AL_SOURCE_STATE:
1470 case AL_SEC_OFFSET:
1471 case AL_SAMPLE_OFFSET:
1472 case AL_BYTE_OFFSET:
1473 case AL_MAX_DISTANCE:
1474 case AL_ROLLOFF_FACTOR:
1475 case AL_REFERENCE_DISTANCE:
1476 case AL_DIRECT_FILTER_GAINHF_AUTO:
1477 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1478 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1479 case AL_DISTANCE_MODEL:
1480 case AL_DIRECT_CHANNELS_SOFT:
1481 case AL_BUFFER:
1482 case AL_DIRECT_FILTER:
1484 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1486 case AL_POSITION:
1487 case AL_VELOCITY:
1488 case AL_DIRECTION:
1489 case AL_AUXILIARY_SEND_FILTER:
1490 SetSourcei64v(Source, Context, param, values);
1491 break;
1493 default:
1494 alSetError(Context, AL_INVALID_ENUM);
1497 ALCcontext_DecRef(Context);
1501 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1503 ALCcontext *Context;
1504 ALsource *Source;
1505 ALdouble dval;
1507 Context = GetContextRef();
1508 if(!Context) return;
1510 if((Source=LookupSource(Context, source)) == NULL)
1511 alSetError(Context, AL_INVALID_NAME);
1512 else if(!value)
1513 alSetError(Context, AL_INVALID_VALUE);
1514 else switch(param)
1516 case AL_PITCH:
1517 case AL_GAIN:
1518 case AL_MIN_GAIN:
1519 case AL_MAX_GAIN:
1520 case AL_MAX_DISTANCE:
1521 case AL_ROLLOFF_FACTOR:
1522 case AL_CONE_OUTER_GAIN:
1523 case AL_CONE_OUTER_GAINHF:
1524 case AL_SEC_OFFSET:
1525 case AL_SAMPLE_OFFSET:
1526 case AL_BYTE_OFFSET:
1527 case AL_CONE_INNER_ANGLE:
1528 case AL_CONE_OUTER_ANGLE:
1529 case AL_REFERENCE_DISTANCE:
1530 case AL_AIR_ABSORPTION_FACTOR:
1531 case AL_ROOM_ROLLOFF_FACTOR:
1532 case AL_DOPPLER_FACTOR:
1533 if(GetSourcedv(Source, Context, param, &dval) == AL_NO_ERROR)
1534 *value = (ALfloat)dval;
1535 break;
1537 default:
1538 alSetError(Context, AL_INVALID_ENUM);
1541 ALCcontext_DecRef(Context);
1545 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1547 ALCcontext *Context;
1548 ALsource *Source;
1549 ALdouble dvals[3];
1551 Context = GetContextRef();
1552 if(!Context) return;
1554 if((Source=LookupSource(Context, source)) == NULL)
1555 alSetError(Context, AL_INVALID_NAME);
1556 else if(!(value1 && value2 && value3))
1557 alSetError(Context, AL_INVALID_VALUE);
1558 else switch(param)
1560 case AL_POSITION:
1561 case AL_VELOCITY:
1562 case AL_DIRECTION:
1563 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1565 *value1 = (ALfloat)dvals[0];
1566 *value2 = (ALfloat)dvals[1];
1567 *value3 = (ALfloat)dvals[2];
1569 break;
1571 default:
1572 alSetError(Context, AL_INVALID_ENUM);
1575 ALCcontext_DecRef(Context);
1579 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1581 ALCcontext *Context;
1582 ALsource *Source;
1583 ALdouble dvals[2];
1585 switch(param)
1587 case AL_PITCH:
1588 case AL_GAIN:
1589 case AL_MIN_GAIN:
1590 case AL_MAX_GAIN:
1591 case AL_MAX_DISTANCE:
1592 case AL_ROLLOFF_FACTOR:
1593 case AL_DOPPLER_FACTOR:
1594 case AL_CONE_OUTER_GAIN:
1595 case AL_SEC_OFFSET:
1596 case AL_SAMPLE_OFFSET:
1597 case AL_BYTE_OFFSET:
1598 case AL_CONE_INNER_ANGLE:
1599 case AL_CONE_OUTER_ANGLE:
1600 case AL_REFERENCE_DISTANCE:
1601 case AL_CONE_OUTER_GAINHF:
1602 case AL_AIR_ABSORPTION_FACTOR:
1603 case AL_ROOM_ROLLOFF_FACTOR:
1604 alGetSourcef(source, param, values);
1605 return;
1607 case AL_POSITION:
1608 case AL_VELOCITY:
1609 case AL_DIRECTION:
1610 alGetSource3f(source, param, values+0, values+1, values+2);
1611 return;
1614 Context = GetContextRef();
1615 if(!Context) return;
1617 if((Source=LookupSource(Context, source)) == NULL)
1618 alSetError(Context, AL_INVALID_NAME);
1619 else if(!values)
1620 alSetError(Context, AL_INVALID_VALUE);
1621 else switch(param)
1623 case AL_SAMPLE_RW_OFFSETS_SOFT:
1624 case AL_BYTE_RW_OFFSETS_SOFT:
1625 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1627 values[0] = (ALfloat)dvals[0];
1628 values[1] = (ALfloat)dvals[1];
1630 break;
1632 default:
1633 alSetError(Context, AL_INVALID_ENUM);
1636 ALCcontext_DecRef(Context);
1640 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1642 ALCcontext *Context;
1643 ALsource *Source;
1645 Context = GetContextRef();
1646 if(!Context) return;
1648 if((Source=LookupSource(Context, source)) == NULL)
1649 alSetError(Context, AL_INVALID_NAME);
1650 else if(!value)
1651 alSetError(Context, AL_INVALID_VALUE);
1652 else switch(param)
1654 case AL_PITCH:
1655 case AL_GAIN:
1656 case AL_MIN_GAIN:
1657 case AL_MAX_GAIN:
1658 case AL_MAX_DISTANCE:
1659 case AL_ROLLOFF_FACTOR:
1660 case AL_CONE_OUTER_GAIN:
1661 case AL_CONE_OUTER_GAINHF:
1662 case AL_SEC_OFFSET:
1663 case AL_SAMPLE_OFFSET:
1664 case AL_BYTE_OFFSET:
1665 case AL_CONE_INNER_ANGLE:
1666 case AL_CONE_OUTER_ANGLE:
1667 case AL_REFERENCE_DISTANCE:
1668 case AL_AIR_ABSORPTION_FACTOR:
1669 case AL_ROOM_ROLLOFF_FACTOR:
1670 case AL_DOPPLER_FACTOR:
1671 GetSourcedv(Source, Context, param, value);
1672 break;
1674 default:
1675 alSetError(Context, AL_INVALID_ENUM);
1678 ALCcontext_DecRef(Context);
1681 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1683 ALCcontext *Context;
1684 ALsource *Source;
1685 ALdouble dvals[3];
1687 Context = GetContextRef();
1688 if(!Context) return;
1690 if((Source=LookupSource(Context, source)) == NULL)
1691 alSetError(Context, AL_INVALID_NAME);
1692 else if(!(value1 && value2 && value3))
1693 alSetError(Context, AL_INVALID_VALUE);
1694 else switch(param)
1696 case AL_POSITION:
1697 case AL_VELOCITY:
1698 case AL_DIRECTION:
1699 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1701 *value1 = dvals[0];
1702 *value2 = dvals[1];
1703 *value3 = dvals[2];
1705 break;
1707 default:
1708 alSetError(Context, AL_INVALID_ENUM);
1711 ALCcontext_DecRef(Context);
1714 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1716 ALCcontext *Context;
1717 ALsource *Source;
1719 Context = GetContextRef();
1720 if(!Context) return;
1722 if((Source=LookupSource(Context, source)) == NULL)
1723 alSetError(Context, AL_INVALID_NAME);
1724 else if(!values)
1725 alSetError(Context, AL_INVALID_VALUE);
1726 else switch(param)
1728 case AL_PITCH:
1729 case AL_GAIN:
1730 case AL_MIN_GAIN:
1731 case AL_MAX_GAIN:
1732 case AL_MAX_DISTANCE:
1733 case AL_ROLLOFF_FACTOR:
1734 case AL_DOPPLER_FACTOR:
1735 case AL_CONE_OUTER_GAIN:
1736 case AL_SEC_OFFSET:
1737 case AL_SAMPLE_OFFSET:
1738 case AL_BYTE_OFFSET:
1739 case AL_CONE_INNER_ANGLE:
1740 case AL_CONE_OUTER_ANGLE:
1741 case AL_REFERENCE_DISTANCE:
1742 case AL_CONE_OUTER_GAINHF:
1743 case AL_AIR_ABSORPTION_FACTOR:
1744 case AL_ROOM_ROLLOFF_FACTOR:
1746 case AL_SAMPLE_RW_OFFSETS_SOFT:
1747 case AL_BYTE_RW_OFFSETS_SOFT:
1748 case AL_SEC_OFFSET_LATENCY_SOFT:
1750 case AL_POSITION:
1751 case AL_VELOCITY:
1752 case AL_DIRECTION:
1753 GetSourcedv(Source, Context, param, values);
1754 break;
1756 default:
1757 alSetError(Context, AL_INVALID_ENUM);
1760 ALCcontext_DecRef(Context);
1764 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1766 ALCcontext *Context;
1767 ALsource *Source;
1769 Context = GetContextRef();
1770 if(!Context) return;
1772 if((Source=LookupSource(Context, source)) == NULL)
1773 alSetError(Context, AL_INVALID_NAME);
1774 else if(!value)
1775 alSetError(Context, AL_INVALID_VALUE);
1776 else switch(param)
1778 case AL_MAX_DISTANCE:
1779 case AL_ROLLOFF_FACTOR:
1780 case AL_REFERENCE_DISTANCE:
1781 case AL_SOURCE_RELATIVE:
1782 case AL_CONE_INNER_ANGLE:
1783 case AL_CONE_OUTER_ANGLE:
1784 case AL_LOOPING:
1785 case AL_BUFFER:
1786 case AL_SOURCE_STATE:
1787 case AL_BUFFERS_QUEUED:
1788 case AL_BUFFERS_PROCESSED:
1789 case AL_SOURCE_TYPE:
1790 case AL_SEC_OFFSET:
1791 case AL_SAMPLE_OFFSET:
1792 case AL_BYTE_OFFSET:
1793 case AL_DIRECT_FILTER_GAINHF_AUTO:
1794 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1795 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1796 case AL_DOPPLER_FACTOR:
1797 case AL_DIRECT_CHANNELS_SOFT:
1798 case AL_DISTANCE_MODEL:
1799 GetSourceiv(Source, Context, param, value);
1800 break;
1802 default:
1803 alSetError(Context, AL_INVALID_ENUM);
1806 ALCcontext_DecRef(Context);
1810 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
1812 ALCcontext *Context;
1813 ALsource *Source;
1814 ALint ivals[3];
1816 Context = GetContextRef();
1817 if(!Context) return;
1819 if((Source=LookupSource(Context, source)) == NULL)
1820 alSetError(Context, AL_INVALID_NAME);
1821 else if(!(value1 && value2 && value3))
1822 alSetError(Context, AL_INVALID_VALUE);
1823 else switch(param)
1825 case AL_POSITION:
1826 case AL_VELOCITY:
1827 case AL_DIRECTION:
1828 if(GetSourceiv(Source, Context, param, ivals) == AL_NO_ERROR)
1830 *value1 = ivals[0];
1831 *value2 = ivals[1];
1832 *value3 = ivals[2];
1834 break;
1836 default:
1837 alSetError(Context, AL_INVALID_ENUM);
1840 ALCcontext_DecRef(Context);
1844 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
1846 ALCcontext *Context;
1847 ALsource *Source;
1849 Context = GetContextRef();
1850 if(!Context) return;
1852 if((Source=LookupSource(Context, source)) == NULL)
1853 alSetError(Context, AL_INVALID_NAME);
1854 else if(!values)
1855 alSetError(Context, AL_INVALID_VALUE);
1856 else switch(param)
1858 case AL_SOURCE_RELATIVE:
1859 case AL_CONE_INNER_ANGLE:
1860 case AL_CONE_OUTER_ANGLE:
1861 case AL_LOOPING:
1862 case AL_BUFFER:
1863 case AL_SOURCE_STATE:
1864 case AL_BUFFERS_QUEUED:
1865 case AL_BUFFERS_PROCESSED:
1866 case AL_SEC_OFFSET:
1867 case AL_SAMPLE_OFFSET:
1868 case AL_BYTE_OFFSET:
1869 case AL_MAX_DISTANCE:
1870 case AL_ROLLOFF_FACTOR:
1871 case AL_DOPPLER_FACTOR:
1872 case AL_REFERENCE_DISTANCE:
1873 case AL_SOURCE_TYPE:
1874 case AL_DIRECT_FILTER:
1875 case AL_DIRECT_FILTER_GAINHF_AUTO:
1876 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1877 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1878 case AL_DISTANCE_MODEL:
1879 case AL_DIRECT_CHANNELS_SOFT:
1881 case AL_SAMPLE_RW_OFFSETS_SOFT:
1882 case AL_BYTE_RW_OFFSETS_SOFT:
1884 case AL_POSITION:
1885 case AL_VELOCITY:
1886 case AL_DIRECTION:
1887 GetSourceiv(Source, Context, param, values);
1888 break;
1890 default:
1891 alSetError(Context, AL_INVALID_ENUM);
1894 ALCcontext_DecRef(Context);
1898 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
1900 ALCcontext *Context;
1901 ALsource *Source;
1903 Context = GetContextRef();
1904 if(!Context) return;
1906 if((Source=LookupSource(Context, source)) == NULL)
1907 alSetError(Context, AL_INVALID_NAME);
1908 else if(!value)
1909 alSetError(Context, AL_INVALID_VALUE);
1910 else switch(param)
1912 case AL_MAX_DISTANCE:
1913 case AL_ROLLOFF_FACTOR:
1914 case AL_REFERENCE_DISTANCE:
1915 case AL_SOURCE_RELATIVE:
1916 case AL_CONE_INNER_ANGLE:
1917 case AL_CONE_OUTER_ANGLE:
1918 case AL_LOOPING:
1919 case AL_BUFFER:
1920 case AL_SOURCE_STATE:
1921 case AL_BUFFERS_QUEUED:
1922 case AL_BUFFERS_PROCESSED:
1923 case AL_SOURCE_TYPE:
1924 case AL_SEC_OFFSET:
1925 case AL_SAMPLE_OFFSET:
1926 case AL_BYTE_OFFSET:
1927 case AL_DIRECT_FILTER_GAINHF_AUTO:
1928 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1929 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1930 case AL_DOPPLER_FACTOR:
1931 case AL_DIRECT_CHANNELS_SOFT:
1932 case AL_DISTANCE_MODEL:
1933 GetSourcei64v(Source, Context, param, value);
1934 break;
1936 default:
1937 alSetError(Context, AL_INVALID_ENUM);
1940 ALCcontext_DecRef(Context);
1943 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
1945 ALCcontext *Context;
1946 ALsource *Source;
1947 ALint64 i64vals[3];
1949 Context = GetContextRef();
1950 if(!Context) return;
1952 if((Source=LookupSource(Context, source)) == NULL)
1953 alSetError(Context, AL_INVALID_NAME);
1954 else if(!(value1 && value2 && value3))
1955 alSetError(Context, AL_INVALID_VALUE);
1956 else switch(param)
1958 case AL_POSITION:
1959 case AL_VELOCITY:
1960 case AL_DIRECTION:
1961 if(GetSourcei64v(Source, Context, param, i64vals) == AL_NO_ERROR)
1963 *value1 = i64vals[0];
1964 *value2 = i64vals[1];
1965 *value3 = i64vals[2];
1967 break;
1969 default:
1970 alSetError(Context, AL_INVALID_ENUM);
1973 ALCcontext_DecRef(Context);
1976 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
1978 ALCcontext *Context;
1979 ALsource *Source;
1981 Context = GetContextRef();
1982 if(!Context) return;
1984 if((Source=LookupSource(Context, source)) == NULL)
1985 alSetError(Context, AL_INVALID_NAME);
1986 else if(!values)
1987 alSetError(Context, AL_INVALID_VALUE);
1988 else switch(param)
1990 case AL_MAX_DISTANCE:
1991 case AL_ROLLOFF_FACTOR:
1992 case AL_REFERENCE_DISTANCE:
1993 case AL_SOURCE_RELATIVE:
1994 case AL_CONE_INNER_ANGLE:
1995 case AL_CONE_OUTER_ANGLE:
1996 case AL_LOOPING:
1997 case AL_BUFFER:
1998 case AL_SOURCE_STATE:
1999 case AL_BUFFERS_QUEUED:
2000 case AL_BUFFERS_PROCESSED:
2001 case AL_SOURCE_TYPE:
2002 case AL_SEC_OFFSET:
2003 case AL_SAMPLE_OFFSET:
2004 case AL_BYTE_OFFSET:
2005 case AL_DIRECT_FILTER_GAINHF_AUTO:
2006 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
2007 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
2008 case AL_DOPPLER_FACTOR:
2009 case AL_DIRECT_CHANNELS_SOFT:
2010 case AL_DISTANCE_MODEL:
2012 case AL_SAMPLE_RW_OFFSETS_SOFT:
2013 case AL_BYTE_RW_OFFSETS_SOFT:
2014 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
2016 case AL_POSITION:
2017 case AL_VELOCITY:
2018 case AL_DIRECTION:
2019 GetSourcei64v(Source, Context, param, values);
2020 break;
2022 default:
2023 alSetError(Context, AL_INVALID_ENUM);
2026 ALCcontext_DecRef(Context);
2030 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2032 alSourcePlayv(1, &source);
2034 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2036 ALCcontext *Context;
2037 ALsource *Source;
2038 ALsizei i;
2040 Context = GetContextRef();
2041 if(!Context) return;
2043 al_try
2045 CHECK_VALUE(Context, n >= 0);
2046 for(i = 0;i < n;i++)
2048 if(!LookupSource(Context, sources[i]))
2049 al_throwerr(Context, AL_INVALID_NAME);
2052 LockContext(Context);
2053 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
2055 void *temp = NULL;
2056 ALsizei newcount;
2058 newcount = Context->MaxActiveSources << 1;
2059 if(newcount > 0)
2060 temp = realloc(Context->ActiveSources,
2061 sizeof(*Context->ActiveSources) * newcount);
2062 if(!temp)
2064 UnlockContext(Context);
2065 al_throwerr(Context, AL_OUT_OF_MEMORY);
2068 Context->ActiveSources = temp;
2069 Context->MaxActiveSources = newcount;
2072 for(i = 0;i < n;i++)
2074 Source = LookupSource(Context, sources[i]);
2075 if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
2076 else SetSourceState(Source, Context, AL_PLAYING);
2078 UnlockContext(Context);
2080 al_endtry;
2082 ALCcontext_DecRef(Context);
2085 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2087 alSourcePausev(1, &source);
2089 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2091 ALCcontext *Context;
2092 ALsource *Source;
2093 ALsizei i;
2095 Context = GetContextRef();
2096 if(!Context) return;
2098 al_try
2100 CHECK_VALUE(Context, n >= 0);
2101 for(i = 0;i < n;i++)
2103 if(!LookupSource(Context, sources[i]))
2104 al_throwerr(Context, AL_INVALID_NAME);
2107 LockContext(Context);
2108 for(i = 0;i < n;i++)
2110 Source = LookupSource(Context, sources[i]);
2111 if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
2112 else SetSourceState(Source, Context, AL_PAUSED);
2114 UnlockContext(Context);
2116 al_endtry;
2118 ALCcontext_DecRef(Context);
2121 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2123 alSourceStopv(1, &source);
2125 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2127 ALCcontext *Context;
2128 ALsource *Source;
2129 ALsizei i;
2131 Context = GetContextRef();
2132 if(!Context) return;
2134 al_try
2136 CHECK_VALUE(Context, n >= 0);
2137 for(i = 0;i < n;i++)
2139 if(!LookupSource(Context, sources[i]))
2140 al_throwerr(Context, AL_INVALID_NAME);
2143 LockContext(Context);
2144 for(i = 0;i < n;i++)
2146 Source = LookupSource(Context, sources[i]);
2147 Source->new_state = AL_NONE;
2148 SetSourceState(Source, Context, AL_STOPPED);
2150 UnlockContext(Context);
2152 al_endtry;
2154 ALCcontext_DecRef(Context);
2157 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2159 alSourceRewindv(1, &source);
2161 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2163 ALCcontext *Context;
2164 ALsource *Source;
2165 ALsizei i;
2167 Context = GetContextRef();
2168 if(!Context) return;
2170 al_try
2172 CHECK_VALUE(Context, n >= 0);
2173 for(i = 0;i < n;i++)
2175 if(!LookupSource(Context, sources[i]))
2176 al_throwerr(Context, AL_INVALID_NAME);
2179 LockContext(Context);
2180 for(i = 0;i < n;i++)
2182 Source = LookupSource(Context, sources[i]);
2183 Source->new_state = AL_NONE;
2184 SetSourceState(Source, Context, AL_INITIAL);
2186 UnlockContext(Context);
2188 al_endtry;
2190 ALCcontext_DecRef(Context);
2194 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers)
2196 ALCcontext *Context;
2197 ALsource *Source;
2198 ALsizei i;
2199 ALbufferlistitem *BufferListStart = NULL;
2200 ALbufferlistitem *BufferList;
2201 ALbuffer *BufferFmt;
2203 if(nb == 0)
2204 return;
2206 Context = GetContextRef();
2207 if(!Context) return;
2209 al_try
2211 ALCdevice *device = Context->Device;
2213 CHECK_VALUE(Context, nb >= 0);
2215 if((Source=LookupSource(Context, source)) == NULL)
2216 al_throwerr(Context, AL_INVALID_NAME);
2218 LockContext(Context);
2219 if(Source->SourceType == AL_STATIC)
2221 UnlockContext(Context);
2222 /* Can't queue on a Static Source */
2223 al_throwerr(Context, AL_INVALID_OPERATION);
2226 BufferFmt = NULL;
2228 /* Check for a valid Buffer, for its frequency and format */
2229 BufferList = Source->queue;
2230 while(BufferList)
2232 if(BufferList->buffer)
2234 BufferFmt = BufferList->buffer;
2235 break;
2237 BufferList = BufferList->next;
2240 for(i = 0;i < nb;i++)
2242 ALbuffer *buffer = NULL;
2243 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2245 UnlockContext(Context);
2246 al_throwerr(Context, AL_INVALID_NAME);
2249 if(!BufferListStart)
2251 BufferListStart = malloc(sizeof(ALbufferlistitem));
2252 BufferListStart->buffer = buffer;
2253 BufferListStart->next = NULL;
2254 BufferListStart->prev = NULL;
2255 BufferList = BufferListStart;
2257 else
2259 BufferList->next = malloc(sizeof(ALbufferlistitem));
2260 BufferList->next->buffer = buffer;
2261 BufferList->next->next = NULL;
2262 BufferList->next->prev = BufferList;
2263 BufferList = BufferList->next;
2265 if(!buffer) continue;
2266 IncrementRef(&buffer->ref);
2268 ReadLock(&buffer->lock);
2269 if(BufferFmt == NULL)
2271 BufferFmt = buffer;
2273 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2274 Source->SampleSize = BytesFromFmt(buffer->FmtType);
2275 if(buffer->FmtChannels == FmtMono)
2276 Source->Update = CalcSourceParams;
2277 else
2278 Source->Update = CalcNonAttnSourceParams;
2280 Source->NeedsUpdate = AL_TRUE;
2282 else if(BufferFmt->Frequency != buffer->Frequency ||
2283 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2284 BufferFmt->OriginalType != buffer->OriginalType)
2286 ReadUnlock(&buffer->lock);
2287 UnlockContext(Context);
2288 al_throwerr(Context, AL_INVALID_OPERATION);
2290 ReadUnlock(&buffer->lock);
2293 /* Source is now streaming */
2294 Source->SourceType = AL_STREAMING;
2296 if(Source->queue == NULL)
2297 Source->queue = BufferListStart;
2298 else
2300 /* Append to the end of the queue */
2301 BufferList = Source->queue;
2302 while(BufferList->next != NULL)
2303 BufferList = BufferList->next;
2305 BufferListStart->prev = BufferList;
2306 BufferList->next = BufferListStart;
2309 Source->BuffersInQueue += nb;
2311 UnlockContext(Context);
2313 al_catchany()
2315 while(BufferListStart)
2317 BufferList = BufferListStart;
2318 BufferListStart = BufferList->next;
2320 if(BufferList->buffer)
2321 DecrementRef(&BufferList->buffer->ref);
2322 free(BufferList);
2325 al_endtry;
2327 ALCcontext_DecRef(Context);
2330 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers)
2332 ALCcontext *Context;
2333 ALsource *Source;
2334 ALsizei i;
2335 ALbufferlistitem *BufferList;
2337 if(nb == 0)
2338 return;
2340 Context = GetContextRef();
2341 if(!Context) return;
2343 al_try
2345 CHECK_VALUE(Context, nb >= 0);
2347 if((Source=LookupSource(Context, source)) == NULL)
2348 al_throwerr(Context, AL_INVALID_NAME);
2350 LockContext(Context);
2351 if(Source->Looping || Source->SourceType != AL_STREAMING ||
2352 (ALuint)nb > Source->BuffersPlayed)
2354 UnlockContext(Context);
2355 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2356 al_throwerr(Context, AL_INVALID_VALUE);
2359 for(i = 0;i < nb;i++)
2361 BufferList = Source->queue;
2362 Source->queue = BufferList->next;
2363 Source->BuffersInQueue--;
2364 Source->BuffersPlayed--;
2366 if(BufferList->buffer)
2368 buffers[i] = BufferList->buffer->id;
2369 DecrementRef(&BufferList->buffer->ref);
2371 else
2372 buffers[i] = 0;
2374 free(BufferList);
2376 if(Source->queue)
2377 Source->queue->prev = NULL;
2378 UnlockContext(Context);
2380 al_endtry;
2382 ALCcontext_DecRef(Context);
2386 static ALvoid InitSourceParams(ALsource *Source)
2388 ALuint i;
2390 Source->InnerAngle = 360.0f;
2391 Source->OuterAngle = 360.0f;
2392 Source->Pitch = 1.0f;
2393 Source->Position[0] = 0.0f;
2394 Source->Position[1] = 0.0f;
2395 Source->Position[2] = 0.0f;
2396 Source->Orientation[0] = 0.0f;
2397 Source->Orientation[1] = 0.0f;
2398 Source->Orientation[2] = 0.0f;
2399 Source->Velocity[0] = 0.0f;
2400 Source->Velocity[1] = 0.0f;
2401 Source->Velocity[2] = 0.0f;
2402 Source->RefDistance = 1.0f;
2403 Source->MaxDistance = FLT_MAX;
2404 Source->RollOffFactor = 1.0f;
2405 Source->Looping = AL_FALSE;
2406 Source->Gain = 1.0f;
2407 Source->MinGain = 0.0f;
2408 Source->MaxGain = 1.0f;
2409 Source->OuterGain = 0.0f;
2410 Source->OuterGainHF = 1.0f;
2412 Source->DryGainHFAuto = AL_TRUE;
2413 Source->WetGainAuto = AL_TRUE;
2414 Source->WetGainHFAuto = AL_TRUE;
2415 Source->AirAbsorptionFactor = 0.0f;
2416 Source->RoomRolloffFactor = 0.0f;
2417 Source->DopplerFactor = 1.0f;
2418 Source->DirectChannels = AL_FALSE;
2420 Source->DistanceModel = DefaultDistanceModel;
2422 Source->Resampler = DefaultResampler;
2424 Source->state = AL_INITIAL;
2425 Source->new_state = AL_NONE;
2426 Source->SourceType = AL_UNDETERMINED;
2427 Source->Offset = -1.0;
2429 Source->DirectGain = 1.0f;
2430 Source->DirectGainHF = 1.0f;
2431 for(i = 0;i < MAX_SENDS;i++)
2433 Source->Send[i].Gain = 1.0f;
2434 Source->Send[i].GainHF = 1.0f;
2437 Source->NeedsUpdate = AL_TRUE;
2439 Source->Hrtf.Moving = AL_FALSE;
2440 Source->Hrtf.Counter = 0;
2444 /* SetSourceState
2446 * Sets the source's new play state given its current state.
2448 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2450 if(state == AL_PLAYING)
2452 ALbufferlistitem *BufferList;
2453 ALsizei j, k;
2455 /* Check that there is a queue containing at least one valid, non zero
2456 * length Buffer. */
2457 BufferList = Source->queue;
2458 while(BufferList)
2460 if(BufferList->buffer != NULL && BufferList->buffer->SampleLen)
2461 break;
2462 BufferList = BufferList->next;
2465 if(Source->state != AL_PLAYING)
2467 for(j = 0;j < MaxChannels;j++)
2469 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
2470 Source->Hrtf.History[j][k] = 0.0f;
2471 for(k = 0;k < HRIR_LENGTH;k++)
2473 Source->Hrtf.Values[j][k][0] = 0.0f;
2474 Source->Hrtf.Values[j][k][1] = 0.0f;
2479 if(Source->state != AL_PAUSED)
2481 Source->state = AL_PLAYING;
2482 Source->position = 0;
2483 Source->position_fraction = 0;
2484 Source->BuffersPlayed = 0;
2486 else
2487 Source->state = AL_PLAYING;
2489 // Check if an Offset has been set
2490 if(Source->Offset >= 0.0)
2491 ApplyOffset(Source);
2493 /* If there's nothing to play, or device is disconnected, go right to
2494 * stopped */
2495 if(!BufferList || !Context->Device->Connected)
2497 SetSourceState(Source, Context, AL_STOPPED);
2498 return;
2501 for(j = 0;j < Context->ActiveSourceCount;j++)
2503 if(Context->ActiveSources[j] == Source)
2504 break;
2506 if(j == Context->ActiveSourceCount)
2507 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
2509 else if(state == AL_PAUSED)
2511 if(Source->state == AL_PLAYING)
2513 Source->state = AL_PAUSED;
2514 Source->Hrtf.Moving = AL_FALSE;
2515 Source->Hrtf.Counter = 0;
2518 else if(state == AL_STOPPED)
2520 if(Source->state != AL_INITIAL)
2522 Source->state = AL_STOPPED;
2523 Source->BuffersPlayed = Source->BuffersInQueue;
2524 Source->Hrtf.Moving = AL_FALSE;
2525 Source->Hrtf.Counter = 0;
2527 Source->Offset = -1.0;
2529 else if(state == AL_INITIAL)
2531 if(Source->state != AL_INITIAL)
2533 Source->state = AL_INITIAL;
2534 Source->position = 0;
2535 Source->position_fraction = 0;
2536 Source->BuffersPlayed = 0;
2537 Source->Hrtf.Moving = AL_FALSE;
2538 Source->Hrtf.Counter = 0;
2540 Source->Offset = -1.0;
2544 /* GetSourceOffset
2546 * Gets the current read offset for the given Source, in 32.32 fixed-point
2547 * samples. The offset is relative to the start of the queue (not the start of
2548 * the current buffer).
2550 static ALint64 GetSourceOffset(const ALsource *Source)
2552 const ALbufferlistitem *BufferList;
2553 ALuint64 readPos;
2554 ALuint i;
2556 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2557 return 0;
2559 /* NOTE: This is the offset into the *current* buffer, so add the length of
2560 * any played buffers */
2561 readPos = (ALuint64)Source->position << 32;
2562 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2563 BufferList = Source->queue;
2564 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2566 if(BufferList->buffer)
2567 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2568 BufferList = BufferList->next;
2571 return (ALint64)minu64(readPos, MAKEU64(0x7fffffff,0xffffffff));
2574 /* GetSourceSecOffset
2576 * Gets the current read offset for the given Source, in seconds. The offset is
2577 * relative to the start of the queue (not the start of the current buffer).
2579 static ALdouble GetSourceSecOffset(const ALsource *Source)
2581 const ALbufferlistitem *BufferList;
2582 const ALbuffer *Buffer = NULL;
2583 ALuint64 readPos;
2584 ALuint i;
2586 BufferList = Source->queue;
2587 while(BufferList)
2589 if(BufferList->buffer)
2591 Buffer = BufferList->buffer;
2592 break;
2594 BufferList = BufferList->next;
2597 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2598 return 0.0;
2600 /* NOTE: This is the offset into the *current* buffer, so add the length of
2601 * any played buffers */
2602 readPos = (ALuint64)Source->position << FRACTIONBITS;
2603 readPos |= (ALuint64)Source->position_fraction;
2604 BufferList = Source->queue;
2605 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2607 if(BufferList->buffer)
2608 readPos += (ALuint64)BufferList->buffer->SampleLen << FRACTIONBITS;
2609 BufferList = BufferList->next;
2612 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2615 /* GetSourceOffsets
2617 * Gets the current read and write offsets for the given Source, in the
2618 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2619 * the start of the queue (not the start of the current buffer).
2621 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2623 const ALbufferlistitem *BufferList;
2624 const ALbuffer *Buffer = NULL;
2625 ALuint readPos, writePos;
2626 ALuint totalBufferLen;
2627 ALuint i;
2629 // Find the first valid Buffer in the Queue
2630 BufferList = Source->queue;
2631 while(BufferList)
2633 if(BufferList->buffer)
2635 Buffer = BufferList->buffer;
2636 break;
2638 BufferList = BufferList->next;
2641 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2643 offset[0] = 0.0;
2644 offset[1] = 0.0;
2645 return;
2648 if(updateLen > 0.0 && updateLen < 0.015)
2649 updateLen = 0.015;
2651 /* NOTE: This is the offset into the *current* buffer, so add the length of
2652 * any played buffers */
2653 readPos = Source->position;
2654 totalBufferLen = 0;
2655 BufferList = Source->queue;
2656 for(i = 0;BufferList;i++)
2658 if(BufferList->buffer)
2660 if(i < Source->BuffersPlayed)
2661 readPos += BufferList->buffer->SampleLen;
2662 totalBufferLen += BufferList->buffer->SampleLen;
2664 BufferList = BufferList->next;
2666 if(Source->state == AL_PLAYING)
2667 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
2668 else
2669 writePos = readPos;
2671 if(Source->Looping)
2673 readPos %= totalBufferLen;
2674 writePos %= totalBufferLen;
2676 else
2678 /* Wrap positions back to 0 */
2679 if(readPos >= totalBufferLen)
2680 readPos = 0;
2681 if(writePos >= totalBufferLen)
2682 writePos = 0;
2685 switch(name)
2687 case AL_SEC_OFFSET:
2688 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2689 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2690 break;
2692 case AL_SAMPLE_OFFSET:
2693 case AL_SAMPLE_RW_OFFSETS_SOFT:
2694 offset[0] = (ALdouble)readPos;
2695 offset[1] = (ALdouble)writePos;
2696 break;
2698 case AL_BYTE_OFFSET:
2699 case AL_BYTE_RW_OFFSETS_SOFT:
2700 if(Buffer->OriginalType == UserFmtIMA4)
2702 ALuint BlockSize = 36 * ChannelsFromFmt(Buffer->FmtChannels);
2703 ALuint FrameBlockSize = 65;
2705 /* Round down to nearest ADPCM block */
2706 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2707 if(Source->state != AL_PLAYING)
2708 offset[1] = offset[0];
2709 else
2711 /* Round up to nearest ADPCM block */
2712 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2713 FrameBlockSize * BlockSize);
2716 else
2718 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2719 offset[0] = (ALdouble)(readPos * FrameSize);
2720 offset[1] = (ALdouble)(writePos * FrameSize);
2722 break;
2727 /* ApplyOffset
2729 * Apply the stored playback offset to the Source. This function will update
2730 * the number of buffers "played" given the stored offset.
2732 ALboolean ApplyOffset(ALsource *Source)
2734 const ALbufferlistitem *BufferList;
2735 const ALbuffer *Buffer;
2736 ALint bufferLen, totalBufferLen;
2737 ALint buffersPlayed;
2738 ALint offset;
2740 /* Get sample frame offset */
2741 offset = GetSampleOffset(Source);
2742 if(offset == -1)
2743 return AL_FALSE;
2745 buffersPlayed = 0;
2746 totalBufferLen = 0;
2748 BufferList = Source->queue;
2749 while(BufferList)
2751 Buffer = BufferList->buffer;
2752 bufferLen = Buffer ? Buffer->SampleLen : 0;
2754 if(bufferLen <= offset-totalBufferLen)
2756 /* Offset is past this buffer so increment to the next buffer */
2757 buffersPlayed++;
2759 else if(totalBufferLen <= offset)
2761 /* Offset is in this buffer */
2762 Source->BuffersPlayed = buffersPlayed;
2764 Source->position = offset - totalBufferLen;
2765 Source->position_fraction = 0;
2766 return AL_TRUE;
2769 totalBufferLen += bufferLen;
2771 BufferList = BufferList->next;
2774 /* Offset is out of range of the queue */
2775 return AL_FALSE;
2779 /* GetSampleOffset
2781 * Returns the sample offset into the Source's queue (from the Sample, Byte or
2782 * Second offset supplied by the application). This takes into account the fact
2783 * that the buffer format may have been modifed since.
2785 static ALint GetSampleOffset(ALsource *Source)
2787 const ALbuffer *Buffer = NULL;
2788 const ALbufferlistitem *BufferList;
2789 ALint Offset = -1;
2791 /* Find the first valid Buffer in the Queue */
2792 BufferList = Source->queue;
2793 while(BufferList)
2795 if(BufferList->buffer)
2797 Buffer = BufferList->buffer;
2798 break;
2800 BufferList = BufferList->next;
2803 if(!Buffer)
2805 Source->Offset = -1.0;
2806 return -1;
2809 switch(Source->OffsetType)
2811 case AL_BYTE_OFFSET:
2812 /* Determine the ByteOffset (and ensure it is block aligned) */
2813 Offset = (ALint)Source->Offset;
2814 if(Buffer->OriginalType == UserFmtIMA4)
2816 Offset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
2817 Offset *= 65;
2819 else
2820 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2821 break;
2823 case AL_SAMPLE_OFFSET:
2824 Offset = (ALint)Source->Offset;
2825 break;
2827 case AL_SEC_OFFSET:
2828 Offset = (ALint)(Source->Offset * Buffer->Frequency);
2829 break;
2831 Source->Offset = -1.0;
2833 return Offset;
2837 /* ReleaseALSources
2839 * Destroys all sources in the source map.
2841 ALvoid ReleaseALSources(ALCcontext *Context)
2843 ALsizei pos;
2844 ALuint j;
2845 for(pos = 0;pos < Context->SourceMap.size;pos++)
2847 ALsource *temp = Context->SourceMap.array[pos].value;
2848 Context->SourceMap.array[pos].value = NULL;
2850 while(temp->queue != NULL)
2852 ALbufferlistitem *BufferList = temp->queue;
2853 temp->queue = BufferList->next;
2855 if(BufferList->buffer != NULL)
2856 DecrementRef(&BufferList->buffer->ref);
2857 free(BufferList);
2860 for(j = 0;j < MAX_SENDS;++j)
2862 if(temp->Send[j].Slot)
2863 DecrementRef(&temp->Send[j].Slot->ref);
2864 temp->Send[j].Slot = NULL;
2867 FreeThunkEntry(temp->id);
2868 memset(temp, 0, sizeof(*temp));
2869 al_free(temp);