Fix matrix multiply used by the SSE cubic resampler
[openal-soft/openal-hmr.git] / OpenAL32 / alSource.c
blob21ccb60ae6029e4ca46a18bc464f9a3f1d2b5254
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_CONE_OUTER_GAINHF:
512 *values = Source->OuterGainHF;
513 break;
515 case AL_AIR_ABSORPTION_FACTOR:
516 *values = Source->AirAbsorptionFactor;
517 break;
519 case AL_ROOM_ROLLOFF_FACTOR:
520 *values = Source->RoomRolloffFactor;
521 break;
523 case AL_DOPPLER_FACTOR:
524 *values = Source->DopplerFactor;
525 break;
527 case AL_SAMPLE_RW_OFFSETS_SOFT:
528 case AL_BYTE_RW_OFFSETS_SOFT:
529 LockContext(Context);
530 updateLen = (ALdouble)Context->Device->UpdateSize /
531 Context->Device->Frequency;
532 GetSourceOffsets(Source, name, values, updateLen);
533 UnlockContext(Context);
534 break;
536 case AL_SEC_OFFSET_LATENCY_SOFT:
537 LockContext(Context);
538 values[0] = GetSourceSecOffset(Source);
539 values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) /
540 1000000000.0;
541 UnlockContext(Context);
542 break;
544 case AL_POSITION:
545 LockContext(Context);
546 values[0] = Source->Position[0];
547 values[1] = Source->Position[1];
548 values[2] = Source->Position[2];
549 UnlockContext(Context);
550 break;
552 case AL_VELOCITY:
553 LockContext(Context);
554 values[0] = Source->Velocity[0];
555 values[1] = Source->Velocity[1];
556 values[2] = Source->Velocity[2];
557 UnlockContext(Context);
558 break;
560 case AL_DIRECTION:
561 LockContext(Context);
562 values[0] = Source->Orientation[0];
563 values[1] = Source->Orientation[1];
564 values[2] = Source->Orientation[2];
565 UnlockContext(Context);
566 break;
568 case AL_SOURCE_RELATIVE:
569 case AL_LOOPING:
570 case AL_BUFFER:
571 case AL_SOURCE_STATE:
572 case AL_BUFFERS_QUEUED:
573 case AL_BUFFERS_PROCESSED:
574 case AL_SOURCE_TYPE:
575 case AL_DIRECT_FILTER_GAINHF_AUTO:
576 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
577 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
578 case AL_DIRECT_CHANNELS_SOFT:
579 case AL_DISTANCE_MODEL:
580 if((err=GetSourceiv(Source, Context, name, ivals)) != AL_NO_ERROR)
581 return err;
582 *values = (ALdouble)ivals[0];
583 break;
585 default:
586 RETERR(AL_INVALID_ENUM);
589 return AL_NO_ERROR;
592 static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, ALenum name, ALint *values)
594 ALbufferlistitem *BufferList;
595 ALdouble dvals[3];
596 ALenum err;
598 switch(name)
600 case AL_SOURCE_RELATIVE:
601 *values = Source->HeadRelative;
602 break;
604 case AL_LOOPING:
605 *values = Source->Looping;
606 break;
608 case AL_BUFFER:
609 LockContext(Context);
610 BufferList = Source->queue;
611 if(Source->SourceType != AL_STATIC)
613 ALuint i = Source->BuffersPlayed;
614 while(i > 0)
616 BufferList = BufferList->next;
617 i--;
620 *values = ((BufferList && BufferList->buffer) ?
621 BufferList->buffer->id : 0);
622 UnlockContext(Context);
623 break;
625 case AL_SOURCE_STATE:
626 *values = Source->state;
627 break;
629 case AL_BUFFERS_QUEUED:
630 *values = Source->BuffersInQueue;
631 break;
633 case AL_BUFFERS_PROCESSED:
634 LockContext(Context);
635 if(Source->Looping || Source->SourceType != AL_STREAMING)
637 /* Buffers on a looping source are in a perpetual state of
638 * PENDING, so don't report any as PROCESSED */
639 *values = 0;
641 else
642 *values = Source->BuffersPlayed;
643 UnlockContext(Context);
644 break;
646 case AL_SOURCE_TYPE:
647 *values = Source->SourceType;
648 break;
650 case AL_DIRECT_FILTER_GAINHF_AUTO:
651 *values = Source->DryGainHFAuto;
652 break;
654 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
655 *values = Source->WetGainAuto;
656 break;
658 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
659 *values = Source->WetGainHFAuto;
660 break;
662 case AL_DIRECT_CHANNELS_SOFT:
663 *values = Source->DirectChannels;
664 break;
666 case AL_DISTANCE_MODEL:
667 *values = Source->DistanceModel;
668 break;
670 case AL_MAX_DISTANCE:
671 case AL_ROLLOFF_FACTOR:
672 case AL_REFERENCE_DISTANCE:
673 case AL_CONE_INNER_ANGLE:
674 case AL_CONE_OUTER_ANGLE:
675 case AL_SEC_OFFSET:
676 case AL_SAMPLE_OFFSET:
677 case AL_BYTE_OFFSET:
678 case AL_DOPPLER_FACTOR:
679 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
680 return err;
681 *values = (ALint)dvals[0];
682 break;
684 case AL_SAMPLE_RW_OFFSETS_SOFT:
685 case AL_BYTE_RW_OFFSETS_SOFT:
686 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
687 return err;
688 values[0] = (ALint)dvals[0];
689 values[1] = (ALint)dvals[0];
690 break;
692 case AL_POSITION:
693 case AL_VELOCITY:
694 case AL_DIRECTION:
695 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
696 return err;
697 values[0] = (ALint)dvals[0];
698 values[1] = (ALint)dvals[1];
699 values[2] = (ALint)dvals[2];
700 break;
702 default:
703 RETERR(AL_INVALID_ENUM);
706 return AL_NO_ERROR;
709 static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, ALenum name, ALint64 *values)
711 ALdouble dvals[3];
712 ALint ivals[3];
713 ALenum err;
715 switch(name)
717 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
718 LockContext(Context);
719 values[0] = GetSourceOffset(Source);
720 values[1] = ALCdevice_GetLatency(Context->Device);
721 UnlockContext(Context);
722 break;
724 case AL_MAX_DISTANCE:
725 case AL_ROLLOFF_FACTOR:
726 case AL_REFERENCE_DISTANCE:
727 case AL_CONE_INNER_ANGLE:
728 case AL_CONE_OUTER_ANGLE:
729 case AL_SEC_OFFSET:
730 case AL_SAMPLE_OFFSET:
731 case AL_BYTE_OFFSET:
732 case AL_DOPPLER_FACTOR:
733 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
734 return err;
735 *values = (ALint64)dvals[0];
736 break;
738 case AL_SAMPLE_RW_OFFSETS_SOFT:
739 case AL_BYTE_RW_OFFSETS_SOFT:
740 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
741 return err;
742 values[0] = (ALint64)dvals[0];
743 values[1] = (ALint64)dvals[0];
744 break;
746 case AL_POSITION:
747 case AL_VELOCITY:
748 case AL_DIRECTION:
749 if((err=GetSourcedv(Source, Context, name, dvals)) != AL_NO_ERROR)
750 return err;
751 values[0] = (ALint64)dvals[0];
752 values[1] = (ALint64)dvals[1];
753 values[2] = (ALint64)dvals[2];
754 break;
756 case AL_SOURCE_RELATIVE:
757 case AL_LOOPING:
758 case AL_BUFFER:
759 case AL_SOURCE_STATE:
760 case AL_BUFFERS_QUEUED:
761 case AL_BUFFERS_PROCESSED:
762 case AL_SOURCE_TYPE:
763 case AL_DIRECT_FILTER_GAINHF_AUTO:
764 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
765 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
766 case AL_DIRECT_CHANNELS_SOFT:
767 case AL_DISTANCE_MODEL:
768 if((err=GetSourceiv(Source, Context, name, ivals)) != AL_NO_ERROR)
769 return err;
770 *values = ivals[0];
771 break;
773 default:
774 RETERR(AL_INVALID_ENUM);
777 return AL_NO_ERROR;
780 #undef RETERR
783 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
785 ALCcontext *Context;
786 ALsizei cur = 0;
788 Context = GetContextRef();
789 if(!Context) return;
791 al_try
793 ALenum err;
795 CHECK_VALUE(Context, n >= 0);
796 for(cur = 0;cur < n;cur++)
798 ALsource *source = al_calloc(16, sizeof(ALsource));
799 if(!source)
800 al_throwerr(Context, AL_OUT_OF_MEMORY);
801 InitSourceParams(source);
803 err = NewThunkEntry(&source->id);
804 if(err == AL_NO_ERROR)
805 err = InsertUIntMapEntry(&Context->SourceMap, source->id, source);
806 if(err != AL_NO_ERROR)
808 FreeThunkEntry(source->id);
809 memset(source, 0, sizeof(ALsource));
810 al_free(source);
812 al_throwerr(Context, err);
815 sources[cur] = source->id;
818 al_catchany()
820 if(cur > 0)
821 alDeleteSources(cur, sources);
823 al_endtry;
825 ALCcontext_DecRef(Context);
829 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
831 ALCcontext *Context;
833 Context = GetContextRef();
834 if(!Context) return;
836 al_try
838 ALbufferlistitem *BufferList;
839 ALsource *Source;
840 ALsizei i, j;
842 CHECK_VALUE(Context, n >= 0);
844 /* Check that all Sources are valid */
845 for(i = 0;i < n;i++)
847 if(LookupSource(Context, sources[i]) == NULL)
848 al_throwerr(Context, AL_INVALID_NAME);
851 for(i = 0;i < n;i++)
853 ALsource **srclist, **srclistend;
855 if((Source=RemoveSource(Context, sources[i])) == NULL)
856 continue;
857 FreeThunkEntry(Source->id);
859 LockContext(Context);
860 srclist = Context->ActiveSources;
861 srclistend = srclist + Context->ActiveSourceCount;
862 while(srclist != srclistend)
864 if(*srclist == Source)
866 Context->ActiveSourceCount--;
867 *srclist = *(--srclistend);
868 break;
870 srclist++;
872 UnlockContext(Context);
874 while(Source->queue != NULL)
876 BufferList = Source->queue;
877 Source->queue = BufferList->next;
879 if(BufferList->buffer != NULL)
880 DecrementRef(&BufferList->buffer->ref);
881 free(BufferList);
884 for(j = 0;j < MAX_SENDS;++j)
886 if(Source->Send[j].Slot)
887 DecrementRef(&Source->Send[j].Slot->ref);
888 Source->Send[j].Slot = NULL;
891 memset(Source, 0, sizeof(*Source));
892 al_free(Source);
895 al_endtry;
897 ALCcontext_DecRef(Context);
901 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
903 ALCcontext *Context;
904 ALboolean result;
906 Context = GetContextRef();
907 if(!Context) return AL_FALSE;
909 result = (LookupSource(Context, source) ? AL_TRUE : AL_FALSE);
911 ALCcontext_DecRef(Context);
913 return result;
917 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
919 ALCcontext *Context;
920 ALsource *Source;
922 Context = GetContextRef();
923 if(!Context) return;
925 if((Source=LookupSource(Context, source)) == NULL)
926 alSetError(Context, AL_INVALID_NAME);
927 else switch(param)
929 case AL_PITCH:
930 case AL_CONE_INNER_ANGLE:
931 case AL_CONE_OUTER_ANGLE:
932 case AL_GAIN:
933 case AL_MAX_DISTANCE:
934 case AL_ROLLOFF_FACTOR:
935 case AL_REFERENCE_DISTANCE:
936 case AL_MIN_GAIN:
937 case AL_MAX_GAIN:
938 case AL_CONE_OUTER_GAIN:
939 case AL_CONE_OUTER_GAINHF:
940 case AL_AIR_ABSORPTION_FACTOR:
941 case AL_ROOM_ROLLOFF_FACTOR:
942 case AL_DOPPLER_FACTOR:
943 case AL_SEC_OFFSET:
944 case AL_SAMPLE_OFFSET:
945 case AL_BYTE_OFFSET:
946 SetSourcefv(Source, Context, param, &value);
947 break;
949 default:
950 alSetError(Context, AL_INVALID_ENUM);
953 ALCcontext_DecRef(Context);
957 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
959 ALCcontext *Context;
960 ALsource *Source;
961 ALfloat fvals[3];
963 Context = GetContextRef();
964 if(!Context) return;
966 if((Source=LookupSource(Context, source)) == NULL)
967 alSetError(Context, AL_INVALID_NAME);
968 else switch(param)
970 case AL_POSITION:
971 case AL_VELOCITY:
972 case AL_DIRECTION:
973 fvals[0] = value1;
974 fvals[1] = value2;
975 fvals[2] = value3;
976 SetSourcefv(Source, Context, param, fvals);
977 break;
979 default:
980 alSetError(Context, AL_INVALID_ENUM);
983 ALCcontext_DecRef(Context);
987 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
989 ALCcontext *Context;
990 ALsource *Source;
992 Context = GetContextRef();
993 if(!Context) return;
995 if((Source=LookupSource(Context, source)) == NULL)
996 alSetError(Context, AL_INVALID_NAME);
997 else if(!values)
998 alSetError(Context, AL_INVALID_VALUE);
999 else switch(param)
1001 case AL_PITCH:
1002 case AL_CONE_INNER_ANGLE:
1003 case AL_CONE_OUTER_ANGLE:
1004 case AL_GAIN:
1005 case AL_MAX_DISTANCE:
1006 case AL_ROLLOFF_FACTOR:
1007 case AL_REFERENCE_DISTANCE:
1008 case AL_MIN_GAIN:
1009 case AL_MAX_GAIN:
1010 case AL_CONE_OUTER_GAIN:
1011 case AL_CONE_OUTER_GAINHF:
1012 case AL_SEC_OFFSET:
1013 case AL_SAMPLE_OFFSET:
1014 case AL_BYTE_OFFSET:
1015 case AL_AIR_ABSORPTION_FACTOR:
1016 case AL_ROOM_ROLLOFF_FACTOR:
1018 case AL_POSITION:
1019 case AL_VELOCITY:
1020 case AL_DIRECTION:
1021 SetSourcefv(Source, Context, param, values);
1022 break;
1024 default:
1025 alSetError(Context, AL_INVALID_ENUM);
1028 ALCcontext_DecRef(Context);
1032 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint 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_MAX_DISTANCE:
1045 case AL_ROLLOFF_FACTOR:
1046 case AL_CONE_INNER_ANGLE:
1047 case AL_CONE_OUTER_ANGLE:
1048 case AL_REFERENCE_DISTANCE:
1049 case AL_SOURCE_RELATIVE:
1050 case AL_LOOPING:
1051 case AL_BUFFER:
1052 case AL_SOURCE_STATE:
1053 case AL_SEC_OFFSET:
1054 case AL_SAMPLE_OFFSET:
1055 case AL_BYTE_OFFSET:
1056 case AL_DIRECT_FILTER:
1057 case AL_DIRECT_FILTER_GAINHF_AUTO:
1058 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1059 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1060 case AL_DIRECT_CHANNELS_SOFT:
1061 case AL_DISTANCE_MODEL:
1062 SetSourceiv(Source, Context, param, &value);
1063 break;
1065 default:
1066 alSetError(Context, AL_INVALID_ENUM);
1069 ALCcontext_DecRef(Context);
1073 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1075 ALCcontext *Context;
1076 ALsource *Source;
1077 ALint ivals[3];
1079 Context = GetContextRef();
1080 if(!Context) return;
1082 if((Source=LookupSource(Context, source)) == NULL)
1083 alSetError(Context, AL_INVALID_NAME);
1084 else switch(param)
1086 case AL_POSITION:
1087 case AL_VELOCITY:
1088 case AL_DIRECTION:
1089 case AL_AUXILIARY_SEND_FILTER:
1090 ivals[0] = value1;
1091 ivals[1] = value2;
1092 ivals[2] = value3;
1093 SetSourceiv(Source, Context, param, ivals);
1094 break;
1096 default:
1097 alSetError(Context, AL_INVALID_ENUM);
1100 ALCcontext_DecRef(Context);
1104 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1106 ALCcontext *Context;
1107 ALsource *Source;
1109 Context = GetContextRef();
1110 if(!Context) return;
1112 if((Source=LookupSource(Context, source)) == NULL)
1113 alSetError(Context, AL_INVALID_NAME);
1114 else if(!values)
1115 alSetError(Context, AL_INVALID_VALUE);
1116 else switch(param)
1118 case AL_SOURCE_RELATIVE:
1119 case AL_CONE_INNER_ANGLE:
1120 case AL_CONE_OUTER_ANGLE:
1121 case AL_LOOPING:
1122 case AL_BUFFER:
1123 case AL_SOURCE_STATE:
1124 case AL_SEC_OFFSET:
1125 case AL_SAMPLE_OFFSET:
1126 case AL_BYTE_OFFSET:
1127 case AL_MAX_DISTANCE:
1128 case AL_ROLLOFF_FACTOR:
1129 case AL_REFERENCE_DISTANCE:
1130 case AL_DIRECT_FILTER:
1131 case AL_DIRECT_FILTER_GAINHF_AUTO:
1132 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1133 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1134 case AL_DISTANCE_MODEL:
1135 case AL_DIRECT_CHANNELS_SOFT:
1137 case AL_POSITION:
1138 case AL_VELOCITY:
1139 case AL_DIRECTION:
1140 case AL_AUXILIARY_SEND_FILTER:
1141 SetSourceiv(Source, Context, param, values);
1142 break;
1144 default:
1145 alSetError(Context, AL_INVALID_ENUM);
1148 ALCcontext_DecRef(Context);
1152 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1154 ALCcontext *Context;
1155 ALsource *Source;
1156 ALdouble dval;
1158 Context = GetContextRef();
1159 if(!Context) return;
1161 if((Source=LookupSource(Context, source)) == NULL)
1162 alSetError(Context, AL_INVALID_NAME);
1163 else if(!value)
1164 alSetError(Context, AL_INVALID_VALUE);
1165 else switch(param)
1167 case AL_PITCH:
1168 case AL_GAIN:
1169 case AL_MIN_GAIN:
1170 case AL_MAX_GAIN:
1171 case AL_MAX_DISTANCE:
1172 case AL_ROLLOFF_FACTOR:
1173 case AL_CONE_OUTER_GAIN:
1174 case AL_CONE_OUTER_GAINHF:
1175 case AL_SEC_OFFSET:
1176 case AL_SAMPLE_OFFSET:
1177 case AL_BYTE_OFFSET:
1178 case AL_CONE_INNER_ANGLE:
1179 case AL_CONE_OUTER_ANGLE:
1180 case AL_REFERENCE_DISTANCE:
1181 case AL_AIR_ABSORPTION_FACTOR:
1182 case AL_ROOM_ROLLOFF_FACTOR:
1183 case AL_DOPPLER_FACTOR:
1184 if(GetSourcedv(Source, Context, param, &dval) == AL_NO_ERROR)
1185 *value = (ALfloat)dval;
1186 break;
1188 default:
1189 alSetError(Context, AL_INVALID_ENUM);
1192 ALCcontext_DecRef(Context);
1196 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1198 ALCcontext *Context;
1199 ALsource *Source;
1200 ALdouble dvals[3];
1202 Context = GetContextRef();
1203 if(!Context) return;
1205 if((Source=LookupSource(Context, source)) == NULL)
1206 alSetError(Context, AL_INVALID_NAME);
1207 else if(!(value1 && value2 && value3))
1208 alSetError(Context, AL_INVALID_VALUE);
1209 else switch(param)
1211 case AL_POSITION:
1212 case AL_VELOCITY:
1213 case AL_DIRECTION:
1214 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1216 *value1 = (ALfloat)dvals[0];
1217 *value2 = (ALfloat)dvals[1];
1218 *value3 = (ALfloat)dvals[2];
1220 break;
1222 default:
1223 alSetError(Context, AL_INVALID_ENUM);
1226 ALCcontext_DecRef(Context);
1230 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1232 ALCcontext *Context;
1233 ALsource *Source;
1234 ALdouble dvals[2];
1236 switch(param)
1238 case AL_PITCH:
1239 case AL_GAIN:
1240 case AL_MIN_GAIN:
1241 case AL_MAX_GAIN:
1242 case AL_MAX_DISTANCE:
1243 case AL_ROLLOFF_FACTOR:
1244 case AL_DOPPLER_FACTOR:
1245 case AL_CONE_OUTER_GAIN:
1246 case AL_SEC_OFFSET:
1247 case AL_SAMPLE_OFFSET:
1248 case AL_BYTE_OFFSET:
1249 case AL_CONE_INNER_ANGLE:
1250 case AL_CONE_OUTER_ANGLE:
1251 case AL_REFERENCE_DISTANCE:
1252 case AL_CONE_OUTER_GAINHF:
1253 case AL_AIR_ABSORPTION_FACTOR:
1254 case AL_ROOM_ROLLOFF_FACTOR:
1255 alGetSourcef(source, param, values);
1256 return;
1258 case AL_POSITION:
1259 case AL_VELOCITY:
1260 case AL_DIRECTION:
1261 alGetSource3f(source, param, values+0, values+1, values+2);
1262 return;
1265 Context = GetContextRef();
1266 if(!Context) return;
1268 if((Source=LookupSource(Context, source)) == NULL)
1269 alSetError(Context, AL_INVALID_NAME);
1270 else if(!values)
1271 alSetError(Context, AL_INVALID_VALUE);
1272 else switch(param)
1274 case AL_SAMPLE_RW_OFFSETS_SOFT:
1275 case AL_BYTE_RW_OFFSETS_SOFT:
1276 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1278 values[0] = (ALfloat)dvals[0];
1279 values[1] = (ALfloat)dvals[1];
1281 break;
1283 default:
1284 alSetError(Context, AL_INVALID_ENUM);
1287 ALCcontext_DecRef(Context);
1291 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1293 ALCcontext *Context;
1294 ALsource *Source;
1296 Context = GetContextRef();
1297 if(!Context) return;
1299 if((Source=LookupSource(Context, source)) == NULL)
1300 alSetError(Context, AL_INVALID_NAME);
1301 else if(!value)
1302 alSetError(Context, AL_INVALID_VALUE);
1303 else switch(param)
1305 case AL_PITCH:
1306 case AL_GAIN:
1307 case AL_MIN_GAIN:
1308 case AL_MAX_GAIN:
1309 case AL_MAX_DISTANCE:
1310 case AL_ROLLOFF_FACTOR:
1311 case AL_CONE_OUTER_GAIN:
1312 case AL_CONE_OUTER_GAINHF:
1313 case AL_SEC_OFFSET:
1314 case AL_SAMPLE_OFFSET:
1315 case AL_BYTE_OFFSET:
1316 case AL_CONE_INNER_ANGLE:
1317 case AL_CONE_OUTER_ANGLE:
1318 case AL_REFERENCE_DISTANCE:
1319 case AL_AIR_ABSORPTION_FACTOR:
1320 case AL_ROOM_ROLLOFF_FACTOR:
1321 case AL_DOPPLER_FACTOR:
1322 GetSourcedv(Source, Context, param, value);
1323 break;
1325 default:
1326 alSetError(Context, AL_INVALID_ENUM);
1329 ALCcontext_DecRef(Context);
1332 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1334 ALCcontext *Context;
1335 ALsource *Source;
1336 ALdouble dvals[3];
1338 Context = GetContextRef();
1339 if(!Context) return;
1341 if((Source=LookupSource(Context, source)) == NULL)
1342 alSetError(Context, AL_INVALID_NAME);
1343 else if(!(value1 && value2 && value3))
1344 alSetError(Context, AL_INVALID_VALUE);
1345 else switch(param)
1347 case AL_POSITION:
1348 case AL_VELOCITY:
1349 case AL_DIRECTION:
1350 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1352 *value1 = dvals[0];
1353 *value2 = dvals[1];
1354 *value3 = dvals[2];
1356 break;
1358 default:
1359 alSetError(Context, AL_INVALID_ENUM);
1362 ALCcontext_DecRef(Context);
1365 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1367 ALCcontext *Context;
1368 ALsource *Source;
1370 Context = GetContextRef();
1371 if(!Context) return;
1373 if((Source=LookupSource(Context, source)) == NULL)
1374 alSetError(Context, AL_INVALID_NAME);
1375 else if(!values)
1376 alSetError(Context, AL_INVALID_VALUE);
1377 else switch(param)
1379 case AL_PITCH:
1380 case AL_GAIN:
1381 case AL_MIN_GAIN:
1382 case AL_MAX_GAIN:
1383 case AL_MAX_DISTANCE:
1384 case AL_ROLLOFF_FACTOR:
1385 case AL_DOPPLER_FACTOR:
1386 case AL_CONE_OUTER_GAIN:
1387 case AL_SEC_OFFSET:
1388 case AL_SAMPLE_OFFSET:
1389 case AL_BYTE_OFFSET:
1390 case AL_CONE_INNER_ANGLE:
1391 case AL_CONE_OUTER_ANGLE:
1392 case AL_REFERENCE_DISTANCE:
1393 case AL_CONE_OUTER_GAINHF:
1394 case AL_AIR_ABSORPTION_FACTOR:
1395 case AL_ROOM_ROLLOFF_FACTOR:
1397 case AL_SAMPLE_RW_OFFSETS_SOFT:
1398 case AL_BYTE_RW_OFFSETS_SOFT:
1399 case AL_SEC_OFFSET_LATENCY_SOFT:
1401 case AL_POSITION:
1402 case AL_VELOCITY:
1403 case AL_DIRECTION:
1404 GetSourcedv(Source, Context, param, values);
1405 break;
1407 default:
1408 alSetError(Context, AL_INVALID_ENUM);
1411 ALCcontext_DecRef(Context);
1415 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1417 ALCcontext *Context;
1418 ALsource *Source;
1420 Context = GetContextRef();
1421 if(!Context) return;
1423 if((Source=LookupSource(Context, source)) == NULL)
1424 alSetError(Context, AL_INVALID_NAME);
1425 else if(!value)
1426 alSetError(Context, AL_INVALID_VALUE);
1427 else switch(param)
1429 case AL_MAX_DISTANCE:
1430 case AL_ROLLOFF_FACTOR:
1431 case AL_REFERENCE_DISTANCE:
1432 case AL_SOURCE_RELATIVE:
1433 case AL_CONE_INNER_ANGLE:
1434 case AL_CONE_OUTER_ANGLE:
1435 case AL_LOOPING:
1436 case AL_BUFFER:
1437 case AL_SOURCE_STATE:
1438 case AL_BUFFERS_QUEUED:
1439 case AL_BUFFERS_PROCESSED:
1440 case AL_SOURCE_TYPE:
1441 case AL_SEC_OFFSET:
1442 case AL_SAMPLE_OFFSET:
1443 case AL_BYTE_OFFSET:
1444 case AL_DIRECT_FILTER_GAINHF_AUTO:
1445 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1446 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1447 case AL_DOPPLER_FACTOR:
1448 case AL_DIRECT_CHANNELS_SOFT:
1449 case AL_DISTANCE_MODEL:
1450 GetSourceiv(Source, Context, param, value);
1451 break;
1453 default:
1454 alSetError(Context, AL_INVALID_ENUM);
1457 ALCcontext_DecRef(Context);
1461 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
1463 ALCcontext *Context;
1464 ALsource *Source;
1465 ALint ivals[3];
1467 Context = GetContextRef();
1468 if(!Context) return;
1470 if((Source=LookupSource(Context, source)) == NULL)
1471 alSetError(Context, AL_INVALID_NAME);
1472 else if(!(value1 && value2 && value3))
1473 alSetError(Context, AL_INVALID_VALUE);
1474 else switch(param)
1476 case AL_POSITION:
1477 case AL_VELOCITY:
1478 case AL_DIRECTION:
1479 if(GetSourceiv(Source, Context, param, ivals) == AL_NO_ERROR)
1481 *value1 = ivals[0];
1482 *value2 = ivals[1];
1483 *value3 = ivals[2];
1485 break;
1487 default:
1488 alSetError(Context, AL_INVALID_ENUM);
1491 ALCcontext_DecRef(Context);
1495 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
1497 ALCcontext *Context;
1498 ALsource *Source;
1500 Context = GetContextRef();
1501 if(!Context) return;
1503 if((Source=LookupSource(Context, source)) == NULL)
1504 alSetError(Context, AL_INVALID_NAME);
1505 else if(!values)
1506 alSetError(Context, AL_INVALID_VALUE);
1507 else switch(param)
1509 case AL_SOURCE_RELATIVE:
1510 case AL_CONE_INNER_ANGLE:
1511 case AL_CONE_OUTER_ANGLE:
1512 case AL_LOOPING:
1513 case AL_BUFFER:
1514 case AL_SOURCE_STATE:
1515 case AL_BUFFERS_QUEUED:
1516 case AL_BUFFERS_PROCESSED:
1517 case AL_SEC_OFFSET:
1518 case AL_SAMPLE_OFFSET:
1519 case AL_BYTE_OFFSET:
1520 case AL_MAX_DISTANCE:
1521 case AL_ROLLOFF_FACTOR:
1522 case AL_DOPPLER_FACTOR:
1523 case AL_REFERENCE_DISTANCE:
1524 case AL_SOURCE_TYPE:
1525 case AL_DIRECT_FILTER:
1526 case AL_DIRECT_FILTER_GAINHF_AUTO:
1527 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1528 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1529 case AL_DISTANCE_MODEL:
1530 case AL_DIRECT_CHANNELS_SOFT:
1532 case AL_SAMPLE_RW_OFFSETS_SOFT:
1533 case AL_BYTE_RW_OFFSETS_SOFT:
1535 case AL_POSITION:
1536 case AL_VELOCITY:
1537 case AL_DIRECTION:
1538 GetSourceiv(Source, Context, param, values);
1539 break;
1541 default:
1542 alSetError(Context, AL_INVALID_ENUM);
1545 ALCcontext_DecRef(Context);
1549 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
1551 ALCcontext *Context;
1552 ALsource *Source;
1554 Context = GetContextRef();
1555 if(!Context) return;
1557 if((Source=LookupSource(Context, source)) == NULL)
1558 alSetError(Context, AL_INVALID_NAME);
1559 else if(!value)
1560 alSetError(Context, AL_INVALID_VALUE);
1561 else switch(param)
1563 case AL_MAX_DISTANCE:
1564 case AL_ROLLOFF_FACTOR:
1565 case AL_REFERENCE_DISTANCE:
1566 case AL_SOURCE_RELATIVE:
1567 case AL_CONE_INNER_ANGLE:
1568 case AL_CONE_OUTER_ANGLE:
1569 case AL_LOOPING:
1570 case AL_BUFFER:
1571 case AL_SOURCE_STATE:
1572 case AL_BUFFERS_QUEUED:
1573 case AL_BUFFERS_PROCESSED:
1574 case AL_SOURCE_TYPE:
1575 case AL_SEC_OFFSET:
1576 case AL_SAMPLE_OFFSET:
1577 case AL_BYTE_OFFSET:
1578 case AL_DIRECT_FILTER_GAINHF_AUTO:
1579 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1580 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1581 case AL_DOPPLER_FACTOR:
1582 case AL_DIRECT_CHANNELS_SOFT:
1583 case AL_DISTANCE_MODEL:
1584 GetSourcei64v(Source, Context, param, value);
1585 break;
1587 default:
1588 alSetError(Context, AL_INVALID_ENUM);
1591 ALCcontext_DecRef(Context);
1594 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
1596 ALCcontext *Context;
1597 ALsource *Source;
1598 ALint64 i64vals[3];
1600 Context = GetContextRef();
1601 if(!Context) return;
1603 if((Source=LookupSource(Context, source)) == NULL)
1604 alSetError(Context, AL_INVALID_NAME);
1605 else if(!(value1 && value2 && value3))
1606 alSetError(Context, AL_INVALID_VALUE);
1607 else switch(param)
1609 case AL_POSITION:
1610 case AL_VELOCITY:
1611 case AL_DIRECTION:
1612 if(GetSourcei64v(Source, Context, param, i64vals) == AL_NO_ERROR)
1614 *value1 = i64vals[0];
1615 *value2 = i64vals[1];
1616 *value3 = i64vals[2];
1618 break;
1620 default:
1621 alSetError(Context, AL_INVALID_ENUM);
1624 ALCcontext_DecRef(Context);
1627 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
1629 ALCcontext *Context;
1630 ALsource *Source;
1632 Context = GetContextRef();
1633 if(!Context) return;
1635 if((Source=LookupSource(Context, source)) == NULL)
1636 alSetError(Context, AL_INVALID_NAME);
1637 else if(!values)
1638 alSetError(Context, AL_INVALID_VALUE);
1639 else switch(param)
1641 case AL_MAX_DISTANCE:
1642 case AL_ROLLOFF_FACTOR:
1643 case AL_REFERENCE_DISTANCE:
1644 case AL_SOURCE_RELATIVE:
1645 case AL_CONE_INNER_ANGLE:
1646 case AL_CONE_OUTER_ANGLE:
1647 case AL_LOOPING:
1648 case AL_BUFFER:
1649 case AL_SOURCE_STATE:
1650 case AL_BUFFERS_QUEUED:
1651 case AL_BUFFERS_PROCESSED:
1652 case AL_SOURCE_TYPE:
1653 case AL_SEC_OFFSET:
1654 case AL_SAMPLE_OFFSET:
1655 case AL_BYTE_OFFSET:
1656 case AL_DIRECT_FILTER_GAINHF_AUTO:
1657 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1658 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1659 case AL_DOPPLER_FACTOR:
1660 case AL_DIRECT_CHANNELS_SOFT:
1661 case AL_DISTANCE_MODEL:
1663 case AL_SAMPLE_RW_OFFSETS_SOFT:
1664 case AL_BYTE_RW_OFFSETS_SOFT:
1665 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1667 case AL_POSITION:
1668 case AL_VELOCITY:
1669 case AL_DIRECTION:
1670 GetSourcei64v(Source, Context, param, values);
1671 break;
1673 default:
1674 alSetError(Context, AL_INVALID_ENUM);
1677 ALCcontext_DecRef(Context);
1681 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1683 alSourcePlayv(1, &source);
1685 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1687 ALCcontext *Context;
1688 ALsource *Source;
1689 ALsizei i;
1691 Context = GetContextRef();
1692 if(!Context) return;
1694 al_try
1696 CHECK_VALUE(Context, n >= 0);
1697 for(i = 0;i < n;i++)
1699 if(!LookupSource(Context, sources[i]))
1700 al_throwerr(Context, AL_INVALID_NAME);
1703 LockContext(Context);
1704 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1706 void *temp = NULL;
1707 ALsizei newcount;
1709 newcount = Context->MaxActiveSources << 1;
1710 if(newcount > 0)
1711 temp = realloc(Context->ActiveSources,
1712 sizeof(*Context->ActiveSources) * newcount);
1713 if(!temp)
1715 UnlockContext(Context);
1716 al_throwerr(Context, AL_OUT_OF_MEMORY);
1719 Context->ActiveSources = temp;
1720 Context->MaxActiveSources = newcount;
1723 for(i = 0;i < n;i++)
1725 Source = LookupSource(Context, sources[i]);
1726 if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
1727 else SetSourceState(Source, Context, AL_PLAYING);
1729 UnlockContext(Context);
1731 al_endtry;
1733 ALCcontext_DecRef(Context);
1736 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1738 alSourcePausev(1, &source);
1740 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1742 ALCcontext *Context;
1743 ALsource *Source;
1744 ALsizei i;
1746 Context = GetContextRef();
1747 if(!Context) return;
1749 al_try
1751 CHECK_VALUE(Context, n >= 0);
1752 for(i = 0;i < n;i++)
1754 if(!LookupSource(Context, sources[i]))
1755 al_throwerr(Context, AL_INVALID_NAME);
1758 LockContext(Context);
1759 for(i = 0;i < n;i++)
1761 Source = LookupSource(Context, sources[i]);
1762 if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
1763 else SetSourceState(Source, Context, AL_PAUSED);
1765 UnlockContext(Context);
1767 al_endtry;
1769 ALCcontext_DecRef(Context);
1772 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1774 alSourceStopv(1, &source);
1776 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1778 ALCcontext *Context;
1779 ALsource *Source;
1780 ALsizei i;
1782 Context = GetContextRef();
1783 if(!Context) return;
1785 al_try
1787 CHECK_VALUE(Context, n >= 0);
1788 for(i = 0;i < n;i++)
1790 if(!LookupSource(Context, sources[i]))
1791 al_throwerr(Context, AL_INVALID_NAME);
1794 LockContext(Context);
1795 for(i = 0;i < n;i++)
1797 Source = LookupSource(Context, sources[i]);
1798 Source->new_state = AL_NONE;
1799 SetSourceState(Source, Context, AL_STOPPED);
1801 UnlockContext(Context);
1803 al_endtry;
1805 ALCcontext_DecRef(Context);
1808 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1810 alSourceRewindv(1, &source);
1812 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1814 ALCcontext *Context;
1815 ALsource *Source;
1816 ALsizei i;
1818 Context = GetContextRef();
1819 if(!Context) return;
1821 al_try
1823 CHECK_VALUE(Context, n >= 0);
1824 for(i = 0;i < n;i++)
1826 if(!LookupSource(Context, sources[i]))
1827 al_throwerr(Context, AL_INVALID_NAME);
1830 LockContext(Context);
1831 for(i = 0;i < n;i++)
1833 Source = LookupSource(Context, sources[i]);
1834 Source->new_state = AL_NONE;
1835 SetSourceState(Source, Context, AL_INITIAL);
1837 UnlockContext(Context);
1839 al_endtry;
1841 ALCcontext_DecRef(Context);
1845 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers)
1847 ALCcontext *Context;
1848 ALsource *Source;
1849 ALsizei i;
1850 ALbufferlistitem *BufferListStart = NULL;
1851 ALbufferlistitem *BufferList;
1852 ALbuffer *BufferFmt;
1854 if(nb == 0)
1855 return;
1857 Context = GetContextRef();
1858 if(!Context) return;
1860 al_try
1862 ALCdevice *device = Context->Device;
1864 CHECK_VALUE(Context, nb >= 0);
1866 if((Source=LookupSource(Context, source)) == NULL)
1867 al_throwerr(Context, AL_INVALID_NAME);
1869 LockContext(Context);
1870 if(Source->SourceType == AL_STATIC)
1872 UnlockContext(Context);
1873 /* Can't queue on a Static Source */
1874 al_throwerr(Context, AL_INVALID_OPERATION);
1877 BufferFmt = NULL;
1879 /* Check for a valid Buffer, for its frequency and format */
1880 BufferList = Source->queue;
1881 while(BufferList)
1883 if(BufferList->buffer)
1885 BufferFmt = BufferList->buffer;
1886 break;
1888 BufferList = BufferList->next;
1891 for(i = 0;i < nb;i++)
1893 ALbuffer *buffer = NULL;
1894 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
1896 UnlockContext(Context);
1897 al_throwerr(Context, AL_INVALID_NAME);
1900 if(!BufferListStart)
1902 BufferListStart = malloc(sizeof(ALbufferlistitem));
1903 BufferListStart->buffer = buffer;
1904 BufferListStart->next = NULL;
1905 BufferListStart->prev = NULL;
1906 BufferList = BufferListStart;
1908 else
1910 BufferList->next = malloc(sizeof(ALbufferlistitem));
1911 BufferList->next->buffer = buffer;
1912 BufferList->next->next = NULL;
1913 BufferList->next->prev = BufferList;
1914 BufferList = BufferList->next;
1916 if(!buffer) continue;
1917 IncrementRef(&buffer->ref);
1919 ReadLock(&buffer->lock);
1920 if(BufferFmt == NULL)
1922 BufferFmt = buffer;
1924 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
1925 Source->SampleSize = BytesFromFmt(buffer->FmtType);
1926 if(buffer->FmtChannels == FmtMono)
1927 Source->Update = CalcSourceParams;
1928 else
1929 Source->Update = CalcNonAttnSourceParams;
1931 Source->NeedsUpdate = AL_TRUE;
1933 else if(BufferFmt->Frequency != buffer->Frequency ||
1934 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
1935 BufferFmt->OriginalType != buffer->OriginalType)
1937 ReadUnlock(&buffer->lock);
1938 UnlockContext(Context);
1939 al_throwerr(Context, AL_INVALID_OPERATION);
1941 ReadUnlock(&buffer->lock);
1944 /* Source is now streaming */
1945 Source->SourceType = AL_STREAMING;
1947 if(Source->queue == NULL)
1948 Source->queue = BufferListStart;
1949 else
1951 /* Append to the end of the queue */
1952 BufferList = Source->queue;
1953 while(BufferList->next != NULL)
1954 BufferList = BufferList->next;
1956 BufferListStart->prev = BufferList;
1957 BufferList->next = BufferListStart;
1960 Source->BuffersInQueue += nb;
1962 UnlockContext(Context);
1964 al_catchany()
1966 while(BufferListStart)
1968 BufferList = BufferListStart;
1969 BufferListStart = BufferList->next;
1971 if(BufferList->buffer)
1972 DecrementRef(&BufferList->buffer->ref);
1973 free(BufferList);
1976 al_endtry;
1978 ALCcontext_DecRef(Context);
1981 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers)
1983 ALCcontext *Context;
1984 ALsource *Source;
1985 ALsizei i;
1986 ALbufferlistitem *BufferList;
1988 if(nb == 0)
1989 return;
1991 Context = GetContextRef();
1992 if(!Context) return;
1994 al_try
1996 CHECK_VALUE(Context, nb >= 0);
1998 if((Source=LookupSource(Context, source)) == NULL)
1999 al_throwerr(Context, AL_INVALID_NAME);
2001 LockContext(Context);
2002 if(Source->Looping || Source->SourceType != AL_STREAMING ||
2003 (ALuint)nb > Source->BuffersPlayed)
2005 UnlockContext(Context);
2006 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2007 al_throwerr(Context, AL_INVALID_VALUE);
2010 for(i = 0;i < nb;i++)
2012 BufferList = Source->queue;
2013 Source->queue = BufferList->next;
2014 Source->BuffersInQueue--;
2015 Source->BuffersPlayed--;
2017 if(BufferList->buffer)
2019 buffers[i] = BufferList->buffer->id;
2020 DecrementRef(&BufferList->buffer->ref);
2022 else
2023 buffers[i] = 0;
2025 free(BufferList);
2027 if(Source->queue)
2028 Source->queue->prev = NULL;
2029 UnlockContext(Context);
2031 al_endtry;
2033 ALCcontext_DecRef(Context);
2037 static ALvoid InitSourceParams(ALsource *Source)
2039 ALuint i;
2041 Source->InnerAngle = 360.0f;
2042 Source->OuterAngle = 360.0f;
2043 Source->Pitch = 1.0f;
2044 Source->Position[0] = 0.0f;
2045 Source->Position[1] = 0.0f;
2046 Source->Position[2] = 0.0f;
2047 Source->Orientation[0] = 0.0f;
2048 Source->Orientation[1] = 0.0f;
2049 Source->Orientation[2] = 0.0f;
2050 Source->Velocity[0] = 0.0f;
2051 Source->Velocity[1] = 0.0f;
2052 Source->Velocity[2] = 0.0f;
2053 Source->RefDistance = 1.0f;
2054 Source->MaxDistance = FLT_MAX;
2055 Source->RollOffFactor = 1.0f;
2056 Source->Looping = AL_FALSE;
2057 Source->Gain = 1.0f;
2058 Source->MinGain = 0.0f;
2059 Source->MaxGain = 1.0f;
2060 Source->OuterGain = 0.0f;
2061 Source->OuterGainHF = 1.0f;
2063 Source->DryGainHFAuto = AL_TRUE;
2064 Source->WetGainAuto = AL_TRUE;
2065 Source->WetGainHFAuto = AL_TRUE;
2066 Source->AirAbsorptionFactor = 0.0f;
2067 Source->RoomRolloffFactor = 0.0f;
2068 Source->DopplerFactor = 1.0f;
2069 Source->DirectChannels = AL_FALSE;
2071 Source->DistanceModel = DefaultDistanceModel;
2073 Source->Resampler = DefaultResampler;
2075 Source->state = AL_INITIAL;
2076 Source->new_state = AL_NONE;
2077 Source->SourceType = AL_UNDETERMINED;
2078 Source->Offset = -1.0;
2080 Source->DirectGain = 1.0f;
2081 Source->DirectGainHF = 1.0f;
2082 for(i = 0;i < MAX_SENDS;i++)
2084 Source->Send[i].Gain = 1.0f;
2085 Source->Send[i].GainHF = 1.0f;
2088 Source->NeedsUpdate = AL_TRUE;
2090 Source->Hrtf.Moving = AL_FALSE;
2091 Source->Hrtf.Counter = 0;
2095 /* SetSourceState
2097 * Sets the source's new play state given its current state.
2099 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2101 if(state == AL_PLAYING)
2103 ALbufferlistitem *BufferList;
2104 ALsizei j, k;
2106 /* Check that there is a queue containing at least one valid, non zero
2107 * length Buffer. */
2108 BufferList = Source->queue;
2109 while(BufferList)
2111 if(BufferList->buffer != NULL && BufferList->buffer->SampleLen)
2112 break;
2113 BufferList = BufferList->next;
2116 if(Source->state != AL_PLAYING)
2118 for(j = 0;j < MaxChannels;j++)
2120 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
2121 Source->Hrtf.History[j][k] = 0.0f;
2122 for(k = 0;k < HRIR_LENGTH;k++)
2124 Source->Hrtf.Values[j][k][0] = 0.0f;
2125 Source->Hrtf.Values[j][k][1] = 0.0f;
2130 if(Source->state != AL_PAUSED)
2132 Source->state = AL_PLAYING;
2133 Source->position = 0;
2134 Source->position_fraction = 0;
2135 Source->BuffersPlayed = 0;
2137 else
2138 Source->state = AL_PLAYING;
2140 // Check if an Offset has been set
2141 if(Source->Offset >= 0.0)
2142 ApplyOffset(Source);
2144 /* If there's nothing to play, or device is disconnected, go right to
2145 * stopped */
2146 if(!BufferList || !Context->Device->Connected)
2148 SetSourceState(Source, Context, AL_STOPPED);
2149 return;
2152 for(j = 0;j < Context->ActiveSourceCount;j++)
2154 if(Context->ActiveSources[j] == Source)
2155 break;
2157 if(j == Context->ActiveSourceCount)
2158 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
2160 else if(state == AL_PAUSED)
2162 if(Source->state == AL_PLAYING)
2164 Source->state = AL_PAUSED;
2165 Source->Hrtf.Moving = AL_FALSE;
2166 Source->Hrtf.Counter = 0;
2169 else if(state == AL_STOPPED)
2171 if(Source->state != AL_INITIAL)
2173 Source->state = AL_STOPPED;
2174 Source->BuffersPlayed = Source->BuffersInQueue;
2175 Source->Hrtf.Moving = AL_FALSE;
2176 Source->Hrtf.Counter = 0;
2178 Source->Offset = -1.0;
2180 else if(state == AL_INITIAL)
2182 if(Source->state != AL_INITIAL)
2184 Source->state = AL_INITIAL;
2185 Source->position = 0;
2186 Source->position_fraction = 0;
2187 Source->BuffersPlayed = 0;
2188 Source->Hrtf.Moving = AL_FALSE;
2189 Source->Hrtf.Counter = 0;
2191 Source->Offset = -1.0;
2195 /* GetSourceOffset
2197 * Gets the current read offset for the given Source, in 32.32 fixed-point
2198 * samples. The offset is relative to the start of the queue (not the start of
2199 * the current buffer).
2201 static ALint64 GetSourceOffset(const ALsource *Source)
2203 const ALbufferlistitem *BufferList;
2204 ALuint64 readPos;
2205 ALuint i;
2207 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2208 return 0;
2210 /* NOTE: This is the offset into the *current* buffer, so add the length of
2211 * any played buffers */
2212 readPos = (ALuint64)Source->position << 32;
2213 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2214 BufferList = Source->queue;
2215 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2217 if(BufferList->buffer)
2218 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2219 BufferList = BufferList->next;
2222 return (ALint64)minu64(readPos, MAKEU64(0x7fffffff,0xffffffff));
2225 /* GetSourceSecOffset
2227 * Gets the current read offset for the given Source, in seconds. The offset is
2228 * relative to the start of the queue (not the start of the current buffer).
2230 static ALdouble GetSourceSecOffset(const ALsource *Source)
2232 const ALbufferlistitem *BufferList;
2233 const ALbuffer *Buffer = NULL;
2234 ALuint64 readPos;
2235 ALuint i;
2237 BufferList = Source->queue;
2238 while(BufferList)
2240 if(BufferList->buffer)
2242 Buffer = BufferList->buffer;
2243 break;
2245 BufferList = BufferList->next;
2248 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2249 return 0.0;
2251 /* NOTE: This is the offset into the *current* buffer, so add the length of
2252 * any played buffers */
2253 readPos = (ALuint64)Source->position << FRACTIONBITS;
2254 readPos |= (ALuint64)Source->position_fraction;
2255 BufferList = Source->queue;
2256 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2258 if(BufferList->buffer)
2259 readPos += (ALuint64)BufferList->buffer->SampleLen << FRACTIONBITS;
2260 BufferList = BufferList->next;
2263 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2266 /* GetSourceOffsets
2268 * Gets the current read and write offsets for the given Source, in the
2269 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2270 * the start of the queue (not the start of the current buffer).
2272 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2274 const ALbufferlistitem *BufferList;
2275 const ALbuffer *Buffer = NULL;
2276 ALuint readPos, writePos;
2277 ALuint totalBufferLen;
2278 ALuint i;
2280 // Find the first valid Buffer in the Queue
2281 BufferList = Source->queue;
2282 while(BufferList)
2284 if(BufferList->buffer)
2286 Buffer = BufferList->buffer;
2287 break;
2289 BufferList = BufferList->next;
2292 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2294 offset[0] = 0.0;
2295 offset[1] = 0.0;
2296 return;
2299 if(updateLen > 0.0 && updateLen < 0.015)
2300 updateLen = 0.015;
2302 /* NOTE: This is the offset into the *current* buffer, so add the length of
2303 * any played buffers */
2304 readPos = Source->position;
2305 totalBufferLen = 0;
2306 BufferList = Source->queue;
2307 for(i = 0;BufferList;i++)
2309 if(BufferList->buffer)
2311 if(i < Source->BuffersPlayed)
2312 readPos += BufferList->buffer->SampleLen;
2313 totalBufferLen += BufferList->buffer->SampleLen;
2315 BufferList = BufferList->next;
2317 if(Source->state == AL_PLAYING)
2318 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
2319 else
2320 writePos = readPos;
2322 if(Source->Looping)
2324 readPos %= totalBufferLen;
2325 writePos %= totalBufferLen;
2327 else
2329 /* Wrap positions back to 0 */
2330 if(readPos >= totalBufferLen)
2331 readPos = 0;
2332 if(writePos >= totalBufferLen)
2333 writePos = 0;
2336 switch(name)
2338 case AL_SEC_OFFSET:
2339 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2340 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2341 break;
2343 case AL_SAMPLE_OFFSET:
2344 case AL_SAMPLE_RW_OFFSETS_SOFT:
2345 offset[0] = (ALdouble)readPos;
2346 offset[1] = (ALdouble)writePos;
2347 break;
2349 case AL_BYTE_OFFSET:
2350 case AL_BYTE_RW_OFFSETS_SOFT:
2351 if(Buffer->OriginalType == UserFmtIMA4)
2353 ALuint BlockSize = 36 * ChannelsFromFmt(Buffer->FmtChannels);
2354 ALuint FrameBlockSize = 65;
2356 /* Round down to nearest ADPCM block */
2357 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2358 if(Source->state != AL_PLAYING)
2359 offset[1] = offset[0];
2360 else
2362 /* Round up to nearest ADPCM block */
2363 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2364 FrameBlockSize * BlockSize);
2367 else
2369 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2370 offset[0] = (ALdouble)(readPos * FrameSize);
2371 offset[1] = (ALdouble)(writePos * FrameSize);
2373 break;
2378 /* ApplyOffset
2380 * Apply the stored playback offset to the Source. This function will update
2381 * the number of buffers "played" given the stored offset.
2383 ALboolean ApplyOffset(ALsource *Source)
2385 const ALbufferlistitem *BufferList;
2386 const ALbuffer *Buffer;
2387 ALint bufferLen, totalBufferLen;
2388 ALint buffersPlayed;
2389 ALint offset;
2391 /* Get sample frame offset */
2392 offset = GetSampleOffset(Source);
2393 if(offset == -1)
2394 return AL_FALSE;
2396 buffersPlayed = 0;
2397 totalBufferLen = 0;
2399 BufferList = Source->queue;
2400 while(BufferList)
2402 Buffer = BufferList->buffer;
2403 bufferLen = Buffer ? Buffer->SampleLen : 0;
2405 if(bufferLen <= offset-totalBufferLen)
2407 /* Offset is past this buffer so increment to the next buffer */
2408 buffersPlayed++;
2410 else if(totalBufferLen <= offset)
2412 /* Offset is in this buffer */
2413 Source->BuffersPlayed = buffersPlayed;
2415 Source->position = offset - totalBufferLen;
2416 Source->position_fraction = 0;
2417 return AL_TRUE;
2420 totalBufferLen += bufferLen;
2422 BufferList = BufferList->next;
2425 /* Offset is out of range of the queue */
2426 return AL_FALSE;
2430 /* GetSampleOffset
2432 * Returns the sample offset into the Source's queue (from the Sample, Byte or
2433 * Second offset supplied by the application). This takes into account the fact
2434 * that the buffer format may have been modifed since.
2436 static ALint GetSampleOffset(ALsource *Source)
2438 const ALbuffer *Buffer = NULL;
2439 const ALbufferlistitem *BufferList;
2440 ALint Offset = -1;
2442 /* Find the first valid Buffer in the Queue */
2443 BufferList = Source->queue;
2444 while(BufferList)
2446 if(BufferList->buffer)
2448 Buffer = BufferList->buffer;
2449 break;
2451 BufferList = BufferList->next;
2454 if(!Buffer)
2456 Source->Offset = -1.0;
2457 return -1;
2460 switch(Source->OffsetType)
2462 case AL_BYTE_OFFSET:
2463 /* Determine the ByteOffset (and ensure it is block aligned) */
2464 Offset = (ALint)Source->Offset;
2465 if(Buffer->OriginalType == UserFmtIMA4)
2467 Offset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
2468 Offset *= 65;
2470 else
2471 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2472 break;
2474 case AL_SAMPLE_OFFSET:
2475 Offset = (ALint)Source->Offset;
2476 break;
2478 case AL_SEC_OFFSET:
2479 Offset = (ALint)(Source->Offset * Buffer->Frequency);
2480 break;
2482 Source->Offset = -1.0;
2484 return Offset;
2488 /* ReleaseALSources
2490 * Destroys all sources in the source map.
2492 ALvoid ReleaseALSources(ALCcontext *Context)
2494 ALsizei pos;
2495 ALuint j;
2496 for(pos = 0;pos < Context->SourceMap.size;pos++)
2498 ALsource *temp = Context->SourceMap.array[pos].value;
2499 Context->SourceMap.array[pos].value = NULL;
2501 while(temp->queue != NULL)
2503 ALbufferlistitem *BufferList = temp->queue;
2504 temp->queue = BufferList->next;
2506 if(BufferList->buffer != NULL)
2507 DecrementRef(&BufferList->buffer->ref);
2508 free(BufferList);
2511 for(j = 0;j < MAX_SENDS;++j)
2513 if(temp->Send[j].Slot)
2514 DecrementRef(&temp->Send[j].Slot->ref);
2515 temp->Send[j].Slot = NULL;
2518 FreeThunkEntry(temp->id);
2519 memset(temp, 0, sizeof(*temp));
2520 al_free(temp);