22686a03a63df8b4a72fe40e5c4ad3bfe47717a1
[openal-soft.git] / OpenAL32 / alSource.c
blob22686a03a63df8b4a72fe40e5c4ad3bfe47717a1
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 ERR("Unexpected param: 0x%04x\n", name);
239 RETERR(AL_INVALID_ENUM);
242 return AL_NO_ERROR;
245 static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, ALenum name, const ALint *values)
247 ALCdevice *device = Context->Device;
248 ALbuffer *buffer = NULL;
249 ALfilter *filter = NULL;
250 ALeffectslot *slot = NULL;
251 ALbufferlistitem *oldlist;
252 ALfloat fvals[3];
253 ALenum err;
255 switch(name)
257 case AL_SOURCE_RELATIVE:
258 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
260 Source->HeadRelative = (ALboolean)*values;
261 Source->NeedsUpdate = AL_TRUE;
262 break;
264 case AL_LOOPING:
265 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
267 Source->Looping = (ALboolean)*values;
268 break;
270 case AL_BUFFER:
271 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
273 LockContext(Context);
274 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
276 UnlockContext(Context);
277 RETERR(AL_INVALID_OPERATION);
280 Source->BuffersInQueue = 0;
281 Source->BuffersPlayed = 0;
283 if(buffer != NULL)
285 ALbufferlistitem *BufferListItem;
287 /* Source is now Static */
288 Source->SourceType = AL_STATIC;
290 /* Add the selected buffer to a one-item queue */
291 BufferListItem = malloc(sizeof(ALbufferlistitem));
292 BufferListItem->buffer = buffer;
293 BufferListItem->next = NULL;
294 BufferListItem->prev = NULL;
295 IncrementRef(&buffer->ref);
297 oldlist = ExchangePtr((XchgPtr*)&Source->queue, BufferListItem);
298 Source->BuffersInQueue = 1;
300 ReadLock(&buffer->lock);
301 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
302 Source->SampleSize = BytesFromFmt(buffer->FmtType);
303 ReadUnlock(&buffer->lock);
304 if(buffer->FmtChannels == FmtMono)
305 Source->Update = CalcSourceParams;
306 else
307 Source->Update = CalcNonAttnSourceParams;
308 Source->NeedsUpdate = AL_TRUE;
310 else
312 /* Source is now Undetermined */
313 Source->SourceType = AL_UNDETERMINED;
314 oldlist = ExchangePtr((XchgPtr*)&Source->queue, NULL);
317 /* Delete all elements in the previous queue */
318 while(oldlist != NULL)
320 ALbufferlistitem *temp = oldlist;
321 oldlist = temp->next;
323 if(temp->buffer)
324 DecrementRef(&temp->buffer->ref);
325 free(temp);
327 UnlockContext(Context);
328 break;
330 case AL_SOURCE_STATE:
331 /* Query only */
332 RETERR(AL_INVALID_OPERATION);
334 case AL_SEC_OFFSET:
335 case AL_SAMPLE_OFFSET:
336 case AL_BYTE_OFFSET:
337 CHECKVAL(*values >= 0);
339 LockContext(Context);
340 Source->OffsetType = name;
341 Source->Offset = *values;
343 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
344 !Context->DeferUpdates)
346 if(ApplyOffset(Source) == AL_FALSE)
348 UnlockContext(Context);
349 RETERR(AL_INVALID_VALUE);
352 UnlockContext(Context);
353 break;
355 case AL_DIRECT_FILTER:
356 CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
358 LockContext(Context);
359 if(!filter)
361 Source->DirectGain = 1.0f;
362 Source->DirectGainHF = 1.0f;
364 else
366 Source->DirectGain = filter->Gain;
367 Source->DirectGainHF = filter->GainHF;
369 UnlockContext(Context);
370 Source->NeedsUpdate = AL_TRUE;
371 break;
373 case AL_DIRECT_FILTER_GAINHF_AUTO:
374 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
376 Source->DryGainHFAuto = *values;
377 Source->NeedsUpdate = AL_TRUE;
378 break;
380 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
381 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
383 Source->WetGainAuto = *values;
384 Source->NeedsUpdate = AL_TRUE;
385 break;
387 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
388 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
390 Source->WetGainHFAuto = *values;
391 Source->NeedsUpdate = AL_TRUE;
392 break;
394 case AL_DIRECT_CHANNELS_SOFT:
395 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
397 Source->DirectChannels = *values;
398 Source->NeedsUpdate = AL_TRUE;
399 break;
401 case AL_DISTANCE_MODEL:
402 CHECKVAL(*values == AL_NONE ||
403 *values == AL_INVERSE_DISTANCE ||
404 *values == AL_INVERSE_DISTANCE_CLAMPED ||
405 *values == AL_LINEAR_DISTANCE ||
406 *values == AL_LINEAR_DISTANCE_CLAMPED ||
407 *values == AL_EXPONENT_DISTANCE ||
408 *values == AL_EXPONENT_DISTANCE_CLAMPED);
410 Source->DistanceModel = *values;
411 if(Context->SourceDistanceModel)
412 Source->NeedsUpdate = AL_TRUE;
413 break;
416 case AL_AUXILIARY_SEND_FILTER:
417 LockContext(Context);
418 if(!((ALuint)values[1] < device->NumAuxSends &&
419 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
420 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
422 UnlockContext(Context);
423 RETERR(AL_INVALID_VALUE);
426 /* Add refcount on the new slot, and release the previous slot */
427 if(slot) IncrementRef(&slot->ref);
428 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
429 if(slot) DecrementRef(&slot->ref);
431 if(!filter)
433 /* Disable filter */
434 Source->Send[values[1]].Gain = 1.0f;
435 Source->Send[values[1]].GainHF = 1.0f;
437 else
439 Source->Send[values[1]].Gain = filter->Gain;
440 Source->Send[values[1]].GainHF = filter->GainHF;
442 Source->NeedsUpdate = AL_TRUE;
443 UnlockContext(Context);
444 break;
447 case AL_MAX_DISTANCE:
448 case AL_ROLLOFF_FACTOR:
449 case AL_CONE_INNER_ANGLE:
450 case AL_CONE_OUTER_ANGLE:
451 case AL_REFERENCE_DISTANCE:
452 fvals[0] = (ALfloat)*values;
453 if((err=SetSourcefv(Source, Context, name, fvals)) != AL_NO_ERROR)
454 return err;
455 break;
457 case AL_POSITION:
458 case AL_VELOCITY:
459 case AL_DIRECTION:
460 fvals[0] = (ALfloat)values[0];
461 fvals[1] = (ALfloat)values[1];
462 fvals[2] = (ALfloat)values[2];
463 if((err=SetSourcefv(Source, Context, name, fvals)) != AL_NO_ERROR)
464 return err;
465 break;
467 default:
468 ERR("Unexpected param: 0x%04x\n", name);
469 RETERR(AL_INVALID_ENUM);
472 return AL_NO_ERROR;
475 static ALenum SetSourcei64v(ALsource *Source, ALCcontext *Context, ALenum name, const ALint64SOFT *values)
477 ALfloat fvals[3];
478 ALint ivals[3];
479 ALenum err;
481 switch(name)
483 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
484 /* Query only */
485 RETERR(AL_INVALID_OPERATION);
488 /* 1x int */
489 case AL_SOURCE_RELATIVE:
490 case AL_LOOPING:
491 case AL_SOURCE_STATE:
492 case AL_BYTE_OFFSET:
493 case AL_SAMPLE_OFFSET:
494 case AL_DIRECT_FILTER_GAINHF_AUTO:
495 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
496 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
497 case AL_DIRECT_CHANNELS_SOFT:
498 case AL_DISTANCE_MODEL:
499 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
501 ivals[0] = (ALint)*values;
502 if((err=SetSourceiv(Source, Context, name, ivals)))
503 return err;
504 break;
506 /* 1x uint */
507 case AL_BUFFER:
508 case AL_DIRECT_FILTER:
509 CHECKVAL(*values <= UINT_MAX && *values >= 0);
511 ivals[0] = (ALuint)*values;
512 if((err=SetSourceiv(Source, Context, name, ivals)))
513 return err;
514 break;
516 /* 3x uint */
517 case AL_AUXILIARY_SEND_FILTER:
518 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
519 values[1] <= UINT_MAX && values[1] >= 0 &&
520 values[2] <= UINT_MAX && values[2] >= 0);
522 ivals[0] = (ALuint)values[0];
523 ivals[1] = (ALuint)values[1];
524 ivals[2] = (ALuint)values[2];
525 if((err=SetSourceiv(Source, Context, name, ivals)))
526 return err;
527 break;
529 /* 1x float */
530 case AL_MAX_DISTANCE:
531 case AL_ROLLOFF_FACTOR:
532 case AL_CONE_INNER_ANGLE:
533 case AL_CONE_OUTER_ANGLE:
534 case AL_REFERENCE_DISTANCE:
535 case AL_SEC_OFFSET:
536 fvals[0] = (ALfloat)*values;
537 if((err=SetSourcefv(Source, Context, name, fvals)) != AL_NO_ERROR)
538 return err;
539 break;
541 /* 3x float */
542 case AL_POSITION:
543 case AL_VELOCITY:
544 case AL_DIRECTION:
545 fvals[0] = (ALfloat)values[0];
546 fvals[1] = (ALfloat)values[1];
547 fvals[2] = (ALfloat)values[2];
548 if((err=SetSourcefv(Source, Context, name, fvals)) != AL_NO_ERROR)
549 return err;
550 break;
552 default:
553 ERR("Unexpected param: 0x%04x\n", name);
554 RETERR(AL_INVALID_ENUM);
557 return AL_NO_ERROR;
560 #undef CHECKVAL
563 static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, ALenum name, ALdouble *values)
565 ALdouble offsets[2];
566 ALdouble updateLen;
567 ALint ivals[3];
568 ALenum err;
570 switch(name)
572 case AL_GAIN:
573 *values = Source->Gain;
574 break;
576 case AL_PITCH:
577 *values = Source->Pitch;
578 break;
580 case AL_MAX_DISTANCE:
581 *values = Source->MaxDistance;
582 break;
584 case AL_ROLLOFF_FACTOR:
585 *values = Source->RollOffFactor;
586 break;
588 case AL_REFERENCE_DISTANCE:
589 *values = Source->RefDistance;
590 break;
592 case AL_CONE_INNER_ANGLE:
593 *values = Source->InnerAngle;
594 break;
596 case AL_CONE_OUTER_ANGLE:
597 *values = Source->OuterAngle;
598 break;
600 case AL_MIN_GAIN:
601 *values = Source->MinGain;
602 break;
604 case AL_MAX_GAIN:
605 *values = Source->MaxGain;
606 break;
608 case AL_CONE_OUTER_GAIN:
609 *values = Source->OuterGain;
610 break;
612 case AL_SEC_OFFSET:
613 case AL_SAMPLE_OFFSET:
614 case AL_BYTE_OFFSET:
615 LockContext(Context);
616 updateLen = (ALdouble)Context->Device->UpdateSize /
617 Context->Device->Frequency;
618 GetSourceOffsets(Source, name, offsets, updateLen);
619 UnlockContext(Context);
620 *values = offsets[0];
621 break;
623 case AL_CONE_OUTER_GAINHF:
624 *values = Source->OuterGainHF;
625 break;
627 case AL_AIR_ABSORPTION_FACTOR:
628 *values = Source->AirAbsorptionFactor;
629 break;
631 case AL_ROOM_ROLLOFF_FACTOR:
632 *values = Source->RoomRolloffFactor;
633 break;
635 case AL_DOPPLER_FACTOR:
636 *values = Source->DopplerFactor;
637 break;
639 case AL_SAMPLE_RW_OFFSETS_SOFT:
640 case AL_BYTE_RW_OFFSETS_SOFT:
641 LockContext(Context);
642 updateLen = (ALdouble)Context->Device->UpdateSize /
643 Context->Device->Frequency;
644 GetSourceOffsets(Source, name, values, updateLen);
645 UnlockContext(Context);
646 break;
648 case AL_SEC_OFFSET_LATENCY_SOFT:
649 LockContext(Context);
650 values[0] = GetSourceSecOffset(Source);
651 values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) /
652 1000000000.0;
653 UnlockContext(Context);
654 break;
656 case AL_POSITION:
657 LockContext(Context);
658 values[0] = Source->Position[0];
659 values[1] = Source->Position[1];
660 values[2] = Source->Position[2];
661 UnlockContext(Context);
662 break;
664 case AL_VELOCITY:
665 LockContext(Context);
666 values[0] = Source->Velocity[0];
667 values[1] = Source->Velocity[1];
668 values[2] = Source->Velocity[2];
669 UnlockContext(Context);
670 break;
672 case AL_DIRECTION:
673 LockContext(Context);
674 values[0] = Source->Orientation[0];
675 values[1] = Source->Orientation[1];
676 values[2] = Source->Orientation[2];
677 UnlockContext(Context);
678 break;
680 case AL_SOURCE_RELATIVE:
681 case AL_LOOPING:
682 case AL_BUFFER:
683 case AL_SOURCE_STATE:
684 case AL_BUFFERS_QUEUED:
685 case AL_BUFFERS_PROCESSED:
686 case AL_SOURCE_TYPE:
687 case AL_DIRECT_FILTER_GAINHF_AUTO:
688 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
689 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
690 case AL_DIRECT_CHANNELS_SOFT:
691 case AL_DISTANCE_MODEL:
692 if((err=GetSourceiv(Source, Context, name, ivals)) != AL_NO_ERROR)
693 return err;
694 *values = (ALdouble)ivals[0];
695 break;
697 default:
698 ERR("Unexpected param: 0x%04x\n", name);
699 RETERR(AL_INVALID_ENUM);
702 return AL_NO_ERROR;
705 static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, ALenum name, ALint *values)
707 ALbufferlistitem *BufferList;
708 ALdouble dvals[3];
709 ALenum err;
711 switch(name)
713 case AL_SOURCE_RELATIVE:
714 *values = Source->HeadRelative;
715 break;
717 case AL_LOOPING:
718 *values = Source->Looping;
719 break;
721 case AL_BUFFER:
722 LockContext(Context);
723 BufferList = Source->queue;
724 if(Source->SourceType != AL_STATIC)
726 ALuint i = Source->BuffersPlayed;
727 while(i > 0)
729 BufferList = BufferList->next;
730 i--;
733 *values = ((BufferList && BufferList->buffer) ?
734 BufferList->buffer->id : 0);
735 UnlockContext(Context);
736 break;
738 case AL_SOURCE_STATE:
739 *values = Source->state;
740 break;
742 case AL_BUFFERS_QUEUED:
743 *values = Source->BuffersInQueue;
744 break;
746 case AL_BUFFERS_PROCESSED:
747 LockContext(Context);
748 if(Source->Looping || Source->SourceType != AL_STREAMING)
750 /* Buffers on a looping source are in a perpetual state of
751 * PENDING, so don't report any as PROCESSED */
752 *values = 0;
754 else
755 *values = Source->BuffersPlayed;
756 UnlockContext(Context);
757 break;
759 case AL_SOURCE_TYPE:
760 *values = Source->SourceType;
761 break;
763 case AL_DIRECT_FILTER_GAINHF_AUTO:
764 *values = Source->DryGainHFAuto;
765 break;
767 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
768 *values = Source->WetGainAuto;
769 break;
771 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
772 *values = Source->WetGainHFAuto;
773 break;
775 case AL_DIRECT_CHANNELS_SOFT:
776 *values = Source->DirectChannels;
777 break;
779 case AL_DISTANCE_MODEL:
780 *values = Source->DistanceModel;
781 break;
783 case AL_MAX_DISTANCE:
784 case AL_ROLLOFF_FACTOR:
785 case AL_REFERENCE_DISTANCE:
786 case AL_CONE_INNER_ANGLE:
787 case AL_CONE_OUTER_ANGLE:
788 case AL_SEC_OFFSET:
789 case AL_SAMPLE_OFFSET:
790 case AL_BYTE_OFFSET:
791 case AL_DOPPLER_FACTOR:
792 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
793 return err;
794 *values = (ALint)dvals[0];
795 break;
797 case AL_SAMPLE_RW_OFFSETS_SOFT:
798 case AL_BYTE_RW_OFFSETS_SOFT:
799 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
800 return err;
801 values[0] = (ALint)dvals[0];
802 values[1] = (ALint)dvals[1];
803 break;
805 case AL_POSITION:
806 case AL_VELOCITY:
807 case AL_DIRECTION:
808 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
809 return err;
810 values[0] = (ALint)dvals[0];
811 values[1] = (ALint)dvals[1];
812 values[2] = (ALint)dvals[2];
813 break;
815 default:
816 ERR("Unexpected param: 0x%04x\n", name);
817 RETERR(AL_INVALID_ENUM);
820 return AL_NO_ERROR;
823 static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, ALenum name, ALint64 *values)
825 ALdouble dvals[3];
826 ALint ivals[3];
827 ALenum err;
829 switch(name)
831 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
832 LockContext(Context);
833 values[0] = GetSourceOffset(Source);
834 values[1] = ALCdevice_GetLatency(Context->Device);
835 UnlockContext(Context);
836 break;
838 case AL_MAX_DISTANCE:
839 case AL_ROLLOFF_FACTOR:
840 case AL_REFERENCE_DISTANCE:
841 case AL_CONE_INNER_ANGLE:
842 case AL_CONE_OUTER_ANGLE:
843 case AL_SEC_OFFSET:
844 case AL_SAMPLE_OFFSET:
845 case AL_BYTE_OFFSET:
846 case AL_DOPPLER_FACTOR:
847 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
848 return err;
849 *values = (ALint64)dvals[0];
850 break;
852 case AL_SAMPLE_RW_OFFSETS_SOFT:
853 case AL_BYTE_RW_OFFSETS_SOFT:
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 break;
860 case AL_POSITION:
861 case AL_VELOCITY:
862 case AL_DIRECTION:
863 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
864 return err;
865 values[0] = (ALint64)dvals[0];
866 values[1] = (ALint64)dvals[1];
867 values[2] = (ALint64)dvals[2];
868 break;
870 case AL_SOURCE_RELATIVE:
871 case AL_LOOPING:
872 case AL_BUFFER:
873 case AL_SOURCE_STATE:
874 case AL_BUFFERS_QUEUED:
875 case AL_BUFFERS_PROCESSED:
876 case AL_SOURCE_TYPE:
877 case AL_DIRECT_FILTER_GAINHF_AUTO:
878 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
879 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
880 case AL_DIRECT_CHANNELS_SOFT:
881 case AL_DISTANCE_MODEL:
882 if((err=GetSourceiv(Source, Context, name, ivals)) != AL_NO_ERROR)
883 return err;
884 *values = ivals[0];
885 break;
887 default:
888 ERR("Unexpected param: 0x%04x\n", name);
889 RETERR(AL_INVALID_ENUM);
892 return AL_NO_ERROR;
895 #undef RETERR
898 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
900 ALCcontext *Context;
901 ALsizei cur = 0;
903 Context = GetContextRef();
904 if(!Context) return;
906 al_try
908 ALenum err;
910 CHECK_VALUE(Context, n >= 0);
911 for(cur = 0;cur < n;cur++)
913 ALsource *source = al_calloc(16, sizeof(ALsource));
914 if(!source)
915 al_throwerr(Context, AL_OUT_OF_MEMORY);
916 InitSourceParams(source);
918 err = NewThunkEntry(&source->id);
919 if(err == AL_NO_ERROR)
920 err = InsertUIntMapEntry(&Context->SourceMap, source->id, source);
921 if(err != AL_NO_ERROR)
923 FreeThunkEntry(source->id);
924 memset(source, 0, sizeof(ALsource));
925 al_free(source);
927 al_throwerr(Context, err);
930 sources[cur] = source->id;
933 al_catchany()
935 if(cur > 0)
936 alDeleteSources(cur, sources);
938 al_endtry;
940 ALCcontext_DecRef(Context);
944 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
946 ALCcontext *Context;
948 Context = GetContextRef();
949 if(!Context) return;
951 al_try
953 ALbufferlistitem *BufferList;
954 ALsource *Source;
955 ALsizei i, j;
957 CHECK_VALUE(Context, n >= 0);
959 /* Check that all Sources are valid */
960 for(i = 0;i < n;i++)
962 if(LookupSource(Context, sources[i]) == NULL)
963 al_throwerr(Context, AL_INVALID_NAME);
966 for(i = 0;i < n;i++)
968 ALsource **srclist, **srclistend;
970 if((Source=RemoveSource(Context, sources[i])) == NULL)
971 continue;
972 FreeThunkEntry(Source->id);
974 LockContext(Context);
975 srclist = Context->ActiveSources;
976 srclistend = srclist + Context->ActiveSourceCount;
977 while(srclist != srclistend)
979 if(*srclist == Source)
981 Context->ActiveSourceCount--;
982 *srclist = *(--srclistend);
983 break;
985 srclist++;
987 UnlockContext(Context);
989 while(Source->queue != NULL)
991 BufferList = Source->queue;
992 Source->queue = BufferList->next;
994 if(BufferList->buffer != NULL)
995 DecrementRef(&BufferList->buffer->ref);
996 free(BufferList);
999 for(j = 0;j < MAX_SENDS;++j)
1001 if(Source->Send[j].Slot)
1002 DecrementRef(&Source->Send[j].Slot->ref);
1003 Source->Send[j].Slot = NULL;
1006 memset(Source, 0, sizeof(*Source));
1007 al_free(Source);
1010 al_endtry;
1012 ALCcontext_DecRef(Context);
1016 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1018 ALCcontext *Context;
1019 ALboolean result;
1021 Context = GetContextRef();
1022 if(!Context) return AL_FALSE;
1024 result = (LookupSource(Context, source) ? AL_TRUE : AL_FALSE);
1026 ALCcontext_DecRef(Context);
1028 return result;
1032 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1034 ALCcontext *Context;
1035 ALsource *Source;
1037 Context = GetContextRef();
1038 if(!Context) return;
1040 if((Source=LookupSource(Context, source)) == NULL)
1041 alSetError(Context, AL_INVALID_NAME);
1042 else switch(param)
1044 case AL_PITCH:
1045 case AL_CONE_INNER_ANGLE:
1046 case AL_CONE_OUTER_ANGLE:
1047 case AL_GAIN:
1048 case AL_MAX_DISTANCE:
1049 case AL_ROLLOFF_FACTOR:
1050 case AL_REFERENCE_DISTANCE:
1051 case AL_MIN_GAIN:
1052 case AL_MAX_GAIN:
1053 case AL_CONE_OUTER_GAIN:
1054 case AL_CONE_OUTER_GAINHF:
1055 case AL_AIR_ABSORPTION_FACTOR:
1056 case AL_ROOM_ROLLOFF_FACTOR:
1057 case AL_DOPPLER_FACTOR:
1058 case AL_SEC_OFFSET:
1059 case AL_SAMPLE_OFFSET:
1060 case AL_BYTE_OFFSET:
1061 SetSourcefv(Source, Context, param, &value);
1062 break;
1064 default:
1065 alSetError(Context, AL_INVALID_ENUM);
1068 ALCcontext_DecRef(Context);
1071 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1073 ALCcontext *Context;
1074 ALsource *Source;
1075 ALfloat fvals[3];
1077 Context = GetContextRef();
1078 if(!Context) return;
1080 if((Source=LookupSource(Context, source)) == NULL)
1081 alSetError(Context, AL_INVALID_NAME);
1082 else switch(param)
1084 case AL_POSITION:
1085 case AL_VELOCITY:
1086 case AL_DIRECTION:
1087 fvals[0] = value1;
1088 fvals[1] = value2;
1089 fvals[2] = value3;
1090 SetSourcefv(Source, Context, param, fvals);
1091 break;
1093 default:
1094 alSetError(Context, AL_INVALID_ENUM);
1097 ALCcontext_DecRef(Context);
1100 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1102 ALCcontext *Context;
1103 ALsource *Source;
1105 Context = GetContextRef();
1106 if(!Context) return;
1108 if((Source=LookupSource(Context, source)) == NULL)
1109 alSetError(Context, AL_INVALID_NAME);
1110 else if(!values)
1111 alSetError(Context, AL_INVALID_VALUE);
1112 else switch(param)
1114 case AL_PITCH:
1115 case AL_CONE_INNER_ANGLE:
1116 case AL_CONE_OUTER_ANGLE:
1117 case AL_GAIN:
1118 case AL_MAX_DISTANCE:
1119 case AL_ROLLOFF_FACTOR:
1120 case AL_REFERENCE_DISTANCE:
1121 case AL_MIN_GAIN:
1122 case AL_MAX_GAIN:
1123 case AL_CONE_OUTER_GAIN:
1124 case AL_CONE_OUTER_GAINHF:
1125 case AL_SEC_OFFSET:
1126 case AL_SAMPLE_OFFSET:
1127 case AL_BYTE_OFFSET:
1128 case AL_AIR_ABSORPTION_FACTOR:
1129 case AL_ROOM_ROLLOFF_FACTOR:
1131 case AL_POSITION:
1132 case AL_VELOCITY:
1133 case AL_DIRECTION:
1134 SetSourcefv(Source, Context, param, values);
1135 break;
1137 default:
1138 alSetError(Context, AL_INVALID_ENUM);
1141 ALCcontext_DecRef(Context);
1145 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1147 ALCcontext *Context;
1148 ALsource *Source;
1149 ALfloat fval;
1151 Context = GetContextRef();
1152 if(!Context) return;
1154 if((Source=LookupSource(Context, source)) == NULL)
1155 alSetError(Context, AL_INVALID_NAME);
1156 else switch(param)
1158 case AL_PITCH:
1159 case AL_CONE_INNER_ANGLE:
1160 case AL_CONE_OUTER_ANGLE:
1161 case AL_GAIN:
1162 case AL_MAX_DISTANCE:
1163 case AL_ROLLOFF_FACTOR:
1164 case AL_REFERENCE_DISTANCE:
1165 case AL_MIN_GAIN:
1166 case AL_MAX_GAIN:
1167 case AL_CONE_OUTER_GAIN:
1168 case AL_CONE_OUTER_GAINHF:
1169 case AL_AIR_ABSORPTION_FACTOR:
1170 case AL_ROOM_ROLLOFF_FACTOR:
1171 case AL_DOPPLER_FACTOR:
1172 case AL_SEC_OFFSET:
1173 case AL_SAMPLE_OFFSET:
1174 case AL_BYTE_OFFSET:
1175 fval = (ALfloat)value;
1176 SetSourcefv(Source, Context, param, &fval);
1177 break;
1179 default:
1180 alSetError(Context, AL_INVALID_ENUM);
1183 ALCcontext_DecRef(Context);
1186 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1188 ALCcontext *Context;
1189 ALsource *Source;
1190 ALfloat fvals[3];
1192 Context = GetContextRef();
1193 if(!Context) return;
1195 if((Source=LookupSource(Context, source)) == NULL)
1196 alSetError(Context, AL_INVALID_NAME);
1197 else switch(param)
1199 case AL_POSITION:
1200 case AL_VELOCITY:
1201 case AL_DIRECTION:
1202 fvals[0] = (ALfloat)value1;
1203 fvals[1] = (ALfloat)value2;
1204 fvals[2] = (ALfloat)value3;
1205 SetSourcefv(Source, Context, param, fvals);
1206 break;
1208 default:
1209 alSetError(Context, AL_INVALID_ENUM);
1212 ALCcontext_DecRef(Context);
1215 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1217 ALCcontext *Context;
1218 ALsource *Source;
1219 ALfloat fvals[3];
1221 Context = GetContextRef();
1222 if(!Context) return;
1224 if((Source=LookupSource(Context, source)) == NULL)
1225 alSetError(Context, AL_INVALID_NAME);
1226 else if(!values)
1227 alSetError(Context, AL_INVALID_VALUE);
1228 else switch(param)
1230 case AL_PITCH:
1231 case AL_CONE_INNER_ANGLE:
1232 case AL_CONE_OUTER_ANGLE:
1233 case AL_GAIN:
1234 case AL_MAX_DISTANCE:
1235 case AL_ROLLOFF_FACTOR:
1236 case AL_REFERENCE_DISTANCE:
1237 case AL_MIN_GAIN:
1238 case AL_MAX_GAIN:
1239 case AL_CONE_OUTER_GAIN:
1240 case AL_CONE_OUTER_GAINHF:
1241 case AL_SEC_OFFSET:
1242 case AL_SAMPLE_OFFSET:
1243 case AL_BYTE_OFFSET:
1244 case AL_AIR_ABSORPTION_FACTOR:
1245 case AL_ROOM_ROLLOFF_FACTOR:
1246 fvals[0] = (ALfloat)values[0];
1247 SetSourcefv(Source, Context, param, fvals);
1248 break;
1250 case AL_SEC_OFFSET_LATENCY_SOFT:
1251 fvals[0] = (ALfloat)values[0];
1252 fvals[1] = (ALfloat)values[1];
1253 SetSourcefv(Source, Context, param, fvals);
1254 break;
1256 case AL_POSITION:
1257 case AL_VELOCITY:
1258 case AL_DIRECTION:
1259 fvals[0] = (ALfloat)values[0];
1260 fvals[1] = (ALfloat)values[1];
1261 fvals[2] = (ALfloat)values[2];
1262 SetSourcefv(Source, Context, param, fvals);
1263 break;
1265 default:
1266 alSetError(Context, AL_INVALID_ENUM);
1269 ALCcontext_DecRef(Context);
1273 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1275 ALCcontext *Context;
1276 ALsource *Source;
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_MAX_DISTANCE:
1286 case AL_ROLLOFF_FACTOR:
1287 case AL_CONE_INNER_ANGLE:
1288 case AL_CONE_OUTER_ANGLE:
1289 case AL_REFERENCE_DISTANCE:
1290 case AL_SOURCE_RELATIVE:
1291 case AL_LOOPING:
1292 case AL_BUFFER:
1293 case AL_SOURCE_STATE:
1294 case AL_SEC_OFFSET:
1295 case AL_SAMPLE_OFFSET:
1296 case AL_BYTE_OFFSET:
1297 case AL_DIRECT_FILTER:
1298 case AL_DIRECT_FILTER_GAINHF_AUTO:
1299 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1300 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1301 case AL_DIRECT_CHANNELS_SOFT:
1302 case AL_DISTANCE_MODEL:
1303 SetSourceiv(Source, Context, param, &value);
1304 break;
1306 default:
1307 alSetError(Context, AL_INVALID_ENUM);
1310 ALCcontext_DecRef(Context);
1313 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1315 ALCcontext *Context;
1316 ALsource *Source;
1317 ALint ivals[3];
1319 Context = GetContextRef();
1320 if(!Context) return;
1322 if((Source=LookupSource(Context, source)) == NULL)
1323 alSetError(Context, AL_INVALID_NAME);
1324 else switch(param)
1326 case AL_POSITION:
1327 case AL_VELOCITY:
1328 case AL_DIRECTION:
1329 case AL_AUXILIARY_SEND_FILTER:
1330 ivals[0] = value1;
1331 ivals[1] = value2;
1332 ivals[2] = value3;
1333 SetSourceiv(Source, Context, param, ivals);
1334 break;
1336 default:
1337 alSetError(Context, AL_INVALID_ENUM);
1340 ALCcontext_DecRef(Context);
1343 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1345 ALCcontext *Context;
1346 ALsource *Source;
1348 Context = GetContextRef();
1349 if(!Context) return;
1351 if((Source=LookupSource(Context, source)) == NULL)
1352 alSetError(Context, AL_INVALID_NAME);
1353 else if(!values)
1354 alSetError(Context, AL_INVALID_VALUE);
1355 else switch(param)
1357 case AL_SOURCE_RELATIVE:
1358 case AL_CONE_INNER_ANGLE:
1359 case AL_CONE_OUTER_ANGLE:
1360 case AL_LOOPING:
1361 case AL_BUFFER:
1362 case AL_SOURCE_STATE:
1363 case AL_SEC_OFFSET:
1364 case AL_SAMPLE_OFFSET:
1365 case AL_BYTE_OFFSET:
1366 case AL_MAX_DISTANCE:
1367 case AL_ROLLOFF_FACTOR:
1368 case AL_REFERENCE_DISTANCE:
1369 case AL_DIRECT_FILTER:
1370 case AL_DIRECT_FILTER_GAINHF_AUTO:
1371 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1372 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1373 case AL_DISTANCE_MODEL:
1374 case AL_DIRECT_CHANNELS_SOFT:
1376 case AL_POSITION:
1377 case AL_VELOCITY:
1378 case AL_DIRECTION:
1379 case AL_AUXILIARY_SEND_FILTER:
1380 SetSourceiv(Source, Context, param, values);
1381 break;
1383 default:
1384 alSetError(Context, AL_INVALID_ENUM);
1387 ALCcontext_DecRef(Context);
1391 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1393 ALCcontext *Context;
1394 ALsource *Source;
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_MAX_DISTANCE:
1404 case AL_ROLLOFF_FACTOR:
1405 case AL_CONE_INNER_ANGLE:
1406 case AL_CONE_OUTER_ANGLE:
1407 case AL_REFERENCE_DISTANCE:
1408 case AL_SOURCE_RELATIVE:
1409 case AL_LOOPING:
1410 case AL_SOURCE_STATE:
1411 case AL_SEC_OFFSET:
1412 case AL_SAMPLE_OFFSET:
1413 case AL_BYTE_OFFSET:
1414 case AL_DIRECT_FILTER_GAINHF_AUTO:
1415 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1416 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1417 case AL_DIRECT_CHANNELS_SOFT:
1418 case AL_DISTANCE_MODEL:
1419 case AL_BUFFER:
1420 case AL_DIRECT_FILTER:
1421 SetSourcei64v(Source, Context, param, &value);
1422 break;
1424 default:
1425 alSetError(Context, AL_INVALID_ENUM);
1428 ALCcontext_DecRef(Context);
1431 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1433 ALCcontext *Context;
1434 ALsource *Source;
1435 ALint64SOFT i64vals[3];
1437 Context = GetContextRef();
1438 if(!Context) return;
1440 if((Source=LookupSource(Context, source)) == NULL)
1441 alSetError(Context, AL_INVALID_NAME);
1442 else switch(param)
1444 case AL_POSITION:
1445 case AL_VELOCITY:
1446 case AL_DIRECTION:
1447 case AL_AUXILIARY_SEND_FILTER:
1448 i64vals[0] = value1;
1449 i64vals[1] = value2;
1450 i64vals[2] = value3;
1451 SetSourcei64v(Source, Context, param, i64vals);
1452 break;
1454 default:
1455 alSetError(Context, AL_INVALID_ENUM);
1458 ALCcontext_DecRef(Context);
1461 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1463 ALCcontext *Context;
1464 ALsource *Source;
1466 Context = GetContextRef();
1467 if(!Context) return;
1469 if((Source=LookupSource(Context, source)) == NULL)
1470 alSetError(Context, AL_INVALID_NAME);
1471 else if(!values)
1472 alSetError(Context, AL_INVALID_VALUE);
1473 else switch(param)
1475 case AL_SOURCE_RELATIVE:
1476 case AL_CONE_INNER_ANGLE:
1477 case AL_CONE_OUTER_ANGLE:
1478 case AL_LOOPING:
1479 case AL_SOURCE_STATE:
1480 case AL_SEC_OFFSET:
1481 case AL_SAMPLE_OFFSET:
1482 case AL_BYTE_OFFSET:
1483 case AL_MAX_DISTANCE:
1484 case AL_ROLLOFF_FACTOR:
1485 case AL_REFERENCE_DISTANCE:
1486 case AL_DIRECT_FILTER_GAINHF_AUTO:
1487 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1488 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1489 case AL_DISTANCE_MODEL:
1490 case AL_DIRECT_CHANNELS_SOFT:
1491 case AL_BUFFER:
1492 case AL_DIRECT_FILTER:
1494 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1496 case AL_POSITION:
1497 case AL_VELOCITY:
1498 case AL_DIRECTION:
1499 case AL_AUXILIARY_SEND_FILTER:
1500 SetSourcei64v(Source, Context, param, values);
1501 break;
1503 default:
1504 alSetError(Context, AL_INVALID_ENUM);
1507 ALCcontext_DecRef(Context);
1511 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1513 ALCcontext *Context;
1514 ALsource *Source;
1515 ALdouble dval;
1517 Context = GetContextRef();
1518 if(!Context) return;
1520 if((Source=LookupSource(Context, source)) == NULL)
1521 alSetError(Context, AL_INVALID_NAME);
1522 else if(!value)
1523 alSetError(Context, AL_INVALID_VALUE);
1524 else switch(param)
1526 case AL_PITCH:
1527 case AL_GAIN:
1528 case AL_MIN_GAIN:
1529 case AL_MAX_GAIN:
1530 case AL_MAX_DISTANCE:
1531 case AL_ROLLOFF_FACTOR:
1532 case AL_CONE_OUTER_GAIN:
1533 case AL_CONE_OUTER_GAINHF:
1534 case AL_SEC_OFFSET:
1535 case AL_SAMPLE_OFFSET:
1536 case AL_BYTE_OFFSET:
1537 case AL_CONE_INNER_ANGLE:
1538 case AL_CONE_OUTER_ANGLE:
1539 case AL_REFERENCE_DISTANCE:
1540 case AL_AIR_ABSORPTION_FACTOR:
1541 case AL_ROOM_ROLLOFF_FACTOR:
1542 case AL_DOPPLER_FACTOR:
1543 if(GetSourcedv(Source, Context, param, &dval) == AL_NO_ERROR)
1544 *value = (ALfloat)dval;
1545 break;
1547 default:
1548 alSetError(Context, AL_INVALID_ENUM);
1551 ALCcontext_DecRef(Context);
1555 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1557 ALCcontext *Context;
1558 ALsource *Source;
1559 ALdouble dvals[3];
1561 Context = GetContextRef();
1562 if(!Context) return;
1564 if((Source=LookupSource(Context, source)) == NULL)
1565 alSetError(Context, AL_INVALID_NAME);
1566 else if(!(value1 && value2 && value3))
1567 alSetError(Context, AL_INVALID_VALUE);
1568 else switch(param)
1570 case AL_POSITION:
1571 case AL_VELOCITY:
1572 case AL_DIRECTION:
1573 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1575 *value1 = (ALfloat)dvals[0];
1576 *value2 = (ALfloat)dvals[1];
1577 *value3 = (ALfloat)dvals[2];
1579 break;
1581 default:
1582 alSetError(Context, AL_INVALID_ENUM);
1585 ALCcontext_DecRef(Context);
1589 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1591 ALCcontext *Context;
1592 ALsource *Source;
1593 ALdouble dvals[2];
1595 switch(param)
1597 case AL_PITCH:
1598 case AL_GAIN:
1599 case AL_MIN_GAIN:
1600 case AL_MAX_GAIN:
1601 case AL_MAX_DISTANCE:
1602 case AL_ROLLOFF_FACTOR:
1603 case AL_DOPPLER_FACTOR:
1604 case AL_CONE_OUTER_GAIN:
1605 case AL_SEC_OFFSET:
1606 case AL_SAMPLE_OFFSET:
1607 case AL_BYTE_OFFSET:
1608 case AL_CONE_INNER_ANGLE:
1609 case AL_CONE_OUTER_ANGLE:
1610 case AL_REFERENCE_DISTANCE:
1611 case AL_CONE_OUTER_GAINHF:
1612 case AL_AIR_ABSORPTION_FACTOR:
1613 case AL_ROOM_ROLLOFF_FACTOR:
1614 alGetSourcef(source, param, values);
1615 return;
1617 case AL_POSITION:
1618 case AL_VELOCITY:
1619 case AL_DIRECTION:
1620 alGetSource3f(source, param, values+0, values+1, values+2);
1621 return;
1624 Context = GetContextRef();
1625 if(!Context) return;
1627 if((Source=LookupSource(Context, source)) == NULL)
1628 alSetError(Context, AL_INVALID_NAME);
1629 else if(!values)
1630 alSetError(Context, AL_INVALID_VALUE);
1631 else switch(param)
1633 case AL_SAMPLE_RW_OFFSETS_SOFT:
1634 case AL_BYTE_RW_OFFSETS_SOFT:
1635 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1637 values[0] = (ALfloat)dvals[0];
1638 values[1] = (ALfloat)dvals[1];
1640 break;
1642 default:
1643 alSetError(Context, AL_INVALID_ENUM);
1646 ALCcontext_DecRef(Context);
1650 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1652 ALCcontext *Context;
1653 ALsource *Source;
1655 Context = GetContextRef();
1656 if(!Context) return;
1658 if((Source=LookupSource(Context, source)) == NULL)
1659 alSetError(Context, AL_INVALID_NAME);
1660 else if(!value)
1661 alSetError(Context, AL_INVALID_VALUE);
1662 else switch(param)
1664 case AL_PITCH:
1665 case AL_GAIN:
1666 case AL_MIN_GAIN:
1667 case AL_MAX_GAIN:
1668 case AL_MAX_DISTANCE:
1669 case AL_ROLLOFF_FACTOR:
1670 case AL_CONE_OUTER_GAIN:
1671 case AL_CONE_OUTER_GAINHF:
1672 case AL_SEC_OFFSET:
1673 case AL_SAMPLE_OFFSET:
1674 case AL_BYTE_OFFSET:
1675 case AL_CONE_INNER_ANGLE:
1676 case AL_CONE_OUTER_ANGLE:
1677 case AL_REFERENCE_DISTANCE:
1678 case AL_AIR_ABSORPTION_FACTOR:
1679 case AL_ROOM_ROLLOFF_FACTOR:
1680 case AL_DOPPLER_FACTOR:
1681 GetSourcedv(Source, Context, param, value);
1682 break;
1684 default:
1685 alSetError(Context, AL_INVALID_ENUM);
1688 ALCcontext_DecRef(Context);
1691 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1693 ALCcontext *Context;
1694 ALsource *Source;
1695 ALdouble dvals[3];
1697 Context = GetContextRef();
1698 if(!Context) return;
1700 if((Source=LookupSource(Context, source)) == NULL)
1701 alSetError(Context, AL_INVALID_NAME);
1702 else if(!(value1 && value2 && value3))
1703 alSetError(Context, AL_INVALID_VALUE);
1704 else switch(param)
1706 case AL_POSITION:
1707 case AL_VELOCITY:
1708 case AL_DIRECTION:
1709 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1711 *value1 = dvals[0];
1712 *value2 = dvals[1];
1713 *value3 = dvals[2];
1715 break;
1717 default:
1718 alSetError(Context, AL_INVALID_ENUM);
1721 ALCcontext_DecRef(Context);
1724 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1726 ALCcontext *Context;
1727 ALsource *Source;
1729 Context = GetContextRef();
1730 if(!Context) return;
1732 if((Source=LookupSource(Context, source)) == NULL)
1733 alSetError(Context, AL_INVALID_NAME);
1734 else if(!values)
1735 alSetError(Context, AL_INVALID_VALUE);
1736 else switch(param)
1738 case AL_PITCH:
1739 case AL_GAIN:
1740 case AL_MIN_GAIN:
1741 case AL_MAX_GAIN:
1742 case AL_MAX_DISTANCE:
1743 case AL_ROLLOFF_FACTOR:
1744 case AL_DOPPLER_FACTOR:
1745 case AL_CONE_OUTER_GAIN:
1746 case AL_SEC_OFFSET:
1747 case AL_SAMPLE_OFFSET:
1748 case AL_BYTE_OFFSET:
1749 case AL_CONE_INNER_ANGLE:
1750 case AL_CONE_OUTER_ANGLE:
1751 case AL_REFERENCE_DISTANCE:
1752 case AL_CONE_OUTER_GAINHF:
1753 case AL_AIR_ABSORPTION_FACTOR:
1754 case AL_ROOM_ROLLOFF_FACTOR:
1756 case AL_SAMPLE_RW_OFFSETS_SOFT:
1757 case AL_BYTE_RW_OFFSETS_SOFT:
1758 case AL_SEC_OFFSET_LATENCY_SOFT:
1760 case AL_POSITION:
1761 case AL_VELOCITY:
1762 case AL_DIRECTION:
1763 GetSourcedv(Source, Context, param, values);
1764 break;
1766 default:
1767 alSetError(Context, AL_INVALID_ENUM);
1770 ALCcontext_DecRef(Context);
1774 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1776 ALCcontext *Context;
1777 ALsource *Source;
1779 Context = GetContextRef();
1780 if(!Context) return;
1782 if((Source=LookupSource(Context, source)) == NULL)
1783 alSetError(Context, AL_INVALID_NAME);
1784 else if(!value)
1785 alSetError(Context, AL_INVALID_VALUE);
1786 else switch(param)
1788 case AL_MAX_DISTANCE:
1789 case AL_ROLLOFF_FACTOR:
1790 case AL_REFERENCE_DISTANCE:
1791 case AL_SOURCE_RELATIVE:
1792 case AL_CONE_INNER_ANGLE:
1793 case AL_CONE_OUTER_ANGLE:
1794 case AL_LOOPING:
1795 case AL_BUFFER:
1796 case AL_SOURCE_STATE:
1797 case AL_BUFFERS_QUEUED:
1798 case AL_BUFFERS_PROCESSED:
1799 case AL_SOURCE_TYPE:
1800 case AL_SEC_OFFSET:
1801 case AL_SAMPLE_OFFSET:
1802 case AL_BYTE_OFFSET:
1803 case AL_DIRECT_FILTER_GAINHF_AUTO:
1804 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1805 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1806 case AL_DOPPLER_FACTOR:
1807 case AL_DIRECT_CHANNELS_SOFT:
1808 case AL_DISTANCE_MODEL:
1809 GetSourceiv(Source, Context, param, value);
1810 break;
1812 default:
1813 alSetError(Context, AL_INVALID_ENUM);
1816 ALCcontext_DecRef(Context);
1820 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
1822 ALCcontext *Context;
1823 ALsource *Source;
1824 ALint ivals[3];
1826 Context = GetContextRef();
1827 if(!Context) return;
1829 if((Source=LookupSource(Context, source)) == NULL)
1830 alSetError(Context, AL_INVALID_NAME);
1831 else if(!(value1 && value2 && value3))
1832 alSetError(Context, AL_INVALID_VALUE);
1833 else switch(param)
1835 case AL_POSITION:
1836 case AL_VELOCITY:
1837 case AL_DIRECTION:
1838 if(GetSourceiv(Source, Context, param, ivals) == AL_NO_ERROR)
1840 *value1 = ivals[0];
1841 *value2 = ivals[1];
1842 *value3 = ivals[2];
1844 break;
1846 default:
1847 alSetError(Context, AL_INVALID_ENUM);
1850 ALCcontext_DecRef(Context);
1854 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
1856 ALCcontext *Context;
1857 ALsource *Source;
1859 Context = GetContextRef();
1860 if(!Context) return;
1862 if((Source=LookupSource(Context, source)) == NULL)
1863 alSetError(Context, AL_INVALID_NAME);
1864 else if(!values)
1865 alSetError(Context, AL_INVALID_VALUE);
1866 else switch(param)
1868 case AL_SOURCE_RELATIVE:
1869 case AL_CONE_INNER_ANGLE:
1870 case AL_CONE_OUTER_ANGLE:
1871 case AL_LOOPING:
1872 case AL_BUFFER:
1873 case AL_SOURCE_STATE:
1874 case AL_BUFFERS_QUEUED:
1875 case AL_BUFFERS_PROCESSED:
1876 case AL_SEC_OFFSET:
1877 case AL_SAMPLE_OFFSET:
1878 case AL_BYTE_OFFSET:
1879 case AL_MAX_DISTANCE:
1880 case AL_ROLLOFF_FACTOR:
1881 case AL_DOPPLER_FACTOR:
1882 case AL_REFERENCE_DISTANCE:
1883 case AL_SOURCE_TYPE:
1884 case AL_DIRECT_FILTER:
1885 case AL_DIRECT_FILTER_GAINHF_AUTO:
1886 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1887 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1888 case AL_DISTANCE_MODEL:
1889 case AL_DIRECT_CHANNELS_SOFT:
1891 case AL_SAMPLE_RW_OFFSETS_SOFT:
1892 case AL_BYTE_RW_OFFSETS_SOFT:
1894 case AL_POSITION:
1895 case AL_VELOCITY:
1896 case AL_DIRECTION:
1897 GetSourceiv(Source, Context, param, values);
1898 break;
1900 default:
1901 alSetError(Context, AL_INVALID_ENUM);
1904 ALCcontext_DecRef(Context);
1908 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
1910 ALCcontext *Context;
1911 ALsource *Source;
1913 Context = GetContextRef();
1914 if(!Context) return;
1916 if((Source=LookupSource(Context, source)) == NULL)
1917 alSetError(Context, AL_INVALID_NAME);
1918 else if(!value)
1919 alSetError(Context, AL_INVALID_VALUE);
1920 else switch(param)
1922 case AL_MAX_DISTANCE:
1923 case AL_ROLLOFF_FACTOR:
1924 case AL_REFERENCE_DISTANCE:
1925 case AL_SOURCE_RELATIVE:
1926 case AL_CONE_INNER_ANGLE:
1927 case AL_CONE_OUTER_ANGLE:
1928 case AL_LOOPING:
1929 case AL_BUFFER:
1930 case AL_SOURCE_STATE:
1931 case AL_BUFFERS_QUEUED:
1932 case AL_BUFFERS_PROCESSED:
1933 case AL_SOURCE_TYPE:
1934 case AL_SEC_OFFSET:
1935 case AL_SAMPLE_OFFSET:
1936 case AL_BYTE_OFFSET:
1937 case AL_DIRECT_FILTER_GAINHF_AUTO:
1938 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1939 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1940 case AL_DOPPLER_FACTOR:
1941 case AL_DIRECT_CHANNELS_SOFT:
1942 case AL_DISTANCE_MODEL:
1943 GetSourcei64v(Source, Context, param, value);
1944 break;
1946 default:
1947 alSetError(Context, AL_INVALID_ENUM);
1950 ALCcontext_DecRef(Context);
1953 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
1955 ALCcontext *Context;
1956 ALsource *Source;
1957 ALint64 i64vals[3];
1959 Context = GetContextRef();
1960 if(!Context) return;
1962 if((Source=LookupSource(Context, source)) == NULL)
1963 alSetError(Context, AL_INVALID_NAME);
1964 else if(!(value1 && value2 && value3))
1965 alSetError(Context, AL_INVALID_VALUE);
1966 else switch(param)
1968 case AL_POSITION:
1969 case AL_VELOCITY:
1970 case AL_DIRECTION:
1971 if(GetSourcei64v(Source, Context, param, i64vals) == AL_NO_ERROR)
1973 *value1 = i64vals[0];
1974 *value2 = i64vals[1];
1975 *value3 = i64vals[2];
1977 break;
1979 default:
1980 alSetError(Context, AL_INVALID_ENUM);
1983 ALCcontext_DecRef(Context);
1986 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
1988 ALCcontext *Context;
1989 ALsource *Source;
1991 Context = GetContextRef();
1992 if(!Context) return;
1994 if((Source=LookupSource(Context, source)) == NULL)
1995 alSetError(Context, AL_INVALID_NAME);
1996 else if(!values)
1997 alSetError(Context, AL_INVALID_VALUE);
1998 else switch(param)
2000 case AL_MAX_DISTANCE:
2001 case AL_ROLLOFF_FACTOR:
2002 case AL_REFERENCE_DISTANCE:
2003 case AL_SOURCE_RELATIVE:
2004 case AL_CONE_INNER_ANGLE:
2005 case AL_CONE_OUTER_ANGLE:
2006 case AL_LOOPING:
2007 case AL_BUFFER:
2008 case AL_SOURCE_STATE:
2009 case AL_BUFFERS_QUEUED:
2010 case AL_BUFFERS_PROCESSED:
2011 case AL_SOURCE_TYPE:
2012 case AL_SEC_OFFSET:
2013 case AL_SAMPLE_OFFSET:
2014 case AL_BYTE_OFFSET:
2015 case AL_DIRECT_FILTER_GAINHF_AUTO:
2016 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
2017 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
2018 case AL_DOPPLER_FACTOR:
2019 case AL_DIRECT_CHANNELS_SOFT:
2020 case AL_DISTANCE_MODEL:
2022 case AL_SAMPLE_RW_OFFSETS_SOFT:
2023 case AL_BYTE_RW_OFFSETS_SOFT:
2024 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
2026 case AL_POSITION:
2027 case AL_VELOCITY:
2028 case AL_DIRECTION:
2029 GetSourcei64v(Source, Context, param, values);
2030 break;
2032 default:
2033 alSetError(Context, AL_INVALID_ENUM);
2036 ALCcontext_DecRef(Context);
2040 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2042 alSourcePlayv(1, &source);
2044 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2046 ALCcontext *Context;
2047 ALsource *Source;
2048 ALsizei i;
2050 Context = GetContextRef();
2051 if(!Context) return;
2053 al_try
2055 CHECK_VALUE(Context, n >= 0);
2056 for(i = 0;i < n;i++)
2058 if(!LookupSource(Context, sources[i]))
2059 al_throwerr(Context, AL_INVALID_NAME);
2062 LockContext(Context);
2063 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
2065 void *temp = NULL;
2066 ALsizei newcount;
2068 newcount = Context->MaxActiveSources << 1;
2069 if(newcount > 0)
2070 temp = realloc(Context->ActiveSources,
2071 sizeof(*Context->ActiveSources) * newcount);
2072 if(!temp)
2074 UnlockContext(Context);
2075 al_throwerr(Context, AL_OUT_OF_MEMORY);
2078 Context->ActiveSources = temp;
2079 Context->MaxActiveSources = newcount;
2082 for(i = 0;i < n;i++)
2084 Source = LookupSource(Context, sources[i]);
2085 if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
2086 else SetSourceState(Source, Context, AL_PLAYING);
2088 UnlockContext(Context);
2090 al_endtry;
2092 ALCcontext_DecRef(Context);
2095 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2097 alSourcePausev(1, &source);
2099 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2101 ALCcontext *Context;
2102 ALsource *Source;
2103 ALsizei i;
2105 Context = GetContextRef();
2106 if(!Context) return;
2108 al_try
2110 CHECK_VALUE(Context, n >= 0);
2111 for(i = 0;i < n;i++)
2113 if(!LookupSource(Context, sources[i]))
2114 al_throwerr(Context, AL_INVALID_NAME);
2117 LockContext(Context);
2118 for(i = 0;i < n;i++)
2120 Source = LookupSource(Context, sources[i]);
2121 if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
2122 else SetSourceState(Source, Context, AL_PAUSED);
2124 UnlockContext(Context);
2126 al_endtry;
2128 ALCcontext_DecRef(Context);
2131 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2133 alSourceStopv(1, &source);
2135 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2137 ALCcontext *Context;
2138 ALsource *Source;
2139 ALsizei i;
2141 Context = GetContextRef();
2142 if(!Context) return;
2144 al_try
2146 CHECK_VALUE(Context, n >= 0);
2147 for(i = 0;i < n;i++)
2149 if(!LookupSource(Context, sources[i]))
2150 al_throwerr(Context, AL_INVALID_NAME);
2153 LockContext(Context);
2154 for(i = 0;i < n;i++)
2156 Source = LookupSource(Context, sources[i]);
2157 Source->new_state = AL_NONE;
2158 SetSourceState(Source, Context, AL_STOPPED);
2160 UnlockContext(Context);
2162 al_endtry;
2164 ALCcontext_DecRef(Context);
2167 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2169 alSourceRewindv(1, &source);
2171 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2173 ALCcontext *Context;
2174 ALsource *Source;
2175 ALsizei i;
2177 Context = GetContextRef();
2178 if(!Context) return;
2180 al_try
2182 CHECK_VALUE(Context, n >= 0);
2183 for(i = 0;i < n;i++)
2185 if(!LookupSource(Context, sources[i]))
2186 al_throwerr(Context, AL_INVALID_NAME);
2189 LockContext(Context);
2190 for(i = 0;i < n;i++)
2192 Source = LookupSource(Context, sources[i]);
2193 Source->new_state = AL_NONE;
2194 SetSourceState(Source, Context, AL_INITIAL);
2196 UnlockContext(Context);
2198 al_endtry;
2200 ALCcontext_DecRef(Context);
2204 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers)
2206 ALCcontext *Context;
2207 ALsource *Source;
2208 ALsizei i;
2209 ALbufferlistitem *BufferListStart = NULL;
2210 ALbufferlistitem *BufferList;
2211 ALbuffer *BufferFmt;
2213 if(nb == 0)
2214 return;
2216 Context = GetContextRef();
2217 if(!Context) return;
2219 al_try
2221 ALCdevice *device = Context->Device;
2223 CHECK_VALUE(Context, nb >= 0);
2225 if((Source=LookupSource(Context, source)) == NULL)
2226 al_throwerr(Context, AL_INVALID_NAME);
2228 LockContext(Context);
2229 if(Source->SourceType == AL_STATIC)
2231 UnlockContext(Context);
2232 /* Can't queue on a Static Source */
2233 al_throwerr(Context, AL_INVALID_OPERATION);
2236 BufferFmt = NULL;
2238 /* Check for a valid Buffer, for its frequency and format */
2239 BufferList = Source->queue;
2240 while(BufferList)
2242 if(BufferList->buffer)
2244 BufferFmt = BufferList->buffer;
2245 break;
2247 BufferList = BufferList->next;
2250 for(i = 0;i < nb;i++)
2252 ALbuffer *buffer = NULL;
2253 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2255 UnlockContext(Context);
2256 al_throwerr(Context, AL_INVALID_NAME);
2259 if(!BufferListStart)
2261 BufferListStart = malloc(sizeof(ALbufferlistitem));
2262 BufferListStart->buffer = buffer;
2263 BufferListStart->next = NULL;
2264 BufferListStart->prev = NULL;
2265 BufferList = BufferListStart;
2267 else
2269 BufferList->next = malloc(sizeof(ALbufferlistitem));
2270 BufferList->next->buffer = buffer;
2271 BufferList->next->next = NULL;
2272 BufferList->next->prev = BufferList;
2273 BufferList = BufferList->next;
2275 if(!buffer) continue;
2276 IncrementRef(&buffer->ref);
2278 ReadLock(&buffer->lock);
2279 if(BufferFmt == NULL)
2281 BufferFmt = buffer;
2283 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2284 Source->SampleSize = BytesFromFmt(buffer->FmtType);
2285 if(buffer->FmtChannels == FmtMono)
2286 Source->Update = CalcSourceParams;
2287 else
2288 Source->Update = CalcNonAttnSourceParams;
2290 Source->NeedsUpdate = AL_TRUE;
2292 else if(BufferFmt->Frequency != buffer->Frequency ||
2293 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2294 BufferFmt->OriginalType != buffer->OriginalType)
2296 ReadUnlock(&buffer->lock);
2297 UnlockContext(Context);
2298 al_throwerr(Context, AL_INVALID_OPERATION);
2300 ReadUnlock(&buffer->lock);
2303 /* Source is now streaming */
2304 Source->SourceType = AL_STREAMING;
2306 if(Source->queue == NULL)
2307 Source->queue = BufferListStart;
2308 else
2310 /* Append to the end of the queue */
2311 BufferList = Source->queue;
2312 while(BufferList->next != NULL)
2313 BufferList = BufferList->next;
2315 BufferListStart->prev = BufferList;
2316 BufferList->next = BufferListStart;
2319 Source->BuffersInQueue += nb;
2321 UnlockContext(Context);
2323 al_catchany()
2325 while(BufferListStart)
2327 BufferList = BufferListStart;
2328 BufferListStart = BufferList->next;
2330 if(BufferList->buffer)
2331 DecrementRef(&BufferList->buffer->ref);
2332 free(BufferList);
2335 al_endtry;
2337 ALCcontext_DecRef(Context);
2340 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers)
2342 ALCcontext *Context;
2343 ALsource *Source;
2344 ALsizei i;
2345 ALbufferlistitem *BufferList;
2347 if(nb == 0)
2348 return;
2350 Context = GetContextRef();
2351 if(!Context) return;
2353 al_try
2355 CHECK_VALUE(Context, nb >= 0);
2357 if((Source=LookupSource(Context, source)) == NULL)
2358 al_throwerr(Context, AL_INVALID_NAME);
2360 LockContext(Context);
2361 if(Source->Looping || Source->SourceType != AL_STREAMING ||
2362 (ALuint)nb > Source->BuffersPlayed)
2364 UnlockContext(Context);
2365 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2366 al_throwerr(Context, AL_INVALID_VALUE);
2369 for(i = 0;i < nb;i++)
2371 BufferList = Source->queue;
2372 Source->queue = BufferList->next;
2373 Source->BuffersInQueue--;
2374 Source->BuffersPlayed--;
2376 if(BufferList->buffer)
2378 buffers[i] = BufferList->buffer->id;
2379 DecrementRef(&BufferList->buffer->ref);
2381 else
2382 buffers[i] = 0;
2384 free(BufferList);
2386 if(Source->queue)
2387 Source->queue->prev = NULL;
2388 UnlockContext(Context);
2390 al_endtry;
2392 ALCcontext_DecRef(Context);
2396 static ALvoid InitSourceParams(ALsource *Source)
2398 ALuint i;
2400 Source->InnerAngle = 360.0f;
2401 Source->OuterAngle = 360.0f;
2402 Source->Pitch = 1.0f;
2403 Source->Position[0] = 0.0f;
2404 Source->Position[1] = 0.0f;
2405 Source->Position[2] = 0.0f;
2406 Source->Orientation[0] = 0.0f;
2407 Source->Orientation[1] = 0.0f;
2408 Source->Orientation[2] = 0.0f;
2409 Source->Velocity[0] = 0.0f;
2410 Source->Velocity[1] = 0.0f;
2411 Source->Velocity[2] = 0.0f;
2412 Source->RefDistance = 1.0f;
2413 Source->MaxDistance = FLT_MAX;
2414 Source->RollOffFactor = 1.0f;
2415 Source->Looping = AL_FALSE;
2416 Source->Gain = 1.0f;
2417 Source->MinGain = 0.0f;
2418 Source->MaxGain = 1.0f;
2419 Source->OuterGain = 0.0f;
2420 Source->OuterGainHF = 1.0f;
2422 Source->DryGainHFAuto = AL_TRUE;
2423 Source->WetGainAuto = AL_TRUE;
2424 Source->WetGainHFAuto = AL_TRUE;
2425 Source->AirAbsorptionFactor = 0.0f;
2426 Source->RoomRolloffFactor = 0.0f;
2427 Source->DopplerFactor = 1.0f;
2428 Source->DirectChannels = AL_FALSE;
2430 Source->DistanceModel = DefaultDistanceModel;
2432 Source->Resampler = DefaultResampler;
2434 Source->state = AL_INITIAL;
2435 Source->new_state = AL_NONE;
2436 Source->SourceType = AL_UNDETERMINED;
2437 Source->Offset = -1.0;
2439 Source->DirectGain = 1.0f;
2440 Source->DirectGainHF = 1.0f;
2441 for(i = 0;i < MAX_SENDS;i++)
2443 Source->Send[i].Gain = 1.0f;
2444 Source->Send[i].GainHF = 1.0f;
2447 Source->NeedsUpdate = AL_TRUE;
2449 Source->Hrtf.Moving = AL_FALSE;
2450 Source->Hrtf.Counter = 0;
2454 /* SetSourceState
2456 * Sets the source's new play state given its current state.
2458 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2460 if(state == AL_PLAYING)
2462 ALbufferlistitem *BufferList;
2463 ALsizei j, k;
2465 /* Check that there is a queue containing at least one valid, non zero
2466 * length Buffer. */
2467 BufferList = Source->queue;
2468 while(BufferList)
2470 if(BufferList->buffer != NULL && BufferList->buffer->SampleLen)
2471 break;
2472 BufferList = BufferList->next;
2475 if(Source->state != AL_PLAYING)
2477 for(j = 0;j < MaxChannels;j++)
2479 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
2480 Source->Hrtf.History[j][k] = 0.0f;
2481 for(k = 0;k < HRIR_LENGTH;k++)
2483 Source->Hrtf.Values[j][k][0] = 0.0f;
2484 Source->Hrtf.Values[j][k][1] = 0.0f;
2489 if(Source->state != AL_PAUSED)
2491 Source->state = AL_PLAYING;
2492 Source->position = 0;
2493 Source->position_fraction = 0;
2494 Source->BuffersPlayed = 0;
2496 else
2497 Source->state = AL_PLAYING;
2499 // Check if an Offset has been set
2500 if(Source->Offset >= 0.0)
2501 ApplyOffset(Source);
2503 /* If there's nothing to play, or device is disconnected, go right to
2504 * stopped */
2505 if(!BufferList || !Context->Device->Connected)
2507 SetSourceState(Source, Context, AL_STOPPED);
2508 return;
2511 for(j = 0;j < Context->ActiveSourceCount;j++)
2513 if(Context->ActiveSources[j] == Source)
2514 break;
2516 if(j == Context->ActiveSourceCount)
2517 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
2519 else if(state == AL_PAUSED)
2521 if(Source->state == AL_PLAYING)
2523 Source->state = AL_PAUSED;
2524 Source->Hrtf.Moving = AL_FALSE;
2525 Source->Hrtf.Counter = 0;
2528 else if(state == AL_STOPPED)
2530 if(Source->state != AL_INITIAL)
2532 Source->state = AL_STOPPED;
2533 Source->BuffersPlayed = Source->BuffersInQueue;
2534 Source->Hrtf.Moving = AL_FALSE;
2535 Source->Hrtf.Counter = 0;
2537 Source->Offset = -1.0;
2539 else if(state == AL_INITIAL)
2541 if(Source->state != AL_INITIAL)
2543 Source->state = AL_INITIAL;
2544 Source->position = 0;
2545 Source->position_fraction = 0;
2546 Source->BuffersPlayed = 0;
2547 Source->Hrtf.Moving = AL_FALSE;
2548 Source->Hrtf.Counter = 0;
2550 Source->Offset = -1.0;
2554 /* GetSourceOffset
2556 * Gets the current read offset for the given Source, in 32.32 fixed-point
2557 * samples. The offset is relative to the start of the queue (not the start of
2558 * the current buffer).
2560 static ALint64 GetSourceOffset(const ALsource *Source)
2562 const ALbufferlistitem *BufferList;
2563 ALuint64 readPos;
2564 ALuint i;
2566 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2567 return 0;
2569 /* NOTE: This is the offset into the *current* buffer, so add the length of
2570 * any played buffers */
2571 readPos = (ALuint64)Source->position << 32;
2572 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2573 BufferList = Source->queue;
2574 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2576 if(BufferList->buffer)
2577 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2578 BufferList = BufferList->next;
2581 return (ALint64)minu64(readPos, MAKEU64(0x7fffffff,0xffffffff));
2584 /* GetSourceSecOffset
2586 * Gets the current read offset for the given Source, in seconds. The offset is
2587 * relative to the start of the queue (not the start of the current buffer).
2589 static ALdouble GetSourceSecOffset(const ALsource *Source)
2591 const ALbufferlistitem *BufferList;
2592 const ALbuffer *Buffer = NULL;
2593 ALuint64 readPos;
2594 ALuint i;
2596 BufferList = Source->queue;
2597 while(BufferList)
2599 if(BufferList->buffer)
2601 Buffer = BufferList->buffer;
2602 break;
2604 BufferList = BufferList->next;
2607 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2608 return 0.0;
2610 /* NOTE: This is the offset into the *current* buffer, so add the length of
2611 * any played buffers */
2612 readPos = (ALuint64)Source->position << FRACTIONBITS;
2613 readPos |= (ALuint64)Source->position_fraction;
2614 BufferList = Source->queue;
2615 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2617 if(BufferList->buffer)
2618 readPos += (ALuint64)BufferList->buffer->SampleLen << FRACTIONBITS;
2619 BufferList = BufferList->next;
2622 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2625 /* GetSourceOffsets
2627 * Gets the current read and write offsets for the given Source, in the
2628 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2629 * the start of the queue (not the start of the current buffer).
2631 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2633 const ALbufferlistitem *BufferList;
2634 const ALbuffer *Buffer = NULL;
2635 ALuint readPos, writePos;
2636 ALuint totalBufferLen;
2637 ALuint i;
2639 // Find the first valid Buffer in the Queue
2640 BufferList = Source->queue;
2641 while(BufferList)
2643 if(BufferList->buffer)
2645 Buffer = BufferList->buffer;
2646 break;
2648 BufferList = BufferList->next;
2651 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2653 offset[0] = 0.0;
2654 offset[1] = 0.0;
2655 return;
2658 if(updateLen > 0.0 && updateLen < 0.015)
2659 updateLen = 0.015;
2661 /* NOTE: This is the offset into the *current* buffer, so add the length of
2662 * any played buffers */
2663 readPos = Source->position;
2664 totalBufferLen = 0;
2665 BufferList = Source->queue;
2666 for(i = 0;BufferList;i++)
2668 if(BufferList->buffer)
2670 if(i < Source->BuffersPlayed)
2671 readPos += BufferList->buffer->SampleLen;
2672 totalBufferLen += BufferList->buffer->SampleLen;
2674 BufferList = BufferList->next;
2676 if(Source->state == AL_PLAYING)
2677 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
2678 else
2679 writePos = readPos;
2681 if(Source->Looping)
2683 readPos %= totalBufferLen;
2684 writePos %= totalBufferLen;
2686 else
2688 /* Wrap positions back to 0 */
2689 if(readPos >= totalBufferLen)
2690 readPos = 0;
2691 if(writePos >= totalBufferLen)
2692 writePos = 0;
2695 switch(name)
2697 case AL_SEC_OFFSET:
2698 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2699 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2700 break;
2702 case AL_SAMPLE_OFFSET:
2703 case AL_SAMPLE_RW_OFFSETS_SOFT:
2704 offset[0] = (ALdouble)readPos;
2705 offset[1] = (ALdouble)writePos;
2706 break;
2708 case AL_BYTE_OFFSET:
2709 case AL_BYTE_RW_OFFSETS_SOFT:
2710 if(Buffer->OriginalType == UserFmtIMA4)
2712 ALuint BlockSize = 36 * ChannelsFromFmt(Buffer->FmtChannels);
2713 ALuint FrameBlockSize = 65;
2715 /* Round down to nearest ADPCM block */
2716 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2717 if(Source->state != AL_PLAYING)
2718 offset[1] = offset[0];
2719 else
2721 /* Round up to nearest ADPCM block */
2722 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2723 FrameBlockSize * BlockSize);
2726 else
2728 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2729 offset[0] = (ALdouble)(readPos * FrameSize);
2730 offset[1] = (ALdouble)(writePos * FrameSize);
2732 break;
2737 /* ApplyOffset
2739 * Apply the stored playback offset to the Source. This function will update
2740 * the number of buffers "played" given the stored offset.
2742 ALboolean ApplyOffset(ALsource *Source)
2744 const ALbufferlistitem *BufferList;
2745 const ALbuffer *Buffer;
2746 ALint bufferLen, totalBufferLen;
2747 ALint buffersPlayed;
2748 ALint offset;
2750 /* Get sample frame offset */
2751 offset = GetSampleOffset(Source);
2752 if(offset == -1)
2753 return AL_FALSE;
2755 buffersPlayed = 0;
2756 totalBufferLen = 0;
2758 BufferList = Source->queue;
2759 while(BufferList)
2761 Buffer = BufferList->buffer;
2762 bufferLen = Buffer ? Buffer->SampleLen : 0;
2764 if(bufferLen <= offset-totalBufferLen)
2766 /* Offset is past this buffer so increment to the next buffer */
2767 buffersPlayed++;
2769 else if(totalBufferLen <= offset)
2771 /* Offset is in this buffer */
2772 Source->BuffersPlayed = buffersPlayed;
2774 Source->position = offset - totalBufferLen;
2775 Source->position_fraction = 0;
2776 return AL_TRUE;
2779 totalBufferLen += bufferLen;
2781 BufferList = BufferList->next;
2784 /* Offset is out of range of the queue */
2785 return AL_FALSE;
2789 /* GetSampleOffset
2791 * Returns the sample offset into the Source's queue (from the Sample, Byte or
2792 * Second offset supplied by the application). This takes into account the fact
2793 * that the buffer format may have been modifed since.
2795 static ALint GetSampleOffset(ALsource *Source)
2797 const ALbuffer *Buffer = NULL;
2798 const ALbufferlistitem *BufferList;
2799 ALint Offset = -1;
2801 /* Find the first valid Buffer in the Queue */
2802 BufferList = Source->queue;
2803 while(BufferList)
2805 if(BufferList->buffer)
2807 Buffer = BufferList->buffer;
2808 break;
2810 BufferList = BufferList->next;
2813 if(!Buffer)
2815 Source->Offset = -1.0;
2816 return -1;
2819 switch(Source->OffsetType)
2821 case AL_BYTE_OFFSET:
2822 /* Determine the ByteOffset (and ensure it is block aligned) */
2823 Offset = (ALint)Source->Offset;
2824 if(Buffer->OriginalType == UserFmtIMA4)
2826 Offset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
2827 Offset *= 65;
2829 else
2830 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2831 break;
2833 case AL_SAMPLE_OFFSET:
2834 Offset = (ALint)Source->Offset;
2835 break;
2837 case AL_SEC_OFFSET:
2838 Offset = (ALint)(Source->Offset * Buffer->Frequency);
2839 break;
2841 Source->Offset = -1.0;
2843 return Offset;
2847 /* ReleaseALSources
2849 * Destroys all sources in the source map.
2851 ALvoid ReleaseALSources(ALCcontext *Context)
2853 ALsizei pos;
2854 ALuint j;
2855 for(pos = 0;pos < Context->SourceMap.size;pos++)
2857 ALsource *temp = Context->SourceMap.array[pos].value;
2858 Context->SourceMap.array[pos].value = NULL;
2860 while(temp->queue != NULL)
2862 ALbufferlistitem *BufferList = temp->queue;
2863 temp->queue = BufferList->next;
2865 if(BufferList->buffer != NULL)
2866 DecrementRef(&BufferList->buffer->ref);
2867 free(BufferList);
2870 for(j = 0;j < MAX_SENDS;++j)
2872 if(temp->Send[j].Slot)
2873 DecrementRef(&temp->Send[j].Slot->ref);
2874 temp->Send[j].Slot = NULL;
2877 FreeThunkEntry(temp->id);
2878 memset(temp, 0, sizeof(*temp));
2879 al_free(temp);