Silence a couple MSVC warnings
[openal-soft.git] / OpenAL32 / alSource.c
blobca3daa3eff5694cc29967184f44051a215c7d9fe
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);
59 static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, ALenum name, ALdouble *values);
60 static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, ALenum name, ALint *values);
61 static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, ALenum name, ALint64 *values);
64 #define RETERR(x) do { \
65 alSetError(Context, (x)); \
66 return (x); \
67 } while(0)
69 #define CHECKVAL(x) do { \
70 if(!(x)) \
71 RETERR(AL_INVALID_VALUE); \
72 } while(0)
74 static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, ALenum name, const ALfloat *values)
76 switch(name)
78 case AL_PITCH:
79 CHECKVAL(*values >= 0.0f);
81 Source->Pitch = *values;
82 Source->NeedsUpdate = AL_TRUE;
83 break;
85 case AL_CONE_INNER_ANGLE:
86 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
88 Source->InnerAngle = *values;
89 Source->NeedsUpdate = AL_TRUE;
90 break;
92 case AL_CONE_OUTER_ANGLE:
93 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
95 Source->OuterAngle = *values;
96 Source->NeedsUpdate = AL_TRUE;
97 break;
99 case AL_GAIN:
100 CHECKVAL(*values >= 0.0f);
102 Source->Gain = *values;
103 Source->NeedsUpdate = AL_TRUE;
104 break;
106 case AL_MAX_DISTANCE:
107 CHECKVAL(*values >= 0.0f);
109 Source->MaxDistance = *values;
110 Source->NeedsUpdate = AL_TRUE;
111 break;
113 case AL_ROLLOFF_FACTOR:
114 CHECKVAL(*values >= 0.0f);
116 Source->RollOffFactor = *values;
117 Source->NeedsUpdate = AL_TRUE;
118 break;
120 case AL_REFERENCE_DISTANCE:
121 CHECKVAL(*values >= 0.0f);
123 Source->RefDistance = *values;
124 Source->NeedsUpdate = AL_TRUE;
125 break;
127 case AL_MIN_GAIN:
128 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
130 Source->MinGain = *values;
131 Source->NeedsUpdate = AL_TRUE;
132 break;
134 case AL_MAX_GAIN:
135 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
137 Source->MaxGain = *values;
138 Source->NeedsUpdate = AL_TRUE;
139 break;
141 case AL_CONE_OUTER_GAIN:
142 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
144 Source->OuterGain = *values;
145 Source->NeedsUpdate = AL_TRUE;
146 break;
148 case AL_CONE_OUTER_GAINHF:
149 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
151 Source->OuterGainHF = *values;
152 Source->NeedsUpdate = AL_TRUE;
153 break;
155 case AL_AIR_ABSORPTION_FACTOR:
156 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
158 Source->AirAbsorptionFactor = *values;
159 Source->NeedsUpdate = AL_TRUE;
160 break;
162 case AL_ROOM_ROLLOFF_FACTOR:
163 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
165 Source->RoomRolloffFactor = *values;
166 Source->NeedsUpdate = AL_TRUE;
167 break;
169 case AL_DOPPLER_FACTOR:
170 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
172 Source->DopplerFactor = *values;
173 Source->NeedsUpdate = AL_TRUE;
174 break;
176 case AL_SEC_OFFSET:
177 case AL_SAMPLE_OFFSET:
178 case AL_BYTE_OFFSET:
179 CHECKVAL(*values >= 0.0f);
181 LockContext(Context);
182 Source->OffsetType = name;
183 Source->Offset = *values;
185 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
186 !Context->DeferUpdates)
188 if(ApplyOffset(Source) == AL_FALSE)
190 UnlockContext(Context);
191 RETERR(AL_INVALID_VALUE);
194 UnlockContext(Context);
195 break;
198 case AL_POSITION:
199 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
201 LockContext(Context);
202 Source->Position[0] = values[0];
203 Source->Position[1] = values[1];
204 Source->Position[2] = values[2];
205 UnlockContext(Context);
206 Source->NeedsUpdate = AL_TRUE;
207 break;
209 case AL_VELOCITY:
210 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
212 LockContext(Context);
213 Source->Velocity[0] = values[0];
214 Source->Velocity[1] = values[1];
215 Source->Velocity[2] = values[2];
216 UnlockContext(Context);
217 Source->NeedsUpdate = AL_TRUE;
218 break;
220 case AL_DIRECTION:
221 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
223 LockContext(Context);
224 Source->Orientation[0] = values[0];
225 Source->Orientation[1] = values[1];
226 Source->Orientation[2] = values[2];
227 UnlockContext(Context);
228 Source->NeedsUpdate = AL_TRUE;
229 break;
232 default:
233 RETERR(AL_INVALID_ENUM);
236 return AL_NO_ERROR;
239 static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, ALenum name, const ALint *values)
241 ALCdevice *device = Context->Device;
242 ALbuffer *buffer = NULL;
243 ALfilter *filter = NULL;
244 ALeffectslot *slot = NULL;
245 ALbufferlistitem *oldlist;
246 ALfloat fvals[3];
247 ALenum err;
249 switch(name)
251 case AL_SOURCE_RELATIVE:
252 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
254 Source->HeadRelative = (ALboolean)*values;
255 Source->NeedsUpdate = AL_TRUE;
256 break;
258 case AL_LOOPING:
259 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
261 Source->Looping = (ALboolean)*values;
262 break;
264 case AL_BUFFER:
265 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
267 LockContext(Context);
268 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
270 UnlockContext(Context);
271 RETERR(AL_INVALID_OPERATION);
274 Source->BuffersInQueue = 0;
275 Source->BuffersPlayed = 0;
277 if(buffer != NULL)
279 ALbufferlistitem *BufferListItem;
281 /* Source is now Static */
282 Source->SourceType = AL_STATIC;
284 /* Add the selected buffer to a one-item queue */
285 BufferListItem = malloc(sizeof(ALbufferlistitem));
286 BufferListItem->buffer = buffer;
287 BufferListItem->next = NULL;
288 BufferListItem->prev = NULL;
289 IncrementRef(&buffer->ref);
291 oldlist = ExchangePtr((XchgPtr*)&Source->queue, BufferListItem);
292 Source->BuffersInQueue = 1;
294 ReadLock(&buffer->lock);
295 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
296 Source->SampleSize = BytesFromFmt(buffer->FmtType);
297 ReadUnlock(&buffer->lock);
298 if(buffer->FmtChannels == FmtMono)
299 Source->Update = CalcSourceParams;
300 else
301 Source->Update = CalcNonAttnSourceParams;
302 Source->NeedsUpdate = AL_TRUE;
304 else
306 /* Source is now Undetermined */
307 Source->SourceType = AL_UNDETERMINED;
308 oldlist = ExchangePtr((XchgPtr*)&Source->queue, NULL);
311 /* Delete all elements in the previous queue */
312 while(oldlist != NULL)
314 ALbufferlistitem *temp = oldlist;
315 oldlist = temp->next;
317 if(temp->buffer)
318 DecrementRef(&temp->buffer->ref);
319 free(temp);
321 UnlockContext(Context);
322 break;
324 case AL_SOURCE_STATE:
325 /* Query only */
326 RETERR(AL_INVALID_OPERATION);
328 case AL_SEC_OFFSET:
329 case AL_SAMPLE_OFFSET:
330 case AL_BYTE_OFFSET:
331 CHECKVAL(*values >= 0);
333 LockContext(Context);
334 Source->OffsetType = name;
335 Source->Offset = *values;
337 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
338 !Context->DeferUpdates)
340 if(ApplyOffset(Source) == AL_FALSE)
342 UnlockContext(Context);
343 RETERR(AL_INVALID_VALUE);
346 UnlockContext(Context);
347 break;
349 case AL_DIRECT_FILTER:
350 CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
352 LockContext(Context);
353 if(!filter)
355 Source->DirectGain = 1.0f;
356 Source->DirectGainHF = 1.0f;
358 else
360 Source->DirectGain = filter->Gain;
361 Source->DirectGainHF = filter->GainHF;
363 UnlockContext(Context);
364 Source->NeedsUpdate = AL_TRUE;
365 break;
367 case AL_DIRECT_FILTER_GAINHF_AUTO:
368 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
370 Source->DryGainHFAuto = *values;
371 Source->NeedsUpdate = AL_TRUE;
372 break;
374 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
375 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
377 Source->WetGainAuto = *values;
378 Source->NeedsUpdate = AL_TRUE;
379 break;
381 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
382 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
384 Source->WetGainHFAuto = *values;
385 Source->NeedsUpdate = AL_TRUE;
386 break;
388 case AL_DIRECT_CHANNELS_SOFT:
389 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
391 Source->DirectChannels = *values;
392 Source->NeedsUpdate = AL_TRUE;
393 break;
395 case AL_DISTANCE_MODEL:
396 CHECKVAL(*values == AL_NONE ||
397 *values == AL_INVERSE_DISTANCE ||
398 *values == AL_INVERSE_DISTANCE_CLAMPED ||
399 *values == AL_LINEAR_DISTANCE ||
400 *values == AL_LINEAR_DISTANCE_CLAMPED ||
401 *values == AL_EXPONENT_DISTANCE ||
402 *values == AL_EXPONENT_DISTANCE_CLAMPED);
404 Source->DistanceModel = *values;
405 if(Context->SourceDistanceModel)
406 Source->NeedsUpdate = AL_TRUE;
407 break;
410 case AL_AUXILIARY_SEND_FILTER:
411 LockContext(Context);
412 if(!((ALuint)values[1] < device->NumAuxSends &&
413 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
414 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
416 UnlockContext(Context);
417 RETERR(AL_INVALID_VALUE);
420 /* Add refcount on the new slot, and release the previous slot */
421 if(slot) IncrementRef(&slot->ref);
422 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
423 if(slot) DecrementRef(&slot->ref);
425 if(!filter)
427 /* Disable filter */
428 Source->Send[values[1]].Gain = 1.0f;
429 Source->Send[values[1]].GainHF = 1.0f;
431 else
433 Source->Send[values[1]].Gain = filter->Gain;
434 Source->Send[values[1]].GainHF = filter->GainHF;
436 Source->NeedsUpdate = AL_TRUE;
437 UnlockContext(Context);
438 break;
441 case AL_MAX_DISTANCE:
442 case AL_ROLLOFF_FACTOR:
443 case AL_CONE_INNER_ANGLE:
444 case AL_CONE_OUTER_ANGLE:
445 case AL_REFERENCE_DISTANCE:
446 fvals[0] = (ALfloat)*values;
447 if((err=SetSourcefv(Source, Context, name, fvals)) != AL_NO_ERROR)
448 return err;
449 break;
451 case AL_POSITION:
452 case AL_VELOCITY:
453 case AL_DIRECTION:
454 fvals[0] = (ALfloat)values[0];
455 fvals[1] = (ALfloat)values[1];
456 fvals[2] = (ALfloat)values[2];
457 if((err=SetSourcefv(Source, Context, name, fvals)) != AL_NO_ERROR)
458 return err;
459 break;
461 default:
462 return AL_INVALID_ENUM;
465 return AL_NO_ERROR;
468 #undef CHECKVAL
471 static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, ALenum name, ALdouble *values)
473 ALdouble offsets[2];
474 ALdouble updateLen;
475 ALint ivals[3];
476 ALenum err;
478 switch(name)
480 case AL_MAX_DISTANCE:
481 *values = Source->MaxDistance;
482 break;
484 case AL_ROLLOFF_FACTOR:
485 *values = Source->RollOffFactor;
486 break;
488 case AL_REFERENCE_DISTANCE:
489 *values = Source->RefDistance;
490 break;
492 case AL_CONE_INNER_ANGLE:
493 *values = Source->InnerAngle;
494 break;
496 case AL_CONE_OUTER_ANGLE:
497 *values = Source->OuterAngle;
498 break;
500 case AL_SEC_OFFSET:
501 case AL_SAMPLE_OFFSET:
502 case AL_BYTE_OFFSET:
503 LockContext(Context);
504 updateLen = (ALdouble)Context->Device->UpdateSize /
505 Context->Device->Frequency;
506 GetSourceOffsets(Source, name, offsets, updateLen);
507 UnlockContext(Context);
508 *values = offsets[0];
509 break;
511 case AL_DOPPLER_FACTOR:
512 *values = Source->DopplerFactor;
513 break;
515 case AL_SAMPLE_RW_OFFSETS_SOFT:
516 case AL_BYTE_RW_OFFSETS_SOFT:
517 LockContext(Context);
518 updateLen = (ALdouble)Context->Device->UpdateSize /
519 Context->Device->Frequency;
520 GetSourceOffsets(Source, name, values, updateLen);
521 UnlockContext(Context);
522 break;
524 case AL_SEC_OFFSET_LATENCY_SOFT:
525 LockContext(Context);
526 values[0] = GetSourceSecOffset(Source);
527 values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) /
528 1000000000.0;
529 UnlockContext(Context);
530 break;
532 case AL_POSITION:
533 LockContext(Context);
534 values[0] = Source->Position[0];
535 values[1] = Source->Position[1];
536 values[2] = Source->Position[2];
537 UnlockContext(Context);
538 break;
540 case AL_VELOCITY:
541 LockContext(Context);
542 values[0] = Source->Velocity[0];
543 values[1] = Source->Velocity[1];
544 values[2] = Source->Velocity[2];
545 UnlockContext(Context);
546 break;
548 case AL_DIRECTION:
549 LockContext(Context);
550 values[0] = Source->Orientation[0];
551 values[1] = Source->Orientation[1];
552 values[2] = Source->Orientation[2];
553 UnlockContext(Context);
554 break;
556 case AL_SOURCE_RELATIVE:
557 case AL_LOOPING:
558 case AL_BUFFER:
559 case AL_SOURCE_STATE:
560 case AL_BUFFERS_QUEUED:
561 case AL_BUFFERS_PROCESSED:
562 case AL_SOURCE_TYPE:
563 case AL_DIRECT_FILTER_GAINHF_AUTO:
564 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
565 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
566 case AL_DIRECT_CHANNELS_SOFT:
567 case AL_DISTANCE_MODEL:
568 if((err=GetSourceiv(Source, Context, name, ivals)) != AL_NO_ERROR)
569 return err;
570 *values = (ALdouble)ivals[0];
571 break;
573 default:
574 RETERR(AL_INVALID_ENUM);
577 return AL_NO_ERROR;
580 static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, ALenum name, ALint *values)
582 ALbufferlistitem *BufferList;
583 ALdouble dvals[3];
584 ALenum err;
586 switch(name)
588 case AL_SOURCE_RELATIVE:
589 *values = Source->HeadRelative;
590 break;
592 case AL_LOOPING:
593 *values = Source->Looping;
594 break;
596 case AL_BUFFER:
597 LockContext(Context);
598 BufferList = Source->queue;
599 if(Source->SourceType != AL_STATIC)
601 ALuint i = Source->BuffersPlayed;
602 while(i > 0)
604 BufferList = BufferList->next;
605 i--;
608 *values = ((BufferList && BufferList->buffer) ?
609 BufferList->buffer->id : 0);
610 UnlockContext(Context);
611 break;
613 case AL_SOURCE_STATE:
614 *values = Source->state;
615 break;
617 case AL_BUFFERS_QUEUED:
618 *values = Source->BuffersInQueue;
619 break;
621 case AL_BUFFERS_PROCESSED:
622 LockContext(Context);
623 if(Source->Looping || Source->SourceType != AL_STREAMING)
625 /* Buffers on a looping source are in a perpetual state of
626 * PENDING, so don't report any as PROCESSED */
627 *values = 0;
629 else
630 *values = Source->BuffersPlayed;
631 UnlockContext(Context);
632 break;
634 case AL_SOURCE_TYPE:
635 *values = Source->SourceType;
636 break;
638 case AL_DIRECT_FILTER_GAINHF_AUTO:
639 *values = Source->DryGainHFAuto;
640 break;
642 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
643 *values = Source->WetGainAuto;
644 break;
646 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
647 *values = Source->WetGainHFAuto;
648 break;
650 case AL_DIRECT_CHANNELS_SOFT:
651 *values = Source->DirectChannels;
652 break;
654 case AL_DISTANCE_MODEL:
655 *values = Source->DistanceModel;
656 break;
658 case AL_MAX_DISTANCE:
659 case AL_ROLLOFF_FACTOR:
660 case AL_REFERENCE_DISTANCE:
661 case AL_CONE_INNER_ANGLE:
662 case AL_CONE_OUTER_ANGLE:
663 case AL_SEC_OFFSET:
664 case AL_SAMPLE_OFFSET:
665 case AL_BYTE_OFFSET:
666 case AL_DOPPLER_FACTOR:
667 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
668 return err;
669 *values = (ALint)dvals[0];
670 break;
672 case AL_SAMPLE_RW_OFFSETS_SOFT:
673 case AL_BYTE_RW_OFFSETS_SOFT:
674 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
675 return err;
676 values[0] = (ALint)dvals[0];
677 values[1] = (ALint)dvals[0];
678 break;
680 case AL_POSITION:
681 case AL_VELOCITY:
682 case AL_DIRECTION:
683 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
684 return err;
685 values[0] = (ALint)dvals[0];
686 values[1] = (ALint)dvals[1];
687 values[2] = (ALint)dvals[2];
688 break;
690 default:
691 RETERR(AL_INVALID_ENUM);
694 return AL_NO_ERROR;
697 static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, ALenum name, ALint64 *values)
699 ALdouble dvals[3];
700 ALint ivals[3];
701 ALenum err;
703 switch(name)
705 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
706 LockContext(Context);
707 values[0] = GetSourceOffset(Source);
708 values[1] = ALCdevice_GetLatency(Context->Device);
709 UnlockContext(Context);
710 break;
712 case AL_MAX_DISTANCE:
713 case AL_ROLLOFF_FACTOR:
714 case AL_REFERENCE_DISTANCE:
715 case AL_CONE_INNER_ANGLE:
716 case AL_CONE_OUTER_ANGLE:
717 case AL_SEC_OFFSET:
718 case AL_SAMPLE_OFFSET:
719 case AL_BYTE_OFFSET:
720 case AL_DOPPLER_FACTOR:
721 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
722 return err;
723 *values = (ALint64)dvals[0];
724 break;
726 case AL_SAMPLE_RW_OFFSETS_SOFT:
727 case AL_BYTE_RW_OFFSETS_SOFT:
728 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
729 return err;
730 values[0] = (ALint64)dvals[0];
731 values[1] = (ALint64)dvals[0];
732 break;
734 case AL_POSITION:
735 case AL_VELOCITY:
736 case AL_DIRECTION:
737 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
738 return err;
739 values[0] = (ALint64)dvals[0];
740 values[1] = (ALint64)dvals[1];
741 values[2] = (ALint64)dvals[2];
742 break;
744 case AL_SOURCE_RELATIVE:
745 case AL_LOOPING:
746 case AL_BUFFER:
747 case AL_SOURCE_STATE:
748 case AL_BUFFERS_QUEUED:
749 case AL_BUFFERS_PROCESSED:
750 case AL_SOURCE_TYPE:
751 case AL_DIRECT_FILTER_GAINHF_AUTO:
752 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
753 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
754 case AL_DIRECT_CHANNELS_SOFT:
755 case AL_DISTANCE_MODEL:
756 if((err=GetSourceiv(Source, Context, name, ivals)) != AL_NO_ERROR)
757 return err;
758 *values = ivals[0];
759 break;
761 default:
762 RETERR(AL_INVALID_ENUM);
765 return AL_NO_ERROR;
768 #undef RETERR
771 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
773 ALCcontext *Context;
774 ALsizei cur = 0;
776 Context = GetContextRef();
777 if(!Context) return;
779 al_try
781 ALenum err;
783 CHECK_VALUE(Context, n >= 0);
784 for(cur = 0;cur < n;cur++)
786 ALsource *source = al_calloc(16, sizeof(ALsource));
787 if(!source)
788 al_throwerr(Context, AL_OUT_OF_MEMORY);
789 InitSourceParams(source);
791 err = NewThunkEntry(&source->id);
792 if(err == AL_NO_ERROR)
793 err = InsertUIntMapEntry(&Context->SourceMap, source->id, source);
794 if(err != AL_NO_ERROR)
796 FreeThunkEntry(source->id);
797 memset(source, 0, sizeof(ALsource));
798 al_free(source);
800 al_throwerr(Context, err);
803 sources[cur] = source->id;
806 al_catchany()
808 if(cur > 0)
809 alDeleteSources(cur, sources);
811 al_endtry;
813 ALCcontext_DecRef(Context);
817 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
819 ALCcontext *Context;
821 Context = GetContextRef();
822 if(!Context) return;
824 al_try
826 ALbufferlistitem *BufferList;
827 ALsource *Source;
828 ALsizei i, j;
830 CHECK_VALUE(Context, n >= 0);
832 /* Check that all Sources are valid */
833 for(i = 0;i < n;i++)
835 if(LookupSource(Context, sources[i]) == NULL)
836 al_throwerr(Context, AL_INVALID_NAME);
839 for(i = 0;i < n;i++)
841 ALsource **srclist, **srclistend;
843 if((Source=RemoveSource(Context, sources[i])) == NULL)
844 continue;
845 FreeThunkEntry(Source->id);
847 LockContext(Context);
848 srclist = Context->ActiveSources;
849 srclistend = srclist + Context->ActiveSourceCount;
850 while(srclist != srclistend)
852 if(*srclist == Source)
854 Context->ActiveSourceCount--;
855 *srclist = *(--srclistend);
856 break;
858 srclist++;
860 UnlockContext(Context);
862 while(Source->queue != NULL)
864 BufferList = Source->queue;
865 Source->queue = BufferList->next;
867 if(BufferList->buffer != NULL)
868 DecrementRef(&BufferList->buffer->ref);
869 free(BufferList);
872 for(j = 0;j < MAX_SENDS;++j)
874 if(Source->Send[j].Slot)
875 DecrementRef(&Source->Send[j].Slot->ref);
876 Source->Send[j].Slot = NULL;
879 memset(Source, 0, sizeof(*Source));
880 al_free(Source);
883 al_endtry;
885 ALCcontext_DecRef(Context);
889 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
891 ALCcontext *Context;
892 ALboolean result;
894 Context = GetContextRef();
895 if(!Context) return AL_FALSE;
897 result = (LookupSource(Context, source) ? AL_TRUE : AL_FALSE);
899 ALCcontext_DecRef(Context);
901 return result;
905 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
907 ALCcontext *Context;
908 ALsource *Source;
910 Context = GetContextRef();
911 if(!Context) return;
913 if((Source=LookupSource(Context, source)) == NULL)
914 alSetError(Context, AL_INVALID_NAME);
915 else switch(param)
917 case AL_PITCH:
918 case AL_CONE_INNER_ANGLE:
919 case AL_CONE_OUTER_ANGLE:
920 case AL_GAIN:
921 case AL_MAX_DISTANCE:
922 case AL_ROLLOFF_FACTOR:
923 case AL_REFERENCE_DISTANCE:
924 case AL_MIN_GAIN:
925 case AL_MAX_GAIN:
926 case AL_CONE_OUTER_GAIN:
927 case AL_CONE_OUTER_GAINHF:
928 case AL_AIR_ABSORPTION_FACTOR:
929 case AL_ROOM_ROLLOFF_FACTOR:
930 case AL_DOPPLER_FACTOR:
931 case AL_SEC_OFFSET:
932 case AL_SAMPLE_OFFSET:
933 case AL_BYTE_OFFSET:
934 SetSourcefv(Source, Context, param, &value);
935 break;
937 default:
938 alSetError(Context, AL_INVALID_ENUM);
941 ALCcontext_DecRef(Context);
945 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
947 ALCcontext *Context;
948 ALsource *Source;
949 ALfloat fvals[3];
951 Context = GetContextRef();
952 if(!Context) return;
954 if((Source=LookupSource(Context, source)) == NULL)
955 alSetError(Context, AL_INVALID_NAME);
956 else switch(param)
958 case AL_POSITION:
959 case AL_VELOCITY:
960 case AL_DIRECTION:
961 fvals[0] = value1;
962 fvals[1] = value2;
963 fvals[2] = value3;
964 SetSourcefv(Source, Context, param, fvals);
965 break;
967 default:
968 alSetError(Context, AL_INVALID_ENUM);
971 ALCcontext_DecRef(Context);
975 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
977 ALCcontext *Context;
978 ALsource *Source;
980 Context = GetContextRef();
981 if(!Context) return;
983 if((Source=LookupSource(Context, source)) == NULL)
984 alSetError(Context, AL_INVALID_NAME);
985 else if(!values)
986 alSetError(Context, AL_INVALID_VALUE);
987 else switch(param)
989 case AL_PITCH:
990 case AL_CONE_INNER_ANGLE:
991 case AL_CONE_OUTER_ANGLE:
992 case AL_GAIN:
993 case AL_MAX_DISTANCE:
994 case AL_ROLLOFF_FACTOR:
995 case AL_REFERENCE_DISTANCE:
996 case AL_MIN_GAIN:
997 case AL_MAX_GAIN:
998 case AL_CONE_OUTER_GAIN:
999 case AL_CONE_OUTER_GAINHF:
1000 case AL_SEC_OFFSET:
1001 case AL_SAMPLE_OFFSET:
1002 case AL_BYTE_OFFSET:
1003 case AL_AIR_ABSORPTION_FACTOR:
1004 case AL_ROOM_ROLLOFF_FACTOR:
1006 case AL_POSITION:
1007 case AL_VELOCITY:
1008 case AL_DIRECTION:
1009 SetSourcefv(Source, Context, param, values);
1010 break;
1012 default:
1013 alSetError(Context, AL_INVALID_ENUM);
1016 ALCcontext_DecRef(Context);
1020 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1022 ALCcontext *Context;
1023 ALsource *Source;
1025 Context = GetContextRef();
1026 if(!Context) return;
1028 if((Source=LookupSource(Context, source)) == NULL)
1029 alSetError(Context, AL_INVALID_NAME);
1030 else switch(param)
1032 case AL_MAX_DISTANCE:
1033 case AL_ROLLOFF_FACTOR:
1034 case AL_CONE_INNER_ANGLE:
1035 case AL_CONE_OUTER_ANGLE:
1036 case AL_REFERENCE_DISTANCE:
1037 case AL_SOURCE_RELATIVE:
1038 case AL_LOOPING:
1039 case AL_BUFFER:
1040 case AL_SOURCE_STATE:
1041 case AL_SEC_OFFSET:
1042 case AL_SAMPLE_OFFSET:
1043 case AL_BYTE_OFFSET:
1044 case AL_DIRECT_FILTER:
1045 case AL_DIRECT_FILTER_GAINHF_AUTO:
1046 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1047 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1048 case AL_DIRECT_CHANNELS_SOFT:
1049 case AL_DISTANCE_MODEL:
1050 SetSourceiv(Source, Context, param, &value);
1051 break;
1053 default:
1054 alSetError(Context, AL_INVALID_ENUM);
1057 ALCcontext_DecRef(Context);
1061 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1063 ALCcontext *Context;
1064 ALsource *Source;
1065 ALint ivals[3];
1067 Context = GetContextRef();
1068 if(!Context) return;
1070 if((Source=LookupSource(Context, source)) == NULL)
1071 alSetError(Context, AL_INVALID_NAME);
1072 else switch(param)
1074 case AL_POSITION:
1075 case AL_VELOCITY:
1076 case AL_DIRECTION:
1077 case AL_AUXILIARY_SEND_FILTER:
1078 ivals[0] = value1;
1079 ivals[1] = value2;
1080 ivals[2] = value3;
1081 SetSourceiv(Source, Context, param, ivals);
1082 break;
1084 default:
1085 alSetError(Context, AL_INVALID_ENUM);
1088 ALCcontext_DecRef(Context);
1092 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1094 ALCcontext *Context;
1095 ALsource *Source;
1097 Context = GetContextRef();
1098 if(!Context) return;
1100 if((Source=LookupSource(Context, source)) == NULL)
1101 alSetError(Context, AL_INVALID_NAME);
1102 else if(!values)
1103 alSetError(Context, AL_INVALID_VALUE);
1104 else switch(param)
1106 case AL_SOURCE_RELATIVE:
1107 case AL_CONE_INNER_ANGLE:
1108 case AL_CONE_OUTER_ANGLE:
1109 case AL_LOOPING:
1110 case AL_BUFFER:
1111 case AL_SOURCE_STATE:
1112 case AL_SEC_OFFSET:
1113 case AL_SAMPLE_OFFSET:
1114 case AL_BYTE_OFFSET:
1115 case AL_MAX_DISTANCE:
1116 case AL_ROLLOFF_FACTOR:
1117 case AL_REFERENCE_DISTANCE:
1118 case AL_DIRECT_FILTER:
1119 case AL_DIRECT_FILTER_GAINHF_AUTO:
1120 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1121 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1122 case AL_DISTANCE_MODEL:
1123 case AL_DIRECT_CHANNELS_SOFT:
1125 case AL_POSITION:
1126 case AL_VELOCITY:
1127 case AL_DIRECTION:
1128 case AL_AUXILIARY_SEND_FILTER:
1129 SetSourceiv(Source, Context, param, values);
1130 break;
1132 default:
1133 alSetError(Context, AL_INVALID_ENUM);
1136 ALCcontext_DecRef(Context);
1140 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1142 ALCcontext *Context;
1143 ALsource *Source;
1144 ALdouble dval;
1146 Context = GetContextRef();
1147 if(!Context) return;
1149 if((Source=LookupSource(Context, source)) == NULL)
1150 alSetError(Context, AL_INVALID_NAME);
1151 else if(!value)
1152 alSetError(Context, AL_INVALID_VALUE);
1153 else switch(param)
1155 case AL_PITCH:
1156 case AL_GAIN:
1157 case AL_MIN_GAIN:
1158 case AL_MAX_GAIN:
1159 case AL_MAX_DISTANCE:
1160 case AL_ROLLOFF_FACTOR:
1161 case AL_CONE_OUTER_GAIN:
1162 case AL_CONE_OUTER_GAINHF:
1163 case AL_SEC_OFFSET:
1164 case AL_SAMPLE_OFFSET:
1165 case AL_BYTE_OFFSET:
1166 case AL_CONE_INNER_ANGLE:
1167 case AL_CONE_OUTER_ANGLE:
1168 case AL_REFERENCE_DISTANCE:
1169 case AL_AIR_ABSORPTION_FACTOR:
1170 case AL_ROOM_ROLLOFF_FACTOR:
1171 case AL_DOPPLER_FACTOR:
1172 if(GetSourcedv(Source, Context, param, &dval) == AL_NO_ERROR)
1173 *value = (ALfloat)dval;
1174 break;
1176 default:
1177 alSetError(Context, AL_INVALID_ENUM);
1180 ALCcontext_DecRef(Context);
1184 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1186 ALCcontext *Context;
1187 ALsource *Source;
1188 ALdouble dvals[3];
1190 Context = GetContextRef();
1191 if(!Context) return;
1193 if((Source=LookupSource(Context, source)) == NULL)
1194 alSetError(Context, AL_INVALID_NAME);
1195 else if(!(value1 && value2 && value3))
1196 alSetError(Context, AL_INVALID_VALUE);
1197 else switch(param)
1199 case AL_POSITION:
1200 case AL_VELOCITY:
1201 case AL_DIRECTION:
1202 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1204 *value1 = (ALfloat)dvals[0];
1205 *value2 = (ALfloat)dvals[1];
1206 *value3 = (ALfloat)dvals[2];
1208 break;
1210 default:
1211 alSetError(Context, AL_INVALID_ENUM);
1214 ALCcontext_DecRef(Context);
1218 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1220 ALCcontext *Context;
1221 ALsource *Source;
1222 ALdouble dvals[2];
1224 switch(param)
1226 case AL_PITCH:
1227 case AL_GAIN:
1228 case AL_MIN_GAIN:
1229 case AL_MAX_GAIN:
1230 case AL_MAX_DISTANCE:
1231 case AL_ROLLOFF_FACTOR:
1232 case AL_DOPPLER_FACTOR:
1233 case AL_CONE_OUTER_GAIN:
1234 case AL_SEC_OFFSET:
1235 case AL_SAMPLE_OFFSET:
1236 case AL_BYTE_OFFSET:
1237 case AL_CONE_INNER_ANGLE:
1238 case AL_CONE_OUTER_ANGLE:
1239 case AL_REFERENCE_DISTANCE:
1240 case AL_CONE_OUTER_GAINHF:
1241 case AL_AIR_ABSORPTION_FACTOR:
1242 case AL_ROOM_ROLLOFF_FACTOR:
1243 alGetSourcef(source, param, values);
1244 return;
1246 case AL_POSITION:
1247 case AL_VELOCITY:
1248 case AL_DIRECTION:
1249 alGetSource3f(source, param, values+0, values+1, values+2);
1250 return;
1253 Context = GetContextRef();
1254 if(!Context) return;
1256 if((Source=LookupSource(Context, source)) == NULL)
1257 alSetError(Context, AL_INVALID_NAME);
1258 else if(!values)
1259 alSetError(Context, AL_INVALID_VALUE);
1260 else switch(param)
1262 case AL_SAMPLE_RW_OFFSETS_SOFT:
1263 case AL_BYTE_RW_OFFSETS_SOFT:
1264 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1266 values[0] = (ALfloat)dvals[0];
1267 values[1] = (ALfloat)dvals[1];
1269 break;
1271 default:
1272 alSetError(Context, AL_INVALID_ENUM);
1275 ALCcontext_DecRef(Context);
1279 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1281 ALCcontext *Context;
1282 ALsource *Source;
1284 Context = GetContextRef();
1285 if(!Context) return;
1287 if((Source=LookupSource(Context, source)) == NULL)
1288 alSetError(Context, AL_INVALID_NAME);
1289 else if(!value)
1290 alSetError(Context, AL_INVALID_VALUE);
1291 else switch(param)
1293 case AL_PITCH:
1294 case AL_GAIN:
1295 case AL_MIN_GAIN:
1296 case AL_MAX_GAIN:
1297 case AL_MAX_DISTANCE:
1298 case AL_ROLLOFF_FACTOR:
1299 case AL_CONE_OUTER_GAIN:
1300 case AL_CONE_OUTER_GAINHF:
1301 case AL_SEC_OFFSET:
1302 case AL_SAMPLE_OFFSET:
1303 case AL_BYTE_OFFSET:
1304 case AL_CONE_INNER_ANGLE:
1305 case AL_CONE_OUTER_ANGLE:
1306 case AL_REFERENCE_DISTANCE:
1307 case AL_AIR_ABSORPTION_FACTOR:
1308 case AL_ROOM_ROLLOFF_FACTOR:
1309 case AL_DOPPLER_FACTOR:
1310 GetSourcedv(Source, Context, param, value);
1311 break;
1313 default:
1314 alSetError(Context, AL_INVALID_ENUM);
1317 ALCcontext_DecRef(Context);
1320 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1322 ALCcontext *Context;
1323 ALsource *Source;
1324 ALdouble dvals[3];
1326 Context = GetContextRef();
1327 if(!Context) return;
1329 if((Source=LookupSource(Context, source)) == NULL)
1330 alSetError(Context, AL_INVALID_NAME);
1331 else if(!(value1 && value2 && value3))
1332 alSetError(Context, AL_INVALID_VALUE);
1333 else switch(param)
1335 case AL_POSITION:
1336 case AL_VELOCITY:
1337 case AL_DIRECTION:
1338 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1340 *value1 = dvals[0];
1341 *value2 = dvals[1];
1342 *value3 = dvals[2];
1344 break;
1346 default:
1347 alSetError(Context, AL_INVALID_ENUM);
1350 ALCcontext_DecRef(Context);
1353 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1355 ALCcontext *Context;
1356 ALsource *Source;
1358 Context = GetContextRef();
1359 if(!Context) return;
1361 if((Source=LookupSource(Context, source)) == NULL)
1362 alSetError(Context, AL_INVALID_NAME);
1363 else if(!values)
1364 alSetError(Context, AL_INVALID_VALUE);
1365 else switch(param)
1367 case AL_PITCH:
1368 case AL_GAIN:
1369 case AL_MIN_GAIN:
1370 case AL_MAX_GAIN:
1371 case AL_MAX_DISTANCE:
1372 case AL_ROLLOFF_FACTOR:
1373 case AL_DOPPLER_FACTOR:
1374 case AL_CONE_OUTER_GAIN:
1375 case AL_SEC_OFFSET:
1376 case AL_SAMPLE_OFFSET:
1377 case AL_BYTE_OFFSET:
1378 case AL_CONE_INNER_ANGLE:
1379 case AL_CONE_OUTER_ANGLE:
1380 case AL_REFERENCE_DISTANCE:
1381 case AL_CONE_OUTER_GAINHF:
1382 case AL_AIR_ABSORPTION_FACTOR:
1383 case AL_ROOM_ROLLOFF_FACTOR:
1385 case AL_SAMPLE_RW_OFFSETS_SOFT:
1386 case AL_BYTE_RW_OFFSETS_SOFT:
1387 case AL_SEC_OFFSET_LATENCY_SOFT:
1389 case AL_POSITION:
1390 case AL_VELOCITY:
1391 case AL_DIRECTION:
1392 GetSourcedv(Source, Context, param, values);
1393 break;
1395 default:
1396 alSetError(Context, AL_INVALID_ENUM);
1399 ALCcontext_DecRef(Context);
1403 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1405 ALCcontext *Context;
1406 ALsource *Source;
1408 Context = GetContextRef();
1409 if(!Context) return;
1411 if((Source=LookupSource(Context, source)) == NULL)
1412 alSetError(Context, AL_INVALID_NAME);
1413 else if(!value)
1414 alSetError(Context, AL_INVALID_VALUE);
1415 else switch(param)
1417 case AL_MAX_DISTANCE:
1418 case AL_ROLLOFF_FACTOR:
1419 case AL_REFERENCE_DISTANCE:
1420 case AL_SOURCE_RELATIVE:
1421 case AL_CONE_INNER_ANGLE:
1422 case AL_CONE_OUTER_ANGLE:
1423 case AL_LOOPING:
1424 case AL_BUFFER:
1425 case AL_SOURCE_STATE:
1426 case AL_BUFFERS_QUEUED:
1427 case AL_BUFFERS_PROCESSED:
1428 case AL_SOURCE_TYPE:
1429 case AL_SEC_OFFSET:
1430 case AL_SAMPLE_OFFSET:
1431 case AL_BYTE_OFFSET:
1432 case AL_DIRECT_FILTER_GAINHF_AUTO:
1433 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1434 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1435 case AL_DOPPLER_FACTOR:
1436 case AL_DIRECT_CHANNELS_SOFT:
1437 case AL_DISTANCE_MODEL:
1438 GetSourceiv(Source, Context, param, value);
1439 break;
1441 default:
1442 alSetError(Context, AL_INVALID_ENUM);
1445 ALCcontext_DecRef(Context);
1449 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
1451 ALCcontext *Context;
1452 ALsource *Source;
1453 ALint ivals[3];
1455 Context = GetContextRef();
1456 if(!Context) return;
1458 if((Source=LookupSource(Context, source)) == NULL)
1459 alSetError(Context, AL_INVALID_NAME);
1460 else if(!(value1 && value2 && value3))
1461 alSetError(Context, AL_INVALID_VALUE);
1462 else switch(param)
1464 case AL_POSITION:
1465 case AL_VELOCITY:
1466 case AL_DIRECTION:
1467 if(GetSourceiv(Source, Context, param, ivals) == AL_NO_ERROR)
1469 *value1 = ivals[0];
1470 *value2 = ivals[1];
1471 *value3 = ivals[2];
1473 break;
1475 default:
1476 alSetError(Context, AL_INVALID_ENUM);
1479 ALCcontext_DecRef(Context);
1483 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
1485 ALCcontext *Context;
1486 ALsource *Source;
1488 Context = GetContextRef();
1489 if(!Context) return;
1491 if((Source=LookupSource(Context, source)) == NULL)
1492 alSetError(Context, AL_INVALID_NAME);
1493 else if(!values)
1494 alSetError(Context, AL_INVALID_VALUE);
1495 else switch(param)
1497 case AL_SOURCE_RELATIVE:
1498 case AL_CONE_INNER_ANGLE:
1499 case AL_CONE_OUTER_ANGLE:
1500 case AL_LOOPING:
1501 case AL_BUFFER:
1502 case AL_SOURCE_STATE:
1503 case AL_BUFFERS_QUEUED:
1504 case AL_BUFFERS_PROCESSED:
1505 case AL_SEC_OFFSET:
1506 case AL_SAMPLE_OFFSET:
1507 case AL_BYTE_OFFSET:
1508 case AL_MAX_DISTANCE:
1509 case AL_ROLLOFF_FACTOR:
1510 case AL_DOPPLER_FACTOR:
1511 case AL_REFERENCE_DISTANCE:
1512 case AL_SOURCE_TYPE:
1513 case AL_DIRECT_FILTER:
1514 case AL_DIRECT_FILTER_GAINHF_AUTO:
1515 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1516 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1517 case AL_DISTANCE_MODEL:
1518 case AL_DIRECT_CHANNELS_SOFT:
1520 case AL_SAMPLE_RW_OFFSETS_SOFT:
1521 case AL_BYTE_RW_OFFSETS_SOFT:
1523 case AL_POSITION:
1524 case AL_VELOCITY:
1525 case AL_DIRECTION:
1526 GetSourceiv(Source, Context, param, values);
1527 break;
1529 default:
1530 alSetError(Context, AL_INVALID_ENUM);
1533 ALCcontext_DecRef(Context);
1537 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
1539 ALCcontext *Context;
1540 ALsource *Source;
1542 Context = GetContextRef();
1543 if(!Context) return;
1545 if((Source=LookupSource(Context, source)) == NULL)
1546 alSetError(Context, AL_INVALID_NAME);
1547 else if(!value)
1548 alSetError(Context, AL_INVALID_VALUE);
1549 else switch(param)
1551 case AL_MAX_DISTANCE:
1552 case AL_ROLLOFF_FACTOR:
1553 case AL_REFERENCE_DISTANCE:
1554 case AL_SOURCE_RELATIVE:
1555 case AL_CONE_INNER_ANGLE:
1556 case AL_CONE_OUTER_ANGLE:
1557 case AL_LOOPING:
1558 case AL_BUFFER:
1559 case AL_SOURCE_STATE:
1560 case AL_BUFFERS_QUEUED:
1561 case AL_BUFFERS_PROCESSED:
1562 case AL_SOURCE_TYPE:
1563 case AL_SEC_OFFSET:
1564 case AL_SAMPLE_OFFSET:
1565 case AL_BYTE_OFFSET:
1566 case AL_DIRECT_FILTER_GAINHF_AUTO:
1567 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1568 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1569 case AL_DOPPLER_FACTOR:
1570 case AL_DIRECT_CHANNELS_SOFT:
1571 case AL_DISTANCE_MODEL:
1572 GetSourcei64v(Source, Context, param, value);
1573 break;
1575 default:
1576 alSetError(Context, AL_INVALID_ENUM);
1579 ALCcontext_DecRef(Context);
1582 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
1584 ALCcontext *Context;
1585 ALsource *Source;
1586 ALint64 i64vals[3];
1588 Context = GetContextRef();
1589 if(!Context) return;
1591 if((Source=LookupSource(Context, source)) == NULL)
1592 alSetError(Context, AL_INVALID_NAME);
1593 else if(!(value1 && value2 && value3))
1594 alSetError(Context, AL_INVALID_VALUE);
1595 else switch(param)
1597 case AL_POSITION:
1598 case AL_VELOCITY:
1599 case AL_DIRECTION:
1600 if(GetSourcei64v(Source, Context, param, i64vals) == AL_NO_ERROR)
1602 *value1 = i64vals[0];
1603 *value2 = i64vals[1];
1604 *value3 = i64vals[2];
1606 break;
1608 default:
1609 alSetError(Context, AL_INVALID_ENUM);
1612 ALCcontext_DecRef(Context);
1615 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
1617 ALCcontext *Context;
1618 ALsource *Source;
1620 Context = GetContextRef();
1621 if(!Context) return;
1623 if((Source=LookupSource(Context, source)) == NULL)
1624 alSetError(Context, AL_INVALID_NAME);
1625 else if(!values)
1626 alSetError(Context, AL_INVALID_VALUE);
1627 else switch(param)
1629 case AL_MAX_DISTANCE:
1630 case AL_ROLLOFF_FACTOR:
1631 case AL_REFERENCE_DISTANCE:
1632 case AL_SOURCE_RELATIVE:
1633 case AL_CONE_INNER_ANGLE:
1634 case AL_CONE_OUTER_ANGLE:
1635 case AL_LOOPING:
1636 case AL_BUFFER:
1637 case AL_SOURCE_STATE:
1638 case AL_BUFFERS_QUEUED:
1639 case AL_BUFFERS_PROCESSED:
1640 case AL_SOURCE_TYPE:
1641 case AL_SEC_OFFSET:
1642 case AL_SAMPLE_OFFSET:
1643 case AL_BYTE_OFFSET:
1644 case AL_DIRECT_FILTER_GAINHF_AUTO:
1645 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1646 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1647 case AL_DOPPLER_FACTOR:
1648 case AL_DIRECT_CHANNELS_SOFT:
1649 case AL_DISTANCE_MODEL:
1651 case AL_SAMPLE_RW_OFFSETS_SOFT:
1652 case AL_BYTE_RW_OFFSETS_SOFT:
1653 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1655 case AL_POSITION:
1656 case AL_VELOCITY:
1657 case AL_DIRECTION:
1658 GetSourcei64v(Source, Context, param, values);
1659 break;
1661 default:
1662 alSetError(Context, AL_INVALID_ENUM);
1665 ALCcontext_DecRef(Context);
1669 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1671 alSourcePlayv(1, &source);
1673 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1675 ALCcontext *Context;
1676 ALsource *Source;
1677 ALsizei i;
1679 Context = GetContextRef();
1680 if(!Context) return;
1682 al_try
1684 CHECK_VALUE(Context, n >= 0);
1685 for(i = 0;i < n;i++)
1687 if(!LookupSource(Context, sources[i]))
1688 al_throwerr(Context, AL_INVALID_NAME);
1691 LockContext(Context);
1692 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1694 void *temp = NULL;
1695 ALsizei newcount;
1697 newcount = Context->MaxActiveSources << 1;
1698 if(newcount > 0)
1699 temp = realloc(Context->ActiveSources,
1700 sizeof(*Context->ActiveSources) * newcount);
1701 if(!temp)
1703 UnlockContext(Context);
1704 al_throwerr(Context, AL_OUT_OF_MEMORY);
1707 Context->ActiveSources = temp;
1708 Context->MaxActiveSources = newcount;
1711 for(i = 0;i < n;i++)
1713 Source = LookupSource(Context, sources[i]);
1714 if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
1715 else SetSourceState(Source, Context, AL_PLAYING);
1717 UnlockContext(Context);
1719 al_endtry;
1721 ALCcontext_DecRef(Context);
1724 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1726 alSourcePausev(1, &source);
1728 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1730 ALCcontext *Context;
1731 ALsource *Source;
1732 ALsizei i;
1734 Context = GetContextRef();
1735 if(!Context) return;
1737 al_try
1739 CHECK_VALUE(Context, n >= 0);
1740 for(i = 0;i < n;i++)
1742 if(!LookupSource(Context, sources[i]))
1743 al_throwerr(Context, AL_INVALID_NAME);
1746 LockContext(Context);
1747 for(i = 0;i < n;i++)
1749 Source = LookupSource(Context, sources[i]);
1750 if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
1751 else SetSourceState(Source, Context, AL_PAUSED);
1753 UnlockContext(Context);
1755 al_endtry;
1757 ALCcontext_DecRef(Context);
1760 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1762 alSourceStopv(1, &source);
1764 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1766 ALCcontext *Context;
1767 ALsource *Source;
1768 ALsizei i;
1770 Context = GetContextRef();
1771 if(!Context) return;
1773 al_try
1775 CHECK_VALUE(Context, n >= 0);
1776 for(i = 0;i < n;i++)
1778 if(!LookupSource(Context, sources[i]))
1779 al_throwerr(Context, AL_INVALID_NAME);
1782 LockContext(Context);
1783 for(i = 0;i < n;i++)
1785 Source = LookupSource(Context, sources[i]);
1786 Source->new_state = AL_NONE;
1787 SetSourceState(Source, Context, AL_STOPPED);
1789 UnlockContext(Context);
1791 al_endtry;
1793 ALCcontext_DecRef(Context);
1796 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1798 alSourceRewindv(1, &source);
1800 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1802 ALCcontext *Context;
1803 ALsource *Source;
1804 ALsizei i;
1806 Context = GetContextRef();
1807 if(!Context) return;
1809 al_try
1811 CHECK_VALUE(Context, n >= 0);
1812 for(i = 0;i < n;i++)
1814 if(!LookupSource(Context, sources[i]))
1815 al_throwerr(Context, AL_INVALID_NAME);
1818 LockContext(Context);
1819 for(i = 0;i < n;i++)
1821 Source = LookupSource(Context, sources[i]);
1822 Source->new_state = AL_NONE;
1823 SetSourceState(Source, Context, AL_INITIAL);
1825 UnlockContext(Context);
1827 al_endtry;
1829 ALCcontext_DecRef(Context);
1833 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers)
1835 ALCcontext *Context;
1836 ALsource *Source;
1837 ALsizei i;
1838 ALbufferlistitem *BufferListStart = NULL;
1839 ALbufferlistitem *BufferList;
1840 ALbuffer *BufferFmt;
1842 if(nb == 0)
1843 return;
1845 Context = GetContextRef();
1846 if(!Context) return;
1848 al_try
1850 ALCdevice *device = Context->Device;
1852 CHECK_VALUE(Context, nb >= 0);
1854 if((Source=LookupSource(Context, source)) == NULL)
1855 al_throwerr(Context, AL_INVALID_NAME);
1857 LockContext(Context);
1858 if(Source->SourceType == AL_STATIC)
1860 UnlockContext(Context);
1861 /* Can't queue on a Static Source */
1862 al_throwerr(Context, AL_INVALID_OPERATION);
1865 BufferFmt = NULL;
1867 /* Check for a valid Buffer, for its frequency and format */
1868 BufferList = Source->queue;
1869 while(BufferList)
1871 if(BufferList->buffer)
1873 BufferFmt = BufferList->buffer;
1874 break;
1876 BufferList = BufferList->next;
1879 for(i = 0;i < nb;i++)
1881 ALbuffer *buffer = NULL;
1882 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
1884 UnlockContext(Context);
1885 al_throwerr(Context, AL_INVALID_NAME);
1888 if(!BufferListStart)
1890 BufferListStart = malloc(sizeof(ALbufferlistitem));
1891 BufferListStart->buffer = buffer;
1892 BufferListStart->next = NULL;
1893 BufferListStart->prev = NULL;
1894 BufferList = BufferListStart;
1896 else
1898 BufferList->next = malloc(sizeof(ALbufferlistitem));
1899 BufferList->next->buffer = buffer;
1900 BufferList->next->next = NULL;
1901 BufferList->next->prev = BufferList;
1902 BufferList = BufferList->next;
1904 if(!buffer) continue;
1905 IncrementRef(&buffer->ref);
1907 ReadLock(&buffer->lock);
1908 if(BufferFmt == NULL)
1910 BufferFmt = buffer;
1912 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
1913 Source->SampleSize = BytesFromFmt(buffer->FmtType);
1914 if(buffer->FmtChannels == FmtMono)
1915 Source->Update = CalcSourceParams;
1916 else
1917 Source->Update = CalcNonAttnSourceParams;
1919 Source->NeedsUpdate = AL_TRUE;
1921 else if(BufferFmt->Frequency != buffer->Frequency ||
1922 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
1923 BufferFmt->OriginalType != buffer->OriginalType)
1925 ReadUnlock(&buffer->lock);
1926 UnlockContext(Context);
1927 al_throwerr(Context, AL_INVALID_OPERATION);
1929 ReadUnlock(&buffer->lock);
1932 /* Source is now streaming */
1933 Source->SourceType = AL_STREAMING;
1935 if(Source->queue == NULL)
1936 Source->queue = BufferListStart;
1937 else
1939 /* Append to the end of the queue */
1940 BufferList = Source->queue;
1941 while(BufferList->next != NULL)
1942 BufferList = BufferList->next;
1944 BufferListStart->prev = BufferList;
1945 BufferList->next = BufferListStart;
1948 Source->BuffersInQueue += nb;
1950 UnlockContext(Context);
1952 al_catchany()
1954 while(BufferListStart)
1956 BufferList = BufferListStart;
1957 BufferListStart = BufferList->next;
1959 if(BufferList->buffer)
1960 DecrementRef(&BufferList->buffer->ref);
1961 free(BufferList);
1964 al_endtry;
1966 ALCcontext_DecRef(Context);
1969 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers)
1971 ALCcontext *Context;
1972 ALsource *Source;
1973 ALsizei i;
1974 ALbufferlistitem *BufferList;
1976 if(nb == 0)
1977 return;
1979 Context = GetContextRef();
1980 if(!Context) return;
1982 al_try
1984 CHECK_VALUE(Context, nb >= 0);
1986 if((Source=LookupSource(Context, source)) == NULL)
1987 al_throwerr(Context, AL_INVALID_NAME);
1989 LockContext(Context);
1990 if(Source->Looping || Source->SourceType != AL_STREAMING ||
1991 (ALuint)nb > Source->BuffersPlayed)
1993 UnlockContext(Context);
1994 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
1995 al_throwerr(Context, AL_INVALID_VALUE);
1998 for(i = 0;i < nb;i++)
2000 BufferList = Source->queue;
2001 Source->queue = BufferList->next;
2002 Source->BuffersInQueue--;
2003 Source->BuffersPlayed--;
2005 if(BufferList->buffer)
2007 buffers[i] = BufferList->buffer->id;
2008 DecrementRef(&BufferList->buffer->ref);
2010 else
2011 buffers[i] = 0;
2013 free(BufferList);
2015 if(Source->queue)
2016 Source->queue->prev = NULL;
2017 UnlockContext(Context);
2019 al_endtry;
2021 ALCcontext_DecRef(Context);
2025 static ALvoid InitSourceParams(ALsource *Source)
2027 ALuint i;
2029 Source->InnerAngle = 360.0f;
2030 Source->OuterAngle = 360.0f;
2031 Source->Pitch = 1.0f;
2032 Source->Position[0] = 0.0f;
2033 Source->Position[1] = 0.0f;
2034 Source->Position[2] = 0.0f;
2035 Source->Orientation[0] = 0.0f;
2036 Source->Orientation[1] = 0.0f;
2037 Source->Orientation[2] = 0.0f;
2038 Source->Velocity[0] = 0.0f;
2039 Source->Velocity[1] = 0.0f;
2040 Source->Velocity[2] = 0.0f;
2041 Source->RefDistance = 1.0f;
2042 Source->MaxDistance = FLT_MAX;
2043 Source->RollOffFactor = 1.0f;
2044 Source->Looping = AL_FALSE;
2045 Source->Gain = 1.0f;
2046 Source->MinGain = 0.0f;
2047 Source->MaxGain = 1.0f;
2048 Source->OuterGain = 0.0f;
2049 Source->OuterGainHF = 1.0f;
2051 Source->DryGainHFAuto = AL_TRUE;
2052 Source->WetGainAuto = AL_TRUE;
2053 Source->WetGainHFAuto = AL_TRUE;
2054 Source->AirAbsorptionFactor = 0.0f;
2055 Source->RoomRolloffFactor = 0.0f;
2056 Source->DopplerFactor = 1.0f;
2057 Source->DirectChannels = AL_FALSE;
2059 Source->DistanceModel = DefaultDistanceModel;
2061 Source->Resampler = DefaultResampler;
2063 Source->state = AL_INITIAL;
2064 Source->new_state = AL_NONE;
2065 Source->SourceType = AL_UNDETERMINED;
2066 Source->Offset = -1.0;
2068 Source->DirectGain = 1.0f;
2069 Source->DirectGainHF = 1.0f;
2070 for(i = 0;i < MAX_SENDS;i++)
2072 Source->Send[i].Gain = 1.0f;
2073 Source->Send[i].GainHF = 1.0f;
2076 Source->NeedsUpdate = AL_TRUE;
2078 Source->Hrtf.Moving = AL_FALSE;
2079 Source->Hrtf.Counter = 0;
2083 /* SetSourceState
2085 * Sets the source's new play state given its current state.
2087 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2089 if(state == AL_PLAYING)
2091 ALbufferlistitem *BufferList;
2092 ALsizei j, k;
2094 /* Check that there is a queue containing at least one valid, non zero
2095 * length Buffer. */
2096 BufferList = Source->queue;
2097 while(BufferList)
2099 if(BufferList->buffer != NULL && BufferList->buffer->SampleLen)
2100 break;
2101 BufferList = BufferList->next;
2104 if(Source->state != AL_PLAYING)
2106 for(j = 0;j < MaxChannels;j++)
2108 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
2109 Source->Hrtf.History[j][k] = 0.0f;
2110 for(k = 0;k < HRIR_LENGTH;k++)
2112 Source->Hrtf.Values[j][k][0] = 0.0f;
2113 Source->Hrtf.Values[j][k][1] = 0.0f;
2118 if(Source->state != AL_PAUSED)
2120 Source->state = AL_PLAYING;
2121 Source->position = 0;
2122 Source->position_fraction = 0;
2123 Source->BuffersPlayed = 0;
2125 else
2126 Source->state = AL_PLAYING;
2128 // Check if an Offset has been set
2129 if(Source->Offset >= 0.0)
2130 ApplyOffset(Source);
2132 /* If there's nothing to play, or device is disconnected, go right to
2133 * stopped */
2134 if(!BufferList || !Context->Device->Connected)
2136 SetSourceState(Source, Context, AL_STOPPED);
2137 return;
2140 for(j = 0;j < Context->ActiveSourceCount;j++)
2142 if(Context->ActiveSources[j] == Source)
2143 break;
2145 if(j == Context->ActiveSourceCount)
2146 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
2148 else if(state == AL_PAUSED)
2150 if(Source->state == AL_PLAYING)
2152 Source->state = AL_PAUSED;
2153 Source->Hrtf.Moving = AL_FALSE;
2154 Source->Hrtf.Counter = 0;
2157 else if(state == AL_STOPPED)
2159 if(Source->state != AL_INITIAL)
2161 Source->state = AL_STOPPED;
2162 Source->BuffersPlayed = Source->BuffersInQueue;
2163 Source->Hrtf.Moving = AL_FALSE;
2164 Source->Hrtf.Counter = 0;
2166 Source->Offset = -1.0;
2168 else if(state == AL_INITIAL)
2170 if(Source->state != AL_INITIAL)
2172 Source->state = AL_INITIAL;
2173 Source->position = 0;
2174 Source->position_fraction = 0;
2175 Source->BuffersPlayed = 0;
2176 Source->Hrtf.Moving = AL_FALSE;
2177 Source->Hrtf.Counter = 0;
2179 Source->Offset = -1.0;
2183 /* GetSourceOffset
2185 * Gets the current read offset for the given Source, in 32.32 fixed-point
2186 * samples. The offset is relative to the start of the queue (not the start of
2187 * the current buffer).
2189 static ALint64 GetSourceOffset(const ALsource *Source)
2191 const ALbufferlistitem *BufferList;
2192 ALuint64 readPos;
2193 ALuint i;
2195 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2196 return 0;
2198 /* NOTE: This is the offset into the *current* buffer, so add the length of
2199 * any played buffers */
2200 readPos = (ALuint64)Source->position << 32;
2201 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2202 BufferList = Source->queue;
2203 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2205 if(BufferList->buffer)
2206 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2207 BufferList = BufferList->next;
2210 return (ALint64)minu64(readPos, MAKEU64(0x7fffffff,0xffffffff));
2213 /* GetSourceSecOffset
2215 * Gets the current read offset for the given Source, in seconds. The offset is
2216 * relative to the start of the queue (not the start of the current buffer).
2218 static ALdouble GetSourceSecOffset(const ALsource *Source)
2220 const ALbufferlistitem *BufferList;
2221 const ALbuffer *Buffer = NULL;
2222 ALuint64 readPos;
2223 ALuint i;
2225 BufferList = Source->queue;
2226 while(BufferList)
2228 if(BufferList->buffer)
2230 Buffer = BufferList->buffer;
2231 break;
2233 BufferList = BufferList->next;
2236 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2237 return 0.0;
2239 /* NOTE: This is the offset into the *current* buffer, so add the length of
2240 * any played buffers */
2241 readPos = (ALuint64)Source->position << FRACTIONBITS;
2242 readPos |= (ALuint64)Source->position_fraction;
2243 BufferList = Source->queue;
2244 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2246 if(BufferList->buffer)
2247 readPos += (ALuint64)BufferList->buffer->SampleLen << FRACTIONBITS;
2248 BufferList = BufferList->next;
2251 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2254 /* GetSourceOffsets
2256 * Gets the current read and write offsets for the given Source, in the
2257 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2258 * the start of the queue (not the start of the current buffer).
2260 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2262 const ALbufferlistitem *BufferList;
2263 const ALbuffer *Buffer = NULL;
2264 ALuint readPos, writePos;
2265 ALuint totalBufferLen;
2266 ALuint i;
2268 // Find the first valid Buffer in the Queue
2269 BufferList = Source->queue;
2270 while(BufferList)
2272 if(BufferList->buffer)
2274 Buffer = BufferList->buffer;
2275 break;
2277 BufferList = BufferList->next;
2280 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2282 offset[0] = 0.0;
2283 offset[1] = 0.0;
2284 return;
2287 if(updateLen > 0.0 && updateLen < 0.015)
2288 updateLen = 0.015;
2290 /* NOTE: This is the offset into the *current* buffer, so add the length of
2291 * any played buffers */
2292 readPos = Source->position;
2293 totalBufferLen = 0;
2294 BufferList = Source->queue;
2295 for(i = 0;BufferList;i++)
2297 if(BufferList->buffer)
2299 if(i < Source->BuffersPlayed)
2300 readPos += BufferList->buffer->SampleLen;
2301 totalBufferLen += BufferList->buffer->SampleLen;
2303 BufferList = BufferList->next;
2305 if(Source->state == AL_PLAYING)
2306 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
2307 else
2308 writePos = readPos;
2310 if(Source->Looping)
2312 readPos %= totalBufferLen;
2313 writePos %= totalBufferLen;
2315 else
2317 /* Wrap positions back to 0 */
2318 if(readPos >= totalBufferLen)
2319 readPos = 0;
2320 if(writePos >= totalBufferLen)
2321 writePos = 0;
2324 switch(name)
2326 case AL_SEC_OFFSET:
2327 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2328 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2329 break;
2331 case AL_SAMPLE_OFFSET:
2332 case AL_SAMPLE_RW_OFFSETS_SOFT:
2333 offset[0] = (ALdouble)readPos;
2334 offset[1] = (ALdouble)writePos;
2335 break;
2337 case AL_BYTE_OFFSET:
2338 case AL_BYTE_RW_OFFSETS_SOFT:
2339 if(Buffer->OriginalType == UserFmtIMA4)
2341 ALuint BlockSize = 36 * ChannelsFromFmt(Buffer->FmtChannels);
2342 ALuint FrameBlockSize = 65;
2344 /* Round down to nearest ADPCM block */
2345 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2346 if(Source->state != AL_PLAYING)
2347 offset[1] = offset[0];
2348 else
2350 /* Round up to nearest ADPCM block */
2351 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2352 FrameBlockSize * BlockSize);
2355 else
2357 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2358 offset[0] = (ALdouble)(readPos * FrameSize);
2359 offset[1] = (ALdouble)(writePos * FrameSize);
2361 break;
2366 /* ApplyOffset
2368 * Apply the stored playback offset to the Source. This function will update
2369 * the number of buffers "played" given the stored offset.
2371 ALboolean ApplyOffset(ALsource *Source)
2373 const ALbufferlistitem *BufferList;
2374 const ALbuffer *Buffer;
2375 ALint bufferLen, totalBufferLen;
2376 ALint buffersPlayed;
2377 ALint offset;
2379 /* Get sample frame offset */
2380 offset = GetSampleOffset(Source);
2381 if(offset == -1)
2382 return AL_FALSE;
2384 buffersPlayed = 0;
2385 totalBufferLen = 0;
2387 BufferList = Source->queue;
2388 while(BufferList)
2390 Buffer = BufferList->buffer;
2391 bufferLen = Buffer ? Buffer->SampleLen : 0;
2393 if(bufferLen <= offset-totalBufferLen)
2395 /* Offset is past this buffer so increment to the next buffer */
2396 buffersPlayed++;
2398 else if(totalBufferLen <= offset)
2400 /* Offset is in this buffer */
2401 Source->BuffersPlayed = buffersPlayed;
2403 Source->position = offset - totalBufferLen;
2404 Source->position_fraction = 0;
2405 return AL_TRUE;
2408 totalBufferLen += bufferLen;
2410 BufferList = BufferList->next;
2413 /* Offset is out of range of the queue */
2414 return AL_FALSE;
2418 /* GetSampleOffset
2420 * Returns the sample offset into the Source's queue (from the Sample, Byte or
2421 * Second offset supplied by the application). This takes into account the fact
2422 * that the buffer format may have been modifed since.
2424 static ALint GetSampleOffset(ALsource *Source)
2426 const ALbuffer *Buffer = NULL;
2427 const ALbufferlistitem *BufferList;
2428 ALint Offset = -1;
2430 /* Find the first valid Buffer in the Queue */
2431 BufferList = Source->queue;
2432 while(BufferList)
2434 if(BufferList->buffer)
2436 Buffer = BufferList->buffer;
2437 break;
2439 BufferList = BufferList->next;
2442 if(!Buffer)
2444 Source->Offset = -1.0;
2445 return -1;
2448 switch(Source->OffsetType)
2450 case AL_BYTE_OFFSET:
2451 /* Determine the ByteOffset (and ensure it is block aligned) */
2452 Offset = (ALint)Source->Offset;
2453 if(Buffer->OriginalType == UserFmtIMA4)
2455 Offset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
2456 Offset *= 65;
2458 else
2459 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2460 break;
2462 case AL_SAMPLE_OFFSET:
2463 Offset = (ALint)Source->Offset;
2464 break;
2466 case AL_SEC_OFFSET:
2467 Offset = (ALint)(Source->Offset * Buffer->Frequency);
2468 break;
2470 Source->Offset = -1.0;
2472 return Offset;
2476 /* ReleaseALSources
2478 * Destroys all sources in the source map.
2480 ALvoid ReleaseALSources(ALCcontext *Context)
2482 ALsizei pos;
2483 ALuint j;
2484 for(pos = 0;pos < Context->SourceMap.size;pos++)
2486 ALsource *temp = Context->SourceMap.array[pos].value;
2487 Context->SourceMap.array[pos].value = NULL;
2489 while(temp->queue != NULL)
2491 ALbufferlistitem *BufferList = temp->queue;
2492 temp->queue = BufferList->next;
2494 if(BufferList->buffer != NULL)
2495 DecrementRef(&BufferList->buffer->ref);
2496 free(BufferList);
2499 for(j = 0;j < MAX_SENDS;++j)
2501 if(temp->Send[j].Slot)
2502 DecrementRef(&temp->Send[j].Slot->ref);
2503 temp->Send[j].Slot = NULL;
2506 FreeThunkEntry(temp->id);
2507 memset(temp, 0, sizeof(*temp));
2508 al_free(temp);