Avoid some alIs* calls while under the context lock
[openal-soft.git] / OpenAL32 / alSource.c
blobf9c3eddc91b795f1e72cced6bd411f5190b5af93
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 ALboolean 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 ALAPI ALvoid ALAPIENTRY 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 ALAPI ALvoid ALAPIENTRY 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 alSourceStop((ALuint)ALSource->source);
144 // For each buffer in the source's queue, decrement its reference counter and remove it
145 while (ALSource->queue != NULL)
147 ALBufferList = ALSource->queue;
148 // Decrement buffer's reference counter
149 if(ALBufferList->buffer != NULL)
150 ALBufferList->buffer->refcount--;
151 // Update queue to point to next element in list
152 ALSource->queue = ALBufferList->next;
153 // Release memory allocated for buffer list item
154 free(ALBufferList);
157 for(j = 0;j < MAX_SENDS;++j)
159 if(ALSource->Send[j].Slot)
160 ALSource->Send[j].Slot->refcount--;
161 ALSource->Send[j].Slot = NULL;
164 // Decrement Source count
165 Context->SourceCount--;
167 // Remove Source from list of Sources
168 list = &Context->SourceList;
169 while(*list && *list != ALSource)
170 list = &(*list)->next;
172 if(*list)
173 *list = (*list)->next;
174 ALTHUNK_REMOVEENTRY(ALSource->source);
176 memset(ALSource,0,sizeof(ALsource));
177 free(ALSource);
182 else
183 alSetError(Context, AL_INVALID_VALUE);
185 ProcessContext(Context);
189 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
191 ALCcontext *Context;
192 ALboolean result;
194 Context = GetContextSuspended();
195 if(!Context) return AL_FALSE;
197 result = (VerifySource(Context->SourceList, source) ? AL_TRUE : AL_FALSE);
199 ProcessContext(Context);
201 return result;
205 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
207 ALCcontext *pContext;
208 ALsource *pSource;
210 pContext = GetContextSuspended();
211 if(!pContext) return;
213 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
215 switch(eParam)
217 case AL_PITCH:
218 if(flValue >= 0.0f)
220 pSource->flPitch = flValue;
221 if(pSource->flPitch < 0.001f)
222 pSource->flPitch = 0.001f;
223 pSource->NeedsUpdate = AL_TRUE;
225 else
226 alSetError(pContext, AL_INVALID_VALUE);
227 break;
229 case AL_CONE_INNER_ANGLE:
230 if(flValue >= 0.0f && flValue <= 360.0f)
232 pSource->flInnerAngle = flValue;
233 pSource->NeedsUpdate = AL_TRUE;
235 else
236 alSetError(pContext, AL_INVALID_VALUE);
237 break;
239 case AL_CONE_OUTER_ANGLE:
240 if(flValue >= 0.0f && flValue <= 360.0f)
242 pSource->flOuterAngle = flValue;
243 pSource->NeedsUpdate = AL_TRUE;
245 else
246 alSetError(pContext, AL_INVALID_VALUE);
247 break;
249 case AL_GAIN:
250 if(flValue >= 0.0f)
252 pSource->flGain = flValue;
253 pSource->NeedsUpdate = AL_TRUE;
255 else
256 alSetError(pContext, AL_INVALID_VALUE);
257 break;
259 case AL_MAX_DISTANCE:
260 if(flValue >= 0.0f)
262 pSource->flMaxDistance = flValue;
263 pSource->NeedsUpdate = AL_TRUE;
265 else
266 alSetError(pContext, AL_INVALID_VALUE);
267 break;
269 case AL_ROLLOFF_FACTOR:
270 if(flValue >= 0.0f)
272 pSource->flRollOffFactor = flValue;
273 pSource->NeedsUpdate = AL_TRUE;
275 else
276 alSetError(pContext, AL_INVALID_VALUE);
277 break;
279 case AL_REFERENCE_DISTANCE:
280 if(flValue >= 0.0f)
282 pSource->flRefDistance = flValue;
283 pSource->NeedsUpdate = AL_TRUE;
285 else
286 alSetError(pContext, AL_INVALID_VALUE);
287 break;
289 case AL_MIN_GAIN:
290 if(flValue >= 0.0f && flValue <= 1.0f)
292 pSource->flMinGain = flValue;
293 pSource->NeedsUpdate = AL_TRUE;
295 else
296 alSetError(pContext, AL_INVALID_VALUE);
297 break;
299 case AL_MAX_GAIN:
300 if(flValue >= 0.0f && flValue <= 1.0f)
302 pSource->flMaxGain = flValue;
303 pSource->NeedsUpdate = AL_TRUE;
305 else
306 alSetError(pContext, AL_INVALID_VALUE);
307 break;
309 case AL_CONE_OUTER_GAIN:
310 if(flValue >= 0.0f && flValue <= 1.0f)
312 pSource->flOuterGain = flValue;
313 pSource->NeedsUpdate = AL_TRUE;
315 else
316 alSetError(pContext, AL_INVALID_VALUE);
317 break;
319 case AL_CONE_OUTER_GAINHF:
320 if(flValue >= 0.0f && flValue <= 1.0f)
322 pSource->OuterGainHF = flValue;
323 pSource->NeedsUpdate = AL_TRUE;
325 else
326 alSetError(pContext, AL_INVALID_VALUE);
327 break;
329 case AL_AIR_ABSORPTION_FACTOR:
330 if(flValue >= 0.0f && flValue <= 10.0f)
332 pSource->AirAbsorptionFactor = flValue;
333 pSource->NeedsUpdate = AL_TRUE;
335 else
336 alSetError(pContext, AL_INVALID_VALUE);
337 break;
339 case AL_ROOM_ROLLOFF_FACTOR:
340 if(flValue >= 0.0f && flValue <= 10.0f)
342 pSource->RoomRolloffFactor = flValue;
343 pSource->NeedsUpdate = AL_TRUE;
345 else
346 alSetError(pContext, AL_INVALID_VALUE);
347 break;
349 case AL_DOPPLER_FACTOR:
350 if(flValue >= 0.0f && flValue <= 1.0f)
352 pSource->DopplerFactor = flValue;
353 pSource->NeedsUpdate = AL_TRUE;
355 else
356 alSetError(pContext, AL_INVALID_VALUE);
357 break;
359 case AL_SEC_OFFSET:
360 case AL_SAMPLE_OFFSET:
361 case AL_BYTE_OFFSET:
362 if(flValue >= 0.0f)
364 pSource->lOffsetType = eParam;
366 // Store Offset (convert Seconds into Milliseconds)
367 if(eParam == AL_SEC_OFFSET)
368 pSource->lOffset = (ALint)(flValue * 1000.0f);
369 else
370 pSource->lOffset = (ALint)flValue;
372 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
374 if(ApplyOffset(pSource) == AL_FALSE)
375 alSetError(pContext, AL_INVALID_VALUE);
378 else
379 alSetError(pContext, AL_INVALID_VALUE);
380 break;
382 default:
383 alSetError(pContext, AL_INVALID_ENUM);
384 break;
387 else
389 // Invalid Source Name
390 alSetError(pContext, AL_INVALID_NAME);
393 ProcessContext(pContext);
397 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
399 ALCcontext *pContext;
400 ALsource *pSource;
402 pContext = GetContextSuspended();
403 if(!pContext) return;
405 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
407 switch(eParam)
409 case AL_POSITION:
410 pSource->vPosition[0] = flValue1;
411 pSource->vPosition[1] = flValue2;
412 pSource->vPosition[2] = flValue3;
413 pSource->NeedsUpdate = AL_TRUE;
414 break;
416 case AL_VELOCITY:
417 pSource->vVelocity[0] = flValue1;
418 pSource->vVelocity[1] = flValue2;
419 pSource->vVelocity[2] = flValue3;
420 pSource->NeedsUpdate = AL_TRUE;
421 break;
423 case AL_DIRECTION:
424 pSource->vOrientation[0] = flValue1;
425 pSource->vOrientation[1] = flValue2;
426 pSource->vOrientation[2] = flValue3;
427 pSource->NeedsUpdate = AL_TRUE;
428 break;
430 default:
431 alSetError(pContext, AL_INVALID_ENUM);
432 break;
435 else
436 alSetError(pContext, AL_INVALID_NAME);
438 ProcessContext(pContext);
442 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
444 ALCcontext *pContext;
446 pContext = GetContextSuspended();
447 if(!pContext) return;
449 if(pflValues)
451 if(VerifySource(pContext->SourceList, source) != NULL)
453 switch(eParam)
455 case AL_PITCH:
456 case AL_CONE_INNER_ANGLE:
457 case AL_CONE_OUTER_ANGLE:
458 case AL_GAIN:
459 case AL_MAX_DISTANCE:
460 case AL_ROLLOFF_FACTOR:
461 case AL_REFERENCE_DISTANCE:
462 case AL_MIN_GAIN:
463 case AL_MAX_GAIN:
464 case AL_CONE_OUTER_GAIN:
465 case AL_CONE_OUTER_GAINHF:
466 case AL_SEC_OFFSET:
467 case AL_SAMPLE_OFFSET:
468 case AL_BYTE_OFFSET:
469 case AL_AIR_ABSORPTION_FACTOR:
470 case AL_ROOM_ROLLOFF_FACTOR:
471 alSourcef(source, eParam, pflValues[0]);
472 break;
474 case AL_POSITION:
475 case AL_VELOCITY:
476 case AL_DIRECTION:
477 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
478 break;
480 default:
481 alSetError(pContext, AL_INVALID_ENUM);
482 break;
485 else
486 alSetError(pContext, AL_INVALID_NAME);
488 else
489 alSetError(pContext, AL_INVALID_VALUE);
491 ProcessContext(pContext);
495 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
497 ALCcontext *pContext;
498 ALsource *pSource;
499 ALbufferlistitem *pALBufferListItem;
501 pContext = GetContextSuspended();
502 if(!pContext) return;
504 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
506 ALCdevice *device = pContext->Device;
508 switch(eParam)
510 case AL_MAX_DISTANCE:
511 case AL_ROLLOFF_FACTOR:
512 case AL_CONE_INNER_ANGLE:
513 case AL_CONE_OUTER_ANGLE:
514 case AL_REFERENCE_DISTANCE:
515 alSourcef(source, eParam, (ALfloat)lValue);
516 break;
518 case AL_SOURCE_RELATIVE:
519 if(lValue == AL_FALSE || lValue == AL_TRUE)
521 pSource->bHeadRelative = (ALboolean)lValue;
522 pSource->NeedsUpdate = AL_TRUE;
524 else
525 alSetError(pContext, AL_INVALID_VALUE);
526 break;
528 case AL_LOOPING:
529 if(lValue == AL_FALSE || lValue == AL_TRUE)
530 pSource->bLooping = (ALboolean)lValue;
531 else
532 alSetError(pContext, AL_INVALID_VALUE);
533 break;
535 case AL_BUFFER:
536 if(pSource->state == AL_STOPPED || pSource->state == AL_INITIAL)
538 ALbuffer *buffer = NULL;
540 if(lValue == 0 ||
541 (buffer=VerifyBuffer(device->BufferList, lValue)) != NULL)
543 // Remove all elements in the queue
544 while(pSource->queue != NULL)
546 pALBufferListItem = pSource->queue;
547 pSource->queue = pALBufferListItem->next;
548 // Decrement reference counter for buffer
549 if(pALBufferListItem->buffer)
550 pALBufferListItem->buffer->refcount--;
551 // Release memory for buffer list item
552 free(pALBufferListItem);
553 // Decrement the number of buffers in the queue
554 pSource->BuffersInQueue--;
557 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
558 if(lValue != 0)
560 // Source is now in STATIC mode
561 pSource->lSourceType = AL_STATIC;
563 // Add the selected buffer to the queue
564 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
565 pALBufferListItem->buffer = buffer;
566 pALBufferListItem->next = NULL;
568 pSource->queue = pALBufferListItem;
569 pSource->BuffersInQueue = 1;
571 // Increment reference counter for buffer
572 buffer->refcount++;
574 else
576 // Source is now in UNDETERMINED mode
577 pSource->lSourceType = AL_UNDETERMINED;
578 pSource->BuffersPlayed = 0;
581 // Update AL_BUFFER parameter
582 pSource->Buffer = buffer;
583 pSource->NeedsUpdate = AL_TRUE;
585 else
586 alSetError(pContext, AL_INVALID_VALUE);
588 else
589 alSetError(pContext, AL_INVALID_OPERATION);
590 break;
592 case AL_SOURCE_STATE:
593 // Query only
594 alSetError(pContext, AL_INVALID_OPERATION);
595 break;
597 case AL_SEC_OFFSET:
598 case AL_SAMPLE_OFFSET:
599 case AL_BYTE_OFFSET:
600 if(lValue >= 0)
602 pSource->lOffsetType = eParam;
604 // Store Offset (convert Seconds into Milliseconds)
605 if(eParam == AL_SEC_OFFSET)
606 pSource->lOffset = lValue * 1000;
607 else
608 pSource->lOffset = lValue;
610 if(pSource->state == AL_PLAYING || pSource->state == AL_PAUSED)
612 if(ApplyOffset(pSource) == AL_FALSE)
613 alSetError(pContext, AL_INVALID_VALUE);
616 else
617 alSetError(pContext, AL_INVALID_VALUE);
618 break;
620 case AL_DIRECT_FILTER: {
621 ALfilter *filter = NULL;
623 if(lValue == 0 ||
624 (filter=VerifyFilter(pContext->Device->FilterList, lValue)) != NULL)
626 if(!filter)
628 pSource->DirectFilter.type = AL_FILTER_NULL;
629 pSource->DirectFilter.filter = 0;
631 else
632 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
633 pSource->NeedsUpdate = AL_TRUE;
635 else
636 alSetError(pContext, AL_INVALID_VALUE);
637 } break;
639 case AL_DIRECT_FILTER_GAINHF_AUTO:
640 if(lValue == AL_TRUE || lValue == AL_FALSE)
642 pSource->DryGainHFAuto = lValue;
643 pSource->NeedsUpdate = AL_TRUE;
645 else
646 alSetError(pContext, AL_INVALID_VALUE);
647 break;
649 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
650 if(lValue == AL_TRUE || lValue == AL_FALSE)
652 pSource->WetGainAuto = lValue;
653 pSource->NeedsUpdate = AL_TRUE;
655 else
656 alSetError(pContext, AL_INVALID_VALUE);
657 break;
659 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
660 if(lValue == AL_TRUE || lValue == AL_FALSE)
662 pSource->WetGainHFAuto = lValue;
663 pSource->NeedsUpdate = AL_TRUE;
665 else
666 alSetError(pContext, AL_INVALID_VALUE);
667 break;
669 case AL_DISTANCE_MODEL:
670 if(lValue == AL_NONE ||
671 lValue == AL_INVERSE_DISTANCE ||
672 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
673 lValue == AL_LINEAR_DISTANCE ||
674 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
675 lValue == AL_EXPONENT_DISTANCE ||
676 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
678 pSource->DistanceModel = lValue;
679 if(pContext->SourceDistanceModel)
680 pSource->NeedsUpdate = AL_TRUE;
682 else
683 alSetError(pContext, AL_INVALID_VALUE);
684 break;
686 default:
687 alSetError(pContext, AL_INVALID_ENUM);
688 break;
691 else
692 alSetError(pContext, AL_INVALID_NAME);
694 ProcessContext(pContext);
698 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
700 ALCcontext *pContext;
701 ALsource *pSource;
703 pContext = GetContextSuspended();
704 if(!pContext) return;
706 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
708 ALCdevice *device = pContext->Device;
710 switch (eParam)
712 case AL_POSITION:
713 case AL_VELOCITY:
714 case AL_DIRECTION:
715 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
716 break;
718 case AL_AUXILIARY_SEND_FILTER: {
719 ALeffectslot *ALEffectSlot = NULL;
720 ALfilter *ALFilter = NULL;
722 if((ALuint)lValue2 < device->NumAuxSends &&
723 (lValue1 == 0 ||
724 (ALEffectSlot=VerifyEffectSlot(pContext->EffectSlotList, lValue1)) != NULL) &&
725 (lValue3 == 0 ||
726 (ALFilter=VerifyFilter(device->FilterList, lValue3)) != NULL))
728 /* Release refcount on the previous slot, and add one for
729 * the new slot */
730 if(pSource->Send[lValue2].Slot)
731 pSource->Send[lValue2].Slot->refcount--;
732 pSource->Send[lValue2].Slot = ALEffectSlot;
733 if(pSource->Send[lValue2].Slot)
734 pSource->Send[lValue2].Slot->refcount++;
736 if(!ALFilter)
738 /* Disable filter */
739 pSource->Send[lValue2].WetFilter.type = 0;
740 pSource->Send[lValue2].WetFilter.filter = 0;
742 else
743 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
744 pSource->NeedsUpdate = AL_TRUE;
746 else
747 alSetError(pContext, AL_INVALID_VALUE);
748 } break;
750 default:
751 alSetError(pContext, AL_INVALID_ENUM);
752 break;
755 else
756 alSetError(pContext, AL_INVALID_NAME);
758 ProcessContext(pContext);
762 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
764 ALCcontext *pContext;
766 pContext = GetContextSuspended();
767 if(!pContext) return;
769 if(plValues)
771 if(VerifySource(pContext->SourceList, source) != NULL)
773 switch(eParam)
775 case AL_SOURCE_RELATIVE:
776 case AL_CONE_INNER_ANGLE:
777 case AL_CONE_OUTER_ANGLE:
778 case AL_LOOPING:
779 case AL_BUFFER:
780 case AL_SOURCE_STATE:
781 case AL_SEC_OFFSET:
782 case AL_SAMPLE_OFFSET:
783 case AL_BYTE_OFFSET:
784 case AL_MAX_DISTANCE:
785 case AL_ROLLOFF_FACTOR:
786 case AL_REFERENCE_DISTANCE:
787 case AL_DIRECT_FILTER:
788 case AL_DIRECT_FILTER_GAINHF_AUTO:
789 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
790 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
791 case AL_DISTANCE_MODEL:
792 alSourcei(source, eParam, plValues[0]);
793 break;
795 case AL_POSITION:
796 case AL_VELOCITY:
797 case AL_DIRECTION:
798 case AL_AUXILIARY_SEND_FILTER:
799 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
800 break;
802 default:
803 alSetError(pContext, AL_INVALID_ENUM);
804 break;
807 else
808 alSetError(pContext, AL_INVALID_NAME);
810 else
811 alSetError(pContext, AL_INVALID_VALUE);
813 ProcessContext(pContext);
817 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
819 ALCcontext *pContext;
820 ALsource *pSource;
821 ALfloat flOffset[2];
822 ALfloat updateLen;
824 pContext = GetContextSuspended();
825 if(!pContext) return;
827 if(pflValue)
829 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
831 switch(eParam)
833 case AL_PITCH:
834 *pflValue = pSource->flPitch;
835 break;
837 case AL_GAIN:
838 *pflValue = pSource->flGain;
839 break;
841 case AL_MIN_GAIN:
842 *pflValue = pSource->flMinGain;
843 break;
845 case AL_MAX_GAIN:
846 *pflValue = pSource->flMaxGain;
847 break;
849 case AL_MAX_DISTANCE:
850 *pflValue = pSource->flMaxDistance;
851 break;
853 case AL_ROLLOFF_FACTOR:
854 *pflValue = pSource->flRollOffFactor;
855 break;
857 case AL_CONE_OUTER_GAIN:
858 *pflValue = pSource->flOuterGain;
859 break;
861 case AL_CONE_OUTER_GAINHF:
862 *pflValue = pSource->OuterGainHF;
863 break;
865 case AL_SEC_OFFSET:
866 case AL_SAMPLE_OFFSET:
867 case AL_BYTE_OFFSET:
868 updateLen = (ALfloat)pContext->Device->UpdateSize /
869 pContext->Device->Frequency;
870 if(GetSourceOffset(pSource, eParam, flOffset, updateLen))
871 *pflValue = flOffset[0];
872 else
873 alSetError(pContext, AL_INVALID_OPERATION);
874 break;
876 case AL_CONE_INNER_ANGLE:
877 *pflValue = pSource->flInnerAngle;
878 break;
880 case AL_CONE_OUTER_ANGLE:
881 *pflValue = pSource->flOuterAngle;
882 break;
884 case AL_REFERENCE_DISTANCE:
885 *pflValue = pSource->flRefDistance;
886 break;
888 case AL_AIR_ABSORPTION_FACTOR:
889 *pflValue = pSource->AirAbsorptionFactor;
890 break;
892 case AL_ROOM_ROLLOFF_FACTOR:
893 *pflValue = pSource->RoomRolloffFactor;
894 break;
896 case AL_DOPPLER_FACTOR:
897 *pflValue = pSource->DopplerFactor;
898 break;
900 default:
901 alSetError(pContext, AL_INVALID_ENUM);
902 break;
905 else
906 alSetError(pContext, AL_INVALID_NAME);
908 else
909 alSetError(pContext, AL_INVALID_VALUE);
911 ProcessContext(pContext);
915 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
917 ALCcontext *pContext;
918 ALsource *pSource;
920 pContext = GetContextSuspended();
921 if(!pContext) return;
923 if(pflValue1 && pflValue2 && pflValue3)
925 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
927 switch(eParam)
929 case AL_POSITION:
930 *pflValue1 = pSource->vPosition[0];
931 *pflValue2 = pSource->vPosition[1];
932 *pflValue3 = pSource->vPosition[2];
933 break;
935 case AL_VELOCITY:
936 *pflValue1 = pSource->vVelocity[0];
937 *pflValue2 = pSource->vVelocity[1];
938 *pflValue3 = pSource->vVelocity[2];
939 break;
941 case AL_DIRECTION:
942 *pflValue1 = pSource->vOrientation[0];
943 *pflValue2 = pSource->vOrientation[1];
944 *pflValue3 = pSource->vOrientation[2];
945 break;
947 default:
948 alSetError(pContext, AL_INVALID_ENUM);
949 break;
952 else
953 alSetError(pContext, AL_INVALID_NAME);
955 else
956 alSetError(pContext, AL_INVALID_VALUE);
958 ProcessContext(pContext);
962 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
964 ALCcontext *pContext;
965 ALsource *pSource;
966 ALfloat flOffset[2];
967 ALfloat updateLen;
969 pContext = GetContextSuspended();
970 if(!pContext) return;
972 if(pflValues)
974 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
976 switch(eParam)
978 case AL_PITCH:
979 case AL_GAIN:
980 case AL_MIN_GAIN:
981 case AL_MAX_GAIN:
982 case AL_MAX_DISTANCE:
983 case AL_ROLLOFF_FACTOR:
984 case AL_DOPPLER_FACTOR:
985 case AL_CONE_OUTER_GAIN:
986 case AL_SEC_OFFSET:
987 case AL_SAMPLE_OFFSET:
988 case AL_BYTE_OFFSET:
989 case AL_CONE_INNER_ANGLE:
990 case AL_CONE_OUTER_ANGLE:
991 case AL_REFERENCE_DISTANCE:
992 case AL_CONE_OUTER_GAINHF:
993 case AL_AIR_ABSORPTION_FACTOR:
994 case AL_ROOM_ROLLOFF_FACTOR:
995 alGetSourcef(source, eParam, pflValues);
996 break;
998 case AL_SAMPLE_RW_OFFSETS_EXT:
999 case AL_BYTE_RW_OFFSETS_EXT:
1000 updateLen = (ALfloat)pContext->Device->UpdateSize /
1001 pContext->Device->Frequency;
1002 if(GetSourceOffset(pSource, eParam, flOffset, updateLen))
1004 pflValues[0] = flOffset[0];
1005 pflValues[1] = flOffset[1];
1007 else
1008 alSetError(pContext, AL_INVALID_OPERATION);
1009 break;
1011 case AL_POSITION:
1012 pflValues[0] = pSource->vPosition[0];
1013 pflValues[1] = pSource->vPosition[1];
1014 pflValues[2] = pSource->vPosition[2];
1015 break;
1017 case AL_VELOCITY:
1018 pflValues[0] = pSource->vVelocity[0];
1019 pflValues[1] = pSource->vVelocity[1];
1020 pflValues[2] = pSource->vVelocity[2];
1021 break;
1023 case AL_DIRECTION:
1024 pflValues[0] = pSource->vOrientation[0];
1025 pflValues[1] = pSource->vOrientation[1];
1026 pflValues[2] = pSource->vOrientation[2];
1027 break;
1029 default:
1030 alSetError(pContext, AL_INVALID_ENUM);
1031 break;
1034 else
1035 alSetError(pContext, AL_INVALID_NAME);
1037 else
1038 alSetError(pContext, AL_INVALID_VALUE);
1040 ProcessContext(pContext);
1044 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1046 ALCcontext *pContext;
1047 ALsource *pSource;
1048 ALfloat flOffset[2];
1049 ALfloat updateLen;
1051 pContext = GetContextSuspended();
1052 if(!pContext) return;
1054 if(plValue)
1056 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
1058 switch(eParam)
1060 case AL_MAX_DISTANCE:
1061 *plValue = (ALint)pSource->flMaxDistance;
1062 break;
1064 case AL_ROLLOFF_FACTOR:
1065 *plValue = (ALint)pSource->flRollOffFactor;
1066 break;
1068 case AL_REFERENCE_DISTANCE:
1069 *plValue = (ALint)pSource->flRefDistance;
1070 break;
1072 case AL_SOURCE_RELATIVE:
1073 *plValue = pSource->bHeadRelative;
1074 break;
1076 case AL_CONE_INNER_ANGLE:
1077 *plValue = (ALint)pSource->flInnerAngle;
1078 break;
1080 case AL_CONE_OUTER_ANGLE:
1081 *plValue = (ALint)pSource->flOuterAngle;
1082 break;
1084 case AL_LOOPING:
1085 *plValue = pSource->bLooping;
1086 break;
1088 case AL_BUFFER:
1089 *plValue = (pSource->Buffer ? pSource->Buffer->buffer : 0);
1090 break;
1092 case AL_SOURCE_STATE:
1093 *plValue = pSource->state;
1094 break;
1096 case AL_BUFFERS_QUEUED:
1097 *plValue = pSource->BuffersInQueue;
1098 break;
1100 case AL_BUFFERS_PROCESSED:
1101 if(pSource->bLooping)
1103 /* Buffers on a looping source are in a perpetual state
1104 * of PENDING, so don't report any as PROCESSED */
1105 *plValue = 0;
1107 else
1108 *plValue = pSource->BuffersPlayed;
1109 break;
1111 case AL_SOURCE_TYPE:
1112 *plValue = pSource->lSourceType;
1113 break;
1115 case AL_SEC_OFFSET:
1116 case AL_SAMPLE_OFFSET:
1117 case AL_BYTE_OFFSET:
1118 updateLen = (ALfloat)pContext->Device->UpdateSize /
1119 pContext->Device->Frequency;
1120 if(GetSourceOffset(pSource, eParam, flOffset, updateLen))
1121 *plValue = (ALint)flOffset[0];
1122 else
1123 alSetError(pContext, AL_INVALID_OPERATION);
1124 break;
1126 case AL_DIRECT_FILTER:
1127 *plValue = pSource->DirectFilter.filter;
1128 break;
1130 case AL_DIRECT_FILTER_GAINHF_AUTO:
1131 *plValue = pSource->DryGainHFAuto;
1132 break;
1134 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1135 *plValue = pSource->WetGainAuto;
1136 break;
1138 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1139 *plValue = pSource->WetGainHFAuto;
1140 break;
1142 case AL_DOPPLER_FACTOR:
1143 *plValue = (ALint)pSource->DopplerFactor;
1144 break;
1146 case AL_DISTANCE_MODEL:
1147 *plValue = pSource->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 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1167 ALCcontext *pContext;
1168 ALsource *pSource;
1170 pContext = GetContextSuspended();
1171 if(!pContext) return;
1173 if(plValue1 && plValue2 && plValue3)
1175 if((pSource=VerifySource(pContext->SourceList, source)) != NULL)
1177 switch(eParam)
1179 case AL_POSITION:
1180 *plValue1 = (ALint)pSource->vPosition[0];
1181 *plValue2 = (ALint)pSource->vPosition[1];
1182 *plValue3 = (ALint)pSource->vPosition[2];
1183 break;
1185 case AL_VELOCITY:
1186 *plValue1 = (ALint)pSource->vVelocity[0];
1187 *plValue2 = (ALint)pSource->vVelocity[1];
1188 *plValue3 = (ALint)pSource->vVelocity[2];
1189 break;
1191 case AL_DIRECTION:
1192 *plValue1 = (ALint)pSource->vOrientation[0];
1193 *plValue2 = (ALint)pSource->vOrientation[1];
1194 *plValue3 = (ALint)pSource->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 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1214 ALCcontext *pContext;
1215 ALsource *pSource;
1216 ALfloat flOffset[2];
1217 ALfloat updateLen;
1219 pContext = GetContextSuspended();
1220 if(!pContext) return;
1222 if(plValues)
1224 if((pSource=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 if(GetSourceOffset(pSource, eParam, flOffset, updateLen))
1258 plValues[0] = (ALint)flOffset[0];
1259 plValues[1] = (ALint)flOffset[1];
1261 else
1262 alSetError(pContext, AL_INVALID_OPERATION);
1263 break;
1265 case AL_POSITION:
1266 plValues[0] = (ALint)pSource->vPosition[0];
1267 plValues[1] = (ALint)pSource->vPosition[1];
1268 plValues[2] = (ALint)pSource->vPosition[2];
1269 break;
1271 case AL_VELOCITY:
1272 plValues[0] = (ALint)pSource->vVelocity[0];
1273 plValues[1] = (ALint)pSource->vVelocity[1];
1274 plValues[2] = (ALint)pSource->vVelocity[2];
1275 break;
1277 case AL_DIRECTION:
1278 plValues[0] = (ALint)pSource->vOrientation[0];
1279 plValues[1] = (ALint)pSource->vOrientation[1];
1280 plValues[2] = (ALint)pSource->vOrientation[2];
1281 break;
1283 default:
1284 alSetError(pContext, AL_INVALID_ENUM);
1285 break;
1288 else
1289 alSetError(pContext, AL_INVALID_NAME);
1291 else
1292 alSetError(pContext, AL_INVALID_VALUE);
1294 ProcessContext(pContext);
1298 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1300 alSourcePlayv(1, &source);
1303 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1305 ALCcontext *pContext;
1306 ALsource *pSource;
1307 ALbufferlistitem *ALBufferList;
1308 ALboolean bSourcesValid = AL_TRUE;
1309 ALboolean bPlay;
1310 ALsizei i, j;
1312 pContext = GetContextSuspended();
1313 if(!pContext) return;
1315 if(pSourceList)
1317 // Check that all the Sources are valid
1318 for(i = 0; i < n; i++)
1320 if(!VerifySource(pContext->SourceList, pSourceList[i]))
1322 alSetError(pContext, AL_INVALID_NAME);
1323 bSourcesValid = AL_FALSE;
1324 break;
1328 if(bSourcesValid)
1330 for(i = 0; i < n; i++)
1332 // Assume Source won't need to play
1333 bPlay = AL_FALSE;
1335 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]);
1337 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1338 ALBufferList = pSource->queue;
1339 while(ALBufferList)
1341 if(ALBufferList->buffer != NULL && ALBufferList->buffer->size)
1343 bPlay = AL_TRUE;
1344 break;
1346 ALBufferList = ALBufferList->next;
1349 if (bPlay)
1351 for(j = 0;j < OUTPUTCHANNELS;j++)
1352 pSource->DryGains[j] = 0.0f;
1353 for(j = 0;j < MAX_SENDS;j++)
1354 pSource->WetGains[j] = 0.0f;
1356 if(pSource->state != AL_PAUSED)
1358 pSource->state = AL_PLAYING;
1359 pSource->position = 0;
1360 pSource->position_fraction = 0;
1361 pSource->BuffersPlayed = 0;
1363 pSource->Buffer = pSource->queue->buffer;
1365 else
1366 pSource->state = AL_PLAYING;
1368 // Check if an Offset has been set
1369 if(pSource->lOffset)
1370 ApplyOffset(pSource);
1372 if(pSource->BuffersPlayed == 0 && pSource->position == 0 &&
1373 pSource->position_fraction == 0)
1374 pSource->FirstStart = AL_TRUE;
1375 else
1376 pSource->FirstStart = AL_FALSE;
1378 // If device is disconnected, go right to stopped
1379 if(!pContext->Device->Connected)
1381 pSource->state = AL_STOPPED;
1382 pSource->BuffersPlayed = pSource->BuffersInQueue;
1383 pSource->position = 0;
1384 pSource->position_fraction = 0;
1387 else
1388 pSource->BuffersPlayed = pSource->BuffersInQueue;
1392 else
1394 // sources is a NULL pointer
1395 alSetError(pContext, AL_INVALID_VALUE);
1398 ProcessContext(pContext);
1401 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1403 alSourcePausev(1, &source);
1406 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1408 ALCcontext *Context;
1409 ALsource *Source;
1410 ALsizei i;
1411 ALboolean bSourcesValid = AL_TRUE;
1413 Context = GetContextSuspended();
1414 if(!Context) return;
1416 if(sources)
1418 // Check all the Sources are valid
1419 for(i=0;i<n;i++)
1421 if(!VerifySource(Context->SourceList, sources[i]))
1423 alSetError(Context, AL_INVALID_NAME);
1424 bSourcesValid = AL_FALSE;
1425 break;
1429 if(bSourcesValid)
1431 for(i = 0;i < n;i++)
1433 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1434 if(Source->state == AL_PLAYING)
1435 Source->state = AL_PAUSED;
1439 else
1441 // sources is a NULL pointer
1442 alSetError(Context, AL_INVALID_VALUE);
1445 ProcessContext(Context);
1448 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1450 alSourceStopv(1, &source);
1453 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1455 ALCcontext *Context;
1456 ALsource *Source;
1457 ALsizei i;
1458 ALboolean bSourcesValid = AL_TRUE;
1460 Context = GetContextSuspended();
1461 if(!Context) return;
1463 if(sources)
1465 // Check all the Sources are valid
1466 for(i = 0;i < n;i++)
1468 if(!VerifySource(Context->SourceList, sources[i]))
1470 alSetError(Context, AL_INVALID_NAME);
1471 bSourcesValid = AL_FALSE;
1472 break;
1476 if(bSourcesValid)
1478 for(i = 0;i < n;i++)
1480 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1481 if(Source->state != AL_INITIAL)
1483 Source->state = AL_STOPPED;
1484 Source->BuffersPlayed = Source->BuffersInQueue;
1486 Source->lOffset = 0;
1490 else
1492 // sources is a NULL pointer
1493 alSetError(Context, AL_INVALID_VALUE);
1496 ProcessContext(Context);
1499 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1501 alSourceRewindv(1, &source);
1504 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1506 ALCcontext *Context;
1507 ALsource *Source;
1508 ALsizei i;
1509 ALboolean bSourcesValid = AL_TRUE;
1511 Context = GetContextSuspended();
1512 if(!Context) return;
1514 if(sources)
1516 // Check all the Sources are valid
1517 for(i = 0;i < n;i++)
1519 if(!VerifySource(Context->SourceList, sources[i]))
1521 alSetError(Context, AL_INVALID_NAME);
1522 bSourcesValid = AL_FALSE;
1523 break;
1527 if(bSourcesValid)
1529 for(i = 0;i < n;i++)
1531 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1532 if(Source->state != AL_INITIAL)
1534 Source->state = AL_INITIAL;
1535 Source->position = 0;
1536 Source->position_fraction = 0;
1537 Source->BuffersPlayed = 0;
1538 if(Source->queue)
1539 Source->Buffer = Source->queue->buffer;
1541 Source->lOffset = 0;
1545 else
1547 // sources is a NULL pointer
1548 alSetError(Context, AL_INVALID_VALUE);
1551 ProcessContext(Context);
1555 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1557 ALCcontext *Context;
1558 ALsource *ALSource;
1559 ALsizei i;
1560 ALbufferlistitem *ALBufferList;
1561 ALbufferlistitem *ALBufferListStart;
1562 ALint iFrequency;
1563 ALint iFormat;
1564 ALboolean bBuffersValid = AL_TRUE;
1565 ALboolean hadFormat = AL_FALSE;
1567 if (n == 0)
1568 return;
1570 Context = GetContextSuspended();
1571 if(!Context) return;
1573 // Check that all buffers are valid or zero and that the source is valid
1575 // Check that this is a valid source
1576 if((ALSource=VerifySource(Context->SourceList, source)) != NULL)
1578 // Check that this is not a STATIC Source
1579 if(ALSource->lSourceType != AL_STATIC)
1581 ALCdevice *device = Context->Device;
1583 iFrequency = -1;
1584 iFormat = -1;
1586 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1587 ALBufferList = ALSource->queue;
1588 while(ALBufferList)
1590 if (ALBufferList->buffer)
1592 iFrequency = ALBufferList->buffer->frequency;
1593 iFormat = ALBufferList->buffer->format;
1594 hadFormat = AL_TRUE;
1595 break;
1597 ALBufferList = ALBufferList->next;
1600 for(i = 0; i < n; i++)
1602 ALbuffer *buffer;
1604 if(!buffers[i])
1605 continue;
1607 if((buffer=VerifyBuffer(device->BufferList, buffers[i])) == NULL)
1609 alSetError(Context, AL_INVALID_NAME);
1610 bBuffersValid = AL_FALSE;
1611 break;
1614 if(iFrequency == -1 && iFormat == -1)
1616 iFrequency = buffer->frequency;
1617 iFormat = buffer->format;
1619 else if(iFrequency != buffer->frequency ||
1620 iFormat != buffer->format)
1622 alSetError(Context, AL_INVALID_OPERATION);
1623 bBuffersValid = AL_FALSE;
1624 break;
1628 if(bBuffersValid)
1630 ALbuffer *buffer;
1632 // Change Source Type
1633 ALSource->lSourceType = AL_STREAMING;
1635 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1637 // All buffers are valid - so add them to the list
1638 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1639 ALBufferListStart->buffer = buffer;
1640 ALBufferListStart->next = NULL;
1642 // Increment reference counter for buffer
1643 if(buffer) buffer->refcount++;
1645 ALBufferList = ALBufferListStart;
1647 for(i = 1; i < n; i++)
1649 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1651 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1652 ALBufferList->next->buffer = buffer;
1653 ALBufferList->next->next = NULL;
1655 // Increment reference counter for buffer
1656 if(buffer) buffer->refcount++;
1658 ALBufferList = ALBufferList->next;
1661 if(ALSource->queue == NULL)
1663 ALSource->queue = ALBufferListStart;
1664 // Update Current Buffer
1665 ALSource->Buffer = ALBufferListStart->buffer;
1667 else
1669 // Find end of queue
1670 ALBufferList = ALSource->queue;
1671 while(ALBufferList->next != NULL)
1672 ALBufferList = ALBufferList->next;
1674 ALBufferList->next = ALBufferListStart;
1677 // Update number of buffers in queue
1678 ALSource->BuffersInQueue += n;
1679 // If no previous format, mark the source dirty now that it may
1680 // have one
1681 if(!hadFormat)
1682 ALSource->NeedsUpdate = AL_TRUE;
1685 else
1687 // Invalid Source Type (can't queue on a Static Source)
1688 alSetError(Context, AL_INVALID_OPERATION);
1691 else
1693 // Invalid Source Name
1694 alSetError(Context, AL_INVALID_NAME);
1697 ProcessContext(Context);
1701 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1702 // an array of buffer IDs that are to be filled with the names of the buffers removed
1703 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1705 ALCcontext *Context;
1706 ALsource *ALSource;
1707 ALsizei i;
1708 ALbufferlistitem *ALBufferList;
1709 ALboolean bBuffersProcessed;
1711 if (n == 0)
1712 return;
1714 bBuffersProcessed = AL_TRUE;
1716 Context = GetContextSuspended();
1717 if(!Context) return;
1719 if((ALSource=VerifySource(Context->SourceList, source)) != NULL)
1721 // If all 'n' buffers have been processed, remove them from the queue
1722 if(!ALSource->bLooping && (ALuint)n <= ALSource->BuffersPlayed)
1724 for(i = 0; i < n; i++)
1726 ALBufferList = ALSource->queue;
1728 ALSource->queue = ALBufferList->next;
1729 if(ALBufferList->buffer)
1731 // Record name of buffer
1732 buffers[i] = ALBufferList->buffer->buffer;
1733 // Decrement buffer reference counter
1734 ALBufferList->buffer->refcount--;
1736 else
1737 buffers[i] = 0;
1739 // Release memory for buffer list item
1740 free(ALBufferList);
1741 ALSource->BuffersInQueue--;
1744 if(ALSource->state != AL_PLAYING)
1746 if(ALSource->queue)
1747 ALSource->Buffer = ALSource->queue->buffer;
1748 else
1749 ALSource->Buffer = NULL;
1752 ALSource->BuffersPlayed -= n;
1754 else
1756 // Some buffers can't be unqueue because they have not been processed
1757 alSetError(Context, AL_INVALID_VALUE);
1760 else
1762 // Invalid Source Name
1763 alSetError(Context, AL_INVALID_NAME);
1766 ProcessContext(Context);
1770 static ALvoid InitSourceParams(ALsource *pSource)
1772 pSource->flInnerAngle = 360.0f;
1773 pSource->flOuterAngle = 360.0f;
1774 pSource->flPitch = 1.0f;
1775 pSource->vPosition[0] = 0.0f;
1776 pSource->vPosition[1] = 0.0f;
1777 pSource->vPosition[2] = 0.0f;
1778 pSource->vOrientation[0] = 0.0f;
1779 pSource->vOrientation[1] = 0.0f;
1780 pSource->vOrientation[2] = 0.0f;
1781 pSource->vVelocity[0] = 0.0f;
1782 pSource->vVelocity[1] = 0.0f;
1783 pSource->vVelocity[2] = 0.0f;
1784 pSource->flRefDistance = 1.0f;
1785 pSource->flMaxDistance = FLT_MAX;
1786 pSource->flRollOffFactor = 1.0f;
1787 pSource->bLooping = AL_FALSE;
1788 pSource->flGain = 1.0f;
1789 pSource->flMinGain = 0.0f;
1790 pSource->flMaxGain = 1.0f;
1791 pSource->flOuterGain = 0.0f;
1792 pSource->OuterGainHF = 1.0f;
1794 pSource->DryGainHFAuto = AL_TRUE;
1795 pSource->WetGainAuto = AL_TRUE;
1796 pSource->WetGainHFAuto = AL_TRUE;
1797 pSource->AirAbsorptionFactor = 0.0f;
1798 pSource->RoomRolloffFactor = 0.0f;
1799 pSource->DopplerFactor = 1.0f;
1801 pSource->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1803 pSource->Resampler = DefaultResampler;
1805 pSource->state = AL_INITIAL;
1806 pSource->lSourceType = AL_UNDETERMINED;
1808 pSource->NeedsUpdate = AL_TRUE;
1810 pSource->Buffer = NULL;
1815 GetSourceOffset
1817 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1818 The offset is relative to the start of the queue (not the start of the current buffer)
1820 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALfloat updateLen)
1822 ALbufferlistitem *pBufferList;
1823 ALbuffer *pBuffer;
1824 ALfloat flBufferFreq;
1825 ALint lChannels, lBytes;
1826 ALint readPos, writePos;
1827 ALenum eOriginalFormat;
1828 ALboolean bReturn = AL_TRUE;
1829 ALint lTotalBufferDataSize;
1830 ALuint i;
1832 if((pSource->state == AL_PLAYING || pSource->state == AL_PAUSED) && pSource->Buffer)
1834 pBuffer = pSource->Buffer;
1835 // Get Current Buffer Size and frequency (in milliseconds)
1836 flBufferFreq = (ALfloat)pBuffer->frequency;
1837 eOriginalFormat = pBuffer->eOriginalFormat;
1838 lChannels = aluChannelsFromFormat(pBuffer->format);
1839 lBytes = aluBytesFromFormat(pBuffer->format);
1841 // Get Current BytesPlayed
1842 readPos = pSource->position * lChannels * lBytes; // NOTE : This is the byte offset into the *current* buffer
1843 // Add byte length of any processed buffers in the queue
1844 pBufferList = pSource->queue;
1845 for(i = 0;i < pSource->BuffersPlayed && pBufferList;i++)
1847 readPos += pBufferList->buffer->size;
1848 pBufferList = pBufferList->next;
1851 if(pSource->state == AL_PLAYING)
1852 writePos = readPos + ((ALuint)(updateLen*flBufferFreq) * lChannels * lBytes);
1853 else
1854 writePos = readPos;
1856 lTotalBufferDataSize = 0;
1857 pBufferList = pSource->queue;
1858 while (pBufferList)
1860 if (pBufferList->buffer)
1861 lTotalBufferDataSize += pBufferList->buffer->size;
1862 pBufferList = pBufferList->next;
1865 if (pSource->bLooping)
1867 if(readPos < 0)
1868 readPos = 0;
1869 else
1870 readPos %= lTotalBufferDataSize;
1871 if(writePos < 0)
1872 writePos = 0;
1873 else
1874 writePos %= lTotalBufferDataSize;
1876 else
1878 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1879 if(readPos < 0)
1880 readPos = 0;
1881 else if(readPos > lTotalBufferDataSize)
1882 readPos = lTotalBufferDataSize;
1883 if(writePos < 0)
1884 writePos = 0;
1885 else if(writePos > lTotalBufferDataSize)
1886 writePos = lTotalBufferDataSize;
1889 switch (eName)
1891 case AL_SEC_OFFSET:
1892 pflOffset[0] = (ALfloat)readPos / (lChannels * lBytes * flBufferFreq);
1893 pflOffset[1] = (ALfloat)writePos / (lChannels * lBytes * flBufferFreq);
1894 break;
1895 case AL_SAMPLE_OFFSET:
1896 case AL_SAMPLE_RW_OFFSETS_EXT:
1897 pflOffset[0] = (ALfloat)(readPos / (lChannels * lBytes));
1898 pflOffset[1] = (ALfloat)(writePos / (lChannels * lBytes));
1899 break;
1900 case AL_BYTE_OFFSET:
1901 case AL_BYTE_RW_OFFSETS_EXT:
1902 // Take into account the original format of the Buffer
1903 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
1904 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1906 // Round down to nearest ADPCM block
1907 pflOffset[0] = (ALfloat)((readPos / (65 * lBytes * lChannels)) * 36 * lChannels);
1908 if(pSource->state == AL_PLAYING)
1910 // Round up to nearest ADPCM block
1911 pflOffset[1] = (ALfloat)(((writePos + (65 * lBytes * lChannels) - 1) / (65 * lBytes * lChannels)) * 36 * lChannels);
1913 else
1914 pflOffset[1] = pflOffset[0];
1916 else if (eOriginalFormat == AL_FORMAT_REAR8)
1918 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 1);
1919 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 1);
1921 else if (eOriginalFormat == AL_FORMAT_REAR16)
1923 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 2);
1924 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 2);
1926 else if (eOriginalFormat == AL_FORMAT_REAR32)
1928 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 4);
1929 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 4);
1931 else
1933 ALuint OrigBytes = aluBytesFromFormat(eOriginalFormat);
1934 pflOffset[0] = (ALfloat)(readPos / lBytes * OrigBytes);
1935 pflOffset[1] = (ALfloat)(writePos / lBytes * OrigBytes);
1937 break;
1940 else
1942 pflOffset[0] = 0.0f;
1943 pflOffset[1] = 0.0f;
1946 return bReturn;
1951 ApplyOffset
1953 Apply a playback offset to the Source. This function will update the queue (to correctly
1954 mark buffers as 'pending' or 'processed' depending upon the new offset.
1956 static ALboolean ApplyOffset(ALsource *pSource)
1958 ALbufferlistitem *pBufferList;
1959 ALbuffer *pBuffer;
1960 ALint lBufferSize, lTotalBufferSize;
1961 ALint lByteOffset;
1963 // Get true byte offset
1964 lByteOffset = GetByteOffset(pSource);
1966 // If the offset is invalid, don't apply it
1967 if(lByteOffset == -1)
1968 return AL_FALSE;
1970 // Sort out the queue (pending and processed states)
1971 pBufferList = pSource->queue;
1972 lTotalBufferSize = 0;
1973 pSource->BuffersPlayed = 0;
1975 while(pBufferList)
1977 pBuffer = pBufferList->buffer;
1978 lBufferSize = pBuffer ? pBuffer->size : 0;
1980 if(lTotalBufferSize+lBufferSize <= lByteOffset)
1982 // Offset is past this buffer so increment BuffersPlayed
1983 pSource->BuffersPlayed++;
1985 else if(lTotalBufferSize <= lByteOffset)
1987 // Offset is within this buffer
1988 // Set Current Buffer
1989 pSource->Buffer = pBufferList->buffer;
1991 // SW Mixer Positions are in Samples
1992 pSource->position = (lByteOffset - lTotalBufferSize) /
1993 aluBytesFromFormat(pBuffer->format) /
1994 aluChannelsFromFormat(pBuffer->format);
1995 break;
1998 // Increment the TotalBufferSize
1999 lTotalBufferSize += lBufferSize;
2001 // Move on to next buffer in the Queue
2002 pBufferList = pBufferList->next;
2005 return AL_TRUE;
2010 GetByteOffset
2012 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2013 offset supplied by the application). This takes into account the fact that the buffer format
2014 may have been modifed by AL (e.g 8bit samples are converted to float)
2016 static ALint GetByteOffset(ALsource *pSource)
2018 ALbuffer *pBuffer = NULL;
2019 ALbufferlistitem *pBufferList;
2020 ALfloat flBufferFreq;
2021 ALint lChannels, lBytes;
2022 ALint lByteOffset = -1;
2023 ALint lTotalBufferDataSize;
2024 ALenum OriginalFormat;
2026 // Find the first non-NULL Buffer in the Queue
2027 pBufferList = pSource->queue;
2028 while (pBufferList)
2030 if (pBufferList->buffer)
2032 pBuffer = pBufferList->buffer;
2033 break;
2035 pBufferList = pBufferList->next;
2038 if (pBuffer)
2040 flBufferFreq = ((ALfloat)pBuffer->frequency);
2041 lChannels = aluChannelsFromFormat(pBuffer->format);
2042 lBytes = aluBytesFromFormat(pBuffer->format);
2043 OriginalFormat = pBuffer->eOriginalFormat;
2045 // Determine the ByteOffset (and ensure it is block aligned)
2046 switch (pSource->lOffsetType)
2048 case AL_BYTE_OFFSET:
2049 // Take into consideration the original format
2050 if(OriginalFormat == AL_FORMAT_MONO_IMA4 ||
2051 OriginalFormat == AL_FORMAT_STEREO_IMA4)
2053 // Round down to nearest ADPCM block
2054 lByteOffset = pSource->lOffset / (36 * lChannels);
2055 // Multiply by compression rate
2056 lByteOffset = lByteOffset * 65 * lChannels * lBytes;
2057 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2059 else if(OriginalFormat == AL_FORMAT_REAR8)
2061 lByteOffset = pSource->lOffset / 1 * lBytes * 2;
2062 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2064 else if(OriginalFormat == AL_FORMAT_REAR16)
2066 lByteOffset = pSource->lOffset / 2 * lBytes * 2;
2067 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2069 else if(OriginalFormat == AL_FORMAT_REAR32)
2071 lByteOffset = pSource->lOffset / 4 * lBytes * 2;
2072 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2074 else
2076 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
2077 lByteOffset = pSource->lOffset / OrigBytes * lBytes;
2078 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;