Use a helper method to convert i64 values to the proper types
[openal-soft.git] / OpenAL32 / alSource.c
blob9f5bd8bcee2c44c5796880bc64cd4dedbd8d08d1
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_POSITION:
200 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
202 LockContext(Context);
203 Source->Position[0] = values[0];
204 Source->Position[1] = values[1];
205 Source->Position[2] = values[2];
206 UnlockContext(Context);
207 Source->NeedsUpdate = AL_TRUE;
208 break;
210 case AL_VELOCITY:
211 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
213 LockContext(Context);
214 Source->Velocity[0] = values[0];
215 Source->Velocity[1] = values[1];
216 Source->Velocity[2] = values[2];
217 UnlockContext(Context);
218 Source->NeedsUpdate = AL_TRUE;
219 break;
221 case AL_DIRECTION:
222 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
224 LockContext(Context);
225 Source->Orientation[0] = values[0];
226 Source->Orientation[1] = values[1];
227 Source->Orientation[2] = values[2];
228 UnlockContext(Context);
229 Source->NeedsUpdate = AL_TRUE;
230 break;
233 default:
234 RETERR(AL_INVALID_ENUM);
237 return AL_NO_ERROR;
240 static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, ALenum name, const ALint *values)
242 ALCdevice *device = Context->Device;
243 ALbuffer *buffer = NULL;
244 ALfilter *filter = NULL;
245 ALeffectslot *slot = NULL;
246 ALbufferlistitem *oldlist;
247 ALfloat fvals[3];
248 ALenum err;
250 switch(name)
252 case AL_SOURCE_RELATIVE:
253 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
255 Source->HeadRelative = (ALboolean)*values;
256 Source->NeedsUpdate = AL_TRUE;
257 break;
259 case AL_LOOPING:
260 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
262 Source->Looping = (ALboolean)*values;
263 break;
265 case AL_BUFFER:
266 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
268 LockContext(Context);
269 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
271 UnlockContext(Context);
272 RETERR(AL_INVALID_OPERATION);
275 Source->BuffersInQueue = 0;
276 Source->BuffersPlayed = 0;
278 if(buffer != NULL)
280 ALbufferlistitem *BufferListItem;
282 /* Source is now Static */
283 Source->SourceType = AL_STATIC;
285 /* Add the selected buffer to a one-item queue */
286 BufferListItem = malloc(sizeof(ALbufferlistitem));
287 BufferListItem->buffer = buffer;
288 BufferListItem->next = NULL;
289 BufferListItem->prev = NULL;
290 IncrementRef(&buffer->ref);
292 oldlist = ExchangePtr((XchgPtr*)&Source->queue, BufferListItem);
293 Source->BuffersInQueue = 1;
295 ReadLock(&buffer->lock);
296 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
297 Source->SampleSize = BytesFromFmt(buffer->FmtType);
298 ReadUnlock(&buffer->lock);
299 if(buffer->FmtChannels == FmtMono)
300 Source->Update = CalcSourceParams;
301 else
302 Source->Update = CalcNonAttnSourceParams;
303 Source->NeedsUpdate = AL_TRUE;
305 else
307 /* Source is now Undetermined */
308 Source->SourceType = AL_UNDETERMINED;
309 oldlist = ExchangePtr((XchgPtr*)&Source->queue, NULL);
312 /* Delete all elements in the previous queue */
313 while(oldlist != NULL)
315 ALbufferlistitem *temp = oldlist;
316 oldlist = temp->next;
318 if(temp->buffer)
319 DecrementRef(&temp->buffer->ref);
320 free(temp);
322 UnlockContext(Context);
323 break;
325 case AL_SOURCE_STATE:
326 /* Query only */
327 RETERR(AL_INVALID_OPERATION);
329 case AL_SEC_OFFSET:
330 case AL_SAMPLE_OFFSET:
331 case AL_BYTE_OFFSET:
332 CHECKVAL(*values >= 0);
334 LockContext(Context);
335 Source->OffsetType = name;
336 Source->Offset = *values;
338 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
339 !Context->DeferUpdates)
341 if(ApplyOffset(Source) == AL_FALSE)
343 UnlockContext(Context);
344 RETERR(AL_INVALID_VALUE);
347 UnlockContext(Context);
348 break;
350 case AL_DIRECT_FILTER:
351 CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
353 LockContext(Context);
354 if(!filter)
356 Source->DirectGain = 1.0f;
357 Source->DirectGainHF = 1.0f;
359 else
361 Source->DirectGain = filter->Gain;
362 Source->DirectGainHF = filter->GainHF;
364 UnlockContext(Context);
365 Source->NeedsUpdate = AL_TRUE;
366 break;
368 case AL_DIRECT_FILTER_GAINHF_AUTO:
369 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
371 Source->DryGainHFAuto = *values;
372 Source->NeedsUpdate = AL_TRUE;
373 break;
375 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
376 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
378 Source->WetGainAuto = *values;
379 Source->NeedsUpdate = AL_TRUE;
380 break;
382 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
383 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
385 Source->WetGainHFAuto = *values;
386 Source->NeedsUpdate = AL_TRUE;
387 break;
389 case AL_DIRECT_CHANNELS_SOFT:
390 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
392 Source->DirectChannels = *values;
393 Source->NeedsUpdate = AL_TRUE;
394 break;
396 case AL_DISTANCE_MODEL:
397 CHECKVAL(*values == AL_NONE ||
398 *values == AL_INVERSE_DISTANCE ||
399 *values == AL_INVERSE_DISTANCE_CLAMPED ||
400 *values == AL_LINEAR_DISTANCE ||
401 *values == AL_LINEAR_DISTANCE_CLAMPED ||
402 *values == AL_EXPONENT_DISTANCE ||
403 *values == AL_EXPONENT_DISTANCE_CLAMPED);
405 Source->DistanceModel = *values;
406 if(Context->SourceDistanceModel)
407 Source->NeedsUpdate = AL_TRUE;
408 break;
411 case AL_AUXILIARY_SEND_FILTER:
412 LockContext(Context);
413 if(!((ALuint)values[1] < device->NumAuxSends &&
414 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
415 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
417 UnlockContext(Context);
418 RETERR(AL_INVALID_VALUE);
421 /* Add refcount on the new slot, and release the previous slot */
422 if(slot) IncrementRef(&slot->ref);
423 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
424 if(slot) DecrementRef(&slot->ref);
426 if(!filter)
428 /* Disable filter */
429 Source->Send[values[1]].Gain = 1.0f;
430 Source->Send[values[1]].GainHF = 1.0f;
432 else
434 Source->Send[values[1]].Gain = filter->Gain;
435 Source->Send[values[1]].GainHF = filter->GainHF;
437 Source->NeedsUpdate = AL_TRUE;
438 UnlockContext(Context);
439 break;
442 case AL_MAX_DISTANCE:
443 case AL_ROLLOFF_FACTOR:
444 case AL_CONE_INNER_ANGLE:
445 case AL_CONE_OUTER_ANGLE:
446 case AL_REFERENCE_DISTANCE:
447 fvals[0] = (ALfloat)*values;
448 if((err=SetSourcefv(Source, Context, name, fvals)) != AL_NO_ERROR)
449 return err;
450 break;
452 case AL_POSITION:
453 case AL_VELOCITY:
454 case AL_DIRECTION:
455 fvals[0] = (ALfloat)values[0];
456 fvals[1] = (ALfloat)values[1];
457 fvals[2] = (ALfloat)values[2];
458 if((err=SetSourcefv(Source, Context, name, fvals)) != AL_NO_ERROR)
459 return err;
460 break;
462 default:
463 RETERR(AL_INVALID_ENUM);
466 return AL_NO_ERROR;
469 static ALenum SetSourcei64v(ALsource *Source, ALCcontext *Context, ALenum name, const ALint64SOFT *values)
471 ALfloat fvals[3];
472 ALint ivals[3];
473 ALenum err;
475 switch(name)
477 /* 1x int */
478 case AL_SOURCE_RELATIVE:
479 case AL_LOOPING:
480 case AL_SOURCE_STATE:
481 case AL_BYTE_OFFSET:
482 case AL_SAMPLE_OFFSET:
483 case AL_DIRECT_FILTER_GAINHF_AUTO:
484 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
485 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
486 case AL_DIRECT_CHANNELS_SOFT:
487 case AL_DISTANCE_MODEL:
488 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
490 ivals[0] = *values;
491 if((err=SetSourceiv(Source, Context, name, ivals)))
492 return err;
493 break;
495 /* 1x uint */
496 case AL_BUFFER:
497 case AL_DIRECT_FILTER:
498 CHECKVAL(*values <= UINT_MAX && *values >= 0);
500 ivals[0] = (ALuint)*values;
501 if((err=SetSourceiv(Source, Context, name, ivals)))
502 return err;
503 break;
505 /* 3x uint */
506 case AL_AUXILIARY_SEND_FILTER:
507 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
508 values[1] <= UINT_MAX && values[1] >= 0 &&
509 values[2] <= UINT_MAX && values[2] >= 0);
511 ivals[0] = (ALuint)values[0];
512 ivals[1] = (ALuint)values[1];
513 ivals[2] = (ALuint)values[2];
514 if((err=SetSourceiv(Source, Context, name, ivals)))
515 return err;
516 break;
518 /* 1x float */
519 case AL_MAX_DISTANCE:
520 case AL_ROLLOFF_FACTOR:
521 case AL_CONE_INNER_ANGLE:
522 case AL_CONE_OUTER_ANGLE:
523 case AL_REFERENCE_DISTANCE:
524 case AL_SEC_OFFSET:
525 fvals[0] = (ALfloat)*values;
526 if((err=SetSourcefv(Source, Context, name, fvals)) != AL_NO_ERROR)
527 return err;
528 break;
530 /* 3x float */
531 case AL_POSITION:
532 case AL_VELOCITY:
533 case AL_DIRECTION:
534 fvals[0] = (ALfloat)values[0];
535 fvals[1] = (ALfloat)values[1];
536 fvals[2] = (ALfloat)values[2];
537 if((err=SetSourcefv(Source, Context, name, fvals)) != AL_NO_ERROR)
538 return err;
539 break;
541 default:
542 RETERR(AL_INVALID_ENUM);
545 return AL_NO_ERROR;
548 #undef CHECKVAL
551 static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, ALenum name, ALdouble *values)
553 ALdouble offsets[2];
554 ALdouble updateLen;
555 ALint ivals[3];
556 ALenum err;
558 switch(name)
560 case AL_MAX_DISTANCE:
561 *values = Source->MaxDistance;
562 break;
564 case AL_ROLLOFF_FACTOR:
565 *values = Source->RollOffFactor;
566 break;
568 case AL_REFERENCE_DISTANCE:
569 *values = Source->RefDistance;
570 break;
572 case AL_CONE_INNER_ANGLE:
573 *values = Source->InnerAngle;
574 break;
576 case AL_CONE_OUTER_ANGLE:
577 *values = Source->OuterAngle;
578 break;
580 case AL_SEC_OFFSET:
581 case AL_SAMPLE_OFFSET:
582 case AL_BYTE_OFFSET:
583 LockContext(Context);
584 updateLen = (ALdouble)Context->Device->UpdateSize /
585 Context->Device->Frequency;
586 GetSourceOffsets(Source, name, offsets, updateLen);
587 UnlockContext(Context);
588 *values = offsets[0];
589 break;
591 case AL_CONE_OUTER_GAINHF:
592 *values = Source->OuterGainHF;
593 break;
595 case AL_AIR_ABSORPTION_FACTOR:
596 *values = Source->AirAbsorptionFactor;
597 break;
599 case AL_ROOM_ROLLOFF_FACTOR:
600 *values = Source->RoomRolloffFactor;
601 break;
603 case AL_DOPPLER_FACTOR:
604 *values = Source->DopplerFactor;
605 break;
607 case AL_SAMPLE_RW_OFFSETS_SOFT:
608 case AL_BYTE_RW_OFFSETS_SOFT:
609 LockContext(Context);
610 updateLen = (ALdouble)Context->Device->UpdateSize /
611 Context->Device->Frequency;
612 GetSourceOffsets(Source, name, values, updateLen);
613 UnlockContext(Context);
614 break;
616 case AL_SEC_OFFSET_LATENCY_SOFT:
617 LockContext(Context);
618 values[0] = GetSourceSecOffset(Source);
619 values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) /
620 1000000000.0;
621 UnlockContext(Context);
622 break;
624 case AL_POSITION:
625 LockContext(Context);
626 values[0] = Source->Position[0];
627 values[1] = Source->Position[1];
628 values[2] = Source->Position[2];
629 UnlockContext(Context);
630 break;
632 case AL_VELOCITY:
633 LockContext(Context);
634 values[0] = Source->Velocity[0];
635 values[1] = Source->Velocity[1];
636 values[2] = Source->Velocity[2];
637 UnlockContext(Context);
638 break;
640 case AL_DIRECTION:
641 LockContext(Context);
642 values[0] = Source->Orientation[0];
643 values[1] = Source->Orientation[1];
644 values[2] = Source->Orientation[2];
645 UnlockContext(Context);
646 break;
648 case AL_SOURCE_RELATIVE:
649 case AL_LOOPING:
650 case AL_BUFFER:
651 case AL_SOURCE_STATE:
652 case AL_BUFFERS_QUEUED:
653 case AL_BUFFERS_PROCESSED:
654 case AL_SOURCE_TYPE:
655 case AL_DIRECT_FILTER_GAINHF_AUTO:
656 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
657 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
658 case AL_DIRECT_CHANNELS_SOFT:
659 case AL_DISTANCE_MODEL:
660 if((err=GetSourceiv(Source, Context, name, ivals)) != AL_NO_ERROR)
661 return err;
662 *values = (ALdouble)ivals[0];
663 break;
665 default:
666 RETERR(AL_INVALID_ENUM);
669 return AL_NO_ERROR;
672 static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, ALenum name, ALint *values)
674 ALbufferlistitem *BufferList;
675 ALdouble dvals[3];
676 ALenum err;
678 switch(name)
680 case AL_SOURCE_RELATIVE:
681 *values = Source->HeadRelative;
682 break;
684 case AL_LOOPING:
685 *values = Source->Looping;
686 break;
688 case AL_BUFFER:
689 LockContext(Context);
690 BufferList = Source->queue;
691 if(Source->SourceType != AL_STATIC)
693 ALuint i = Source->BuffersPlayed;
694 while(i > 0)
696 BufferList = BufferList->next;
697 i--;
700 *values = ((BufferList && BufferList->buffer) ?
701 BufferList->buffer->id : 0);
702 UnlockContext(Context);
703 break;
705 case AL_SOURCE_STATE:
706 *values = Source->state;
707 break;
709 case AL_BUFFERS_QUEUED:
710 *values = Source->BuffersInQueue;
711 break;
713 case AL_BUFFERS_PROCESSED:
714 LockContext(Context);
715 if(Source->Looping || Source->SourceType != AL_STREAMING)
717 /* Buffers on a looping source are in a perpetual state of
718 * PENDING, so don't report any as PROCESSED */
719 *values = 0;
721 else
722 *values = Source->BuffersPlayed;
723 UnlockContext(Context);
724 break;
726 case AL_SOURCE_TYPE:
727 *values = Source->SourceType;
728 break;
730 case AL_DIRECT_FILTER_GAINHF_AUTO:
731 *values = Source->DryGainHFAuto;
732 break;
734 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
735 *values = Source->WetGainAuto;
736 break;
738 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
739 *values = Source->WetGainHFAuto;
740 break;
742 case AL_DIRECT_CHANNELS_SOFT:
743 *values = Source->DirectChannels;
744 break;
746 case AL_DISTANCE_MODEL:
747 *values = Source->DistanceModel;
748 break;
750 case AL_MAX_DISTANCE:
751 case AL_ROLLOFF_FACTOR:
752 case AL_REFERENCE_DISTANCE:
753 case AL_CONE_INNER_ANGLE:
754 case AL_CONE_OUTER_ANGLE:
755 case AL_SEC_OFFSET:
756 case AL_SAMPLE_OFFSET:
757 case AL_BYTE_OFFSET:
758 case AL_DOPPLER_FACTOR:
759 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
760 return err;
761 *values = (ALint)dvals[0];
762 break;
764 case AL_SAMPLE_RW_OFFSETS_SOFT:
765 case AL_BYTE_RW_OFFSETS_SOFT:
766 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
767 return err;
768 values[0] = (ALint)dvals[0];
769 values[1] = (ALint)dvals[0];
770 break;
772 case AL_POSITION:
773 case AL_VELOCITY:
774 case AL_DIRECTION:
775 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
776 return err;
777 values[0] = (ALint)dvals[0];
778 values[1] = (ALint)dvals[1];
779 values[2] = (ALint)dvals[2];
780 break;
782 default:
783 RETERR(AL_INVALID_ENUM);
786 return AL_NO_ERROR;
789 static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, ALenum name, ALint64 *values)
791 ALdouble dvals[3];
792 ALint ivals[3];
793 ALenum err;
795 switch(name)
797 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
798 LockContext(Context);
799 values[0] = GetSourceOffset(Source);
800 values[1] = ALCdevice_GetLatency(Context->Device);
801 UnlockContext(Context);
802 break;
804 case AL_MAX_DISTANCE:
805 case AL_ROLLOFF_FACTOR:
806 case AL_REFERENCE_DISTANCE:
807 case AL_CONE_INNER_ANGLE:
808 case AL_CONE_OUTER_ANGLE:
809 case AL_SEC_OFFSET:
810 case AL_SAMPLE_OFFSET:
811 case AL_BYTE_OFFSET:
812 case AL_DOPPLER_FACTOR:
813 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
814 return err;
815 *values = (ALint64)dvals[0];
816 break;
818 case AL_SAMPLE_RW_OFFSETS_SOFT:
819 case AL_BYTE_RW_OFFSETS_SOFT:
820 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
821 return err;
822 values[0] = (ALint64)dvals[0];
823 values[1] = (ALint64)dvals[0];
824 break;
826 case AL_POSITION:
827 case AL_VELOCITY:
828 case AL_DIRECTION:
829 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
830 return err;
831 values[0] = (ALint64)dvals[0];
832 values[1] = (ALint64)dvals[1];
833 values[2] = (ALint64)dvals[2];
834 break;
836 case AL_SOURCE_RELATIVE:
837 case AL_LOOPING:
838 case AL_BUFFER:
839 case AL_SOURCE_STATE:
840 case AL_BUFFERS_QUEUED:
841 case AL_BUFFERS_PROCESSED:
842 case AL_SOURCE_TYPE:
843 case AL_DIRECT_FILTER_GAINHF_AUTO:
844 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
845 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
846 case AL_DIRECT_CHANNELS_SOFT:
847 case AL_DISTANCE_MODEL:
848 if((err=GetSourceiv(Source, Context, name, ivals)) != AL_NO_ERROR)
849 return err;
850 *values = ivals[0];
851 break;
853 default:
854 RETERR(AL_INVALID_ENUM);
857 return AL_NO_ERROR;
860 #undef RETERR
863 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
865 ALCcontext *Context;
866 ALsizei cur = 0;
868 Context = GetContextRef();
869 if(!Context) return;
871 al_try
873 ALenum err;
875 CHECK_VALUE(Context, n >= 0);
876 for(cur = 0;cur < n;cur++)
878 ALsource *source = al_calloc(16, sizeof(ALsource));
879 if(!source)
880 al_throwerr(Context, AL_OUT_OF_MEMORY);
881 InitSourceParams(source);
883 err = NewThunkEntry(&source->id);
884 if(err == AL_NO_ERROR)
885 err = InsertUIntMapEntry(&Context->SourceMap, source->id, source);
886 if(err != AL_NO_ERROR)
888 FreeThunkEntry(source->id);
889 memset(source, 0, sizeof(ALsource));
890 al_free(source);
892 al_throwerr(Context, err);
895 sources[cur] = source->id;
898 al_catchany()
900 if(cur > 0)
901 alDeleteSources(cur, sources);
903 al_endtry;
905 ALCcontext_DecRef(Context);
909 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
911 ALCcontext *Context;
913 Context = GetContextRef();
914 if(!Context) return;
916 al_try
918 ALbufferlistitem *BufferList;
919 ALsource *Source;
920 ALsizei i, j;
922 CHECK_VALUE(Context, n >= 0);
924 /* Check that all Sources are valid */
925 for(i = 0;i < n;i++)
927 if(LookupSource(Context, sources[i]) == NULL)
928 al_throwerr(Context, AL_INVALID_NAME);
931 for(i = 0;i < n;i++)
933 ALsource **srclist, **srclistend;
935 if((Source=RemoveSource(Context, sources[i])) == NULL)
936 continue;
937 FreeThunkEntry(Source->id);
939 LockContext(Context);
940 srclist = Context->ActiveSources;
941 srclistend = srclist + Context->ActiveSourceCount;
942 while(srclist != srclistend)
944 if(*srclist == Source)
946 Context->ActiveSourceCount--;
947 *srclist = *(--srclistend);
948 break;
950 srclist++;
952 UnlockContext(Context);
954 while(Source->queue != NULL)
956 BufferList = Source->queue;
957 Source->queue = BufferList->next;
959 if(BufferList->buffer != NULL)
960 DecrementRef(&BufferList->buffer->ref);
961 free(BufferList);
964 for(j = 0;j < MAX_SENDS;++j)
966 if(Source->Send[j].Slot)
967 DecrementRef(&Source->Send[j].Slot->ref);
968 Source->Send[j].Slot = NULL;
971 memset(Source, 0, sizeof(*Source));
972 al_free(Source);
975 al_endtry;
977 ALCcontext_DecRef(Context);
981 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
983 ALCcontext *Context;
984 ALboolean result;
986 Context = GetContextRef();
987 if(!Context) return AL_FALSE;
989 result = (LookupSource(Context, source) ? AL_TRUE : AL_FALSE);
991 ALCcontext_DecRef(Context);
993 return result;
997 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
999 ALCcontext *Context;
1000 ALsource *Source;
1002 Context = GetContextRef();
1003 if(!Context) return;
1005 if((Source=LookupSource(Context, source)) == NULL)
1006 alSetError(Context, AL_INVALID_NAME);
1007 else switch(param)
1009 case AL_PITCH:
1010 case AL_CONE_INNER_ANGLE:
1011 case AL_CONE_OUTER_ANGLE:
1012 case AL_GAIN:
1013 case AL_MAX_DISTANCE:
1014 case AL_ROLLOFF_FACTOR:
1015 case AL_REFERENCE_DISTANCE:
1016 case AL_MIN_GAIN:
1017 case AL_MAX_GAIN:
1018 case AL_CONE_OUTER_GAIN:
1019 case AL_CONE_OUTER_GAINHF:
1020 case AL_AIR_ABSORPTION_FACTOR:
1021 case AL_ROOM_ROLLOFF_FACTOR:
1022 case AL_DOPPLER_FACTOR:
1023 case AL_SEC_OFFSET:
1024 case AL_SAMPLE_OFFSET:
1025 case AL_BYTE_OFFSET:
1026 SetSourcefv(Source, Context, param, &value);
1027 break;
1029 default:
1030 alSetError(Context, AL_INVALID_ENUM);
1033 ALCcontext_DecRef(Context);
1036 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1038 ALCcontext *Context;
1039 ALsource *Source;
1040 ALfloat fvals[3];
1042 Context = GetContextRef();
1043 if(!Context) return;
1045 if((Source=LookupSource(Context, source)) == NULL)
1046 alSetError(Context, AL_INVALID_NAME);
1047 else switch(param)
1049 case AL_POSITION:
1050 case AL_VELOCITY:
1051 case AL_DIRECTION:
1052 fvals[0] = value1;
1053 fvals[1] = value2;
1054 fvals[2] = value3;
1055 SetSourcefv(Source, Context, param, fvals);
1056 break;
1058 default:
1059 alSetError(Context, AL_INVALID_ENUM);
1062 ALCcontext_DecRef(Context);
1065 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1067 ALCcontext *Context;
1068 ALsource *Source;
1070 Context = GetContextRef();
1071 if(!Context) return;
1073 if((Source=LookupSource(Context, source)) == NULL)
1074 alSetError(Context, AL_INVALID_NAME);
1075 else if(!values)
1076 alSetError(Context, AL_INVALID_VALUE);
1077 else switch(param)
1079 case AL_PITCH:
1080 case AL_CONE_INNER_ANGLE:
1081 case AL_CONE_OUTER_ANGLE:
1082 case AL_GAIN:
1083 case AL_MAX_DISTANCE:
1084 case AL_ROLLOFF_FACTOR:
1085 case AL_REFERENCE_DISTANCE:
1086 case AL_MIN_GAIN:
1087 case AL_MAX_GAIN:
1088 case AL_CONE_OUTER_GAIN:
1089 case AL_CONE_OUTER_GAINHF:
1090 case AL_SEC_OFFSET:
1091 case AL_SAMPLE_OFFSET:
1092 case AL_BYTE_OFFSET:
1093 case AL_AIR_ABSORPTION_FACTOR:
1094 case AL_ROOM_ROLLOFF_FACTOR:
1096 case AL_POSITION:
1097 case AL_VELOCITY:
1098 case AL_DIRECTION:
1099 SetSourcefv(Source, Context, param, values);
1100 break;
1102 default:
1103 alSetError(Context, AL_INVALID_ENUM);
1106 ALCcontext_DecRef(Context);
1110 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1112 ALCcontext *Context;
1113 ALsource *Source;
1114 ALfloat fval;
1116 Context = GetContextRef();
1117 if(!Context) return;
1119 if((Source=LookupSource(Context, source)) == NULL)
1120 alSetError(Context, AL_INVALID_NAME);
1121 else switch(param)
1123 case AL_PITCH:
1124 case AL_CONE_INNER_ANGLE:
1125 case AL_CONE_OUTER_ANGLE:
1126 case AL_GAIN:
1127 case AL_MAX_DISTANCE:
1128 case AL_ROLLOFF_FACTOR:
1129 case AL_REFERENCE_DISTANCE:
1130 case AL_MIN_GAIN:
1131 case AL_MAX_GAIN:
1132 case AL_CONE_OUTER_GAIN:
1133 case AL_CONE_OUTER_GAINHF:
1134 case AL_AIR_ABSORPTION_FACTOR:
1135 case AL_ROOM_ROLLOFF_FACTOR:
1136 case AL_DOPPLER_FACTOR:
1137 case AL_SEC_OFFSET:
1138 case AL_SAMPLE_OFFSET:
1139 case AL_BYTE_OFFSET:
1140 fval = value;
1141 SetSourcefv(Source, Context, param, &fval);
1142 break;
1144 default:
1145 alSetError(Context, AL_INVALID_ENUM);
1148 ALCcontext_DecRef(Context);
1151 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1153 ALCcontext *Context;
1154 ALsource *Source;
1155 ALfloat fvals[3];
1157 Context = GetContextRef();
1158 if(!Context) return;
1160 if((Source=LookupSource(Context, source)) == NULL)
1161 alSetError(Context, AL_INVALID_NAME);
1162 else switch(param)
1164 case AL_POSITION:
1165 case AL_VELOCITY:
1166 case AL_DIRECTION:
1167 fvals[0] = value1;
1168 fvals[1] = value2;
1169 fvals[2] = value3;
1170 SetSourcefv(Source, Context, param, fvals);
1171 break;
1173 default:
1174 alSetError(Context, AL_INVALID_ENUM);
1177 ALCcontext_DecRef(Context);
1180 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1182 ALCcontext *Context;
1183 ALsource *Source;
1184 ALfloat fvals[3];
1186 Context = GetContextRef();
1187 if(!Context) return;
1189 if((Source=LookupSource(Context, source)) == NULL)
1190 alSetError(Context, AL_INVALID_NAME);
1191 else if(!values)
1192 alSetError(Context, AL_INVALID_VALUE);
1193 else switch(param)
1195 case AL_PITCH:
1196 case AL_CONE_INNER_ANGLE:
1197 case AL_CONE_OUTER_ANGLE:
1198 case AL_GAIN:
1199 case AL_MAX_DISTANCE:
1200 case AL_ROLLOFF_FACTOR:
1201 case AL_REFERENCE_DISTANCE:
1202 case AL_MIN_GAIN:
1203 case AL_MAX_GAIN:
1204 case AL_CONE_OUTER_GAIN:
1205 case AL_CONE_OUTER_GAINHF:
1206 case AL_SEC_OFFSET:
1207 case AL_SAMPLE_OFFSET:
1208 case AL_BYTE_OFFSET:
1209 case AL_AIR_ABSORPTION_FACTOR:
1210 case AL_ROOM_ROLLOFF_FACTOR:
1211 fvals[0] = values[0];
1212 SetSourcefv(Source, Context, param, fvals);
1213 break;
1215 case AL_POSITION:
1216 case AL_VELOCITY:
1217 case AL_DIRECTION:
1218 fvals[0] = values[0];
1219 fvals[1] = values[1];
1220 fvals[2] = values[2];
1221 SetSourcefv(Source, Context, param, fvals);
1222 break;
1224 default:
1225 alSetError(Context, AL_INVALID_ENUM);
1228 ALCcontext_DecRef(Context);
1232 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1234 ALCcontext *Context;
1235 ALsource *Source;
1237 Context = GetContextRef();
1238 if(!Context) return;
1240 if((Source=LookupSource(Context, source)) == NULL)
1241 alSetError(Context, AL_INVALID_NAME);
1242 else switch(param)
1244 case AL_MAX_DISTANCE:
1245 case AL_ROLLOFF_FACTOR:
1246 case AL_CONE_INNER_ANGLE:
1247 case AL_CONE_OUTER_ANGLE:
1248 case AL_REFERENCE_DISTANCE:
1249 case AL_SOURCE_RELATIVE:
1250 case AL_LOOPING:
1251 case AL_BUFFER:
1252 case AL_SOURCE_STATE:
1253 case AL_SEC_OFFSET:
1254 case AL_SAMPLE_OFFSET:
1255 case AL_BYTE_OFFSET:
1256 case AL_DIRECT_FILTER:
1257 case AL_DIRECT_FILTER_GAINHF_AUTO:
1258 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1259 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1260 case AL_DIRECT_CHANNELS_SOFT:
1261 case AL_DISTANCE_MODEL:
1262 SetSourceiv(Source, Context, param, &value);
1263 break;
1265 default:
1266 alSetError(Context, AL_INVALID_ENUM);
1269 ALCcontext_DecRef(Context);
1272 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1274 ALCcontext *Context;
1275 ALsource *Source;
1276 ALint ivals[3];
1278 Context = GetContextRef();
1279 if(!Context) return;
1281 if((Source=LookupSource(Context, source)) == NULL)
1282 alSetError(Context, AL_INVALID_NAME);
1283 else switch(param)
1285 case AL_POSITION:
1286 case AL_VELOCITY:
1287 case AL_DIRECTION:
1288 case AL_AUXILIARY_SEND_FILTER:
1289 ivals[0] = value1;
1290 ivals[1] = value2;
1291 ivals[2] = value3;
1292 SetSourceiv(Source, Context, param, ivals);
1293 break;
1295 default:
1296 alSetError(Context, AL_INVALID_ENUM);
1299 ALCcontext_DecRef(Context);
1302 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1304 ALCcontext *Context;
1305 ALsource *Source;
1307 Context = GetContextRef();
1308 if(!Context) return;
1310 if((Source=LookupSource(Context, source)) == NULL)
1311 alSetError(Context, AL_INVALID_NAME);
1312 else if(!values)
1313 alSetError(Context, AL_INVALID_VALUE);
1314 else switch(param)
1316 case AL_SOURCE_RELATIVE:
1317 case AL_CONE_INNER_ANGLE:
1318 case AL_CONE_OUTER_ANGLE:
1319 case AL_LOOPING:
1320 case AL_BUFFER:
1321 case AL_SOURCE_STATE:
1322 case AL_SEC_OFFSET:
1323 case AL_SAMPLE_OFFSET:
1324 case AL_BYTE_OFFSET:
1325 case AL_MAX_DISTANCE:
1326 case AL_ROLLOFF_FACTOR:
1327 case AL_REFERENCE_DISTANCE:
1328 case AL_DIRECT_FILTER:
1329 case AL_DIRECT_FILTER_GAINHF_AUTO:
1330 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1331 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1332 case AL_DISTANCE_MODEL:
1333 case AL_DIRECT_CHANNELS_SOFT:
1335 case AL_POSITION:
1336 case AL_VELOCITY:
1337 case AL_DIRECTION:
1338 case AL_AUXILIARY_SEND_FILTER:
1339 SetSourceiv(Source, Context, param, values);
1340 break;
1342 default:
1343 alSetError(Context, AL_INVALID_ENUM);
1346 ALCcontext_DecRef(Context);
1350 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1352 ALCcontext *Context;
1353 ALsource *Source;
1355 Context = GetContextRef();
1356 if(!Context) return;
1358 if((Source=LookupSource(Context, source)) == NULL)
1359 alSetError(Context, AL_INVALID_NAME);
1360 else switch(param)
1362 case AL_MAX_DISTANCE:
1363 case AL_ROLLOFF_FACTOR:
1364 case AL_CONE_INNER_ANGLE:
1365 case AL_CONE_OUTER_ANGLE:
1366 case AL_REFERENCE_DISTANCE:
1367 case AL_SOURCE_RELATIVE:
1368 case AL_LOOPING:
1369 case AL_SOURCE_STATE:
1370 case AL_SEC_OFFSET:
1371 case AL_SAMPLE_OFFSET:
1372 case AL_BYTE_OFFSET:
1373 case AL_DIRECT_FILTER_GAINHF_AUTO:
1374 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1375 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1376 case AL_DIRECT_CHANNELS_SOFT:
1377 case AL_DISTANCE_MODEL:
1378 case AL_BUFFER:
1379 case AL_DIRECT_FILTER:
1380 SetSourcei64v(Source, Context, param, &value);
1381 break;
1383 default:
1384 alSetError(Context, AL_INVALID_ENUM);
1387 ALCcontext_DecRef(Context);
1390 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1392 ALCcontext *Context;
1393 ALsource *Source;
1394 ALint64SOFT i64vals[3];
1396 Context = GetContextRef();
1397 if(!Context) return;
1399 if((Source=LookupSource(Context, source)) == NULL)
1400 alSetError(Context, AL_INVALID_NAME);
1401 else switch(param)
1403 case AL_POSITION:
1404 case AL_VELOCITY:
1405 case AL_DIRECTION:
1406 case AL_AUXILIARY_SEND_FILTER:
1407 i64vals[0] = value1;
1408 i64vals[1] = value2;
1409 i64vals[2] = value3;
1410 SetSourcei64v(Source, Context, param, i64vals);
1411 break;
1413 default:
1414 alSetError(Context, AL_INVALID_ENUM);
1417 ALCcontext_DecRef(Context);
1420 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1422 ALCcontext *Context;
1423 ALsource *Source;
1425 Context = GetContextRef();
1426 if(!Context) return;
1428 if((Source=LookupSource(Context, source)) == NULL)
1429 alSetError(Context, AL_INVALID_NAME);
1430 else if(!values)
1431 alSetError(Context, AL_INVALID_VALUE);
1432 else switch(param)
1434 case AL_SOURCE_RELATIVE:
1435 case AL_CONE_INNER_ANGLE:
1436 case AL_CONE_OUTER_ANGLE:
1437 case AL_LOOPING:
1438 case AL_SOURCE_STATE:
1439 case AL_SEC_OFFSET:
1440 case AL_SAMPLE_OFFSET:
1441 case AL_BYTE_OFFSET:
1442 case AL_MAX_DISTANCE:
1443 case AL_ROLLOFF_FACTOR:
1444 case AL_REFERENCE_DISTANCE:
1445 case AL_DIRECT_FILTER_GAINHF_AUTO:
1446 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1447 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1448 case AL_DISTANCE_MODEL:
1449 case AL_DIRECT_CHANNELS_SOFT:
1450 case AL_BUFFER:
1451 case AL_DIRECT_FILTER:
1453 case AL_POSITION:
1454 case AL_VELOCITY:
1455 case AL_DIRECTION:
1456 case AL_AUXILIARY_SEND_FILTER:
1457 SetSourcei64v(Source, Context, param, values);
1458 break;
1460 default:
1461 alSetError(Context, AL_INVALID_ENUM);
1464 ALCcontext_DecRef(Context);
1468 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1470 ALCcontext *Context;
1471 ALsource *Source;
1472 ALdouble dval;
1474 Context = GetContextRef();
1475 if(!Context) return;
1477 if((Source=LookupSource(Context, source)) == NULL)
1478 alSetError(Context, AL_INVALID_NAME);
1479 else if(!value)
1480 alSetError(Context, AL_INVALID_VALUE);
1481 else switch(param)
1483 case AL_PITCH:
1484 case AL_GAIN:
1485 case AL_MIN_GAIN:
1486 case AL_MAX_GAIN:
1487 case AL_MAX_DISTANCE:
1488 case AL_ROLLOFF_FACTOR:
1489 case AL_CONE_OUTER_GAIN:
1490 case AL_CONE_OUTER_GAINHF:
1491 case AL_SEC_OFFSET:
1492 case AL_SAMPLE_OFFSET:
1493 case AL_BYTE_OFFSET:
1494 case AL_CONE_INNER_ANGLE:
1495 case AL_CONE_OUTER_ANGLE:
1496 case AL_REFERENCE_DISTANCE:
1497 case AL_AIR_ABSORPTION_FACTOR:
1498 case AL_ROOM_ROLLOFF_FACTOR:
1499 case AL_DOPPLER_FACTOR:
1500 if(GetSourcedv(Source, Context, param, &dval) == AL_NO_ERROR)
1501 *value = (ALfloat)dval;
1502 break;
1504 default:
1505 alSetError(Context, AL_INVALID_ENUM);
1508 ALCcontext_DecRef(Context);
1512 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1514 ALCcontext *Context;
1515 ALsource *Source;
1516 ALdouble dvals[3];
1518 Context = GetContextRef();
1519 if(!Context) return;
1521 if((Source=LookupSource(Context, source)) == NULL)
1522 alSetError(Context, AL_INVALID_NAME);
1523 else if(!(value1 && value2 && value3))
1524 alSetError(Context, AL_INVALID_VALUE);
1525 else switch(param)
1527 case AL_POSITION:
1528 case AL_VELOCITY:
1529 case AL_DIRECTION:
1530 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1532 *value1 = (ALfloat)dvals[0];
1533 *value2 = (ALfloat)dvals[1];
1534 *value3 = (ALfloat)dvals[2];
1536 break;
1538 default:
1539 alSetError(Context, AL_INVALID_ENUM);
1542 ALCcontext_DecRef(Context);
1546 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1548 ALCcontext *Context;
1549 ALsource *Source;
1550 ALdouble dvals[2];
1552 switch(param)
1554 case AL_PITCH:
1555 case AL_GAIN:
1556 case AL_MIN_GAIN:
1557 case AL_MAX_GAIN:
1558 case AL_MAX_DISTANCE:
1559 case AL_ROLLOFF_FACTOR:
1560 case AL_DOPPLER_FACTOR:
1561 case AL_CONE_OUTER_GAIN:
1562 case AL_SEC_OFFSET:
1563 case AL_SAMPLE_OFFSET:
1564 case AL_BYTE_OFFSET:
1565 case AL_CONE_INNER_ANGLE:
1566 case AL_CONE_OUTER_ANGLE:
1567 case AL_REFERENCE_DISTANCE:
1568 case AL_CONE_OUTER_GAINHF:
1569 case AL_AIR_ABSORPTION_FACTOR:
1570 case AL_ROOM_ROLLOFF_FACTOR:
1571 alGetSourcef(source, param, values);
1572 return;
1574 case AL_POSITION:
1575 case AL_VELOCITY:
1576 case AL_DIRECTION:
1577 alGetSource3f(source, param, values+0, values+1, values+2);
1578 return;
1581 Context = GetContextRef();
1582 if(!Context) return;
1584 if((Source=LookupSource(Context, source)) == NULL)
1585 alSetError(Context, AL_INVALID_NAME);
1586 else if(!values)
1587 alSetError(Context, AL_INVALID_VALUE);
1588 else switch(param)
1590 case AL_SAMPLE_RW_OFFSETS_SOFT:
1591 case AL_BYTE_RW_OFFSETS_SOFT:
1592 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1594 values[0] = (ALfloat)dvals[0];
1595 values[1] = (ALfloat)dvals[1];
1597 break;
1599 default:
1600 alSetError(Context, AL_INVALID_ENUM);
1603 ALCcontext_DecRef(Context);
1607 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1609 ALCcontext *Context;
1610 ALsource *Source;
1612 Context = GetContextRef();
1613 if(!Context) return;
1615 if((Source=LookupSource(Context, source)) == NULL)
1616 alSetError(Context, AL_INVALID_NAME);
1617 else if(!value)
1618 alSetError(Context, AL_INVALID_VALUE);
1619 else switch(param)
1621 case AL_PITCH:
1622 case AL_GAIN:
1623 case AL_MIN_GAIN:
1624 case AL_MAX_GAIN:
1625 case AL_MAX_DISTANCE:
1626 case AL_ROLLOFF_FACTOR:
1627 case AL_CONE_OUTER_GAIN:
1628 case AL_CONE_OUTER_GAINHF:
1629 case AL_SEC_OFFSET:
1630 case AL_SAMPLE_OFFSET:
1631 case AL_BYTE_OFFSET:
1632 case AL_CONE_INNER_ANGLE:
1633 case AL_CONE_OUTER_ANGLE:
1634 case AL_REFERENCE_DISTANCE:
1635 case AL_AIR_ABSORPTION_FACTOR:
1636 case AL_ROOM_ROLLOFF_FACTOR:
1637 case AL_DOPPLER_FACTOR:
1638 GetSourcedv(Source, Context, param, value);
1639 break;
1641 default:
1642 alSetError(Context, AL_INVALID_ENUM);
1645 ALCcontext_DecRef(Context);
1648 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1650 ALCcontext *Context;
1651 ALsource *Source;
1652 ALdouble dvals[3];
1654 Context = GetContextRef();
1655 if(!Context) return;
1657 if((Source=LookupSource(Context, source)) == NULL)
1658 alSetError(Context, AL_INVALID_NAME);
1659 else if(!(value1 && value2 && value3))
1660 alSetError(Context, AL_INVALID_VALUE);
1661 else switch(param)
1663 case AL_POSITION:
1664 case AL_VELOCITY:
1665 case AL_DIRECTION:
1666 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1668 *value1 = dvals[0];
1669 *value2 = dvals[1];
1670 *value3 = dvals[2];
1672 break;
1674 default:
1675 alSetError(Context, AL_INVALID_ENUM);
1678 ALCcontext_DecRef(Context);
1681 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1683 ALCcontext *Context;
1684 ALsource *Source;
1686 Context = GetContextRef();
1687 if(!Context) return;
1689 if((Source=LookupSource(Context, source)) == NULL)
1690 alSetError(Context, AL_INVALID_NAME);
1691 else if(!values)
1692 alSetError(Context, AL_INVALID_VALUE);
1693 else switch(param)
1695 case AL_PITCH:
1696 case AL_GAIN:
1697 case AL_MIN_GAIN:
1698 case AL_MAX_GAIN:
1699 case AL_MAX_DISTANCE:
1700 case AL_ROLLOFF_FACTOR:
1701 case AL_DOPPLER_FACTOR:
1702 case AL_CONE_OUTER_GAIN:
1703 case AL_SEC_OFFSET:
1704 case AL_SAMPLE_OFFSET:
1705 case AL_BYTE_OFFSET:
1706 case AL_CONE_INNER_ANGLE:
1707 case AL_CONE_OUTER_ANGLE:
1708 case AL_REFERENCE_DISTANCE:
1709 case AL_CONE_OUTER_GAINHF:
1710 case AL_AIR_ABSORPTION_FACTOR:
1711 case AL_ROOM_ROLLOFF_FACTOR:
1713 case AL_SAMPLE_RW_OFFSETS_SOFT:
1714 case AL_BYTE_RW_OFFSETS_SOFT:
1715 case AL_SEC_OFFSET_LATENCY_SOFT:
1717 case AL_POSITION:
1718 case AL_VELOCITY:
1719 case AL_DIRECTION:
1720 GetSourcedv(Source, Context, param, values);
1721 break;
1723 default:
1724 alSetError(Context, AL_INVALID_ENUM);
1727 ALCcontext_DecRef(Context);
1731 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1733 ALCcontext *Context;
1734 ALsource *Source;
1736 Context = GetContextRef();
1737 if(!Context) return;
1739 if((Source=LookupSource(Context, source)) == NULL)
1740 alSetError(Context, AL_INVALID_NAME);
1741 else if(!value)
1742 alSetError(Context, AL_INVALID_VALUE);
1743 else switch(param)
1745 case AL_MAX_DISTANCE:
1746 case AL_ROLLOFF_FACTOR:
1747 case AL_REFERENCE_DISTANCE:
1748 case AL_SOURCE_RELATIVE:
1749 case AL_CONE_INNER_ANGLE:
1750 case AL_CONE_OUTER_ANGLE:
1751 case AL_LOOPING:
1752 case AL_BUFFER:
1753 case AL_SOURCE_STATE:
1754 case AL_BUFFERS_QUEUED:
1755 case AL_BUFFERS_PROCESSED:
1756 case AL_SOURCE_TYPE:
1757 case AL_SEC_OFFSET:
1758 case AL_SAMPLE_OFFSET:
1759 case AL_BYTE_OFFSET:
1760 case AL_DIRECT_FILTER_GAINHF_AUTO:
1761 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1762 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1763 case AL_DOPPLER_FACTOR:
1764 case AL_DIRECT_CHANNELS_SOFT:
1765 case AL_DISTANCE_MODEL:
1766 GetSourceiv(Source, Context, param, value);
1767 break;
1769 default:
1770 alSetError(Context, AL_INVALID_ENUM);
1773 ALCcontext_DecRef(Context);
1777 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
1779 ALCcontext *Context;
1780 ALsource *Source;
1781 ALint ivals[3];
1783 Context = GetContextRef();
1784 if(!Context) return;
1786 if((Source=LookupSource(Context, source)) == NULL)
1787 alSetError(Context, AL_INVALID_NAME);
1788 else if(!(value1 && value2 && value3))
1789 alSetError(Context, AL_INVALID_VALUE);
1790 else switch(param)
1792 case AL_POSITION:
1793 case AL_VELOCITY:
1794 case AL_DIRECTION:
1795 if(GetSourceiv(Source, Context, param, ivals) == AL_NO_ERROR)
1797 *value1 = ivals[0];
1798 *value2 = ivals[1];
1799 *value3 = ivals[2];
1801 break;
1803 default:
1804 alSetError(Context, AL_INVALID_ENUM);
1807 ALCcontext_DecRef(Context);
1811 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
1813 ALCcontext *Context;
1814 ALsource *Source;
1816 Context = GetContextRef();
1817 if(!Context) return;
1819 if((Source=LookupSource(Context, source)) == NULL)
1820 alSetError(Context, AL_INVALID_NAME);
1821 else if(!values)
1822 alSetError(Context, AL_INVALID_VALUE);
1823 else switch(param)
1825 case AL_SOURCE_RELATIVE:
1826 case AL_CONE_INNER_ANGLE:
1827 case AL_CONE_OUTER_ANGLE:
1828 case AL_LOOPING:
1829 case AL_BUFFER:
1830 case AL_SOURCE_STATE:
1831 case AL_BUFFERS_QUEUED:
1832 case AL_BUFFERS_PROCESSED:
1833 case AL_SEC_OFFSET:
1834 case AL_SAMPLE_OFFSET:
1835 case AL_BYTE_OFFSET:
1836 case AL_MAX_DISTANCE:
1837 case AL_ROLLOFF_FACTOR:
1838 case AL_DOPPLER_FACTOR:
1839 case AL_REFERENCE_DISTANCE:
1840 case AL_SOURCE_TYPE:
1841 case AL_DIRECT_FILTER:
1842 case AL_DIRECT_FILTER_GAINHF_AUTO:
1843 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1844 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1845 case AL_DISTANCE_MODEL:
1846 case AL_DIRECT_CHANNELS_SOFT:
1848 case AL_SAMPLE_RW_OFFSETS_SOFT:
1849 case AL_BYTE_RW_OFFSETS_SOFT:
1851 case AL_POSITION:
1852 case AL_VELOCITY:
1853 case AL_DIRECTION:
1854 GetSourceiv(Source, Context, param, values);
1855 break;
1857 default:
1858 alSetError(Context, AL_INVALID_ENUM);
1861 ALCcontext_DecRef(Context);
1865 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
1867 ALCcontext *Context;
1868 ALsource *Source;
1870 Context = GetContextRef();
1871 if(!Context) return;
1873 if((Source=LookupSource(Context, source)) == NULL)
1874 alSetError(Context, AL_INVALID_NAME);
1875 else if(!value)
1876 alSetError(Context, AL_INVALID_VALUE);
1877 else switch(param)
1879 case AL_MAX_DISTANCE:
1880 case AL_ROLLOFF_FACTOR:
1881 case AL_REFERENCE_DISTANCE:
1882 case AL_SOURCE_RELATIVE:
1883 case AL_CONE_INNER_ANGLE:
1884 case AL_CONE_OUTER_ANGLE:
1885 case AL_LOOPING:
1886 case AL_BUFFER:
1887 case AL_SOURCE_STATE:
1888 case AL_BUFFERS_QUEUED:
1889 case AL_BUFFERS_PROCESSED:
1890 case AL_SOURCE_TYPE:
1891 case AL_SEC_OFFSET:
1892 case AL_SAMPLE_OFFSET:
1893 case AL_BYTE_OFFSET:
1894 case AL_DIRECT_FILTER_GAINHF_AUTO:
1895 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1896 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1897 case AL_DOPPLER_FACTOR:
1898 case AL_DIRECT_CHANNELS_SOFT:
1899 case AL_DISTANCE_MODEL:
1900 GetSourcei64v(Source, Context, param, value);
1901 break;
1903 default:
1904 alSetError(Context, AL_INVALID_ENUM);
1907 ALCcontext_DecRef(Context);
1910 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
1912 ALCcontext *Context;
1913 ALsource *Source;
1914 ALint64 i64vals[3];
1916 Context = GetContextRef();
1917 if(!Context) return;
1919 if((Source=LookupSource(Context, source)) == NULL)
1920 alSetError(Context, AL_INVALID_NAME);
1921 else if(!(value1 && value2 && value3))
1922 alSetError(Context, AL_INVALID_VALUE);
1923 else switch(param)
1925 case AL_POSITION:
1926 case AL_VELOCITY:
1927 case AL_DIRECTION:
1928 if(GetSourcei64v(Source, Context, param, i64vals) == AL_NO_ERROR)
1930 *value1 = i64vals[0];
1931 *value2 = i64vals[1];
1932 *value3 = i64vals[2];
1934 break;
1936 default:
1937 alSetError(Context, AL_INVALID_ENUM);
1940 ALCcontext_DecRef(Context);
1943 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
1945 ALCcontext *Context;
1946 ALsource *Source;
1948 Context = GetContextRef();
1949 if(!Context) return;
1951 if((Source=LookupSource(Context, source)) == NULL)
1952 alSetError(Context, AL_INVALID_NAME);
1953 else if(!values)
1954 alSetError(Context, AL_INVALID_VALUE);
1955 else switch(param)
1957 case AL_MAX_DISTANCE:
1958 case AL_ROLLOFF_FACTOR:
1959 case AL_REFERENCE_DISTANCE:
1960 case AL_SOURCE_RELATIVE:
1961 case AL_CONE_INNER_ANGLE:
1962 case AL_CONE_OUTER_ANGLE:
1963 case AL_LOOPING:
1964 case AL_BUFFER:
1965 case AL_SOURCE_STATE:
1966 case AL_BUFFERS_QUEUED:
1967 case AL_BUFFERS_PROCESSED:
1968 case AL_SOURCE_TYPE:
1969 case AL_SEC_OFFSET:
1970 case AL_SAMPLE_OFFSET:
1971 case AL_BYTE_OFFSET:
1972 case AL_DIRECT_FILTER_GAINHF_AUTO:
1973 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1974 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1975 case AL_DOPPLER_FACTOR:
1976 case AL_DIRECT_CHANNELS_SOFT:
1977 case AL_DISTANCE_MODEL:
1979 case AL_SAMPLE_RW_OFFSETS_SOFT:
1980 case AL_BYTE_RW_OFFSETS_SOFT:
1981 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1983 case AL_POSITION:
1984 case AL_VELOCITY:
1985 case AL_DIRECTION:
1986 GetSourcei64v(Source, Context, param, values);
1987 break;
1989 default:
1990 alSetError(Context, AL_INVALID_ENUM);
1993 ALCcontext_DecRef(Context);
1997 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1999 alSourcePlayv(1, &source);
2001 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2003 ALCcontext *Context;
2004 ALsource *Source;
2005 ALsizei i;
2007 Context = GetContextRef();
2008 if(!Context) return;
2010 al_try
2012 CHECK_VALUE(Context, n >= 0);
2013 for(i = 0;i < n;i++)
2015 if(!LookupSource(Context, sources[i]))
2016 al_throwerr(Context, AL_INVALID_NAME);
2019 LockContext(Context);
2020 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
2022 void *temp = NULL;
2023 ALsizei newcount;
2025 newcount = Context->MaxActiveSources << 1;
2026 if(newcount > 0)
2027 temp = realloc(Context->ActiveSources,
2028 sizeof(*Context->ActiveSources) * newcount);
2029 if(!temp)
2031 UnlockContext(Context);
2032 al_throwerr(Context, AL_OUT_OF_MEMORY);
2035 Context->ActiveSources = temp;
2036 Context->MaxActiveSources = newcount;
2039 for(i = 0;i < n;i++)
2041 Source = LookupSource(Context, sources[i]);
2042 if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
2043 else SetSourceState(Source, Context, AL_PLAYING);
2045 UnlockContext(Context);
2047 al_endtry;
2049 ALCcontext_DecRef(Context);
2052 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2054 alSourcePausev(1, &source);
2056 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2058 ALCcontext *Context;
2059 ALsource *Source;
2060 ALsizei i;
2062 Context = GetContextRef();
2063 if(!Context) return;
2065 al_try
2067 CHECK_VALUE(Context, n >= 0);
2068 for(i = 0;i < n;i++)
2070 if(!LookupSource(Context, sources[i]))
2071 al_throwerr(Context, AL_INVALID_NAME);
2074 LockContext(Context);
2075 for(i = 0;i < n;i++)
2077 Source = LookupSource(Context, sources[i]);
2078 if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
2079 else SetSourceState(Source, Context, AL_PAUSED);
2081 UnlockContext(Context);
2083 al_endtry;
2085 ALCcontext_DecRef(Context);
2088 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2090 alSourceStopv(1, &source);
2092 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2094 ALCcontext *Context;
2095 ALsource *Source;
2096 ALsizei i;
2098 Context = GetContextRef();
2099 if(!Context) return;
2101 al_try
2103 CHECK_VALUE(Context, n >= 0);
2104 for(i = 0;i < n;i++)
2106 if(!LookupSource(Context, sources[i]))
2107 al_throwerr(Context, AL_INVALID_NAME);
2110 LockContext(Context);
2111 for(i = 0;i < n;i++)
2113 Source = LookupSource(Context, sources[i]);
2114 Source->new_state = AL_NONE;
2115 SetSourceState(Source, Context, AL_STOPPED);
2117 UnlockContext(Context);
2119 al_endtry;
2121 ALCcontext_DecRef(Context);
2124 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2126 alSourceRewindv(1, &source);
2128 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2130 ALCcontext *Context;
2131 ALsource *Source;
2132 ALsizei i;
2134 Context = GetContextRef();
2135 if(!Context) return;
2137 al_try
2139 CHECK_VALUE(Context, n >= 0);
2140 for(i = 0;i < n;i++)
2142 if(!LookupSource(Context, sources[i]))
2143 al_throwerr(Context, AL_INVALID_NAME);
2146 LockContext(Context);
2147 for(i = 0;i < n;i++)
2149 Source = LookupSource(Context, sources[i]);
2150 Source->new_state = AL_NONE;
2151 SetSourceState(Source, Context, AL_INITIAL);
2153 UnlockContext(Context);
2155 al_endtry;
2157 ALCcontext_DecRef(Context);
2161 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers)
2163 ALCcontext *Context;
2164 ALsource *Source;
2165 ALsizei i;
2166 ALbufferlistitem *BufferListStart = NULL;
2167 ALbufferlistitem *BufferList;
2168 ALbuffer *BufferFmt;
2170 if(nb == 0)
2171 return;
2173 Context = GetContextRef();
2174 if(!Context) return;
2176 al_try
2178 ALCdevice *device = Context->Device;
2180 CHECK_VALUE(Context, nb >= 0);
2182 if((Source=LookupSource(Context, source)) == NULL)
2183 al_throwerr(Context, AL_INVALID_NAME);
2185 LockContext(Context);
2186 if(Source->SourceType == AL_STATIC)
2188 UnlockContext(Context);
2189 /* Can't queue on a Static Source */
2190 al_throwerr(Context, AL_INVALID_OPERATION);
2193 BufferFmt = NULL;
2195 /* Check for a valid Buffer, for its frequency and format */
2196 BufferList = Source->queue;
2197 while(BufferList)
2199 if(BufferList->buffer)
2201 BufferFmt = BufferList->buffer;
2202 break;
2204 BufferList = BufferList->next;
2207 for(i = 0;i < nb;i++)
2209 ALbuffer *buffer = NULL;
2210 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2212 UnlockContext(Context);
2213 al_throwerr(Context, AL_INVALID_NAME);
2216 if(!BufferListStart)
2218 BufferListStart = malloc(sizeof(ALbufferlistitem));
2219 BufferListStart->buffer = buffer;
2220 BufferListStart->next = NULL;
2221 BufferListStart->prev = NULL;
2222 BufferList = BufferListStart;
2224 else
2226 BufferList->next = malloc(sizeof(ALbufferlistitem));
2227 BufferList->next->buffer = buffer;
2228 BufferList->next->next = NULL;
2229 BufferList->next->prev = BufferList;
2230 BufferList = BufferList->next;
2232 if(!buffer) continue;
2233 IncrementRef(&buffer->ref);
2235 ReadLock(&buffer->lock);
2236 if(BufferFmt == NULL)
2238 BufferFmt = buffer;
2240 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2241 Source->SampleSize = BytesFromFmt(buffer->FmtType);
2242 if(buffer->FmtChannels == FmtMono)
2243 Source->Update = CalcSourceParams;
2244 else
2245 Source->Update = CalcNonAttnSourceParams;
2247 Source->NeedsUpdate = AL_TRUE;
2249 else if(BufferFmt->Frequency != buffer->Frequency ||
2250 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2251 BufferFmt->OriginalType != buffer->OriginalType)
2253 ReadUnlock(&buffer->lock);
2254 UnlockContext(Context);
2255 al_throwerr(Context, AL_INVALID_OPERATION);
2257 ReadUnlock(&buffer->lock);
2260 /* Source is now streaming */
2261 Source->SourceType = AL_STREAMING;
2263 if(Source->queue == NULL)
2264 Source->queue = BufferListStart;
2265 else
2267 /* Append to the end of the queue */
2268 BufferList = Source->queue;
2269 while(BufferList->next != NULL)
2270 BufferList = BufferList->next;
2272 BufferListStart->prev = BufferList;
2273 BufferList->next = BufferListStart;
2276 Source->BuffersInQueue += nb;
2278 UnlockContext(Context);
2280 al_catchany()
2282 while(BufferListStart)
2284 BufferList = BufferListStart;
2285 BufferListStart = BufferList->next;
2287 if(BufferList->buffer)
2288 DecrementRef(&BufferList->buffer->ref);
2289 free(BufferList);
2292 al_endtry;
2294 ALCcontext_DecRef(Context);
2297 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers)
2299 ALCcontext *Context;
2300 ALsource *Source;
2301 ALsizei i;
2302 ALbufferlistitem *BufferList;
2304 if(nb == 0)
2305 return;
2307 Context = GetContextRef();
2308 if(!Context) return;
2310 al_try
2312 CHECK_VALUE(Context, nb >= 0);
2314 if((Source=LookupSource(Context, source)) == NULL)
2315 al_throwerr(Context, AL_INVALID_NAME);
2317 LockContext(Context);
2318 if(Source->Looping || Source->SourceType != AL_STREAMING ||
2319 (ALuint)nb > Source->BuffersPlayed)
2321 UnlockContext(Context);
2322 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2323 al_throwerr(Context, AL_INVALID_VALUE);
2326 for(i = 0;i < nb;i++)
2328 BufferList = Source->queue;
2329 Source->queue = BufferList->next;
2330 Source->BuffersInQueue--;
2331 Source->BuffersPlayed--;
2333 if(BufferList->buffer)
2335 buffers[i] = BufferList->buffer->id;
2336 DecrementRef(&BufferList->buffer->ref);
2338 else
2339 buffers[i] = 0;
2341 free(BufferList);
2343 if(Source->queue)
2344 Source->queue->prev = NULL;
2345 UnlockContext(Context);
2347 al_endtry;
2349 ALCcontext_DecRef(Context);
2353 static ALvoid InitSourceParams(ALsource *Source)
2355 ALuint i;
2357 Source->InnerAngle = 360.0f;
2358 Source->OuterAngle = 360.0f;
2359 Source->Pitch = 1.0f;
2360 Source->Position[0] = 0.0f;
2361 Source->Position[1] = 0.0f;
2362 Source->Position[2] = 0.0f;
2363 Source->Orientation[0] = 0.0f;
2364 Source->Orientation[1] = 0.0f;
2365 Source->Orientation[2] = 0.0f;
2366 Source->Velocity[0] = 0.0f;
2367 Source->Velocity[1] = 0.0f;
2368 Source->Velocity[2] = 0.0f;
2369 Source->RefDistance = 1.0f;
2370 Source->MaxDistance = FLT_MAX;
2371 Source->RollOffFactor = 1.0f;
2372 Source->Looping = AL_FALSE;
2373 Source->Gain = 1.0f;
2374 Source->MinGain = 0.0f;
2375 Source->MaxGain = 1.0f;
2376 Source->OuterGain = 0.0f;
2377 Source->OuterGainHF = 1.0f;
2379 Source->DryGainHFAuto = AL_TRUE;
2380 Source->WetGainAuto = AL_TRUE;
2381 Source->WetGainHFAuto = AL_TRUE;
2382 Source->AirAbsorptionFactor = 0.0f;
2383 Source->RoomRolloffFactor = 0.0f;
2384 Source->DopplerFactor = 1.0f;
2385 Source->DirectChannels = AL_FALSE;
2387 Source->DistanceModel = DefaultDistanceModel;
2389 Source->Resampler = DefaultResampler;
2391 Source->state = AL_INITIAL;
2392 Source->new_state = AL_NONE;
2393 Source->SourceType = AL_UNDETERMINED;
2394 Source->Offset = -1.0;
2396 Source->DirectGain = 1.0f;
2397 Source->DirectGainHF = 1.0f;
2398 for(i = 0;i < MAX_SENDS;i++)
2400 Source->Send[i].Gain = 1.0f;
2401 Source->Send[i].GainHF = 1.0f;
2404 Source->NeedsUpdate = AL_TRUE;
2406 Source->Hrtf.Moving = AL_FALSE;
2407 Source->Hrtf.Counter = 0;
2411 /* SetSourceState
2413 * Sets the source's new play state given its current state.
2415 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2417 if(state == AL_PLAYING)
2419 ALbufferlistitem *BufferList;
2420 ALsizei j, k;
2422 /* Check that there is a queue containing at least one valid, non zero
2423 * length Buffer. */
2424 BufferList = Source->queue;
2425 while(BufferList)
2427 if(BufferList->buffer != NULL && BufferList->buffer->SampleLen)
2428 break;
2429 BufferList = BufferList->next;
2432 if(Source->state != AL_PLAYING)
2434 for(j = 0;j < MaxChannels;j++)
2436 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
2437 Source->Hrtf.History[j][k] = 0.0f;
2438 for(k = 0;k < HRIR_LENGTH;k++)
2440 Source->Hrtf.Values[j][k][0] = 0.0f;
2441 Source->Hrtf.Values[j][k][1] = 0.0f;
2446 if(Source->state != AL_PAUSED)
2448 Source->state = AL_PLAYING;
2449 Source->position = 0;
2450 Source->position_fraction = 0;
2451 Source->BuffersPlayed = 0;
2453 else
2454 Source->state = AL_PLAYING;
2456 // Check if an Offset has been set
2457 if(Source->Offset >= 0.0)
2458 ApplyOffset(Source);
2460 /* If there's nothing to play, or device is disconnected, go right to
2461 * stopped */
2462 if(!BufferList || !Context->Device->Connected)
2464 SetSourceState(Source, Context, AL_STOPPED);
2465 return;
2468 for(j = 0;j < Context->ActiveSourceCount;j++)
2470 if(Context->ActiveSources[j] == Source)
2471 break;
2473 if(j == Context->ActiveSourceCount)
2474 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
2476 else if(state == AL_PAUSED)
2478 if(Source->state == AL_PLAYING)
2480 Source->state = AL_PAUSED;
2481 Source->Hrtf.Moving = AL_FALSE;
2482 Source->Hrtf.Counter = 0;
2485 else if(state == AL_STOPPED)
2487 if(Source->state != AL_INITIAL)
2489 Source->state = AL_STOPPED;
2490 Source->BuffersPlayed = Source->BuffersInQueue;
2491 Source->Hrtf.Moving = AL_FALSE;
2492 Source->Hrtf.Counter = 0;
2494 Source->Offset = -1.0;
2496 else if(state == AL_INITIAL)
2498 if(Source->state != AL_INITIAL)
2500 Source->state = AL_INITIAL;
2501 Source->position = 0;
2502 Source->position_fraction = 0;
2503 Source->BuffersPlayed = 0;
2504 Source->Hrtf.Moving = AL_FALSE;
2505 Source->Hrtf.Counter = 0;
2507 Source->Offset = -1.0;
2511 /* GetSourceOffset
2513 * Gets the current read offset for the given Source, in 32.32 fixed-point
2514 * samples. The offset is relative to the start of the queue (not the start of
2515 * the current buffer).
2517 static ALint64 GetSourceOffset(const ALsource *Source)
2519 const ALbufferlistitem *BufferList;
2520 ALuint64 readPos;
2521 ALuint i;
2523 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2524 return 0;
2526 /* NOTE: This is the offset into the *current* buffer, so add the length of
2527 * any played buffers */
2528 readPos = (ALuint64)Source->position << 32;
2529 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2530 BufferList = Source->queue;
2531 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2533 if(BufferList->buffer)
2534 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2535 BufferList = BufferList->next;
2538 return (ALint64)minu64(readPos, MAKEU64(0x7fffffff,0xffffffff));
2541 /* GetSourceSecOffset
2543 * Gets the current read offset for the given Source, in seconds. The offset is
2544 * relative to the start of the queue (not the start of the current buffer).
2546 static ALdouble GetSourceSecOffset(const ALsource *Source)
2548 const ALbufferlistitem *BufferList;
2549 const ALbuffer *Buffer = NULL;
2550 ALuint64 readPos;
2551 ALuint i;
2553 BufferList = Source->queue;
2554 while(BufferList)
2556 if(BufferList->buffer)
2558 Buffer = BufferList->buffer;
2559 break;
2561 BufferList = BufferList->next;
2564 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2565 return 0.0;
2567 /* NOTE: This is the offset into the *current* buffer, so add the length of
2568 * any played buffers */
2569 readPos = (ALuint64)Source->position << FRACTIONBITS;
2570 readPos |= (ALuint64)Source->position_fraction;
2571 BufferList = Source->queue;
2572 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2574 if(BufferList->buffer)
2575 readPos += (ALuint64)BufferList->buffer->SampleLen << FRACTIONBITS;
2576 BufferList = BufferList->next;
2579 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2582 /* GetSourceOffsets
2584 * Gets the current read and write offsets for the given Source, in the
2585 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2586 * the start of the queue (not the start of the current buffer).
2588 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2590 const ALbufferlistitem *BufferList;
2591 const ALbuffer *Buffer = NULL;
2592 ALuint readPos, writePos;
2593 ALuint totalBufferLen;
2594 ALuint i;
2596 // Find the first valid Buffer in the Queue
2597 BufferList = Source->queue;
2598 while(BufferList)
2600 if(BufferList->buffer)
2602 Buffer = BufferList->buffer;
2603 break;
2605 BufferList = BufferList->next;
2608 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2610 offset[0] = 0.0;
2611 offset[1] = 0.0;
2612 return;
2615 if(updateLen > 0.0 && updateLen < 0.015)
2616 updateLen = 0.015;
2618 /* NOTE: This is the offset into the *current* buffer, so add the length of
2619 * any played buffers */
2620 readPos = Source->position;
2621 totalBufferLen = 0;
2622 BufferList = Source->queue;
2623 for(i = 0;BufferList;i++)
2625 if(BufferList->buffer)
2627 if(i < Source->BuffersPlayed)
2628 readPos += BufferList->buffer->SampleLen;
2629 totalBufferLen += BufferList->buffer->SampleLen;
2631 BufferList = BufferList->next;
2633 if(Source->state == AL_PLAYING)
2634 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
2635 else
2636 writePos = readPos;
2638 if(Source->Looping)
2640 readPos %= totalBufferLen;
2641 writePos %= totalBufferLen;
2643 else
2645 /* Wrap positions back to 0 */
2646 if(readPos >= totalBufferLen)
2647 readPos = 0;
2648 if(writePos >= totalBufferLen)
2649 writePos = 0;
2652 switch(name)
2654 case AL_SEC_OFFSET:
2655 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2656 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2657 break;
2659 case AL_SAMPLE_OFFSET:
2660 case AL_SAMPLE_RW_OFFSETS_SOFT:
2661 offset[0] = (ALdouble)readPos;
2662 offset[1] = (ALdouble)writePos;
2663 break;
2665 case AL_BYTE_OFFSET:
2666 case AL_BYTE_RW_OFFSETS_SOFT:
2667 if(Buffer->OriginalType == UserFmtIMA4)
2669 ALuint BlockSize = 36 * ChannelsFromFmt(Buffer->FmtChannels);
2670 ALuint FrameBlockSize = 65;
2672 /* Round down to nearest ADPCM block */
2673 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2674 if(Source->state != AL_PLAYING)
2675 offset[1] = offset[0];
2676 else
2678 /* Round up to nearest ADPCM block */
2679 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2680 FrameBlockSize * BlockSize);
2683 else
2685 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2686 offset[0] = (ALdouble)(readPos * FrameSize);
2687 offset[1] = (ALdouble)(writePos * FrameSize);
2689 break;
2694 /* ApplyOffset
2696 * Apply the stored playback offset to the Source. This function will update
2697 * the number of buffers "played" given the stored offset.
2699 ALboolean ApplyOffset(ALsource *Source)
2701 const ALbufferlistitem *BufferList;
2702 const ALbuffer *Buffer;
2703 ALint bufferLen, totalBufferLen;
2704 ALint buffersPlayed;
2705 ALint offset;
2707 /* Get sample frame offset */
2708 offset = GetSampleOffset(Source);
2709 if(offset == -1)
2710 return AL_FALSE;
2712 buffersPlayed = 0;
2713 totalBufferLen = 0;
2715 BufferList = Source->queue;
2716 while(BufferList)
2718 Buffer = BufferList->buffer;
2719 bufferLen = Buffer ? Buffer->SampleLen : 0;
2721 if(bufferLen <= offset-totalBufferLen)
2723 /* Offset is past this buffer so increment to the next buffer */
2724 buffersPlayed++;
2726 else if(totalBufferLen <= offset)
2728 /* Offset is in this buffer */
2729 Source->BuffersPlayed = buffersPlayed;
2731 Source->position = offset - totalBufferLen;
2732 Source->position_fraction = 0;
2733 return AL_TRUE;
2736 totalBufferLen += bufferLen;
2738 BufferList = BufferList->next;
2741 /* Offset is out of range of the queue */
2742 return AL_FALSE;
2746 /* GetSampleOffset
2748 * Returns the sample offset into the Source's queue (from the Sample, Byte or
2749 * Second offset supplied by the application). This takes into account the fact
2750 * that the buffer format may have been modifed since.
2752 static ALint GetSampleOffset(ALsource *Source)
2754 const ALbuffer *Buffer = NULL;
2755 const ALbufferlistitem *BufferList;
2756 ALint Offset = -1;
2758 /* Find the first valid Buffer in the Queue */
2759 BufferList = Source->queue;
2760 while(BufferList)
2762 if(BufferList->buffer)
2764 Buffer = BufferList->buffer;
2765 break;
2767 BufferList = BufferList->next;
2770 if(!Buffer)
2772 Source->Offset = -1.0;
2773 return -1;
2776 switch(Source->OffsetType)
2778 case AL_BYTE_OFFSET:
2779 /* Determine the ByteOffset (and ensure it is block aligned) */
2780 Offset = (ALint)Source->Offset;
2781 if(Buffer->OriginalType == UserFmtIMA4)
2783 Offset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
2784 Offset *= 65;
2786 else
2787 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2788 break;
2790 case AL_SAMPLE_OFFSET:
2791 Offset = (ALint)Source->Offset;
2792 break;
2794 case AL_SEC_OFFSET:
2795 Offset = (ALint)(Source->Offset * Buffer->Frequency);
2796 break;
2798 Source->Offset = -1.0;
2800 return Offset;
2804 /* ReleaseALSources
2806 * Destroys all sources in the source map.
2808 ALvoid ReleaseALSources(ALCcontext *Context)
2810 ALsizei pos;
2811 ALuint j;
2812 for(pos = 0;pos < Context->SourceMap.size;pos++)
2814 ALsource *temp = Context->SourceMap.array[pos].value;
2815 Context->SourceMap.array[pos].value = NULL;
2817 while(temp->queue != NULL)
2819 ALbufferlistitem *BufferList = temp->queue;
2820 temp->queue = BufferList->next;
2822 if(BufferList->buffer != NULL)
2823 DecrementRef(&BufferList->buffer->ref);
2824 free(BufferList);
2827 for(j = 0;j < MAX_SENDS;++j)
2829 if(temp->Send[j].Slot)
2830 DecrementRef(&temp->Send[j].Slot->ref);
2831 temp->Send[j].Slot = NULL;
2834 FreeThunkEntry(temp->id);
2835 memset(temp, 0, sizeof(*temp));
2836 al_free(temp);