Shorten some variable names
[openal-soft.git] / OpenAL32 / alSource.c
blob610e70cba7725ad888ec9c009e6ddcd2acb935ed
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 *Source);
36 static ALvoid GetSourceOffset(ALsource *Source, ALenum eName, ALfloat *pflOffset, ALfloat updateLen);
37 static ALboolean ApplyOffset(ALsource *Source);
38 static ALint GetByteOffset(ALsource *Source);
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 *end;
65 ALsource **list = &Context->SourceList;
66 while(*list)
67 list = &(*list)->next;
69 // Add additional sources to the list (Source->next points to the location for the next Source structure)
70 end = *list;
71 while(i < n)
73 *list = calloc(1, sizeof(ALsource));
74 if(!(*list))
76 while(end->next)
78 ALsource *temp = end->next;
79 end->next = temp->next;
81 ALTHUNK_REMOVEENTRY(temp->source);
82 Context->SourceCount--;
83 free(temp);
85 alSetError(Context, AL_OUT_OF_MEMORY);
86 break;
89 sources[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
90 (*list)->source = sources[i];
92 InitSourceParams(*list);
93 Context->SourceCount++;
94 i++;
96 list = &(*list)->next;
99 else
101 // Not enough resources to create the Sources
102 alSetError(Context, AL_INVALID_VALUE);
105 else
107 // Bad pointer
108 alSetError(Context, AL_INVALID_VALUE);
112 ProcessContext(Context);
116 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
118 ALCcontext *Context;
119 ALCdevice *Device;
120 ALsource *Source;
121 ALsource **list;
122 ALsizei i, j;
123 ALbufferlistitem *BufferList;
124 ALboolean bSourcesValid = AL_TRUE;
126 Context = GetContextSuspended();
127 if(!Context) return;
129 if(n >= 0)
131 Device = Context->Device;
133 // Check that all Sources are valid (and can therefore be deleted)
134 for (i = 0; i < n; i++)
136 if(VerifySource(Context->SourceList, sources[i]) == NULL)
138 alSetError(Context, AL_INVALID_NAME);
139 bSourcesValid = AL_FALSE;
140 break;
144 if(bSourcesValid)
146 // All Sources are valid, and can be deleted
147 for(i = 0; i < n; i++)
149 // Recheck that the Source is valid, because there could be duplicated Source names
150 if((Source=VerifySource(Context->SourceList, sources[i])) != NULL)
152 // For each buffer in the source's queue, decrement its reference counter and remove it
153 while (Source->queue != NULL)
155 BufferList = Source->queue;
156 // Decrement buffer's reference counter
157 if(BufferList->buffer != NULL)
158 BufferList->buffer->refcount--;
159 // Update queue to point to next element in list
160 Source->queue = BufferList->next;
161 // Release memory allocated for buffer list item
162 free(BufferList);
165 for(j = 0;j < MAX_SENDS;++j)
167 if(Source->Send[j].Slot)
168 Source->Send[j].Slot->refcount--;
169 Source->Send[j].Slot = NULL;
172 // Decrement Source count
173 Context->SourceCount--;
175 // Remove Source from list of Sources
176 list = &Context->SourceList;
177 while(*list && *list != Source)
178 list = &(*list)->next;
180 if(*list)
181 *list = (*list)->next;
182 ALTHUNK_REMOVEENTRY(Source->source);
184 memset(Source,0,sizeof(ALsource));
185 free(Source);
190 else
191 alSetError(Context, AL_INVALID_VALUE);
193 ProcessContext(Context);
197 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
199 ALCcontext *Context;
200 ALboolean result;
202 Context = GetContextSuspended();
203 if(!Context) return AL_FALSE;
205 result = (VerifySource(Context->SourceList, source) ? AL_TRUE : AL_FALSE);
207 ProcessContext(Context);
209 return result;
213 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
215 ALCcontext *pContext;
216 ALsource *Source;
218 pContext = GetContextSuspended();
219 if(!pContext) return;
221 if((Source=VerifySource(pContext->SourceList, source)) != NULL)
223 switch(eParam)
225 case AL_PITCH:
226 if(flValue >= 0.0f)
228 Source->flPitch = flValue;
229 if(Source->flPitch < 0.001f)
230 Source->flPitch = 0.001f;
231 Source->NeedsUpdate = AL_TRUE;
233 else
234 alSetError(pContext, AL_INVALID_VALUE);
235 break;
237 case AL_CONE_INNER_ANGLE:
238 if(flValue >= 0.0f && flValue <= 360.0f)
240 Source->flInnerAngle = flValue;
241 Source->NeedsUpdate = AL_TRUE;
243 else
244 alSetError(pContext, AL_INVALID_VALUE);
245 break;
247 case AL_CONE_OUTER_ANGLE:
248 if(flValue >= 0.0f && flValue <= 360.0f)
250 Source->flOuterAngle = flValue;
251 Source->NeedsUpdate = AL_TRUE;
253 else
254 alSetError(pContext, AL_INVALID_VALUE);
255 break;
257 case AL_GAIN:
258 if(flValue >= 0.0f)
260 Source->flGain = flValue;
261 Source->NeedsUpdate = AL_TRUE;
263 else
264 alSetError(pContext, AL_INVALID_VALUE);
265 break;
267 case AL_MAX_DISTANCE:
268 if(flValue >= 0.0f)
270 Source->flMaxDistance = flValue;
271 Source->NeedsUpdate = AL_TRUE;
273 else
274 alSetError(pContext, AL_INVALID_VALUE);
275 break;
277 case AL_ROLLOFF_FACTOR:
278 if(flValue >= 0.0f)
280 Source->flRollOffFactor = flValue;
281 Source->NeedsUpdate = AL_TRUE;
283 else
284 alSetError(pContext, AL_INVALID_VALUE);
285 break;
287 case AL_REFERENCE_DISTANCE:
288 if(flValue >= 0.0f)
290 Source->flRefDistance = flValue;
291 Source->NeedsUpdate = AL_TRUE;
293 else
294 alSetError(pContext, AL_INVALID_VALUE);
295 break;
297 case AL_MIN_GAIN:
298 if(flValue >= 0.0f && flValue <= 1.0f)
300 Source->flMinGain = flValue;
301 Source->NeedsUpdate = AL_TRUE;
303 else
304 alSetError(pContext, AL_INVALID_VALUE);
305 break;
307 case AL_MAX_GAIN:
308 if(flValue >= 0.0f && flValue <= 1.0f)
310 Source->flMaxGain = flValue;
311 Source->NeedsUpdate = AL_TRUE;
313 else
314 alSetError(pContext, AL_INVALID_VALUE);
315 break;
317 case AL_CONE_OUTER_GAIN:
318 if(flValue >= 0.0f && flValue <= 1.0f)
320 Source->flOuterGain = flValue;
321 Source->NeedsUpdate = AL_TRUE;
323 else
324 alSetError(pContext, AL_INVALID_VALUE);
325 break;
327 case AL_CONE_OUTER_GAINHF:
328 if(flValue >= 0.0f && flValue <= 1.0f)
330 Source->OuterGainHF = flValue;
331 Source->NeedsUpdate = AL_TRUE;
333 else
334 alSetError(pContext, AL_INVALID_VALUE);
335 break;
337 case AL_AIR_ABSORPTION_FACTOR:
338 if(flValue >= 0.0f && flValue <= 10.0f)
340 Source->AirAbsorptionFactor = flValue;
341 Source->NeedsUpdate = AL_TRUE;
343 else
344 alSetError(pContext, AL_INVALID_VALUE);
345 break;
347 case AL_ROOM_ROLLOFF_FACTOR:
348 if(flValue >= 0.0f && flValue <= 10.0f)
350 Source->RoomRolloffFactor = flValue;
351 Source->NeedsUpdate = AL_TRUE;
353 else
354 alSetError(pContext, AL_INVALID_VALUE);
355 break;
357 case AL_DOPPLER_FACTOR:
358 if(flValue >= 0.0f && flValue <= 1.0f)
360 Source->DopplerFactor = flValue;
361 Source->NeedsUpdate = AL_TRUE;
363 else
364 alSetError(pContext, AL_INVALID_VALUE);
365 break;
367 case AL_SEC_OFFSET:
368 case AL_SAMPLE_OFFSET:
369 case AL_BYTE_OFFSET:
370 if(flValue >= 0.0f)
372 Source->lOffsetType = eParam;
374 // Store Offset (convert Seconds into Milliseconds)
375 if(eParam == AL_SEC_OFFSET)
376 Source->lOffset = (ALint)(flValue * 1000.0f);
377 else
378 Source->lOffset = (ALint)flValue;
380 if ((Source->state == AL_PLAYING) || (Source->state == AL_PAUSED))
382 if(ApplyOffset(Source) == AL_FALSE)
383 alSetError(pContext, AL_INVALID_VALUE);
386 else
387 alSetError(pContext, AL_INVALID_VALUE);
388 break;
390 default:
391 alSetError(pContext, AL_INVALID_ENUM);
392 break;
395 else
397 // Invalid Source Name
398 alSetError(pContext, AL_INVALID_NAME);
401 ProcessContext(pContext);
405 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
407 ALCcontext *pContext;
408 ALsource *Source;
410 pContext = GetContextSuspended();
411 if(!pContext) return;
413 if((Source=VerifySource(pContext->SourceList, source)) != NULL)
415 switch(eParam)
417 case AL_POSITION:
418 Source->vPosition[0] = flValue1;
419 Source->vPosition[1] = flValue2;
420 Source->vPosition[2] = flValue3;
421 Source->NeedsUpdate = AL_TRUE;
422 break;
424 case AL_VELOCITY:
425 Source->vVelocity[0] = flValue1;
426 Source->vVelocity[1] = flValue2;
427 Source->vVelocity[2] = flValue3;
428 Source->NeedsUpdate = AL_TRUE;
429 break;
431 case AL_DIRECTION:
432 Source->vOrientation[0] = flValue1;
433 Source->vOrientation[1] = flValue2;
434 Source->vOrientation[2] = flValue3;
435 Source->NeedsUpdate = AL_TRUE;
436 break;
438 default:
439 alSetError(pContext, AL_INVALID_ENUM);
440 break;
443 else
444 alSetError(pContext, AL_INVALID_NAME);
446 ProcessContext(pContext);
450 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
452 ALCcontext *pContext;
454 pContext = GetContextSuspended();
455 if(!pContext) return;
457 if(pflValues)
459 if(VerifySource(pContext->SourceList, source) != NULL)
461 switch(eParam)
463 case AL_PITCH:
464 case AL_CONE_INNER_ANGLE:
465 case AL_CONE_OUTER_ANGLE:
466 case AL_GAIN:
467 case AL_MAX_DISTANCE:
468 case AL_ROLLOFF_FACTOR:
469 case AL_REFERENCE_DISTANCE:
470 case AL_MIN_GAIN:
471 case AL_MAX_GAIN:
472 case AL_CONE_OUTER_GAIN:
473 case AL_CONE_OUTER_GAINHF:
474 case AL_SEC_OFFSET:
475 case AL_SAMPLE_OFFSET:
476 case AL_BYTE_OFFSET:
477 case AL_AIR_ABSORPTION_FACTOR:
478 case AL_ROOM_ROLLOFF_FACTOR:
479 alSourcef(source, eParam, pflValues[0]);
480 break;
482 case AL_POSITION:
483 case AL_VELOCITY:
484 case AL_DIRECTION:
485 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
486 break;
488 default:
489 alSetError(pContext, AL_INVALID_ENUM);
490 break;
493 else
494 alSetError(pContext, AL_INVALID_NAME);
496 else
497 alSetError(pContext, AL_INVALID_VALUE);
499 ProcessContext(pContext);
503 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
505 ALCcontext *pContext;
506 ALsource *Source;
507 ALbufferlistitem *BufferListItem;
509 pContext = GetContextSuspended();
510 if(!pContext) return;
512 if((Source=VerifySource(pContext->SourceList, source)) != NULL)
514 ALCdevice *device = pContext->Device;
516 switch(eParam)
518 case AL_MAX_DISTANCE:
519 case AL_ROLLOFF_FACTOR:
520 case AL_CONE_INNER_ANGLE:
521 case AL_CONE_OUTER_ANGLE:
522 case AL_REFERENCE_DISTANCE:
523 alSourcef(source, eParam, (ALfloat)lValue);
524 break;
526 case AL_SOURCE_RELATIVE:
527 if(lValue == AL_FALSE || lValue == AL_TRUE)
529 Source->bHeadRelative = (ALboolean)lValue;
530 Source->NeedsUpdate = AL_TRUE;
532 else
533 alSetError(pContext, AL_INVALID_VALUE);
534 break;
536 case AL_LOOPING:
537 if(lValue == AL_FALSE || lValue == AL_TRUE)
538 Source->bLooping = (ALboolean)lValue;
539 else
540 alSetError(pContext, AL_INVALID_VALUE);
541 break;
543 case AL_BUFFER:
544 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
546 ALbuffer *buffer = NULL;
548 if(lValue == 0 ||
549 (buffer=VerifyBuffer(device->BufferList, lValue)) != NULL)
551 // Remove all elements in the queue
552 while(Source->queue != NULL)
554 BufferListItem = Source->queue;
555 Source->queue = BufferListItem->next;
556 // Decrement reference counter for buffer
557 if(BufferListItem->buffer)
558 BufferListItem->buffer->refcount--;
559 // Release memory for buffer list item
560 free(BufferListItem);
561 // Decrement the number of buffers in the queue
562 Source->BuffersInQueue--;
565 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
566 if(lValue != 0)
568 // Source is now in STATIC mode
569 Source->lSourceType = AL_STATIC;
571 // Add the selected buffer to the queue
572 BufferListItem = malloc(sizeof(ALbufferlistitem));
573 BufferListItem->buffer = buffer;
574 BufferListItem->next = NULL;
576 Source->queue = BufferListItem;
577 Source->BuffersInQueue = 1;
579 // Increment reference counter for buffer
580 buffer->refcount++;
582 else
584 // Source is now in UNDETERMINED mode
585 Source->lSourceType = AL_UNDETERMINED;
586 Source->BuffersPlayed = 0;
589 // Update AL_BUFFER parameter
590 Source->Buffer = buffer;
591 Source->NeedsUpdate = AL_TRUE;
593 else
594 alSetError(pContext, AL_INVALID_VALUE);
596 else
597 alSetError(pContext, AL_INVALID_OPERATION);
598 break;
600 case AL_SOURCE_STATE:
601 // Query only
602 alSetError(pContext, AL_INVALID_OPERATION);
603 break;
605 case AL_SEC_OFFSET:
606 case AL_SAMPLE_OFFSET:
607 case AL_BYTE_OFFSET:
608 if(lValue >= 0)
610 Source->lOffsetType = eParam;
612 // Store Offset (convert Seconds into Milliseconds)
613 if(eParam == AL_SEC_OFFSET)
614 Source->lOffset = lValue * 1000;
615 else
616 Source->lOffset = lValue;
618 if(Source->state == AL_PLAYING || Source->state == AL_PAUSED)
620 if(ApplyOffset(Source) == AL_FALSE)
621 alSetError(pContext, AL_INVALID_VALUE);
624 else
625 alSetError(pContext, AL_INVALID_VALUE);
626 break;
628 case AL_DIRECT_FILTER: {
629 ALfilter *filter = NULL;
631 if(lValue == 0 ||
632 (filter=VerifyFilter(pContext->Device->FilterList, lValue)) != NULL)
634 if(!filter)
636 Source->DirectFilter.type = AL_FILTER_NULL;
637 Source->DirectFilter.filter = 0;
639 else
640 memcpy(&Source->DirectFilter, filter, sizeof(*filter));
641 Source->NeedsUpdate = AL_TRUE;
643 else
644 alSetError(pContext, AL_INVALID_VALUE);
645 } break;
647 case AL_DIRECT_FILTER_GAINHF_AUTO:
648 if(lValue == AL_TRUE || lValue == AL_FALSE)
650 Source->DryGainHFAuto = lValue;
651 Source->NeedsUpdate = AL_TRUE;
653 else
654 alSetError(pContext, AL_INVALID_VALUE);
655 break;
657 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
658 if(lValue == AL_TRUE || lValue == AL_FALSE)
660 Source->WetGainAuto = lValue;
661 Source->NeedsUpdate = AL_TRUE;
663 else
664 alSetError(pContext, AL_INVALID_VALUE);
665 break;
667 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
668 if(lValue == AL_TRUE || lValue == AL_FALSE)
670 Source->WetGainHFAuto = lValue;
671 Source->NeedsUpdate = AL_TRUE;
673 else
674 alSetError(pContext, AL_INVALID_VALUE);
675 break;
677 case AL_DISTANCE_MODEL:
678 if(lValue == AL_NONE ||
679 lValue == AL_INVERSE_DISTANCE ||
680 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
681 lValue == AL_LINEAR_DISTANCE ||
682 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
683 lValue == AL_EXPONENT_DISTANCE ||
684 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
686 Source->DistanceModel = lValue;
687 if(pContext->SourceDistanceModel)
688 Source->NeedsUpdate = AL_TRUE;
690 else
691 alSetError(pContext, AL_INVALID_VALUE);
692 break;
694 default:
695 alSetError(pContext, AL_INVALID_ENUM);
696 break;
699 else
700 alSetError(pContext, AL_INVALID_NAME);
702 ProcessContext(pContext);
706 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
708 ALCcontext *pContext;
709 ALsource *Source;
711 pContext = GetContextSuspended();
712 if(!pContext) return;
714 if((Source=VerifySource(pContext->SourceList, source)) != NULL)
716 ALCdevice *device = pContext->Device;
718 switch (eParam)
720 case AL_POSITION:
721 case AL_VELOCITY:
722 case AL_DIRECTION:
723 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
724 break;
726 case AL_AUXILIARY_SEND_FILTER: {
727 ALeffectslot *ALEffectSlot = NULL;
728 ALfilter *ALFilter = NULL;
730 if((ALuint)lValue2 < device->NumAuxSends &&
731 (lValue1 == 0 ||
732 (ALEffectSlot=VerifyEffectSlot(pContext->EffectSlotList, lValue1)) != NULL) &&
733 (lValue3 == 0 ||
734 (ALFilter=VerifyFilter(device->FilterList, lValue3)) != NULL))
736 /* Release refcount on the previous slot, and add one for
737 * the new slot */
738 if(Source->Send[lValue2].Slot)
739 Source->Send[lValue2].Slot->refcount--;
740 Source->Send[lValue2].Slot = ALEffectSlot;
741 if(Source->Send[lValue2].Slot)
742 Source->Send[lValue2].Slot->refcount++;
744 if(!ALFilter)
746 /* Disable filter */
747 Source->Send[lValue2].WetFilter.type = 0;
748 Source->Send[lValue2].WetFilter.filter = 0;
750 else
751 memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
752 Source->NeedsUpdate = AL_TRUE;
754 else
755 alSetError(pContext, AL_INVALID_VALUE);
756 } break;
758 default:
759 alSetError(pContext, AL_INVALID_ENUM);
760 break;
763 else
764 alSetError(pContext, AL_INVALID_NAME);
766 ProcessContext(pContext);
770 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
772 ALCcontext *pContext;
774 pContext = GetContextSuspended();
775 if(!pContext) return;
777 if(plValues)
779 if(VerifySource(pContext->SourceList, source) != NULL)
781 switch(eParam)
783 case AL_SOURCE_RELATIVE:
784 case AL_CONE_INNER_ANGLE:
785 case AL_CONE_OUTER_ANGLE:
786 case AL_LOOPING:
787 case AL_BUFFER:
788 case AL_SOURCE_STATE:
789 case AL_SEC_OFFSET:
790 case AL_SAMPLE_OFFSET:
791 case AL_BYTE_OFFSET:
792 case AL_MAX_DISTANCE:
793 case AL_ROLLOFF_FACTOR:
794 case AL_REFERENCE_DISTANCE:
795 case AL_DIRECT_FILTER:
796 case AL_DIRECT_FILTER_GAINHF_AUTO:
797 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
798 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
799 case AL_DISTANCE_MODEL:
800 alSourcei(source, eParam, plValues[0]);
801 break;
803 case AL_POSITION:
804 case AL_VELOCITY:
805 case AL_DIRECTION:
806 case AL_AUXILIARY_SEND_FILTER:
807 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
808 break;
810 default:
811 alSetError(pContext, AL_INVALID_ENUM);
812 break;
815 else
816 alSetError(pContext, AL_INVALID_NAME);
818 else
819 alSetError(pContext, AL_INVALID_VALUE);
821 ProcessContext(pContext);
825 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
827 ALCcontext *pContext;
828 ALsource *Source;
829 ALfloat flOffset[2];
830 ALfloat updateLen;
832 pContext = GetContextSuspended();
833 if(!pContext) return;
835 if(pflValue)
837 if((Source=VerifySource(pContext->SourceList, source)) != NULL)
839 switch(eParam)
841 case AL_PITCH:
842 *pflValue = Source->flPitch;
843 break;
845 case AL_GAIN:
846 *pflValue = Source->flGain;
847 break;
849 case AL_MIN_GAIN:
850 *pflValue = Source->flMinGain;
851 break;
853 case AL_MAX_GAIN:
854 *pflValue = Source->flMaxGain;
855 break;
857 case AL_MAX_DISTANCE:
858 *pflValue = Source->flMaxDistance;
859 break;
861 case AL_ROLLOFF_FACTOR:
862 *pflValue = Source->flRollOffFactor;
863 break;
865 case AL_CONE_OUTER_GAIN:
866 *pflValue = Source->flOuterGain;
867 break;
869 case AL_CONE_OUTER_GAINHF:
870 *pflValue = Source->OuterGainHF;
871 break;
873 case AL_SEC_OFFSET:
874 case AL_SAMPLE_OFFSET:
875 case AL_BYTE_OFFSET:
876 updateLen = (ALfloat)pContext->Device->UpdateSize /
877 pContext->Device->Frequency;
878 GetSourceOffset(Source, eParam, flOffset, updateLen);
879 *pflValue = flOffset[0];
880 break;
882 case AL_CONE_INNER_ANGLE:
883 *pflValue = Source->flInnerAngle;
884 break;
886 case AL_CONE_OUTER_ANGLE:
887 *pflValue = Source->flOuterAngle;
888 break;
890 case AL_REFERENCE_DISTANCE:
891 *pflValue = Source->flRefDistance;
892 break;
894 case AL_AIR_ABSORPTION_FACTOR:
895 *pflValue = Source->AirAbsorptionFactor;
896 break;
898 case AL_ROOM_ROLLOFF_FACTOR:
899 *pflValue = Source->RoomRolloffFactor;
900 break;
902 case AL_DOPPLER_FACTOR:
903 *pflValue = Source->DopplerFactor;
904 break;
906 default:
907 alSetError(pContext, AL_INVALID_ENUM);
908 break;
911 else
912 alSetError(pContext, AL_INVALID_NAME);
914 else
915 alSetError(pContext, AL_INVALID_VALUE);
917 ProcessContext(pContext);
921 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
923 ALCcontext *pContext;
924 ALsource *Source;
926 pContext = GetContextSuspended();
927 if(!pContext) return;
929 if(pflValue1 && pflValue2 && pflValue3)
931 if((Source=VerifySource(pContext->SourceList, source)) != NULL)
933 switch(eParam)
935 case AL_POSITION:
936 *pflValue1 = Source->vPosition[0];
937 *pflValue2 = Source->vPosition[1];
938 *pflValue3 = Source->vPosition[2];
939 break;
941 case AL_VELOCITY:
942 *pflValue1 = Source->vVelocity[0];
943 *pflValue2 = Source->vVelocity[1];
944 *pflValue3 = Source->vVelocity[2];
945 break;
947 case AL_DIRECTION:
948 *pflValue1 = Source->vOrientation[0];
949 *pflValue2 = Source->vOrientation[1];
950 *pflValue3 = Source->vOrientation[2];
951 break;
953 default:
954 alSetError(pContext, AL_INVALID_ENUM);
955 break;
958 else
959 alSetError(pContext, AL_INVALID_NAME);
961 else
962 alSetError(pContext, AL_INVALID_VALUE);
964 ProcessContext(pContext);
968 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
970 ALCcontext *pContext;
971 ALsource *Source;
972 ALfloat flOffset[2];
973 ALfloat updateLen;
975 pContext = GetContextSuspended();
976 if(!pContext) return;
978 if(pflValues)
980 if((Source=VerifySource(pContext->SourceList, source)) != NULL)
982 switch(eParam)
984 case AL_PITCH:
985 case AL_GAIN:
986 case AL_MIN_GAIN:
987 case AL_MAX_GAIN:
988 case AL_MAX_DISTANCE:
989 case AL_ROLLOFF_FACTOR:
990 case AL_DOPPLER_FACTOR:
991 case AL_CONE_OUTER_GAIN:
992 case AL_SEC_OFFSET:
993 case AL_SAMPLE_OFFSET:
994 case AL_BYTE_OFFSET:
995 case AL_CONE_INNER_ANGLE:
996 case AL_CONE_OUTER_ANGLE:
997 case AL_REFERENCE_DISTANCE:
998 case AL_CONE_OUTER_GAINHF:
999 case AL_AIR_ABSORPTION_FACTOR:
1000 case AL_ROOM_ROLLOFF_FACTOR:
1001 alGetSourcef(source, eParam, pflValues);
1002 break;
1004 case AL_SAMPLE_RW_OFFSETS_EXT:
1005 case AL_BYTE_RW_OFFSETS_EXT:
1006 updateLen = (ALfloat)pContext->Device->UpdateSize /
1007 pContext->Device->Frequency;
1008 GetSourceOffset(Source, eParam, flOffset, updateLen);
1009 pflValues[0] = flOffset[0];
1010 pflValues[1] = flOffset[1];
1011 break;
1013 case AL_POSITION:
1014 pflValues[0] = Source->vPosition[0];
1015 pflValues[1] = Source->vPosition[1];
1016 pflValues[2] = Source->vPosition[2];
1017 break;
1019 case AL_VELOCITY:
1020 pflValues[0] = Source->vVelocity[0];
1021 pflValues[1] = Source->vVelocity[1];
1022 pflValues[2] = Source->vVelocity[2];
1023 break;
1025 case AL_DIRECTION:
1026 pflValues[0] = Source->vOrientation[0];
1027 pflValues[1] = Source->vOrientation[1];
1028 pflValues[2] = Source->vOrientation[2];
1029 break;
1031 default:
1032 alSetError(pContext, AL_INVALID_ENUM);
1033 break;
1036 else
1037 alSetError(pContext, AL_INVALID_NAME);
1039 else
1040 alSetError(pContext, AL_INVALID_VALUE);
1042 ProcessContext(pContext);
1046 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1048 ALCcontext *pContext;
1049 ALsource *Source;
1050 ALfloat flOffset[2];
1051 ALfloat updateLen;
1053 pContext = GetContextSuspended();
1054 if(!pContext) return;
1056 if(plValue)
1058 if((Source=VerifySource(pContext->SourceList, source)) != NULL)
1060 switch(eParam)
1062 case AL_MAX_DISTANCE:
1063 *plValue = (ALint)Source->flMaxDistance;
1064 break;
1066 case AL_ROLLOFF_FACTOR:
1067 *plValue = (ALint)Source->flRollOffFactor;
1068 break;
1070 case AL_REFERENCE_DISTANCE:
1071 *plValue = (ALint)Source->flRefDistance;
1072 break;
1074 case AL_SOURCE_RELATIVE:
1075 *plValue = Source->bHeadRelative;
1076 break;
1078 case AL_CONE_INNER_ANGLE:
1079 *plValue = (ALint)Source->flInnerAngle;
1080 break;
1082 case AL_CONE_OUTER_ANGLE:
1083 *plValue = (ALint)Source->flOuterAngle;
1084 break;
1086 case AL_LOOPING:
1087 *plValue = Source->bLooping;
1088 break;
1090 case AL_BUFFER:
1091 *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
1092 break;
1094 case AL_SOURCE_STATE:
1095 *plValue = Source->state;
1096 break;
1098 case AL_BUFFERS_QUEUED:
1099 *plValue = Source->BuffersInQueue;
1100 break;
1102 case AL_BUFFERS_PROCESSED:
1103 if(Source->bLooping)
1105 /* Buffers on a looping source are in a perpetual state
1106 * of PENDING, so don't report any as PROCESSED */
1107 *plValue = 0;
1109 else
1110 *plValue = Source->BuffersPlayed;
1111 break;
1113 case AL_SOURCE_TYPE:
1114 *plValue = Source->lSourceType;
1115 break;
1117 case AL_SEC_OFFSET:
1118 case AL_SAMPLE_OFFSET:
1119 case AL_BYTE_OFFSET:
1120 updateLen = (ALfloat)pContext->Device->UpdateSize /
1121 pContext->Device->Frequency;
1122 GetSourceOffset(Source, eParam, flOffset, updateLen);
1123 *plValue = (ALint)flOffset[0];
1124 break;
1126 case AL_DIRECT_FILTER:
1127 *plValue = Source->DirectFilter.filter;
1128 break;
1130 case AL_DIRECT_FILTER_GAINHF_AUTO:
1131 *plValue = Source->DryGainHFAuto;
1132 break;
1134 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1135 *plValue = Source->WetGainAuto;
1136 break;
1138 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1139 *plValue = Source->WetGainHFAuto;
1140 break;
1142 case AL_DOPPLER_FACTOR:
1143 *plValue = (ALint)Source->DopplerFactor;
1144 break;
1146 case AL_DISTANCE_MODEL:
1147 *plValue = Source->DistanceModel;
1148 break;
1150 default:
1151 alSetError(pContext, AL_INVALID_ENUM);
1152 break;
1155 else
1156 alSetError(pContext, AL_INVALID_NAME);
1158 else
1159 alSetError(pContext, AL_INVALID_VALUE);
1161 ProcessContext(pContext);
1165 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1167 ALCcontext *pContext;
1168 ALsource *Source;
1170 pContext = GetContextSuspended();
1171 if(!pContext) return;
1173 if(plValue1 && plValue2 && plValue3)
1175 if((Source=VerifySource(pContext->SourceList, source)) != NULL)
1177 switch(eParam)
1179 case AL_POSITION:
1180 *plValue1 = (ALint)Source->vPosition[0];
1181 *plValue2 = (ALint)Source->vPosition[1];
1182 *plValue3 = (ALint)Source->vPosition[2];
1183 break;
1185 case AL_VELOCITY:
1186 *plValue1 = (ALint)Source->vVelocity[0];
1187 *plValue2 = (ALint)Source->vVelocity[1];
1188 *plValue3 = (ALint)Source->vVelocity[2];
1189 break;
1191 case AL_DIRECTION:
1192 *plValue1 = (ALint)Source->vOrientation[0];
1193 *plValue2 = (ALint)Source->vOrientation[1];
1194 *plValue3 = (ALint)Source->vOrientation[2];
1195 break;
1197 default:
1198 alSetError(pContext, AL_INVALID_ENUM);
1199 break;
1202 else
1203 alSetError(pContext, AL_INVALID_NAME);
1205 else
1206 alSetError(pContext, AL_INVALID_VALUE);
1208 ProcessContext(pContext);
1212 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1214 ALCcontext *pContext;
1215 ALsource *Source;
1216 ALfloat flOffset[2];
1217 ALfloat updateLen;
1219 pContext = GetContextSuspended();
1220 if(!pContext) return;
1222 if(plValues)
1224 if((Source=VerifySource(pContext->SourceList, source)) != NULL)
1226 switch(eParam)
1228 case AL_SOURCE_RELATIVE:
1229 case AL_CONE_INNER_ANGLE:
1230 case AL_CONE_OUTER_ANGLE:
1231 case AL_LOOPING:
1232 case AL_BUFFER:
1233 case AL_SOURCE_STATE:
1234 case AL_BUFFERS_QUEUED:
1235 case AL_BUFFERS_PROCESSED:
1236 case AL_SEC_OFFSET:
1237 case AL_SAMPLE_OFFSET:
1238 case AL_BYTE_OFFSET:
1239 case AL_MAX_DISTANCE:
1240 case AL_ROLLOFF_FACTOR:
1241 case AL_DOPPLER_FACTOR:
1242 case AL_REFERENCE_DISTANCE:
1243 case AL_SOURCE_TYPE:
1244 case AL_DIRECT_FILTER:
1245 case AL_DIRECT_FILTER_GAINHF_AUTO:
1246 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1247 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1248 case AL_DISTANCE_MODEL:
1249 alGetSourcei(source, eParam, plValues);
1250 break;
1252 case AL_SAMPLE_RW_OFFSETS_EXT:
1253 case AL_BYTE_RW_OFFSETS_EXT:
1254 updateLen = (ALfloat)pContext->Device->UpdateSize /
1255 pContext->Device->Frequency;
1256 GetSourceOffset(Source, eParam, flOffset, updateLen);
1257 plValues[0] = (ALint)flOffset[0];
1258 plValues[1] = (ALint)flOffset[1];
1259 break;
1261 case AL_POSITION:
1262 plValues[0] = (ALint)Source->vPosition[0];
1263 plValues[1] = (ALint)Source->vPosition[1];
1264 plValues[2] = (ALint)Source->vPosition[2];
1265 break;
1267 case AL_VELOCITY:
1268 plValues[0] = (ALint)Source->vVelocity[0];
1269 plValues[1] = (ALint)Source->vVelocity[1];
1270 plValues[2] = (ALint)Source->vVelocity[2];
1271 break;
1273 case AL_DIRECTION:
1274 plValues[0] = (ALint)Source->vOrientation[0];
1275 plValues[1] = (ALint)Source->vOrientation[1];
1276 plValues[2] = (ALint)Source->vOrientation[2];
1277 break;
1279 default:
1280 alSetError(pContext, AL_INVALID_ENUM);
1281 break;
1284 else
1285 alSetError(pContext, AL_INVALID_NAME);
1287 else
1288 alSetError(pContext, AL_INVALID_VALUE);
1290 ProcessContext(pContext);
1294 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1296 alSourcePlayv(1, &source);
1299 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1301 ALCcontext *Context;
1302 ALsource *Source;
1303 ALbufferlistitem *BufferList;
1304 ALsizei i, j;
1306 Context = GetContextSuspended();
1307 if(!Context) return;
1309 if(!sources)
1311 alSetError(Context, AL_INVALID_VALUE);
1312 goto done;
1315 // Check that all the Sources are valid
1316 for(i = 0;i < n;i++)
1318 if(!VerifySource(Context->SourceList, sources[i]))
1320 alSetError(Context, AL_INVALID_NAME);
1321 goto done;
1325 for(i = 0;i < n;i++)
1327 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1329 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1330 BufferList = Source->queue;
1331 while(BufferList)
1333 if(BufferList->buffer != NULL && BufferList->buffer->size)
1334 break;
1335 BufferList = BufferList->next;
1338 if(!BufferList)
1340 Source->BuffersPlayed = Source->BuffersInQueue;
1341 continue;
1344 for(j = 0;j < OUTPUTCHANNELS;j++)
1345 Source->DryGains[j] = 0.0f;
1346 for(j = 0;j < MAX_SENDS;j++)
1347 Source->WetGains[j] = 0.0f;
1349 if(Source->state != AL_PAUSED)
1351 Source->state = AL_PLAYING;
1352 Source->position = 0;
1353 Source->position_fraction = 0;
1354 Source->BuffersPlayed = 0;
1356 Source->Buffer = Source->queue->buffer;
1358 else
1359 Source->state = AL_PLAYING;
1361 // Check if an Offset has been set
1362 if(Source->lOffset)
1363 ApplyOffset(Source);
1365 if(Source->BuffersPlayed == 0 && Source->position == 0 &&
1366 Source->position_fraction == 0)
1367 Source->FirstStart = AL_TRUE;
1368 else
1369 Source->FirstStart = AL_FALSE;
1371 // If device is disconnected, go right to stopped
1372 if(!Context->Device->Connected)
1374 Source->state = AL_STOPPED;
1375 Source->BuffersPlayed = Source->BuffersInQueue;
1376 Source->position = 0;
1377 Source->position_fraction = 0;
1381 done:
1382 ProcessContext(Context);
1385 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1387 alSourcePausev(1, &source);
1390 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1392 ALCcontext *Context;
1393 ALsource *Source;
1394 ALsizei i;
1396 Context = GetContextSuspended();
1397 if(!Context) return;
1399 if(!sources)
1401 alSetError(Context, AL_INVALID_VALUE);
1402 goto done;
1405 // Check all the Sources are valid
1406 for(i = 0;i < n;i++)
1408 if(!VerifySource(Context->SourceList, sources[i]))
1410 alSetError(Context, AL_INVALID_NAME);
1411 goto done;
1415 for(i = 0;i < n;i++)
1417 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1418 if(Source->state == AL_PLAYING)
1419 Source->state = AL_PAUSED;
1422 done:
1423 ProcessContext(Context);
1426 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1428 alSourceStopv(1, &source);
1431 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1433 ALCcontext *Context;
1434 ALsource *Source;
1435 ALsizei i;
1437 Context = GetContextSuspended();
1438 if(!Context) return;
1440 if(!sources)
1442 alSetError(Context, AL_INVALID_VALUE);
1443 goto done;
1446 // Check all the Sources are valid
1447 for(i = 0;i < n;i++)
1449 if(!VerifySource(Context->SourceList, sources[i]))
1451 alSetError(Context, AL_INVALID_NAME);
1452 goto done;
1456 for(i = 0;i < n;i++)
1458 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1459 if(Source->state != AL_INITIAL)
1461 Source->state = AL_STOPPED;
1462 Source->BuffersPlayed = Source->BuffersInQueue;
1464 Source->lOffset = 0;
1467 done:
1468 ProcessContext(Context);
1471 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1473 alSourceRewindv(1, &source);
1476 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1478 ALCcontext *Context;
1479 ALsource *Source;
1480 ALsizei i;
1482 Context = GetContextSuspended();
1483 if(!Context) return;
1485 if(!sources)
1487 alSetError(Context, AL_INVALID_VALUE);
1488 goto done;
1491 // Check all the Sources are valid
1492 for(i = 0;i < n;i++)
1494 if(!VerifySource(Context->SourceList, sources[i]))
1496 alSetError(Context, AL_INVALID_NAME);
1497 goto done;
1501 for(i = 0;i < n;i++)
1503 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1504 if(Source->state != AL_INITIAL)
1506 Source->state = AL_INITIAL;
1507 Source->position = 0;
1508 Source->position_fraction = 0;
1509 Source->BuffersPlayed = 0;
1510 if(Source->queue)
1511 Source->Buffer = Source->queue->buffer;
1513 Source->lOffset = 0;
1516 done:
1517 ProcessContext(Context);
1521 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1523 ALCcontext *Context;
1524 ALCdevice *device;
1525 ALsource *Source;
1526 ALbuffer *buffer;
1527 ALsizei i;
1528 ALbufferlistitem *BufferListStart;
1529 ALbufferlistitem *BufferList;
1530 ALboolean HadFormat;
1531 ALint Frequency;
1532 ALint Format;
1534 if(n == 0)
1535 return;
1537 Context = GetContextSuspended();
1538 if(!Context) return;
1540 // Check that all buffers are valid or zero and that the source is valid
1542 // Check that this is a valid source
1543 if((Source=VerifySource(Context->SourceList, source)) == NULL)
1545 alSetError(Context, AL_INVALID_NAME);
1546 goto done;
1549 // Check that this is not a STATIC Source
1550 if(Source->lSourceType == AL_STATIC)
1552 // Invalid Source Type (can't queue on a Static Source)
1553 alSetError(Context, AL_INVALID_OPERATION);
1554 goto done;
1557 device = Context->Device;
1559 Frequency = -1;
1560 Format = -1;
1561 HadFormat = AL_FALSE;
1563 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1564 BufferList = Source->queue;
1565 while(BufferList)
1567 if(BufferList->buffer)
1569 Frequency = BufferList->buffer->frequency;
1570 Format = BufferList->buffer->format;
1571 HadFormat = AL_TRUE;
1572 break;
1574 BufferList = BufferList->next;
1577 for(i = 0;i < n;i++)
1579 if(!buffers[i])
1580 continue;
1582 if((buffer=VerifyBuffer(device->BufferList, buffers[i])) == NULL)
1584 alSetError(Context, AL_INVALID_NAME);
1585 goto done;
1588 if(Frequency == -1 && Format == -1)
1590 Frequency = buffer->frequency;
1591 Format = buffer->format;
1593 else if(Frequency != buffer->frequency || Format != buffer->format)
1595 alSetError(Context, AL_INVALID_OPERATION);
1596 goto done;
1600 // Change Source Type
1601 Source->lSourceType = AL_STREAMING;
1603 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1605 // All buffers are valid - so add them to the list
1606 BufferListStart = malloc(sizeof(ALbufferlistitem));
1607 BufferListStart->buffer = buffer;
1608 BufferListStart->next = NULL;
1610 // Increment reference counter for buffer
1611 if(buffer) buffer->refcount++;
1613 BufferList = BufferListStart;
1615 for(i = 1;i < n;i++)
1617 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1619 BufferList->next = malloc(sizeof(ALbufferlistitem));
1620 BufferList->next->buffer = buffer;
1621 BufferList->next->next = NULL;
1623 // Increment reference counter for buffer
1624 if(buffer) buffer->refcount++;
1626 BufferList = BufferList->next;
1629 if(Source->queue == NULL)
1631 Source->queue = BufferListStart;
1632 // Update Current Buffer
1633 Source->Buffer = BufferListStart->buffer;
1635 else
1637 // Find end of queue
1638 BufferList = Source->queue;
1639 while(BufferList->next != NULL)
1640 BufferList = BufferList->next;
1642 BufferList->next = BufferListStart;
1645 // Update number of buffers in queue
1646 Source->BuffersInQueue += n;
1647 // If no previous format, mark the source dirty now that it may have one
1648 if(!HadFormat)
1649 Source->NeedsUpdate = AL_TRUE;
1651 done:
1652 ProcessContext(Context);
1656 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1657 // an array of buffer IDs that are to be filled with the names of the buffers removed
1658 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1660 ALCcontext *Context;
1661 ALsource *Source;
1662 ALsizei i;
1663 ALbufferlistitem *BufferList;
1665 if(n == 0)
1666 return;
1668 Context = GetContextSuspended();
1669 if(!Context) return;
1671 if((Source=VerifySource(Context->SourceList, source)) == NULL)
1673 alSetError(Context, AL_INVALID_NAME);
1674 goto done;
1677 if(Source->bLooping || (ALuint)n > Source->BuffersPlayed)
1679 // Some buffers can't be unqueue because they have not been processed
1680 alSetError(Context, AL_INVALID_VALUE);
1681 goto done;
1684 for(i = 0;i < n;i++)
1686 BufferList = Source->queue;
1687 Source->queue = BufferList->next;
1689 if(BufferList->buffer)
1691 // Record name of buffer
1692 buffers[i] = BufferList->buffer->buffer;
1693 // Decrement buffer reference counter
1694 BufferList->buffer->refcount--;
1696 else
1697 buffers[i] = 0;
1699 // Release memory for buffer list item
1700 free(BufferList);
1701 Source->BuffersInQueue--;
1704 if(Source->state != AL_PLAYING)
1706 if(Source->queue)
1707 Source->Buffer = Source->queue->buffer;
1708 else
1709 Source->Buffer = NULL;
1711 Source->BuffersPlayed -= n;
1713 done:
1714 ProcessContext(Context);
1718 static ALvoid InitSourceParams(ALsource *Source)
1720 Source->flInnerAngle = 360.0f;
1721 Source->flOuterAngle = 360.0f;
1722 Source->flPitch = 1.0f;
1723 Source->vPosition[0] = 0.0f;
1724 Source->vPosition[1] = 0.0f;
1725 Source->vPosition[2] = 0.0f;
1726 Source->vOrientation[0] = 0.0f;
1727 Source->vOrientation[1] = 0.0f;
1728 Source->vOrientation[2] = 0.0f;
1729 Source->vVelocity[0] = 0.0f;
1730 Source->vVelocity[1] = 0.0f;
1731 Source->vVelocity[2] = 0.0f;
1732 Source->flRefDistance = 1.0f;
1733 Source->flMaxDistance = FLT_MAX;
1734 Source->flRollOffFactor = 1.0f;
1735 Source->bLooping = AL_FALSE;
1736 Source->flGain = 1.0f;
1737 Source->flMinGain = 0.0f;
1738 Source->flMaxGain = 1.0f;
1739 Source->flOuterGain = 0.0f;
1740 Source->OuterGainHF = 1.0f;
1742 Source->DryGainHFAuto = AL_TRUE;
1743 Source->WetGainAuto = AL_TRUE;
1744 Source->WetGainHFAuto = AL_TRUE;
1745 Source->AirAbsorptionFactor = 0.0f;
1746 Source->RoomRolloffFactor = 0.0f;
1747 Source->DopplerFactor = 1.0f;
1749 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1751 Source->Resampler = DefaultResampler;
1753 Source->state = AL_INITIAL;
1754 Source->lSourceType = AL_UNDETERMINED;
1756 Source->NeedsUpdate = AL_TRUE;
1758 Source->Buffer = NULL;
1763 GetSourceOffset
1765 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1766 The offset is relative to the start of the queue (not the start of the current buffer)
1768 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALfloat *offset, ALfloat updateLen)
1770 ALbufferlistitem *BufferList;
1771 ALbuffer *Buffer;
1772 ALfloat BufferFreq;
1773 ALint Channels, Bytes;
1774 ALint readPos, writePos;
1775 ALenum OriginalFormat;
1776 ALint TotalBufferDataSize;
1777 ALuint i;
1779 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) ||
1780 !Source->Buffer)
1782 offset[0] = 0.0f;
1783 offset[1] = 0.0f;
1784 return;
1787 Buffer = Source->Buffer;
1789 // Get Current Buffer Size and frequency (in milliseconds)
1790 BufferFreq = (ALfloat)Buffer->frequency;
1791 OriginalFormat = Buffer->eOriginalFormat;
1792 Channels = aluChannelsFromFormat(Buffer->format);
1793 Bytes = aluBytesFromFormat(Buffer->format);
1795 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1796 readPos = Source->position * Channels * Bytes;
1797 // Add byte length of any processed buffers in the queue
1798 BufferList = Source->queue;
1799 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
1801 readPos += BufferList->buffer->size;
1802 BufferList = BufferList->next;
1805 if(Source->state == AL_PLAYING)
1806 writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
1807 else
1808 writePos = readPos;
1810 TotalBufferDataSize = 0;
1811 BufferList = Source->queue;
1812 while(BufferList)
1814 if(BufferList->buffer)
1815 TotalBufferDataSize += BufferList->buffer->size;
1816 BufferList = BufferList->next;
1819 if(Source->bLooping)
1821 readPos %= TotalBufferDataSize;
1822 writePos %= TotalBufferDataSize;
1824 else
1826 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1827 if(readPos < 0)
1828 readPos = 0;
1829 else if(readPos > TotalBufferDataSize)
1830 readPos = TotalBufferDataSize;
1831 if(writePos < 0)
1832 writePos = 0;
1833 else if(writePos > TotalBufferDataSize)
1834 writePos = TotalBufferDataSize;
1837 switch(name)
1839 case AL_SEC_OFFSET:
1840 offset[0] = (ALfloat)readPos / (Channels * Bytes * BufferFreq);
1841 offset[1] = (ALfloat)writePos / (Channels * Bytes * BufferFreq);
1842 break;
1843 case AL_SAMPLE_OFFSET:
1844 case AL_SAMPLE_RW_OFFSETS_EXT:
1845 offset[0] = (ALfloat)(readPos / (Channels * Bytes));
1846 offset[1] = (ALfloat)(writePos / (Channels * Bytes));
1847 break;
1848 case AL_BYTE_OFFSET:
1849 case AL_BYTE_RW_OFFSETS_EXT:
1850 // Take into account the original format of the Buffer
1851 if((OriginalFormat == AL_FORMAT_MONO_IMA4) ||
1852 (OriginalFormat == AL_FORMAT_STEREO_IMA4))
1854 // Round down to nearest ADPCM block
1855 offset[0] = (ALfloat)((readPos / (65 * Bytes * Channels)) * 36 * Channels);
1856 if(Source->state == AL_PLAYING)
1858 // Round up to nearest ADPCM block
1859 offset[1] = (ALfloat)(((writePos + (65 * Bytes * Channels) - 1) / (65 * Bytes * Channels)) * 36 * Channels);
1861 else
1862 offset[1] = offset[0];
1864 else if(OriginalFormat == AL_FORMAT_MONO_MULAW ||
1865 OriginalFormat == AL_FORMAT_STEREO_MULAW ||
1866 OriginalFormat == AL_FORMAT_QUAD_MULAW ||
1867 OriginalFormat == AL_FORMAT_51CHN_MULAW ||
1868 OriginalFormat == AL_FORMAT_61CHN_MULAW ||
1869 OriginalFormat == AL_FORMAT_71CHN_MULAW)
1871 offset[0] = (ALfloat)(readPos / Bytes * 1);
1872 offset[1] = (ALfloat)(writePos / Bytes * 1);
1874 else if(OriginalFormat == AL_FORMAT_REAR_MULAW)
1876 offset[0] = (ALfloat)(readPos / 2 / Bytes * 1);
1877 offset[1] = (ALfloat)(writePos / 2 / Bytes * 1);
1879 else if(OriginalFormat == AL_FORMAT_REAR8)
1881 offset[0] = (ALfloat)(readPos / 2 / Bytes * 1);
1882 offset[1] = (ALfloat)(writePos / 2 / Bytes * 1);
1884 else if(OriginalFormat == AL_FORMAT_REAR16)
1886 offset[0] = (ALfloat)(readPos / 2 / Bytes * 2);
1887 offset[1] = (ALfloat)(writePos / 2 / Bytes * 2);
1889 else if(OriginalFormat == AL_FORMAT_REAR32)
1891 offset[0] = (ALfloat)(readPos / 2 / Bytes * 4);
1892 offset[1] = (ALfloat)(writePos / 2 / Bytes * 4);
1894 else
1896 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
1897 offset[0] = (ALfloat)(readPos / Bytes * OrigBytes);
1898 offset[1] = (ALfloat)(writePos / Bytes * OrigBytes);
1900 break;
1906 ApplyOffset
1908 Apply a playback offset to the Source. This function will update the queue (to correctly
1909 mark buffers as 'pending' or 'processed' depending upon the new offset.
1911 static ALboolean ApplyOffset(ALsource *Source)
1913 ALbufferlistitem *BufferList;
1914 ALbuffer *Buffer;
1915 ALint lBufferSize, lTotalBufferSize;
1916 ALint lByteOffset;
1918 // Get true byte offset
1919 lByteOffset = GetByteOffset(Source);
1921 // If the offset is invalid, don't apply it
1922 if(lByteOffset == -1)
1923 return AL_FALSE;
1925 // Sort out the queue (pending and processed states)
1926 BufferList = Source->queue;
1927 lTotalBufferSize = 0;
1928 Source->BuffersPlayed = 0;
1930 while(BufferList)
1932 Buffer = BufferList->buffer;
1933 lBufferSize = Buffer ? Buffer->size : 0;
1935 if(lTotalBufferSize+lBufferSize <= lByteOffset)
1937 // Offset is past this buffer so increment BuffersPlayed
1938 Source->BuffersPlayed++;
1940 else if(lTotalBufferSize <= lByteOffset)
1942 // Offset is within this buffer
1943 // Set Current Buffer
1944 Source->Buffer = BufferList->buffer;
1946 // SW Mixer Positions are in Samples
1947 Source->position = (lByteOffset - lTotalBufferSize) /
1948 aluBytesFromFormat(Buffer->format) /
1949 aluChannelsFromFormat(Buffer->format);
1950 break;
1953 // Increment the TotalBufferSize
1954 lTotalBufferSize += lBufferSize;
1956 // Move on to next buffer in the Queue
1957 BufferList = BufferList->next;
1960 return AL_TRUE;
1965 GetByteOffset
1967 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1968 offset supplied by the application). This takes into account the fact that the buffer format
1969 may have been modifed by AL (e.g 8bit samples are converted to float)
1971 static ALint GetByteOffset(ALsource *Source)
1973 ALbuffer *Buffer = NULL;
1974 ALbufferlistitem *BufferList;
1975 ALfloat BufferFreq;
1976 ALint Channels, Bytes;
1977 ALint ByteOffset = -1;
1978 ALint TotalBufferDataSize;
1979 ALenum OriginalFormat;
1981 // Find the first non-NULL Buffer in the Queue
1982 BufferList = Source->queue;
1983 while(BufferList)
1985 if(BufferList->buffer)
1987 Buffer = BufferList->buffer;
1988 break;
1990 BufferList = BufferList->next;
1993 if(!Buffer)
1995 Source->lOffset = 0;
1996 return -1;
1999 BufferFreq = ((ALfloat)Buffer->frequency);
2000 Channels = aluChannelsFromFormat(Buffer->format);
2001 Bytes = aluBytesFromFormat(Buffer->format);
2002 OriginalFormat = Buffer->eOriginalFormat;
2004 // Determine the ByteOffset (and ensure it is block aligned)
2005 switch(Source->lOffsetType)
2007 case AL_BYTE_OFFSET:
2008 // Take into consideration the original format
2009 if(OriginalFormat == AL_FORMAT_MONO_IMA4 ||
2010 OriginalFormat == AL_FORMAT_STEREO_IMA4)
2012 // Round down to nearest ADPCM block
2013 ByteOffset = Source->lOffset / (36 * Channels);
2014 // Multiply by compression rate (65 samples per 36 byte block)
2015 ByteOffset = ByteOffset * 65 * Channels * Bytes;
2017 else if(OriginalFormat == AL_FORMAT_MONO_MULAW ||
2018 OriginalFormat == AL_FORMAT_STEREO_MULAW ||
2019 OriginalFormat == AL_FORMAT_QUAD_MULAW ||
2020 OriginalFormat == AL_FORMAT_51CHN_MULAW ||
2021 OriginalFormat == AL_FORMAT_61CHN_MULAW ||
2022 OriginalFormat == AL_FORMAT_71CHN_MULAW)
2024 /* muLaw has 1 byte per sample */
2025 ByteOffset = Source->lOffset / 1 * Bytes;
2027 else if(OriginalFormat == AL_FORMAT_REAR_MULAW)
2029 /* Rear is converted from 2 -> 4 channel */
2030 ByteOffset = Source->lOffset / 1 * Bytes * 2;
2032 else if(OriginalFormat == AL_FORMAT_REAR8)
2033 ByteOffset = Source->lOffset / 1 * Bytes * 2;
2034 else if(OriginalFormat == AL_FORMAT_REAR16)
2035 ByteOffset = Source->lOffset / 2 * Bytes * 2;
2036 else if(OriginalFormat == AL_FORMAT_REAR32)
2037 ByteOffset = Source->lOffset / 4 * Bytes * 2;
2038 else
2040 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
2041 ByteOffset = Source->lOffset / OrigBytes * Bytes;
2043 ByteOffset -= (ByteOffset % (Channels * Bytes));
2044 break;
2046 case AL_SAMPLE_OFFSET:
2047 ByteOffset = Source->lOffset * Channels * Bytes;
2048 break;
2050 case AL_SEC_OFFSET:
2051 // Note - lOffset is internally stored as Milliseconds
2052 ByteOffset = (ALint)(Source->lOffset / 1000.0f * BufferFreq);
2053 ByteOffset *= Channels * Bytes;
2054 break;
2056 // Clear Offset
2057 Source->lOffset = 0;
2059 TotalBufferDataSize = 0;
2060 BufferList = Source->queue;
2061 while(BufferList)
2063 if(BufferList->buffer)
2064 TotalBufferDataSize += BufferList->buffer->size;
2065 BufferList = BufferList->next;
2068 // Finally, if the ByteOffset is beyond the length of all the buffers in
2069 // the queue, return -1
2070 if(ByteOffset >= TotalBufferDataSize)
2071 return -1;
2072 return ByteOffset;
2076 ALvoid ReleaseALSources(ALCcontext *Context)
2078 ALuint j;
2080 while(Context->SourceList)
2082 ALsource *temp = Context->SourceList;
2083 Context->SourceList = temp->next;
2085 // For each buffer in the source's queue, decrement its reference counter and remove it
2086 while(temp->queue != NULL)
2088 ALbufferlistitem *BufferList = temp->queue;
2089 // Decrement buffer's reference counter
2090 if(BufferList->buffer != NULL)
2091 BufferList->buffer->refcount--;
2092 // Update queue to point to next element in list
2093 temp->queue = BufferList->next;
2094 // Release memory allocated for buffer list item
2095 free(BufferList);
2098 for(j = 0;j < MAX_SENDS;++j)
2100 if(temp->Send[j].Slot)
2101 temp->Send[j].Slot->refcount--;
2104 // Release source structure
2105 ALTHUNK_REMOVEENTRY(temp->source);
2106 memset(temp, 0, sizeof(ALsource));
2107 free(temp);
2109 Context->SourceCount = 0;