Don't use deprecated macros
[openal-soft.git] / OpenAL32 / alSource.c
blobca5b4e2826d2cb38655d7796b3ece16218b2bb3d
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>
26 #include "alMain.h"
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alError.h"
30 #include "alSource.h"
31 #include "alBuffer.h"
32 #include "alThunk.h"
33 #include "alAuxEffectSlot.h"
35 static ALvoid InitSourceParams(ALsource *pSource);
36 static ALvoid GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALfloat updateLen);
37 static ALboolean ApplyOffset(ALsource *pSource);
38 static ALint GetByteOffset(ALsource *pSource);
40 DECL_VERIFIER(Source, ALsource, source)
41 DECL_VERIFIER(Buffer, ALbuffer, buffer)
42 DECL_VERIFIER(Filter, ALfilter, filter)
43 DECL_VERIFIER(EffectSlot, ALeffectslot, effectslot)
45 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources)
47 ALCcontext *Context;
48 ALCdevice *Device;
49 ALsizei i=0;
51 Context = GetContextSuspended();
52 if(!Context) return;
54 if(n > 0)
56 Device = Context->Device;
58 // Check that enough memory has been allocted in the 'sources' array for n Sources
59 if(!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
61 // Check that the requested number of sources can be generated
62 if((Context->SourceCount + n) <= Device->MaxNoOfSources)
64 ALsource **list = &Context->SourceList;
65 while(*list)
66 list = &(*list)->next;
68 // Add additional sources to the list (Source->next points to the location for the next Source structure)
69 while(i < n)
71 *list = calloc(1, sizeof(ALsource));
72 if(!(*list))
74 alDeleteSources(i, sources);
75 alSetError(Context, AL_OUT_OF_MEMORY);
76 break;
79 sources[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
80 (*list)->source = sources[i];
82 InitSourceParams(*list);
83 Context->SourceCount++;
84 i++;
86 list = &(*list)->next;
89 else
91 // Not enough resources to create the Sources
92 alSetError(Context, AL_INVALID_VALUE);
95 else
97 // Bad pointer
98 alSetError(Context, AL_INVALID_VALUE);
102 ProcessContext(Context);
106 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
108 ALCcontext *Context;
109 ALCdevice *Device;
110 ALsource *ALSource;
111 ALsource **list;
112 ALsizei i, j;
113 ALbufferlistitem *ALBufferList;
114 ALboolean bSourcesValid = AL_TRUE;
116 Context = GetContextSuspended();
117 if(!Context) return;
119 if(n >= 0)
121 Device = Context->Device;
123 // Check that all Sources are valid (and can therefore be deleted)
124 for (i = 0; i < n; i++)
126 if(VerifySource(Context->SourceList, sources[i]) == NULL)
128 alSetError(Context, AL_INVALID_NAME);
129 bSourcesValid = AL_FALSE;
130 break;
134 if(bSourcesValid)
136 // All Sources are valid, and can be deleted
137 for(i = 0; i < n; i++)
139 // Recheck that the Source is valid, because there could be duplicated Source names
140 if((ALSource=VerifySource(Context->SourceList, sources[i])) != NULL)
142 // For each buffer in the source's queue, decrement its reference counter and remove it
143 while (ALSource->queue != NULL)
145 ALBufferList = ALSource->queue;
146 // Decrement buffer's reference counter
147 if(ALBufferList->buffer != NULL)
148 ALBufferList->buffer->refcount--;
149 // Update queue to point to next element in list
150 ALSource->queue = ALBufferList->next;
151 // Release memory allocated for buffer list item
152 free(ALBufferList);
155 for(j = 0;j < MAX_SENDS;++j)
157 if(ALSource->Send[j].Slot)
158 ALSource->Send[j].Slot->refcount--;
159 ALSource->Send[j].Slot = NULL;
162 // Decrement Source count
163 Context->SourceCount--;
165 // Remove Source from list of Sources
166 list = &Context->SourceList;
167 while(*list && *list != ALSource)
168 list = &(*list)->next;
170 if(*list)
171 *list = (*list)->next;
172 ALTHUNK_REMOVEENTRY(ALSource->source);
174 memset(ALSource,0,sizeof(ALsource));
175 free(ALSource);
180 else
181 alSetError(Context, AL_INVALID_VALUE);
183 ProcessContext(Context);
187 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
189 ALCcontext *Context;
190 ALboolean result;
192 Context = GetContextSuspended();
193 if(!Context) return AL_FALSE;
195 result = (VerifySource(Context->SourceList, source) ? AL_TRUE : AL_FALSE);
197 ProcessContext(Context);
199 return result;
203 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
205 ALCcontext *pContext;
206 ALsource *pSource;
208 pContext = GetContextSuspended();
209 if(!pContext) return;
211 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
213 switch(eParam)
215 case AL_PITCH:
216 if(flValue >= 0.0f)
218 pSource->flPitch = flValue;
219 if(pSource->flPitch < 0.001f)
220 pSource->flPitch = 0.001f;
221 pSource->NeedsUpdate = AL_TRUE;
223 else
224 alSetError(pContext, AL_INVALID_VALUE);
225 break;
227 case AL_CONE_INNER_ANGLE:
228 if(flValue >= 0.0f && flValue <= 360.0f)
230 pSource->flInnerAngle = flValue;
231 pSource->NeedsUpdate = AL_TRUE;
233 else
234 alSetError(pContext, AL_INVALID_VALUE);
235 break;
237 case AL_CONE_OUTER_ANGLE:
238 if(flValue >= 0.0f && flValue <= 360.0f)
240 pSource->flOuterAngle = flValue;
241 pSource->NeedsUpdate = AL_TRUE;
243 else
244 alSetError(pContext, AL_INVALID_VALUE);
245 break;
247 case AL_GAIN:
248 if(flValue >= 0.0f)
250 pSource->flGain = flValue;
251 pSource->NeedsUpdate = AL_TRUE;
253 else
254 alSetError(pContext, AL_INVALID_VALUE);
255 break;
257 case AL_MAX_DISTANCE:
258 if(flValue >= 0.0f)
260 pSource->flMaxDistance = flValue;
261 pSource->NeedsUpdate = AL_TRUE;
263 else
264 alSetError(pContext, AL_INVALID_VALUE);
265 break;
267 case AL_ROLLOFF_FACTOR:
268 if(flValue >= 0.0f)
270 pSource->flRollOffFactor = flValue;
271 pSource->NeedsUpdate = AL_TRUE;
273 else
274 alSetError(pContext, AL_INVALID_VALUE);
275 break;
277 case AL_REFERENCE_DISTANCE:
278 if(flValue >= 0.0f)
280 pSource->flRefDistance = flValue;
281 pSource->NeedsUpdate = AL_TRUE;
283 else
284 alSetError(pContext, AL_INVALID_VALUE);
285 break;
287 case AL_MIN_GAIN:
288 if(flValue >= 0.0f && flValue <= 1.0f)
290 pSource->flMinGain = flValue;
291 pSource->NeedsUpdate = AL_TRUE;
293 else
294 alSetError(pContext, AL_INVALID_VALUE);
295 break;
297 case AL_MAX_GAIN:
298 if(flValue >= 0.0f && flValue <= 1.0f)
300 pSource->flMaxGain = flValue;
301 pSource->NeedsUpdate = AL_TRUE;
303 else
304 alSetError(pContext, AL_INVALID_VALUE);
305 break;
307 case AL_CONE_OUTER_GAIN:
308 if(flValue >= 0.0f && flValue <= 1.0f)
310 pSource->flOuterGain = flValue;
311 pSource->NeedsUpdate = AL_TRUE;
313 else
314 alSetError(pContext, AL_INVALID_VALUE);
315 break;
317 case AL_CONE_OUTER_GAINHF:
318 if(flValue >= 0.0f && flValue <= 1.0f)
320 pSource->OuterGainHF = flValue;
321 pSource->NeedsUpdate = AL_TRUE;
323 else
324 alSetError(pContext, AL_INVALID_VALUE);
325 break;
327 case AL_AIR_ABSORPTION_FACTOR:
328 if(flValue >= 0.0f && flValue <= 10.0f)
330 pSource->AirAbsorptionFactor = flValue;
331 pSource->NeedsUpdate = AL_TRUE;
333 else
334 alSetError(pContext, AL_INVALID_VALUE);
335 break;
337 case AL_ROOM_ROLLOFF_FACTOR:
338 if(flValue >= 0.0f && flValue <= 10.0f)
340 pSource->RoomRolloffFactor = flValue;
341 pSource->NeedsUpdate = AL_TRUE;
343 else
344 alSetError(pContext, AL_INVALID_VALUE);
345 break;
347 case AL_DOPPLER_FACTOR:
348 if(flValue >= 0.0f && flValue <= 1.0f)
350 pSource->DopplerFactor = flValue;
351 pSource->NeedsUpdate = AL_TRUE;
353 else
354 alSetError(pContext, AL_INVALID_VALUE);
355 break;
357 case AL_SEC_OFFSET:
358 case AL_SAMPLE_OFFSET:
359 case AL_BYTE_OFFSET:
360 if(flValue >= 0.0f)
362 pSource->lOffsetType = eParam;
364 // Store Offset (convert Seconds into Milliseconds)
365 if(eParam == AL_SEC_OFFSET)
366 pSource->lOffset = (ALint)(flValue * 1000.0f);
367 else
368 pSource->lOffset = (ALint)flValue;
370 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
372 if(ApplyOffset(pSource) == AL_FALSE)
373 alSetError(pContext, AL_INVALID_VALUE);
376 else
377 alSetError(pContext, AL_INVALID_VALUE);
378 break;
380 default:
381 alSetError(pContext, AL_INVALID_ENUM);
382 break;
385 else
387 // Invalid Source Name
388 alSetError(pContext, AL_INVALID_NAME);
391 ProcessContext(pContext);
395 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
397 ALCcontext *pContext;
398 ALsource *pSource;
400 pContext = GetContextSuspended();
401 if(!pContext) return;
403 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
405 switch(eParam)
407 case AL_POSITION:
408 pSource->vPosition[0] = flValue1;
409 pSource->vPosition[1] = flValue2;
410 pSource->vPosition[2] = flValue3;
411 pSource->NeedsUpdate = AL_TRUE;
412 break;
414 case AL_VELOCITY:
415 pSource->vVelocity[0] = flValue1;
416 pSource->vVelocity[1] = flValue2;
417 pSource->vVelocity[2] = flValue3;
418 pSource->NeedsUpdate = AL_TRUE;
419 break;
421 case AL_DIRECTION:
422 pSource->vOrientation[0] = flValue1;
423 pSource->vOrientation[1] = flValue2;
424 pSource->vOrientation[2] = flValue3;
425 pSource->NeedsUpdate = AL_TRUE;
426 break;
428 default:
429 alSetError(pContext, AL_INVALID_ENUM);
430 break;
433 else
434 alSetError(pContext, AL_INVALID_NAME);
436 ProcessContext(pContext);
440 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
442 ALCcontext *pContext;
444 pContext = GetContextSuspended();
445 if(!pContext) return;
447 if(pflValues)
449 if(VerifySource(pContext->SourceList, source) != NULL)
451 switch(eParam)
453 case AL_PITCH:
454 case AL_CONE_INNER_ANGLE:
455 case AL_CONE_OUTER_ANGLE:
456 case AL_GAIN:
457 case AL_MAX_DISTANCE:
458 case AL_ROLLOFF_FACTOR:
459 case AL_REFERENCE_DISTANCE:
460 case AL_MIN_GAIN:
461 case AL_MAX_GAIN:
462 case AL_CONE_OUTER_GAIN:
463 case AL_CONE_OUTER_GAINHF:
464 case AL_SEC_OFFSET:
465 case AL_SAMPLE_OFFSET:
466 case AL_BYTE_OFFSET:
467 case AL_AIR_ABSORPTION_FACTOR:
468 case AL_ROOM_ROLLOFF_FACTOR:
469 alSourcef(source, eParam, pflValues[0]);
470 break;
472 case AL_POSITION:
473 case AL_VELOCITY:
474 case AL_DIRECTION:
475 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
476 break;
478 default:
479 alSetError(pContext, AL_INVALID_ENUM);
480 break;
483 else
484 alSetError(pContext, AL_INVALID_NAME);
486 else
487 alSetError(pContext, AL_INVALID_VALUE);
489 ProcessContext(pContext);
493 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
495 ALCcontext *pContext;
496 ALsource *pSource;
497 ALbufferlistitem *pALBufferListItem;
499 pContext = GetContextSuspended();
500 if(!pContext) return;
502 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
504 ALCdevice *device = pContext->Device;
506 switch(eParam)
508 case AL_MAX_DISTANCE:
509 case AL_ROLLOFF_FACTOR:
510 case AL_CONE_INNER_ANGLE:
511 case AL_CONE_OUTER_ANGLE:
512 case AL_REFERENCE_DISTANCE:
513 alSourcef(source, eParam, (ALfloat)lValue);
514 break;
516 case AL_SOURCE_RELATIVE:
517 if(lValue == AL_FALSE || lValue == AL_TRUE)
519 pSource->bHeadRelative = (ALboolean)lValue;
520 pSource->NeedsUpdate = AL_TRUE;
522 else
523 alSetError(pContext, AL_INVALID_VALUE);
524 break;
526 case AL_LOOPING:
527 if(lValue == AL_FALSE || lValue == AL_TRUE)
528 pSource->bLooping = (ALboolean)lValue;
529 else
530 alSetError(pContext, AL_INVALID_VALUE);
531 break;
533 case AL_BUFFER:
534 if(pSource->state == AL_STOPPED || pSource->state == AL_INITIAL)
536 ALbuffer *buffer = NULL;
538 if(lValue == 0 ||
539 (buffer=VerifyBuffer(device->BufferList, lValue)) != NULL)
541 // Remove all elements in the queue
542 while(pSource->queue != NULL)
544 pALBufferListItem = pSource->queue;
545 pSource->queue = pALBufferListItem->next;
546 // Decrement reference counter for buffer
547 if(pALBufferListItem->buffer)
548 pALBufferListItem->buffer->refcount--;
549 // Release memory for buffer list item
550 free(pALBufferListItem);
551 // Decrement the number of buffers in the queue
552 pSource->BuffersInQueue--;
555 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
556 if(lValue != 0)
558 // Source is now in STATIC mode
559 pSource->lSourceType = AL_STATIC;
561 // Add the selected buffer to the queue
562 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
563 pALBufferListItem->buffer = buffer;
564 pALBufferListItem->next = NULL;
566 pSource->queue = pALBufferListItem;
567 pSource->BuffersInQueue = 1;
569 // Increment reference counter for buffer
570 buffer->refcount++;
572 else
574 // Source is now in UNDETERMINED mode
575 pSource->lSourceType = AL_UNDETERMINED;
576 pSource->BuffersPlayed = 0;
579 // Update AL_BUFFER parameter
580 pSource->Buffer = buffer;
581 pSource->NeedsUpdate = AL_TRUE;
583 else
584 alSetError(pContext, AL_INVALID_VALUE);
586 else
587 alSetError(pContext, AL_INVALID_OPERATION);
588 break;
590 case AL_SOURCE_STATE:
591 // Query only
592 alSetError(pContext, AL_INVALID_OPERATION);
593 break;
595 case AL_SEC_OFFSET:
596 case AL_SAMPLE_OFFSET:
597 case AL_BYTE_OFFSET:
598 if(lValue >= 0)
600 pSource->lOffsetType = eParam;
602 // Store Offset (convert Seconds into Milliseconds)
603 if(eParam == AL_SEC_OFFSET)
604 pSource->lOffset = lValue * 1000;
605 else
606 pSource->lOffset = lValue;
608 if(pSource->state == AL_PLAYING || pSource->state == AL_PAUSED)
610 if(ApplyOffset(pSource) == AL_FALSE)
611 alSetError(pContext, AL_INVALID_VALUE);
614 else
615 alSetError(pContext, AL_INVALID_VALUE);
616 break;
618 case AL_DIRECT_FILTER: {
619 ALfilter *filter = NULL;
621 if(lValue == 0 ||
622 (filter=VerifyFilter(pContext->Device->FilterList, lValue)) != NULL)
624 if(!filter)
626 pSource->DirectFilter.type = AL_FILTER_NULL;
627 pSource->DirectFilter.filter = 0;
629 else
630 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
631 pSource->NeedsUpdate = AL_TRUE;
633 else
634 alSetError(pContext, AL_INVALID_VALUE);
635 } break;
637 case AL_DIRECT_FILTER_GAINHF_AUTO:
638 if(lValue == AL_TRUE || lValue == AL_FALSE)
640 pSource->DryGainHFAuto = lValue;
641 pSource->NeedsUpdate = AL_TRUE;
643 else
644 alSetError(pContext, AL_INVALID_VALUE);
645 break;
647 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
648 if(lValue == AL_TRUE || lValue == AL_FALSE)
650 pSource->WetGainAuto = lValue;
651 pSource->NeedsUpdate = AL_TRUE;
653 else
654 alSetError(pContext, AL_INVALID_VALUE);
655 break;
657 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
658 if(lValue == AL_TRUE || lValue == AL_FALSE)
660 pSource->WetGainHFAuto = lValue;
661 pSource->NeedsUpdate = AL_TRUE;
663 else
664 alSetError(pContext, AL_INVALID_VALUE);
665 break;
667 case AL_DISTANCE_MODEL:
668 if(lValue == AL_NONE ||
669 lValue == AL_INVERSE_DISTANCE ||
670 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
671 lValue == AL_LINEAR_DISTANCE ||
672 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
673 lValue == AL_EXPONENT_DISTANCE ||
674 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
676 pSource->DistanceModel = lValue;
677 if(pContext->SourceDistanceModel)
678 pSource->NeedsUpdate = AL_TRUE;
680 else
681 alSetError(pContext, AL_INVALID_VALUE);
682 break;
684 default:
685 alSetError(pContext, AL_INVALID_ENUM);
686 break;
689 else
690 alSetError(pContext, AL_INVALID_NAME);
692 ProcessContext(pContext);
696 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
698 ALCcontext *pContext;
699 ALsource *pSource;
701 pContext = GetContextSuspended();
702 if(!pContext) return;
704 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
706 ALCdevice *device = pContext->Device;
708 switch (eParam)
710 case AL_POSITION:
711 case AL_VELOCITY:
712 case AL_DIRECTION:
713 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
714 break;
716 case AL_AUXILIARY_SEND_FILTER: {
717 ALeffectslot *ALEffectSlot = NULL;
718 ALfilter *ALFilter = NULL;
720 if((ALuint)lValue2 < device->NumAuxSends &&
721 (lValue1 == 0 ||
722 (ALEffectSlot=VerifyEffectSlot(pContext->EffectSlotList, lValue1)) != NULL) &&
723 (lValue3 == 0 ||
724 (ALFilter=VerifyFilter(device->FilterList, lValue3)) != NULL))
726 /* Release refcount on the previous slot, and add one for
727 * the new slot */
728 if(pSource->Send[lValue2].Slot)
729 pSource->Send[lValue2].Slot->refcount--;
730 pSource->Send[lValue2].Slot = ALEffectSlot;
731 if(pSource->Send[lValue2].Slot)
732 pSource->Send[lValue2].Slot->refcount++;
734 if(!ALFilter)
736 /* Disable filter */
737 pSource->Send[lValue2].WetFilter.type = 0;
738 pSource->Send[lValue2].WetFilter.filter = 0;
740 else
741 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
742 pSource->NeedsUpdate = AL_TRUE;
744 else
745 alSetError(pContext, AL_INVALID_VALUE);
746 } break;
748 default:
749 alSetError(pContext, AL_INVALID_ENUM);
750 break;
753 else
754 alSetError(pContext, AL_INVALID_NAME);
756 ProcessContext(pContext);
760 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
762 ALCcontext *pContext;
764 pContext = GetContextSuspended();
765 if(!pContext) return;
767 if(plValues)
769 if(VerifySource(pContext->SourceList, source) != NULL)
771 switch(eParam)
773 case AL_SOURCE_RELATIVE:
774 case AL_CONE_INNER_ANGLE:
775 case AL_CONE_OUTER_ANGLE:
776 case AL_LOOPING:
777 case AL_BUFFER:
778 case AL_SOURCE_STATE:
779 case AL_SEC_OFFSET:
780 case AL_SAMPLE_OFFSET:
781 case AL_BYTE_OFFSET:
782 case AL_MAX_DISTANCE:
783 case AL_ROLLOFF_FACTOR:
784 case AL_REFERENCE_DISTANCE:
785 case AL_DIRECT_FILTER:
786 case AL_DIRECT_FILTER_GAINHF_AUTO:
787 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
788 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
789 case AL_DISTANCE_MODEL:
790 alSourcei(source, eParam, plValues[0]);
791 break;
793 case AL_POSITION:
794 case AL_VELOCITY:
795 case AL_DIRECTION:
796 case AL_AUXILIARY_SEND_FILTER:
797 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
798 break;
800 default:
801 alSetError(pContext, AL_INVALID_ENUM);
802 break;
805 else
806 alSetError(pContext, AL_INVALID_NAME);
808 else
809 alSetError(pContext, AL_INVALID_VALUE);
811 ProcessContext(pContext);
815 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
817 ALCcontext *pContext;
818 ALsource *pSource;
819 ALfloat flOffset[2];
820 ALfloat updateLen;
822 pContext = GetContextSuspended();
823 if(!pContext) return;
825 if(pflValue)
827 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
829 switch(eParam)
831 case AL_PITCH:
832 *pflValue = pSource->flPitch;
833 break;
835 case AL_GAIN:
836 *pflValue = pSource->flGain;
837 break;
839 case AL_MIN_GAIN:
840 *pflValue = pSource->flMinGain;
841 break;
843 case AL_MAX_GAIN:
844 *pflValue = pSource->flMaxGain;
845 break;
847 case AL_MAX_DISTANCE:
848 *pflValue = pSource->flMaxDistance;
849 break;
851 case AL_ROLLOFF_FACTOR:
852 *pflValue = pSource->flRollOffFactor;
853 break;
855 case AL_CONE_OUTER_GAIN:
856 *pflValue = pSource->flOuterGain;
857 break;
859 case AL_CONE_OUTER_GAINHF:
860 *pflValue = pSource->OuterGainHF;
861 break;
863 case AL_SEC_OFFSET:
864 case AL_SAMPLE_OFFSET:
865 case AL_BYTE_OFFSET:
866 updateLen = (ALfloat)pContext->Device->UpdateSize /
867 pContext->Device->Frequency;
868 GetSourceOffset(pSource, eParam, flOffset, updateLen);
869 *pflValue = flOffset[0];
870 break;
872 case AL_CONE_INNER_ANGLE:
873 *pflValue = pSource->flInnerAngle;
874 break;
876 case AL_CONE_OUTER_ANGLE:
877 *pflValue = pSource->flOuterAngle;
878 break;
880 case AL_REFERENCE_DISTANCE:
881 *pflValue = pSource->flRefDistance;
882 break;
884 case AL_AIR_ABSORPTION_FACTOR:
885 *pflValue = pSource->AirAbsorptionFactor;
886 break;
888 case AL_ROOM_ROLLOFF_FACTOR:
889 *pflValue = pSource->RoomRolloffFactor;
890 break;
892 case AL_DOPPLER_FACTOR:
893 *pflValue = pSource->DopplerFactor;
894 break;
896 default:
897 alSetError(pContext, AL_INVALID_ENUM);
898 break;
901 else
902 alSetError(pContext, AL_INVALID_NAME);
904 else
905 alSetError(pContext, AL_INVALID_VALUE);
907 ProcessContext(pContext);
911 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
913 ALCcontext *pContext;
914 ALsource *pSource;
916 pContext = GetContextSuspended();
917 if(!pContext) return;
919 if(pflValue1 && pflValue2 && pflValue3)
921 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
923 switch(eParam)
925 case AL_POSITION:
926 *pflValue1 = pSource->vPosition[0];
927 *pflValue2 = pSource->vPosition[1];
928 *pflValue3 = pSource->vPosition[2];
929 break;
931 case AL_VELOCITY:
932 *pflValue1 = pSource->vVelocity[0];
933 *pflValue2 = pSource->vVelocity[1];
934 *pflValue3 = pSource->vVelocity[2];
935 break;
937 case AL_DIRECTION:
938 *pflValue1 = pSource->vOrientation[0];
939 *pflValue2 = pSource->vOrientation[1];
940 *pflValue3 = pSource->vOrientation[2];
941 break;
943 default:
944 alSetError(pContext, AL_INVALID_ENUM);
945 break;
948 else
949 alSetError(pContext, AL_INVALID_NAME);
951 else
952 alSetError(pContext, AL_INVALID_VALUE);
954 ProcessContext(pContext);
958 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
960 ALCcontext *pContext;
961 ALsource *pSource;
962 ALfloat flOffset[2];
963 ALfloat updateLen;
965 pContext = GetContextSuspended();
966 if(!pContext) return;
968 if(pflValues)
970 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
972 switch(eParam)
974 case AL_PITCH:
975 case AL_GAIN:
976 case AL_MIN_GAIN:
977 case AL_MAX_GAIN:
978 case AL_MAX_DISTANCE:
979 case AL_ROLLOFF_FACTOR:
980 case AL_DOPPLER_FACTOR:
981 case AL_CONE_OUTER_GAIN:
982 case AL_SEC_OFFSET:
983 case AL_SAMPLE_OFFSET:
984 case AL_BYTE_OFFSET:
985 case AL_CONE_INNER_ANGLE:
986 case AL_CONE_OUTER_ANGLE:
987 case AL_REFERENCE_DISTANCE:
988 case AL_CONE_OUTER_GAINHF:
989 case AL_AIR_ABSORPTION_FACTOR:
990 case AL_ROOM_ROLLOFF_FACTOR:
991 alGetSourcef(source, eParam, pflValues);
992 break;
994 case AL_SAMPLE_RW_OFFSETS_EXT:
995 case AL_BYTE_RW_OFFSETS_EXT:
996 updateLen = (ALfloat)pContext->Device->UpdateSize /
997 pContext->Device->Frequency;
998 GetSourceOffset(pSource, eParam, flOffset, updateLen);
999 pflValues[0] = flOffset[0];
1000 pflValues[1] = flOffset[1];
1001 break;
1003 case AL_POSITION:
1004 pflValues[0] = pSource->vPosition[0];
1005 pflValues[1] = pSource->vPosition[1];
1006 pflValues[2] = pSource->vPosition[2];
1007 break;
1009 case AL_VELOCITY:
1010 pflValues[0] = pSource->vVelocity[0];
1011 pflValues[1] = pSource->vVelocity[1];
1012 pflValues[2] = pSource->vVelocity[2];
1013 break;
1015 case AL_DIRECTION:
1016 pflValues[0] = pSource->vOrientation[0];
1017 pflValues[1] = pSource->vOrientation[1];
1018 pflValues[2] = pSource->vOrientation[2];
1019 break;
1021 default:
1022 alSetError(pContext, AL_INVALID_ENUM);
1023 break;
1026 else
1027 alSetError(pContext, AL_INVALID_NAME);
1029 else
1030 alSetError(pContext, AL_INVALID_VALUE);
1032 ProcessContext(pContext);
1036 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1038 ALCcontext *pContext;
1039 ALsource *pSource;
1040 ALfloat flOffset[2];
1041 ALfloat updateLen;
1043 pContext = GetContextSuspended();
1044 if(!pContext) return;
1046 if(plValue)
1048 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
1050 switch(eParam)
1052 case AL_MAX_DISTANCE:
1053 *plValue = (ALint)pSource->flMaxDistance;
1054 break;
1056 case AL_ROLLOFF_FACTOR:
1057 *plValue = (ALint)pSource->flRollOffFactor;
1058 break;
1060 case AL_REFERENCE_DISTANCE:
1061 *plValue = (ALint)pSource->flRefDistance;
1062 break;
1064 case AL_SOURCE_RELATIVE:
1065 *plValue = pSource->bHeadRelative;
1066 break;
1068 case AL_CONE_INNER_ANGLE:
1069 *plValue = (ALint)pSource->flInnerAngle;
1070 break;
1072 case AL_CONE_OUTER_ANGLE:
1073 *plValue = (ALint)pSource->flOuterAngle;
1074 break;
1076 case AL_LOOPING:
1077 *plValue = pSource->bLooping;
1078 break;
1080 case AL_BUFFER:
1081 *plValue = (pSource->Buffer ? pSource->Buffer->buffer : 0);
1082 break;
1084 case AL_SOURCE_STATE:
1085 *plValue = pSource->state;
1086 break;
1088 case AL_BUFFERS_QUEUED:
1089 *plValue = pSource->BuffersInQueue;
1090 break;
1092 case AL_BUFFERS_PROCESSED:
1093 if(pSource->bLooping)
1095 /* Buffers on a looping source are in a perpetual state
1096 * of PENDING, so don't report any as PROCESSED */
1097 *plValue = 0;
1099 else
1100 *plValue = pSource->BuffersPlayed;
1101 break;
1103 case AL_SOURCE_TYPE:
1104 *plValue = pSource->lSourceType;
1105 break;
1107 case AL_SEC_OFFSET:
1108 case AL_SAMPLE_OFFSET:
1109 case AL_BYTE_OFFSET:
1110 updateLen = (ALfloat)pContext->Device->UpdateSize /
1111 pContext->Device->Frequency;
1112 GetSourceOffset(pSource, eParam, flOffset, updateLen);
1113 *plValue = (ALint)flOffset[0];
1114 break;
1116 case AL_DIRECT_FILTER:
1117 *plValue = pSource->DirectFilter.filter;
1118 break;
1120 case AL_DIRECT_FILTER_GAINHF_AUTO:
1121 *plValue = pSource->DryGainHFAuto;
1122 break;
1124 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1125 *plValue = pSource->WetGainAuto;
1126 break;
1128 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1129 *plValue = pSource->WetGainHFAuto;
1130 break;
1132 case AL_DOPPLER_FACTOR:
1133 *plValue = (ALint)pSource->DopplerFactor;
1134 break;
1136 case AL_DISTANCE_MODEL:
1137 *plValue = pSource->DistanceModel;
1138 break;
1140 default:
1141 alSetError(pContext, AL_INVALID_ENUM);
1142 break;
1145 else
1146 alSetError(pContext, AL_INVALID_NAME);
1148 else
1149 alSetError(pContext, AL_INVALID_VALUE);
1151 ProcessContext(pContext);
1155 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1157 ALCcontext *pContext;
1158 ALsource *pSource;
1160 pContext = GetContextSuspended();
1161 if(!pContext) return;
1163 if(plValue1 && plValue2 && plValue3)
1165 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
1167 switch(eParam)
1169 case AL_POSITION:
1170 *plValue1 = (ALint)pSource->vPosition[0];
1171 *plValue2 = (ALint)pSource->vPosition[1];
1172 *plValue3 = (ALint)pSource->vPosition[2];
1173 break;
1175 case AL_VELOCITY:
1176 *plValue1 = (ALint)pSource->vVelocity[0];
1177 *plValue2 = (ALint)pSource->vVelocity[1];
1178 *plValue3 = (ALint)pSource->vVelocity[2];
1179 break;
1181 case AL_DIRECTION:
1182 *plValue1 = (ALint)pSource->vOrientation[0];
1183 *plValue2 = (ALint)pSource->vOrientation[1];
1184 *plValue3 = (ALint)pSource->vOrientation[2];
1185 break;
1187 default:
1188 alSetError(pContext, AL_INVALID_ENUM);
1189 break;
1192 else
1193 alSetError(pContext, AL_INVALID_NAME);
1195 else
1196 alSetError(pContext, AL_INVALID_VALUE);
1198 ProcessContext(pContext);
1202 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1204 ALCcontext *pContext;
1205 ALsource *pSource;
1206 ALfloat flOffset[2];
1207 ALfloat updateLen;
1209 pContext = GetContextSuspended();
1210 if(!pContext) return;
1212 if(plValues)
1214 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
1216 switch(eParam)
1218 case AL_SOURCE_RELATIVE:
1219 case AL_CONE_INNER_ANGLE:
1220 case AL_CONE_OUTER_ANGLE:
1221 case AL_LOOPING:
1222 case AL_BUFFER:
1223 case AL_SOURCE_STATE:
1224 case AL_BUFFERS_QUEUED:
1225 case AL_BUFFERS_PROCESSED:
1226 case AL_SEC_OFFSET:
1227 case AL_SAMPLE_OFFSET:
1228 case AL_BYTE_OFFSET:
1229 case AL_MAX_DISTANCE:
1230 case AL_ROLLOFF_FACTOR:
1231 case AL_DOPPLER_FACTOR:
1232 case AL_REFERENCE_DISTANCE:
1233 case AL_SOURCE_TYPE:
1234 case AL_DIRECT_FILTER:
1235 case AL_DIRECT_FILTER_GAINHF_AUTO:
1236 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1237 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1238 case AL_DISTANCE_MODEL:
1239 alGetSourcei(source, eParam, plValues);
1240 break;
1242 case AL_SAMPLE_RW_OFFSETS_EXT:
1243 case AL_BYTE_RW_OFFSETS_EXT:
1244 updateLen = (ALfloat)pContext->Device->UpdateSize /
1245 pContext->Device->Frequency;
1246 GetSourceOffset(pSource, eParam, flOffset, updateLen);
1247 plValues[0] = (ALint)flOffset[0];
1248 plValues[1] = (ALint)flOffset[1];
1249 break;
1251 case AL_POSITION:
1252 plValues[0] = (ALint)pSource->vPosition[0];
1253 plValues[1] = (ALint)pSource->vPosition[1];
1254 plValues[2] = (ALint)pSource->vPosition[2];
1255 break;
1257 case AL_VELOCITY:
1258 plValues[0] = (ALint)pSource->vVelocity[0];
1259 plValues[1] = (ALint)pSource->vVelocity[1];
1260 plValues[2] = (ALint)pSource->vVelocity[2];
1261 break;
1263 case AL_DIRECTION:
1264 plValues[0] = (ALint)pSource->vOrientation[0];
1265 plValues[1] = (ALint)pSource->vOrientation[1];
1266 plValues[2] = (ALint)pSource->vOrientation[2];
1267 break;
1269 default:
1270 alSetError(pContext, AL_INVALID_ENUM);
1271 break;
1274 else
1275 alSetError(pContext, AL_INVALID_NAME);
1277 else
1278 alSetError(pContext, AL_INVALID_VALUE);
1280 ProcessContext(pContext);
1284 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1286 alSourcePlayv(1, &source);
1289 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1291 ALCcontext *pContext;
1292 ALsource *pSource;
1293 ALbufferlistitem *ALBufferList;
1294 ALboolean bSourcesValid = AL_TRUE;
1295 ALboolean bPlay;
1296 ALsizei i, j;
1298 pContext = GetContextSuspended();
1299 if(!pContext) return;
1301 if(pSourceList)
1303 // Check that all the Sources are valid
1304 for(i = 0; i < n; i++)
1306 if(!VerifySource(pContext->SourceList, pSourceList[i]))
1308 alSetError(pContext, AL_INVALID_NAME);
1309 bSourcesValid = AL_FALSE;
1310 break;
1314 if(bSourcesValid)
1316 for(i = 0; i < n; i++)
1318 // Assume Source won't need to play
1319 bPlay = AL_FALSE;
1321 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]);
1323 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1324 ALBufferList = pSource->queue;
1325 while(ALBufferList)
1327 if(ALBufferList->buffer != NULL && ALBufferList->buffer->size)
1329 bPlay = AL_TRUE;
1330 break;
1332 ALBufferList = ALBufferList->next;
1335 if (bPlay)
1337 for(j = 0;j < OUTPUTCHANNELS;j++)
1338 pSource->DryGains[j] = 0.0f;
1339 for(j = 0;j < MAX_SENDS;j++)
1340 pSource->WetGains[j] = 0.0f;
1342 if(pSource->state != AL_PAUSED)
1344 pSource->state = AL_PLAYING;
1345 pSource->position = 0;
1346 pSource->position_fraction = 0;
1347 pSource->BuffersPlayed = 0;
1349 pSource->Buffer = pSource->queue->buffer;
1351 else
1352 pSource->state = AL_PLAYING;
1354 // Check if an Offset has been set
1355 if(pSource->lOffset)
1356 ApplyOffset(pSource);
1358 if(pSource->BuffersPlayed == 0 && pSource->position == 0 &&
1359 pSource->position_fraction == 0)
1360 pSource->FirstStart = AL_TRUE;
1361 else
1362 pSource->FirstStart = AL_FALSE;
1364 // If device is disconnected, go right to stopped
1365 if(!pContext->Device->Connected)
1367 pSource->state = AL_STOPPED;
1368 pSource->BuffersPlayed = pSource->BuffersInQueue;
1369 pSource->position = 0;
1370 pSource->position_fraction = 0;
1373 else
1374 pSource->BuffersPlayed = pSource->BuffersInQueue;
1378 else
1380 // sources is a NULL pointer
1381 alSetError(pContext, AL_INVALID_VALUE);
1384 ProcessContext(pContext);
1387 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1389 alSourcePausev(1, &source);
1392 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1394 ALCcontext *Context;
1395 ALsource *Source;
1396 ALsizei i;
1397 ALboolean bSourcesValid = AL_TRUE;
1399 Context = GetContextSuspended();
1400 if(!Context) return;
1402 if(sources)
1404 // Check all the Sources are valid
1405 for(i=0;i<n;i++)
1407 if(!VerifySource(Context->SourceList, sources[i]))
1409 alSetError(Context, AL_INVALID_NAME);
1410 bSourcesValid = AL_FALSE;
1411 break;
1415 if(bSourcesValid)
1417 for(i = 0;i < n;i++)
1419 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1420 if(Source->state == AL_PLAYING)
1421 Source->state = AL_PAUSED;
1425 else
1427 // sources is a NULL pointer
1428 alSetError(Context, AL_INVALID_VALUE);
1431 ProcessContext(Context);
1434 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1436 alSourceStopv(1, &source);
1439 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1441 ALCcontext *Context;
1442 ALsource *Source;
1443 ALsizei i;
1444 ALboolean bSourcesValid = AL_TRUE;
1446 Context = GetContextSuspended();
1447 if(!Context) return;
1449 if(sources)
1451 // Check all the Sources are valid
1452 for(i = 0;i < n;i++)
1454 if(!VerifySource(Context->SourceList, sources[i]))
1456 alSetError(Context, AL_INVALID_NAME);
1457 bSourcesValid = AL_FALSE;
1458 break;
1462 if(bSourcesValid)
1464 for(i = 0;i < n;i++)
1466 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1467 if(Source->state != AL_INITIAL)
1469 Source->state = AL_STOPPED;
1470 Source->BuffersPlayed = Source->BuffersInQueue;
1472 Source->lOffset = 0;
1476 else
1478 // sources is a NULL pointer
1479 alSetError(Context, AL_INVALID_VALUE);
1482 ProcessContext(Context);
1485 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1487 alSourceRewindv(1, &source);
1490 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1492 ALCcontext *Context;
1493 ALsource *Source;
1494 ALsizei i;
1495 ALboolean bSourcesValid = AL_TRUE;
1497 Context = GetContextSuspended();
1498 if(!Context) return;
1500 if(sources)
1502 // Check all the Sources are valid
1503 for(i = 0;i < n;i++)
1505 if(!VerifySource(Context->SourceList, sources[i]))
1507 alSetError(Context, AL_INVALID_NAME);
1508 bSourcesValid = AL_FALSE;
1509 break;
1513 if(bSourcesValid)
1515 for(i = 0;i < n;i++)
1517 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1518 if(Source->state != AL_INITIAL)
1520 Source->state = AL_INITIAL;
1521 Source->position = 0;
1522 Source->position_fraction = 0;
1523 Source->BuffersPlayed = 0;
1524 if(Source->queue)
1525 Source->Buffer = Source->queue->buffer;
1527 Source->lOffset = 0;
1531 else
1533 // sources is a NULL pointer
1534 alSetError(Context, AL_INVALID_VALUE);
1537 ProcessContext(Context);
1541 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1543 ALCcontext *Context;
1544 ALsource *ALSource;
1545 ALsizei i;
1546 ALbufferlistitem *ALBufferList;
1547 ALbufferlistitem *ALBufferListStart;
1548 ALint iFrequency;
1549 ALint iFormat;
1550 ALboolean bBuffersValid = AL_TRUE;
1551 ALboolean hadFormat = AL_FALSE;
1553 if (n == 0)
1554 return;
1556 Context = GetContextSuspended();
1557 if(!Context) return;
1559 // Check that all buffers are valid or zero and that the source is valid
1561 // Check that this is a valid source
1562 if((ALSource=VerifySource(Context->SourceList, source)) != NULL)
1564 // Check that this is not a STATIC Source
1565 if(ALSource->lSourceType != AL_STATIC)
1567 ALCdevice *device = Context->Device;
1569 iFrequency = -1;
1570 iFormat = -1;
1572 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1573 ALBufferList = ALSource->queue;
1574 while(ALBufferList)
1576 if (ALBufferList->buffer)
1578 iFrequency = ALBufferList->buffer->frequency;
1579 iFormat = ALBufferList->buffer->format;
1580 hadFormat = AL_TRUE;
1581 break;
1583 ALBufferList = ALBufferList->next;
1586 for(i = 0; i < n; i++)
1588 ALbuffer *buffer;
1590 if(!buffers[i])
1591 continue;
1593 if((buffer=VerifyBuffer(device->BufferList, buffers[i])) == NULL)
1595 alSetError(Context, AL_INVALID_NAME);
1596 bBuffersValid = AL_FALSE;
1597 break;
1600 if(iFrequency == -1 && iFormat == -1)
1602 iFrequency = buffer->frequency;
1603 iFormat = buffer->format;
1605 else if(iFrequency != buffer->frequency ||
1606 iFormat != buffer->format)
1608 alSetError(Context, AL_INVALID_OPERATION);
1609 bBuffersValid = AL_FALSE;
1610 break;
1614 if(bBuffersValid)
1616 ALbuffer *buffer;
1618 // Change Source Type
1619 ALSource->lSourceType = AL_STREAMING;
1621 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1623 // All buffers are valid - so add them to the list
1624 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1625 ALBufferListStart->buffer = buffer;
1626 ALBufferListStart->next = NULL;
1628 // Increment reference counter for buffer
1629 if(buffer) buffer->refcount++;
1631 ALBufferList = ALBufferListStart;
1633 for(i = 1; i < n; i++)
1635 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1637 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1638 ALBufferList->next->buffer = buffer;
1639 ALBufferList->next->next = NULL;
1641 // Increment reference counter for buffer
1642 if(buffer) buffer->refcount++;
1644 ALBufferList = ALBufferList->next;
1647 if(ALSource->queue == NULL)
1649 ALSource->queue = ALBufferListStart;
1650 // Update Current Buffer
1651 ALSource->Buffer = ALBufferListStart->buffer;
1653 else
1655 // Find end of queue
1656 ALBufferList = ALSource->queue;
1657 while(ALBufferList->next != NULL)
1658 ALBufferList = ALBufferList->next;
1660 ALBufferList->next = ALBufferListStart;
1663 // Update number of buffers in queue
1664 ALSource->BuffersInQueue += n;
1665 // If no previous format, mark the source dirty now that it may
1666 // have one
1667 if(!hadFormat)
1668 ALSource->NeedsUpdate = AL_TRUE;
1671 else
1673 // Invalid Source Type (can't queue on a Static Source)
1674 alSetError(Context, AL_INVALID_OPERATION);
1677 else
1679 // Invalid Source Name
1680 alSetError(Context, AL_INVALID_NAME);
1683 ProcessContext(Context);
1687 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1688 // an array of buffer IDs that are to be filled with the names of the buffers removed
1689 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1691 ALCcontext *Context;
1692 ALsource *ALSource;
1693 ALsizei i;
1694 ALbufferlistitem *ALBufferList;
1696 if (n == 0)
1697 return;
1699 Context = GetContextSuspended();
1700 if(!Context) return;
1702 if((ALSource=VerifySource(Context->SourceList, source)) != NULL)
1704 // If all 'n' buffers have been processed, remove them from the queue
1705 if(!ALSource->bLooping && (ALuint)n <= ALSource->BuffersPlayed)
1707 for(i = 0; i < n; i++)
1709 ALBufferList = ALSource->queue;
1711 ALSource->queue = ALBufferList->next;
1712 if(ALBufferList->buffer)
1714 // Record name of buffer
1715 buffers[i] = ALBufferList->buffer->buffer;
1716 // Decrement buffer reference counter
1717 ALBufferList->buffer->refcount--;
1719 else
1720 buffers[i] = 0;
1722 // Release memory for buffer list item
1723 free(ALBufferList);
1724 ALSource->BuffersInQueue--;
1727 if(ALSource->state != AL_PLAYING)
1729 if(ALSource->queue)
1730 ALSource->Buffer = ALSource->queue->buffer;
1731 else
1732 ALSource->Buffer = NULL;
1735 ALSource->BuffersPlayed -= n;
1737 else
1739 // Some buffers can't be unqueue because they have not been processed
1740 alSetError(Context, AL_INVALID_VALUE);
1743 else
1745 // Invalid Source Name
1746 alSetError(Context, AL_INVALID_NAME);
1749 ProcessContext(Context);
1753 static ALvoid InitSourceParams(ALsource *pSource)
1755 pSource->flInnerAngle = 360.0f;
1756 pSource->flOuterAngle = 360.0f;
1757 pSource->flPitch = 1.0f;
1758 pSource->vPosition[0] = 0.0f;
1759 pSource->vPosition[1] = 0.0f;
1760 pSource->vPosition[2] = 0.0f;
1761 pSource->vOrientation[0] = 0.0f;
1762 pSource->vOrientation[1] = 0.0f;
1763 pSource->vOrientation[2] = 0.0f;
1764 pSource->vVelocity[0] = 0.0f;
1765 pSource->vVelocity[1] = 0.0f;
1766 pSource->vVelocity[2] = 0.0f;
1767 pSource->flRefDistance = 1.0f;
1768 pSource->flMaxDistance = FLT_MAX;
1769 pSource->flRollOffFactor = 1.0f;
1770 pSource->bLooping = AL_FALSE;
1771 pSource->flGain = 1.0f;
1772 pSource->flMinGain = 0.0f;
1773 pSource->flMaxGain = 1.0f;
1774 pSource->flOuterGain = 0.0f;
1775 pSource->OuterGainHF = 1.0f;
1777 pSource->DryGainHFAuto = AL_TRUE;
1778 pSource->WetGainAuto = AL_TRUE;
1779 pSource->WetGainHFAuto = AL_TRUE;
1780 pSource->AirAbsorptionFactor = 0.0f;
1781 pSource->RoomRolloffFactor = 0.0f;
1782 pSource->DopplerFactor = 1.0f;
1784 pSource->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1786 pSource->Resampler = DefaultResampler;
1788 pSource->state = AL_INITIAL;
1789 pSource->lSourceType = AL_UNDETERMINED;
1791 pSource->NeedsUpdate = AL_TRUE;
1793 pSource->Buffer = NULL;
1798 GetSourceOffset
1800 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1801 The offset is relative to the start of the queue (not the start of the current buffer)
1803 static ALvoid GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALfloat updateLen)
1805 ALbufferlistitem *pBufferList;
1806 ALbuffer *pBuffer;
1807 ALfloat flBufferFreq;
1808 ALint lChannels, lBytes;
1809 ALint readPos, writePos;
1810 ALenum eOriginalFormat;
1811 ALint lTotalBufferDataSize;
1812 ALuint i;
1814 if((pSource->state == AL_PLAYING || pSource->state == AL_PAUSED) && pSource->Buffer)
1816 pBuffer = pSource->Buffer;
1817 // Get Current Buffer Size and frequency (in milliseconds)
1818 flBufferFreq = (ALfloat)pBuffer->frequency;
1819 eOriginalFormat = pBuffer->eOriginalFormat;
1820 lChannels = aluChannelsFromFormat(pBuffer->format);
1821 lBytes = aluBytesFromFormat(pBuffer->format);
1823 // Get Current BytesPlayed
1824 readPos = pSource->position * lChannels * lBytes; // NOTE : This is the byte offset into the *current* buffer
1825 // Add byte length of any processed buffers in the queue
1826 pBufferList = pSource->queue;
1827 for(i = 0;i < pSource->BuffersPlayed && pBufferList;i++)
1829 readPos += pBufferList->buffer->size;
1830 pBufferList = pBufferList->next;
1833 if(pSource->state == AL_PLAYING)
1834 writePos = readPos + ((ALuint)(updateLen*flBufferFreq) * lChannels * lBytes);
1835 else
1836 writePos = readPos;
1838 lTotalBufferDataSize = 0;
1839 pBufferList = pSource->queue;
1840 while (pBufferList)
1842 if (pBufferList->buffer)
1843 lTotalBufferDataSize += pBufferList->buffer->size;
1844 pBufferList = pBufferList->next;
1847 if (pSource->bLooping)
1849 if(readPos < 0)
1850 readPos = 0;
1851 else
1852 readPos %= lTotalBufferDataSize;
1853 if(writePos < 0)
1854 writePos = 0;
1855 else
1856 writePos %= lTotalBufferDataSize;
1858 else
1860 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1861 if(readPos < 0)
1862 readPos = 0;
1863 else if(readPos > lTotalBufferDataSize)
1864 readPos = lTotalBufferDataSize;
1865 if(writePos < 0)
1866 writePos = 0;
1867 else if(writePos > lTotalBufferDataSize)
1868 writePos = lTotalBufferDataSize;
1871 switch (eName)
1873 case AL_SEC_OFFSET:
1874 pflOffset[0] = (ALfloat)readPos / (lChannels * lBytes * flBufferFreq);
1875 pflOffset[1] = (ALfloat)writePos / (lChannels * lBytes * flBufferFreq);
1876 break;
1877 case AL_SAMPLE_OFFSET:
1878 case AL_SAMPLE_RW_OFFSETS_EXT:
1879 pflOffset[0] = (ALfloat)(readPos / (lChannels * lBytes));
1880 pflOffset[1] = (ALfloat)(writePos / (lChannels * lBytes));
1881 break;
1882 case AL_BYTE_OFFSET:
1883 case AL_BYTE_RW_OFFSETS_EXT:
1884 // Take into account the original format of the Buffer
1885 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
1886 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1888 // Round down to nearest ADPCM block
1889 pflOffset[0] = (ALfloat)((readPos / (65 * lBytes * lChannels)) * 36 * lChannels);
1890 if(pSource->state == AL_PLAYING)
1892 // Round up to nearest ADPCM block
1893 pflOffset[1] = (ALfloat)(((writePos + (65 * lBytes * lChannels) - 1) / (65 * lBytes * lChannels)) * 36 * lChannels);
1895 else
1896 pflOffset[1] = pflOffset[0];
1898 else if(eOriginalFormat == AL_FORMAT_MONO_MULAW ||
1899 eOriginalFormat == AL_FORMAT_STEREO_MULAW ||
1900 eOriginalFormat == AL_FORMAT_QUAD_MULAW ||
1901 eOriginalFormat == AL_FORMAT_51CHN_MULAW ||
1902 eOriginalFormat == AL_FORMAT_61CHN_MULAW ||
1903 eOriginalFormat == AL_FORMAT_71CHN_MULAW)
1905 pflOffset[0] = (ALfloat)(readPos / lBytes * 1);
1906 pflOffset[1] = (ALfloat)(writePos / lBytes * 1);
1908 else if(eOriginalFormat == AL_FORMAT_REAR_MULAW)
1910 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 1);
1911 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 1);
1913 else if (eOriginalFormat == AL_FORMAT_REAR8)
1915 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 1);
1916 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 1);
1918 else if (eOriginalFormat == AL_FORMAT_REAR16)
1920 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 2);
1921 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 2);
1923 else if (eOriginalFormat == AL_FORMAT_REAR32)
1925 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 4);
1926 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 4);
1928 else
1930 ALuint OrigBytes = aluBytesFromFormat(eOriginalFormat);
1931 pflOffset[0] = (ALfloat)(readPos / lBytes * OrigBytes);
1932 pflOffset[1] = (ALfloat)(writePos / lBytes * OrigBytes);
1934 break;
1937 else
1939 pflOffset[0] = 0.0f;
1940 pflOffset[1] = 0.0f;
1946 ApplyOffset
1948 Apply a playback offset to the Source. This function will update the queue (to correctly
1949 mark buffers as 'pending' or 'processed' depending upon the new offset.
1951 static ALboolean ApplyOffset(ALsource *pSource)
1953 ALbufferlistitem *pBufferList;
1954 ALbuffer *pBuffer;
1955 ALint lBufferSize, lTotalBufferSize;
1956 ALint lByteOffset;
1958 // Get true byte offset
1959 lByteOffset = GetByteOffset(pSource);
1961 // If the offset is invalid, don't apply it
1962 if(lByteOffset == -1)
1963 return AL_FALSE;
1965 // Sort out the queue (pending and processed states)
1966 pBufferList = pSource->queue;
1967 lTotalBufferSize = 0;
1968 pSource->BuffersPlayed = 0;
1970 while(pBufferList)
1972 pBuffer = pBufferList->buffer;
1973 lBufferSize = pBuffer ? pBuffer->size : 0;
1975 if(lTotalBufferSize+lBufferSize <= lByteOffset)
1977 // Offset is past this buffer so increment BuffersPlayed
1978 pSource->BuffersPlayed++;
1980 else if(lTotalBufferSize <= lByteOffset)
1982 // Offset is within this buffer
1983 // Set Current Buffer
1984 pSource->Buffer = pBufferList->buffer;
1986 // SW Mixer Positions are in Samples
1987 pSource->position = (lByteOffset - lTotalBufferSize) /
1988 aluBytesFromFormat(pBuffer->format) /
1989 aluChannelsFromFormat(pBuffer->format);
1990 break;
1993 // Increment the TotalBufferSize
1994 lTotalBufferSize += lBufferSize;
1996 // Move on to next buffer in the Queue
1997 pBufferList = pBufferList->next;
2000 return AL_TRUE;
2005 GetByteOffset
2007 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2008 offset supplied by the application). This takes into account the fact that the buffer format
2009 may have been modifed by AL (e.g 8bit samples are converted to float)
2011 static ALint GetByteOffset(ALsource *pSource)
2013 ALbuffer *pBuffer = NULL;
2014 ALbufferlistitem *pBufferList;
2015 ALfloat flBufferFreq;
2016 ALint lChannels, lBytes;
2017 ALint lByteOffset = -1;
2018 ALint lTotalBufferDataSize;
2019 ALenum OriginalFormat;
2021 // Find the first non-NULL Buffer in the Queue
2022 pBufferList = pSource->queue;
2023 while (pBufferList)
2025 if (pBufferList->buffer)
2027 pBuffer = pBufferList->buffer;
2028 break;
2030 pBufferList = pBufferList->next;
2033 if (pBuffer)
2035 flBufferFreq = ((ALfloat)pBuffer->frequency);
2036 lChannels = aluChannelsFromFormat(pBuffer->format);
2037 lBytes = aluBytesFromFormat(pBuffer->format);
2038 OriginalFormat = pBuffer->eOriginalFormat;
2040 // Determine the ByteOffset (and ensure it is block aligned)
2041 switch (pSource->lOffsetType)
2043 case AL_BYTE_OFFSET:
2044 // Take into consideration the original format
2045 if(OriginalFormat == AL_FORMAT_MONO_IMA4 ||
2046 OriginalFormat == AL_FORMAT_STEREO_IMA4)
2048 // Round down to nearest ADPCM block
2049 lByteOffset = pSource->lOffset / (36 * lChannels);
2050 // Multiply by compression rate (65 samples per 36 byte block)
2051 lByteOffset = lByteOffset * 65 * lChannels * lBytes;
2053 else if(OriginalFormat == AL_FORMAT_MONO_MULAW ||
2054 OriginalFormat == AL_FORMAT_STEREO_MULAW ||
2055 OriginalFormat == AL_FORMAT_QUAD_MULAW ||
2056 OriginalFormat == AL_FORMAT_51CHN_MULAW ||
2057 OriginalFormat == AL_FORMAT_61CHN_MULAW ||
2058 OriginalFormat == AL_FORMAT_71CHN_MULAW)
2060 /* muLaw has 1 byte per sample */
2061 lByteOffset = pSource->lOffset / 1 * lBytes;
2063 else if(OriginalFormat == AL_FORMAT_REAR_MULAW)
2065 /* Rear is converted from 2 -> 4 channel */
2066 lByteOffset = pSource->lOffset / 1 * lBytes * 2;
2068 else if(OriginalFormat == AL_FORMAT_REAR8)
2069 lByteOffset = pSource->lOffset / 1 * lBytes * 2;
2070 else if(OriginalFormat == AL_FORMAT_REAR16)
2071 lByteOffset = pSource->lOffset / 2 * lBytes * 2;
2072 else if(OriginalFormat == AL_FORMAT_REAR32)
2073 lByteOffset = pSource->lOffset / 4 * lBytes * 2;
2074 else
2076 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
2077 lByteOffset = pSource->lOffset / OrigBytes * lBytes;
2079 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2080 break;
2082 case AL_SAMPLE_OFFSET:
2083 lByteOffset = pSource->lOffset * lChannels * lBytes;
2084 break;
2086 case AL_SEC_OFFSET:
2087 // Note - lOffset is internally stored as Milliseconds
2088 lByteOffset = (ALint)(pSource->lOffset / 1000.0f * flBufferFreq);
2089 lByteOffset *= lChannels * lBytes;
2090 break;
2093 lTotalBufferDataSize = 0;
2094 pBufferList = pSource->queue;
2095 while (pBufferList)
2097 if (pBufferList->buffer)
2098 lTotalBufferDataSize += pBufferList->buffer->size;
2099 pBufferList = pBufferList->next;
2102 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2103 if (lByteOffset >= lTotalBufferDataSize)
2104 lByteOffset = -1;
2107 // Clear Offset
2108 pSource->lOffset = 0;
2110 return lByteOffset;
2114 ALvoid ReleaseALSources(ALCcontext *Context)
2116 ALuint j;
2118 while(Context->SourceList)
2120 ALsource *temp = Context->SourceList;
2121 Context->SourceList = temp->next;
2123 // For each buffer in the source's queue, decrement its reference counter and remove it
2124 while(temp->queue != NULL)
2126 ALbufferlistitem *ALBufferList = temp->queue;
2127 // Decrement buffer's reference counter
2128 if(ALBufferList->buffer != NULL)
2129 ALBufferList->buffer->refcount--;
2130 // Update queue to point to next element in list
2131 temp->queue = ALBufferList->next;
2132 // Release memory allocated for buffer list item
2133 free(ALBufferList);
2136 for(j = 0;j < MAX_SENDS;++j)
2138 if(temp->Send[j].Slot)
2139 temp->Send[j].Slot->refcount--;
2142 // Release source structure
2143 ALTHUNK_REMOVEENTRY(temp->source);
2144 memset(temp, 0, sizeof(ALsource));
2145 free(temp);
2147 Context->SourceCount = 0;