Store the buffer handle directly in the source and buffer queue list
[openal-soft.git] / OpenAL32 / alSource.c
blob6d5e1dd9059f290457c1599c853c1c4b908bef45
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(ALCcontext *Context, ALsource *pSource);
36 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize);
37 static ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext);
38 static ALint GetByteOffset(ALsource *pSource);
40 ALAPI ALvoid ALAPIENTRY alGenSources(ALsizei n,ALuint *sources)
42 ALCcontext *Context;
43 ALCdevice *Device;
44 ALsizei i=0;
46 Context = GetContextSuspended();
47 if(!Context) return;
49 if(n > 0)
51 Device = Context->Device;
53 // Check that enough memory has been allocted in the 'sources' array for n Sources
54 if(!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
56 // Check that the requested number of sources can be generated
57 if((Context->SourceCount + n) <= Device->MaxNoOfSources)
59 ALsource **list = &Context->Source;
60 while(*list)
61 list = &(*list)->next;
63 // Add additional sources to the list (Source->next points to the location for the next Source structure)
64 while(i < n)
66 *list = calloc(1, sizeof(ALsource));
67 if(!(*list))
69 alDeleteSources(i, sources);
70 alSetError(AL_OUT_OF_MEMORY);
71 break;
74 sources[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
75 (*list)->source = sources[i];
77 InitSourceParams(Context, *list);
78 Context->SourceCount++;
79 i++;
81 list = &(*list)->next;
84 else
86 // Not enough resources to create the Sources
87 alSetError(AL_INVALID_VALUE);
90 else
92 // Bad pointer
93 alSetError(AL_INVALID_VALUE);
97 ProcessContext(Context);
101 ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
103 ALCcontext *Context;
104 ALCdevice *Device;
105 ALsource *ALSource;
106 ALsource **list;
107 ALsizei i, j;
108 ALbufferlistitem *ALBufferList;
109 ALboolean bSourcesValid = AL_TRUE;
111 Context = GetContextSuspended();
112 if(!Context) return;
114 if(n >= 0)
116 Device = Context->Device;
118 // Check that all Sources are valid (and can therefore be deleted)
119 for (i = 0; i < n; i++)
121 if (!alIsSource(sources[i]))
123 alSetError(AL_INVALID_NAME);
124 bSourcesValid = AL_FALSE;
125 break;
129 if(bSourcesValid)
131 // All Sources are valid, and can be deleted
132 for(i = 0; i < n; i++)
134 // Recheck that the Source is valid, because there could be duplicated Source names
135 if(alIsSource(sources[i]))
137 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
138 alSourceStop((ALuint)ALSource->source);
140 // For each buffer in the source's queue, decrement its reference counter and remove it
141 while (ALSource->queue != NULL)
143 ALBufferList = ALSource->queue;
144 // Decrement buffer's reference counter
145 if(ALBufferList->buffer != NULL)
146 ALBufferList->buffer->refcount--;
147 // Update queue to point to next element in list
148 ALSource->queue = ALBufferList->next;
149 // Release memory allocated for buffer list item
150 free(ALBufferList);
153 for(j = 0;j < MAX_SENDS;++j)
155 if(ALSource->Send[j].Slot)
156 ALSource->Send[j].Slot->refcount--;
157 ALSource->Send[j].Slot = NULL;
160 // Decrement Source count
161 Context->SourceCount--;
163 // Remove Source from list of Sources
164 list = &Context->Source;
165 while(*list && *list != ALSource)
166 list = &(*list)->next;
168 if(*list)
169 *list = (*list)->next;
170 ALTHUNK_REMOVEENTRY(ALSource->source);
172 memset(ALSource,0,sizeof(ALsource));
173 free(ALSource);
178 else
179 alSetError(AL_INVALID_VALUE);
181 ProcessContext(Context);
185 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
187 ALboolean result=AL_FALSE;
188 ALCcontext *Context;
189 ALsource *Source;
191 Context = GetContextSuspended();
192 if(!Context) return AL_FALSE;
194 // To determine if this is a valid Source name, look through the list of generated Sources
195 Source = Context->Source;
196 while(Source)
198 if(Source->source == source)
200 result = AL_TRUE;
201 break;
204 Source = Source->next;
207 ProcessContext(Context);
209 return result;
213 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
215 ALCcontext *pContext;
216 ALsource *pSource;
218 pContext = GetContextSuspended();
219 if(!pContext) return;
221 if(alIsSource(source))
223 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
225 switch(eParam)
227 case AL_PITCH:
228 if(flValue >= 0.0f)
230 pSource->flPitch = flValue;
231 if(pSource->flPitch < 0.001f)
232 pSource->flPitch = 0.001f;
234 else
235 alSetError(AL_INVALID_VALUE);
236 break;
238 case AL_CONE_INNER_ANGLE:
239 if(flValue >= 0.0f && flValue <= 360.0f)
240 pSource->flInnerAngle = flValue;
241 else
242 alSetError(AL_INVALID_VALUE);
243 break;
245 case AL_CONE_OUTER_ANGLE:
246 if(flValue >= 0.0f && flValue <= 360.0f)
247 pSource->flOuterAngle = flValue;
248 else
249 alSetError(AL_INVALID_VALUE);
250 break;
252 case AL_GAIN:
253 if(flValue >= 0.0f)
254 pSource->flGain = flValue;
255 else
256 alSetError(AL_INVALID_VALUE);
257 break;
259 case AL_MAX_DISTANCE:
260 if(flValue >= 0.0f)
261 pSource->flMaxDistance = flValue;
262 else
263 alSetError(AL_INVALID_VALUE);
264 break;
266 case AL_ROLLOFF_FACTOR:
267 if(flValue >= 0.0f)
268 pSource->flRollOffFactor = flValue;
269 else
270 alSetError(AL_INVALID_VALUE);
271 break;
273 case AL_REFERENCE_DISTANCE:
274 if(flValue >= 0.0f)
275 pSource->flRefDistance = flValue;
276 else
277 alSetError(AL_INVALID_VALUE);
278 break;
280 case AL_MIN_GAIN:
281 if(flValue >= 0.0f && flValue <= 1.0f)
282 pSource->flMinGain = flValue;
283 else
284 alSetError(AL_INVALID_VALUE);
285 break;
287 case AL_MAX_GAIN:
288 if(flValue >= 0.0f && flValue <= 1.0f)
289 pSource->flMaxGain = flValue;
290 else
291 alSetError(AL_INVALID_VALUE);
292 break;
294 case AL_CONE_OUTER_GAIN:
295 if(flValue >= 0.0f && flValue <= 1.0f)
296 pSource->flOuterGain = flValue;
297 else
298 alSetError(AL_INVALID_VALUE);
299 break;
301 case AL_CONE_OUTER_GAINHF:
302 if(flValue >= 0.0f && flValue <= 1.0f)
303 pSource->OuterGainHF = flValue;
304 else
305 alSetError(AL_INVALID_VALUE);
306 break;
308 case AL_AIR_ABSORPTION_FACTOR:
309 if(flValue >= 0.0f && flValue <= 10.0f)
310 pSource->AirAbsorptionFactor = flValue;
311 else
312 alSetError(AL_INVALID_VALUE);
313 break;
315 case AL_ROOM_ROLLOFF_FACTOR:
316 if(flValue >= 0.0f && flValue <= 10.0f)
317 pSource->RoomRolloffFactor = flValue;
318 else
319 alSetError(AL_INVALID_VALUE);
320 break;
322 case AL_DOPPLER_FACTOR:
323 if(flValue >= 0.0f && flValue <= 1.0f)
324 pSource->DopplerFactor = flValue;
325 else
326 alSetError(AL_INVALID_VALUE);
327 break;
329 case AL_SEC_OFFSET:
330 case AL_SAMPLE_OFFSET:
331 case AL_BYTE_OFFSET:
332 if(flValue >= 0.0f)
334 pSource->lOffsetType = eParam;
336 // Store Offset (convert Seconds into Milliseconds)
337 if(eParam == AL_SEC_OFFSET)
338 pSource->lOffset = (ALint)(flValue * 1000.0f);
339 else
340 pSource->lOffset = (ALint)flValue;
342 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
343 ApplyOffset(pSource, AL_TRUE);
345 else
346 alSetError(AL_INVALID_VALUE);
347 break;
349 default:
350 alSetError(AL_INVALID_ENUM);
351 break;
354 else
356 // Invalid Source Name
357 alSetError(AL_INVALID_NAME);
360 ProcessContext(pContext);
364 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
366 ALCcontext *pContext;
367 ALsource *pSource;
369 pContext = GetContextSuspended();
370 if(!pContext) return;
372 if(alIsSource(source))
374 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
375 switch(eParam)
377 case AL_POSITION:
378 pSource->vPosition[0] = flValue1;
379 pSource->vPosition[1] = flValue2;
380 pSource->vPosition[2] = flValue3;
381 break;
383 case AL_VELOCITY:
384 pSource->vVelocity[0] = flValue1;
385 pSource->vVelocity[1] = flValue2;
386 pSource->vVelocity[2] = flValue3;
387 break;
389 case AL_DIRECTION:
390 pSource->vOrientation[0] = flValue1;
391 pSource->vOrientation[1] = flValue2;
392 pSource->vOrientation[2] = flValue3;
393 break;
395 default:
396 alSetError(AL_INVALID_ENUM);
397 break;
400 else
401 alSetError(AL_INVALID_NAME);
403 ProcessContext(pContext);
407 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
409 ALCcontext *pContext;
411 pContext = GetContextSuspended();
412 if(!pContext) return;
414 if(pflValues)
416 if(alIsSource(source))
418 switch(eParam)
420 case AL_PITCH:
421 case AL_CONE_INNER_ANGLE:
422 case AL_CONE_OUTER_ANGLE:
423 case AL_GAIN:
424 case AL_MAX_DISTANCE:
425 case AL_ROLLOFF_FACTOR:
426 case AL_REFERENCE_DISTANCE:
427 case AL_MIN_GAIN:
428 case AL_MAX_GAIN:
429 case AL_CONE_OUTER_GAIN:
430 case AL_CONE_OUTER_GAINHF:
431 case AL_SEC_OFFSET:
432 case AL_SAMPLE_OFFSET:
433 case AL_BYTE_OFFSET:
434 case AL_AIR_ABSORPTION_FACTOR:
435 case AL_ROOM_ROLLOFF_FACTOR:
436 alSourcef(source, eParam, pflValues[0]);
437 break;
439 case AL_POSITION:
440 case AL_VELOCITY:
441 case AL_DIRECTION:
442 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
443 break;
445 default:
446 alSetError(AL_INVALID_ENUM);
447 break;
450 else
451 alSetError(AL_INVALID_NAME);
453 else
454 alSetError(AL_INVALID_VALUE);
456 ProcessContext(pContext);
460 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
462 ALCcontext *pContext;
463 ALsource *pSource;
464 ALbufferlistitem *pALBufferListItem;
465 ALuint i;
467 pContext = GetContextSuspended();
468 if(!pContext) return;
470 if(alIsSource(source))
472 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
474 switch(eParam)
476 case AL_MAX_DISTANCE:
477 case AL_ROLLOFF_FACTOR:
478 case AL_REFERENCE_DISTANCE:
479 alSourcef(source, eParam, (ALfloat)lValue);
480 break;
482 case AL_SOURCE_RELATIVE:
483 if(lValue == AL_FALSE || lValue == AL_TRUE)
484 pSource->bHeadRelative = (ALboolean)lValue;
485 else
486 alSetError(AL_INVALID_VALUE);
487 break;
489 case AL_CONE_INNER_ANGLE:
490 if(lValue >= 0 && lValue <= 360)
491 pSource->flInnerAngle = (float)lValue;
492 else
493 alSetError(AL_INVALID_VALUE);
494 break;
496 case AL_CONE_OUTER_ANGLE:
497 if(lValue >= 0 && lValue <= 360)
498 pSource->flOuterAngle = (float)lValue;
499 else
500 alSetError(AL_INVALID_VALUE);
501 break;
503 case AL_LOOPING:
504 if(lValue == AL_FALSE || lValue == AL_TRUE)
506 pSource->bLooping = (ALboolean)lValue;
508 pALBufferListItem = pSource->queue;
509 for(i = 0;pALBufferListItem != NULL;i++)
511 if(lValue == AL_FALSE && i <= pSource->BuffersPlayed)
512 pALBufferListItem->bufferstate = PROCESSED;
513 else
514 pALBufferListItem->bufferstate = PENDING;
515 pALBufferListItem = pALBufferListItem->next;
518 else
519 alSetError(AL_INVALID_VALUE);
520 break;
522 case AL_BUFFER:
523 if(pSource->state == AL_STOPPED || pSource->state == AL_INITIAL)
525 if(alIsBuffer(lValue))
527 ALbuffer *buffer = NULL;
529 // Remove all elements in the queue
530 while(pSource->queue != NULL)
532 pALBufferListItem = pSource->queue;
533 pSource->queue = pALBufferListItem->next;
534 // Decrement reference counter for buffer
535 if(pALBufferListItem->buffer)
536 pALBufferListItem->buffer->refcount--;
537 // Release memory for buffer list item
538 free(pALBufferListItem);
539 // Decrement the number of buffers in the queue
540 pSource->BuffersInQueue--;
543 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
544 if(lValue != 0)
546 buffer = (ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue));
548 // Source is now in STATIC mode
549 pSource->lSourceType = AL_STATIC;
551 // Add the selected buffer to the queue
552 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
553 pALBufferListItem->buffer = buffer;
554 pALBufferListItem->bufferstate = PENDING;
555 pALBufferListItem->flag = 0;
556 pALBufferListItem->next = NULL;
558 pSource->queue = pALBufferListItem;
559 pSource->BuffersInQueue = 1;
561 // Increment reference counter for buffer
562 buffer->refcount++;
564 else
566 // Source is now in UNDETERMINED mode
567 pSource->lSourceType = AL_UNDETERMINED;
568 pSource->BuffersPlayed = 0;
571 // Update AL_BUFFER parameter
572 pSource->Buffer = buffer;
574 else
575 alSetError(AL_INVALID_VALUE);
577 else
578 alSetError(AL_INVALID_OPERATION);
579 break;
581 case AL_SOURCE_STATE:
582 // Query only
583 alSetError(AL_INVALID_OPERATION);
584 break;
586 case AL_SEC_OFFSET:
587 case AL_SAMPLE_OFFSET:
588 case AL_BYTE_OFFSET:
589 if(lValue >= 0)
591 pSource->lOffsetType = eParam;
593 // Store Offset (convert Seconds into Milliseconds)
594 if(eParam == AL_SEC_OFFSET)
595 pSource->lOffset = lValue * 1000;
596 else
597 pSource->lOffset = lValue;
599 if(pSource->state == AL_PLAYING || pSource->state == AL_PAUSED)
600 ApplyOffset(pSource, AL_TRUE);
602 else
603 alSetError(AL_INVALID_VALUE);
604 break;
606 case AL_DIRECT_FILTER:
607 if(alIsFilter(lValue))
609 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
610 if(!filter)
612 pSource->DirectFilter.type = AL_FILTER_NULL;
613 pSource->DirectFilter.filter = 0;
615 else
616 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
618 else
619 alSetError(AL_INVALID_VALUE);
620 break;
622 case AL_DIRECT_FILTER_GAINHF_AUTO:
623 if(lValue == AL_TRUE || lValue == AL_FALSE)
624 pSource->DryGainHFAuto = lValue;
625 else
626 alSetError(AL_INVALID_VALUE);
627 break;
629 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
630 if(lValue == AL_TRUE || lValue == AL_FALSE)
631 pSource->WetGainAuto = lValue;
632 else
633 alSetError(AL_INVALID_VALUE);
634 break;
636 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
637 if(lValue == AL_TRUE || lValue == AL_FALSE)
638 pSource->WetGainHFAuto = lValue;
639 else
640 alSetError(AL_INVALID_VALUE);
641 break;
643 case AL_DISTANCE_MODEL:
644 if(lValue == AL_NONE ||
645 lValue == AL_INVERSE_DISTANCE ||
646 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
647 lValue == AL_LINEAR_DISTANCE ||
648 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
649 lValue == AL_EXPONENT_DISTANCE ||
650 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
651 pSource->DistanceModel = lValue;
652 else
653 alSetError(AL_INVALID_VALUE);
654 break;
656 default:
657 alSetError(AL_INVALID_ENUM);
658 break;
661 else
662 alSetError(AL_INVALID_NAME);
664 ProcessContext(pContext);
668 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
670 ALCcontext *pContext;
672 pContext = GetContextSuspended();
673 if(!pContext) return;
675 if(alIsSource(source))
677 ALsource *pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
678 ALCdevice *Device = pContext->Device;
680 switch (eParam)
682 case AL_POSITION:
683 case AL_VELOCITY:
684 case AL_DIRECTION:
685 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
686 break;
688 case AL_AUXILIARY_SEND_FILTER:
689 if((ALuint)lValue2 < Device->NumAuxSends &&
690 (lValue1 == 0 || alIsAuxiliaryEffectSlot(lValue1)) &&
691 alIsFilter(lValue3))
693 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
694 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
696 /* Release refcount on the previous slot, and add one for
697 * the new slot */
698 if(pSource->Send[lValue2].Slot)
699 pSource->Send[lValue2].Slot->refcount--;
700 pSource->Send[lValue2].Slot = ALEffectSlot;
701 if(pSource->Send[lValue2].Slot)
702 pSource->Send[lValue2].Slot->refcount++;
704 if(!ALFilter)
706 /* Disable filter */
707 pSource->Send[lValue2].WetFilter.type = 0;
708 pSource->Send[lValue2].WetFilter.filter = 0;
710 else
711 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
713 else
714 alSetError(AL_INVALID_VALUE);
715 break;
717 default:
718 alSetError(AL_INVALID_ENUM);
719 break;
722 else
723 alSetError(AL_INVALID_NAME);
725 ProcessContext(pContext);
729 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
731 ALCcontext *pContext;
733 pContext = GetContextSuspended();
734 if(!pContext) return;
736 if(plValues)
738 if(alIsSource(source))
740 switch(eParam)
742 case AL_SOURCE_RELATIVE:
743 case AL_CONE_INNER_ANGLE:
744 case AL_CONE_OUTER_ANGLE:
745 case AL_LOOPING:
746 case AL_BUFFER:
747 case AL_SOURCE_STATE:
748 case AL_SEC_OFFSET:
749 case AL_SAMPLE_OFFSET:
750 case AL_BYTE_OFFSET:
751 case AL_MAX_DISTANCE:
752 case AL_ROLLOFF_FACTOR:
753 case AL_REFERENCE_DISTANCE:
754 case AL_DIRECT_FILTER:
755 case AL_DIRECT_FILTER_GAINHF_AUTO:
756 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
757 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
758 case AL_DISTANCE_MODEL:
759 alSourcei(source, eParam, plValues[0]);
760 break;
762 case AL_POSITION:
763 case AL_VELOCITY:
764 case AL_DIRECTION:
765 case AL_AUXILIARY_SEND_FILTER:
766 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
767 break;
769 default:
770 alSetError(AL_INVALID_ENUM);
771 break;
774 else
775 alSetError(AL_INVALID_NAME);
777 else
778 alSetError(AL_INVALID_VALUE);
780 ProcessContext(pContext);
784 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
786 ALCcontext *pContext;
787 ALsource *pSource;
788 ALfloat flOffset[2];
790 pContext = GetContextSuspended();
791 if(!pContext) return;
793 if(pflValue)
795 if(alIsSource(source))
797 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
799 switch(eParam)
801 case AL_PITCH:
802 *pflValue = pSource->flPitch;
803 break;
805 case AL_GAIN:
806 *pflValue = pSource->flGain;
807 break;
809 case AL_MIN_GAIN:
810 *pflValue = pSource->flMinGain;
811 break;
813 case AL_MAX_GAIN:
814 *pflValue = pSource->flMaxGain;
815 break;
817 case AL_MAX_DISTANCE:
818 *pflValue = pSource->flMaxDistance;
819 break;
821 case AL_ROLLOFF_FACTOR:
822 *pflValue = pSource->flRollOffFactor;
823 break;
825 case AL_CONE_OUTER_GAIN:
826 *pflValue = pSource->flOuterGain;
827 break;
829 case AL_CONE_OUTER_GAINHF:
830 *pflValue = pSource->OuterGainHF;
831 break;
833 case AL_SEC_OFFSET:
834 case AL_SAMPLE_OFFSET:
835 case AL_BYTE_OFFSET:
836 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
837 *pflValue = flOffset[0];
838 else
839 alSetError(AL_INVALID_OPERATION);
840 break;
842 case AL_SEC_RW_OFFSETS_EXT:
843 case AL_SAMPLE_RW_OFFSETS_EXT:
844 case AL_BYTE_RW_OFFSETS_EXT:
845 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
847 pflValue[0] = flOffset[0];
848 pflValue[1] = flOffset[1];
850 else
851 alSetError(AL_INVALID_OPERATION);
852 break;
854 case AL_CONE_INNER_ANGLE:
855 *pflValue = pSource->flInnerAngle;
856 break;
858 case AL_CONE_OUTER_ANGLE:
859 *pflValue = pSource->flOuterAngle;
860 break;
862 case AL_REFERENCE_DISTANCE:
863 *pflValue = pSource->flRefDistance;
864 break;
866 case AL_AIR_ABSORPTION_FACTOR:
867 *pflValue = pSource->AirAbsorptionFactor;
868 break;
870 case AL_ROOM_ROLLOFF_FACTOR:
871 *pflValue = pSource->RoomRolloffFactor;
872 break;
874 case AL_DOPPLER_FACTOR:
875 *pflValue = pSource->DopplerFactor;
876 break;
878 default:
879 alSetError(AL_INVALID_ENUM);
880 break;
883 else
884 alSetError(AL_INVALID_NAME);
886 else
887 alSetError(AL_INVALID_VALUE);
889 ProcessContext(pContext);
893 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
895 ALCcontext *pContext;
896 ALsource *pSource;
898 pContext = GetContextSuspended();
899 if(!pContext) return;
901 if(pflValue1 && pflValue2 && pflValue3)
903 if(alIsSource(source))
905 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
907 switch(eParam)
909 case AL_POSITION:
910 *pflValue1 = pSource->vPosition[0];
911 *pflValue2 = pSource->vPosition[1];
912 *pflValue3 = pSource->vPosition[2];
913 break;
915 case AL_VELOCITY:
916 *pflValue1 = pSource->vVelocity[0];
917 *pflValue2 = pSource->vVelocity[1];
918 *pflValue3 = pSource->vVelocity[2];
919 break;
921 case AL_DIRECTION:
922 *pflValue1 = pSource->vOrientation[0];
923 *pflValue2 = pSource->vOrientation[1];
924 *pflValue3 = pSource->vOrientation[2];
925 break;
927 default:
928 alSetError(AL_INVALID_ENUM);
929 break;
932 else
933 alSetError(AL_INVALID_NAME);
935 else
936 alSetError(AL_INVALID_VALUE);
938 ProcessContext(pContext);
942 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
944 ALCcontext *pContext;
945 ALsource *pSource;
947 pContext = GetContextSuspended();
948 if(!pContext) return;
950 if(pflValues)
952 if(alIsSource(source))
954 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
956 switch(eParam)
958 case AL_PITCH:
959 case AL_GAIN:
960 case AL_MIN_GAIN:
961 case AL_MAX_GAIN:
962 case AL_MAX_DISTANCE:
963 case AL_ROLLOFF_FACTOR:
964 case AL_DOPPLER_FACTOR:
965 case AL_CONE_OUTER_GAIN:
966 case AL_SEC_OFFSET:
967 case AL_SAMPLE_OFFSET:
968 case AL_BYTE_OFFSET:
969 case AL_CONE_INNER_ANGLE:
970 case AL_CONE_OUTER_ANGLE:
971 case AL_REFERENCE_DISTANCE:
972 case AL_CONE_OUTER_GAINHF:
973 case AL_AIR_ABSORPTION_FACTOR:
974 case AL_ROOM_ROLLOFF_FACTOR:
975 alGetSourcef(source, eParam, pflValues);
976 break;
978 case AL_POSITION:
979 pflValues[0] = pSource->vPosition[0];
980 pflValues[1] = pSource->vPosition[1];
981 pflValues[2] = pSource->vPosition[2];
982 break;
984 case AL_VELOCITY:
985 pflValues[0] = pSource->vVelocity[0];
986 pflValues[1] = pSource->vVelocity[1];
987 pflValues[2] = pSource->vVelocity[2];
988 break;
990 case AL_DIRECTION:
991 pflValues[0] = pSource->vOrientation[0];
992 pflValues[1] = pSource->vOrientation[1];
993 pflValues[2] = pSource->vOrientation[2];
994 break;
996 default:
997 alSetError(AL_INVALID_ENUM);
998 break;
1001 else
1002 alSetError(AL_INVALID_NAME);
1004 else
1005 alSetError(AL_INVALID_VALUE);
1007 ProcessContext(pContext);
1011 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1013 ALCcontext *pContext;
1014 ALsource *pSource;
1015 ALfloat flOffset[2];
1017 pContext = GetContextSuspended();
1018 if(!pContext) return;
1020 if(plValue)
1022 if(alIsSource(source))
1024 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1026 switch(eParam)
1028 case AL_MAX_DISTANCE:
1029 *plValue = (ALint)pSource->flMaxDistance;
1030 break;
1032 case AL_ROLLOFF_FACTOR:
1033 *plValue = (ALint)pSource->flRollOffFactor;
1034 break;
1036 case AL_REFERENCE_DISTANCE:
1037 *plValue = (ALint)pSource->flRefDistance;
1038 break;
1040 case AL_SOURCE_RELATIVE:
1041 *plValue = pSource->bHeadRelative;
1042 break;
1044 case AL_CONE_INNER_ANGLE:
1045 *plValue = (ALint)pSource->flInnerAngle;
1046 break;
1048 case AL_CONE_OUTER_ANGLE:
1049 *plValue = (ALint)pSource->flOuterAngle;
1050 break;
1052 case AL_LOOPING:
1053 *plValue = pSource->bLooping;
1054 break;
1056 case AL_BUFFER:
1057 *plValue = (pSource->Buffer ? pSource->Buffer->buffer : 0);
1058 break;
1060 case AL_SOURCE_STATE:
1061 *plValue = pSource->state;
1062 break;
1064 case AL_BUFFERS_QUEUED:
1065 *plValue = pSource->BuffersInQueue;
1066 break;
1068 case AL_BUFFERS_PROCESSED:
1069 if(pSource->bLooping)
1071 /* Buffers on a looping source are in a perpetual state
1072 * of PENDING, so don't report any as PROCESSED */
1073 *plValue = 0;
1075 else
1076 *plValue = pSource->BuffersPlayed;
1077 break;
1079 case AL_SOURCE_TYPE:
1080 *plValue = pSource->lSourceType;
1081 break;
1083 case AL_SEC_OFFSET:
1084 case AL_SAMPLE_OFFSET:
1085 case AL_BYTE_OFFSET:
1086 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1087 *plValue = (ALint)flOffset[0];
1088 else
1089 alSetError(AL_INVALID_OPERATION);
1090 break;
1092 case AL_SEC_RW_OFFSETS_EXT:
1093 case AL_SAMPLE_RW_OFFSETS_EXT:
1094 case AL_BYTE_RW_OFFSETS_EXT:
1095 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1097 plValue[0] = (ALint)flOffset[0];
1098 plValue[1] = (ALint)flOffset[1];
1100 else
1101 alSetError(AL_INVALID_OPERATION);
1102 break;
1104 case AL_DIRECT_FILTER:
1105 *plValue = pSource->DirectFilter.filter;
1106 break;
1108 case AL_DIRECT_FILTER_GAINHF_AUTO:
1109 *plValue = pSource->DryGainHFAuto;
1110 break;
1112 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1113 *plValue = pSource->WetGainAuto;
1114 break;
1116 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1117 *plValue = pSource->WetGainHFAuto;
1118 break;
1120 case AL_DOPPLER_FACTOR:
1121 *plValue = (ALint)pSource->DopplerFactor;
1122 break;
1124 case AL_DISTANCE_MODEL:
1125 *plValue = pSource->DistanceModel;
1126 break;
1128 default:
1129 alSetError(AL_INVALID_ENUM);
1130 break;
1133 else
1134 alSetError(AL_INVALID_NAME);
1136 else
1137 alSetError(AL_INVALID_VALUE);
1139 ProcessContext(pContext);
1143 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1145 ALCcontext *pContext;
1146 ALsource *pSource;
1148 pContext = GetContextSuspended();
1149 if(!pContext) return;
1151 if(plValue1 && plValue2 && plValue3)
1153 if(alIsSource(source))
1155 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1157 switch(eParam)
1159 case AL_POSITION:
1160 *plValue1 = (ALint)pSource->vPosition[0];
1161 *plValue2 = (ALint)pSource->vPosition[1];
1162 *plValue3 = (ALint)pSource->vPosition[2];
1163 break;
1165 case AL_VELOCITY:
1166 *plValue1 = (ALint)pSource->vVelocity[0];
1167 *plValue2 = (ALint)pSource->vVelocity[1];
1168 *plValue3 = (ALint)pSource->vVelocity[2];
1169 break;
1171 case AL_DIRECTION:
1172 *plValue1 = (ALint)pSource->vOrientation[0];
1173 *plValue2 = (ALint)pSource->vOrientation[1];
1174 *plValue3 = (ALint)pSource->vOrientation[2];
1175 break;
1177 default:
1178 alSetError(AL_INVALID_ENUM);
1179 break;
1182 else
1183 alSetError(AL_INVALID_NAME);
1185 else
1186 alSetError(AL_INVALID_VALUE);
1188 ProcessContext(pContext);
1192 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1194 ALCcontext *pContext;
1195 ALsource *pSource;
1197 pContext = GetContextSuspended();
1198 if(!pContext) return;
1200 if(plValues)
1202 if(alIsSource(source))
1204 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1206 switch(eParam)
1208 case AL_SOURCE_RELATIVE:
1209 case AL_CONE_INNER_ANGLE:
1210 case AL_CONE_OUTER_ANGLE:
1211 case AL_LOOPING:
1212 case AL_BUFFER:
1213 case AL_SOURCE_STATE:
1214 case AL_BUFFERS_QUEUED:
1215 case AL_BUFFERS_PROCESSED:
1216 case AL_SEC_OFFSET:
1217 case AL_SAMPLE_OFFSET:
1218 case AL_BYTE_OFFSET:
1219 case AL_MAX_DISTANCE:
1220 case AL_ROLLOFF_FACTOR:
1221 case AL_DOPPLER_FACTOR:
1222 case AL_REFERENCE_DISTANCE:
1223 case AL_SOURCE_TYPE:
1224 case AL_DIRECT_FILTER:
1225 case AL_DIRECT_FILTER_GAINHF_AUTO:
1226 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1227 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1228 case AL_DISTANCE_MODEL:
1229 alGetSourcei(source, eParam, plValues);
1230 break;
1232 case AL_POSITION:
1233 plValues[0] = (ALint)pSource->vPosition[0];
1234 plValues[1] = (ALint)pSource->vPosition[1];
1235 plValues[2] = (ALint)pSource->vPosition[2];
1236 break;
1238 case AL_VELOCITY:
1239 plValues[0] = (ALint)pSource->vVelocity[0];
1240 plValues[1] = (ALint)pSource->vVelocity[1];
1241 plValues[2] = (ALint)pSource->vVelocity[2];
1242 break;
1244 case AL_DIRECTION:
1245 plValues[0] = (ALint)pSource->vOrientation[0];
1246 plValues[1] = (ALint)pSource->vOrientation[1];
1247 plValues[2] = (ALint)pSource->vOrientation[2];
1248 break;
1250 default:
1251 alSetError(AL_INVALID_ENUM);
1252 break;
1255 else
1256 alSetError(AL_INVALID_NAME);
1258 else
1259 alSetError(AL_INVALID_VALUE);
1261 ProcessContext(pContext);
1265 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1267 alSourcePlayv(1, &source);
1268 return;
1271 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1273 ALCcontext *pContext;
1274 ALsource *pSource;
1275 ALbufferlistitem *ALBufferList;
1276 ALboolean bSourcesValid = AL_TRUE;
1277 ALboolean bPlay;
1278 ALsizei i, j;
1280 pContext = GetContextSuspended();
1281 if(!pContext) return;
1283 if(pSourceList)
1285 // Check that all the Sources are valid
1286 for(i = 0; i < n; i++)
1288 if(!alIsSource(pSourceList[i]))
1290 alSetError(AL_INVALID_NAME);
1291 bSourcesValid = AL_FALSE;
1292 break;
1296 if(bSourcesValid)
1298 for(i = 0; i < n; i++)
1300 // Assume Source won't need to play
1301 bPlay = AL_FALSE;
1303 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]);
1305 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1306 ALBufferList = pSource->queue;
1307 while(ALBufferList)
1309 if(ALBufferList->buffer != NULL && ALBufferList->buffer->size)
1311 bPlay = AL_TRUE;
1312 break;
1314 ALBufferList = ALBufferList->next;
1317 if (bPlay)
1319 for(j = 0;j < OUTPUTCHANNELS;j++)
1320 pSource->DryGains[j] = 0.0f;
1321 for(j = 0;j < MAX_SENDS;j++)
1322 pSource->WetGains[j] = 0.0f;
1324 if(pSource->state != AL_PAUSED)
1326 pSource->state = AL_PLAYING;
1327 pSource->position = 0;
1328 pSource->position_fraction = 0;
1329 pSource->BuffersPlayed = 0;
1331 pSource->Buffer = pSource->queue->buffer;
1333 // Make sure all the Buffers in the queue are marked as PENDING
1334 ALBufferList = pSource->queue;
1335 while(ALBufferList)
1337 ALBufferList->bufferstate = PENDING;
1338 ALBufferList = ALBufferList->next;
1341 else
1342 pSource->state = AL_PLAYING;
1344 // Check if an Offset has been set
1345 if(pSource->lOffset)
1346 ApplyOffset(pSource, AL_FALSE);
1348 if(pSource->BuffersPlayed == 0 && pSource->position == 0 &&
1349 pSource->position_fraction == 0)
1350 pSource->FirstStart = AL_TRUE;
1351 else
1352 pSource->FirstStart = AL_FALSE;
1354 // If device is disconnected, go right to stopped
1355 if(!pContext->Device->Connected)
1357 pSource->state = AL_STOPPED;
1358 pSource->BuffersPlayed = pSource->BuffersInQueue;
1359 ALBufferList = pSource->queue;
1360 while(ALBufferList != NULL)
1362 ALBufferList->bufferstate = PROCESSED;
1363 ALBufferList = ALBufferList->next;
1365 pSource->position = 0;
1366 pSource->position_fraction = 0;
1369 else
1371 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1372 ALBufferList = pSource->queue;
1373 while(ALBufferList)
1375 ALBufferList->bufferstate = PROCESSED;
1376 ALBufferList = ALBufferList->next;
1379 pSource->BuffersPlayed = pSource->BuffersInQueue;
1384 else
1386 // sources is a NULL pointer
1387 alSetError(AL_INVALID_VALUE);
1390 ProcessContext(pContext);
1393 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1395 alSourcePausev(1, &source);
1396 return;
1399 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1401 ALCcontext *Context;
1402 ALsource *Source;
1403 ALsizei i;
1404 ALboolean bSourcesValid = AL_TRUE;
1406 Context = GetContextSuspended();
1407 if(!Context) return;
1409 if(sources)
1411 // Check all the Sources are valid
1412 for(i=0;i<n;i++)
1414 if(!alIsSource(sources[i]))
1416 alSetError(AL_INVALID_NAME);
1417 bSourcesValid = AL_FALSE;
1418 break;
1422 if(bSourcesValid)
1424 for(i = 0;i < n;i++)
1426 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1427 if(Source->state == AL_PLAYING)
1428 Source->state = AL_PAUSED;
1432 else
1434 // sources is a NULL pointer
1435 alSetError(AL_INVALID_VALUE);
1438 ProcessContext(Context);
1441 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1443 alSourceStopv(1, &source);
1444 return;
1447 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1449 ALCcontext *Context;
1450 ALsource *Source;
1451 ALsizei i;
1452 ALbufferlistitem *ALBufferListItem;
1453 ALboolean bSourcesValid = AL_TRUE;
1455 Context = GetContextSuspended();
1456 if(!Context) return;
1458 if(sources)
1460 // Check all the Sources are valid
1461 for(i = 0;i < n;i++)
1463 if(!alIsSource(sources[i]))
1465 alSetError(AL_INVALID_NAME);
1466 bSourcesValid = AL_FALSE;
1467 break;
1471 if(bSourcesValid)
1473 for(i = 0;i < n;i++)
1475 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1476 if(Source->state != AL_INITIAL)
1478 Source->state = AL_STOPPED;
1479 Source->BuffersPlayed = Source->BuffersInQueue;
1480 ALBufferListItem = Source->queue;
1481 while(ALBufferListItem != NULL)
1483 ALBufferListItem->bufferstate = PROCESSED;
1484 ALBufferListItem = ALBufferListItem->next;
1487 Source->lOffset = 0;
1491 else
1493 // sources is a NULL pointer
1494 alSetError(AL_INVALID_VALUE);
1497 ProcessContext(Context);
1500 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1502 alSourceRewindv(1, &source);
1503 return;
1506 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1508 ALCcontext *Context;
1509 ALsource *Source;
1510 ALsizei i;
1511 ALbufferlistitem *ALBufferListItem;
1512 ALboolean bSourcesValid = AL_TRUE;
1514 Context = GetContextSuspended();
1515 if(!Context) return;
1517 if(sources)
1519 // Check all the Sources are valid
1520 for(i = 0;i < n;i++)
1522 if(!alIsSource(sources[i]))
1524 alSetError(AL_INVALID_NAME);
1525 bSourcesValid = AL_FALSE;
1526 break;
1530 if(bSourcesValid)
1532 for(i = 0;i < n;i++)
1534 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1535 if(Source->state != AL_INITIAL)
1537 Source->state = AL_INITIAL;
1538 Source->position = 0;
1539 Source->position_fraction = 0;
1540 Source->BuffersPlayed = 0;
1541 ALBufferListItem = Source->queue;
1542 while(ALBufferListItem != NULL)
1544 ALBufferListItem->bufferstate = PENDING;
1545 ALBufferListItem = ALBufferListItem->next;
1547 if(Source->queue)
1548 Source->Buffer = Source->queue->buffer;
1550 Source->lOffset = 0;
1554 else
1556 // sources is a NULL pointer
1557 alSetError(AL_INVALID_VALUE);
1560 ProcessContext(Context);
1564 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1566 ALCcontext *Context;
1567 ALsource *ALSource;
1568 ALsizei i;
1569 ALbufferlistitem *ALBufferList;
1570 ALbufferlistitem *ALBufferListStart;
1571 ALint iFrequency;
1572 ALint iFormat;
1573 ALboolean bBuffersValid = AL_TRUE;
1575 if (n == 0)
1576 return;
1578 Context = GetContextSuspended();
1579 if(!Context) return;
1581 // Check that all buffers are valid or zero and that the source is valid
1583 // Check that this is a valid source
1584 if(alIsSource(source))
1586 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1588 // Check that this is not a STATIC Source
1589 if(ALSource->lSourceType != AL_STATIC)
1591 iFrequency = -1;
1592 iFormat = -1;
1594 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1595 ALBufferList = ALSource->queue;
1596 while(ALBufferList)
1598 if (ALBufferList->buffer)
1600 iFrequency = ALBufferList->buffer->frequency;
1601 iFormat = ALBufferList->buffer->format;
1602 break;
1604 ALBufferList = ALBufferList->next;
1607 for(i = 0; i < n; i++)
1609 ALbuffer *buffer;
1611 if(!alIsBuffer(buffers[i]))
1613 alSetError(AL_INVALID_NAME);
1614 bBuffersValid = AL_FALSE;
1615 break;
1617 if(!buffers[i])
1618 continue;
1620 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1621 if(iFrequency == -1 && iFormat == -1)
1623 iFrequency = buffer->frequency;
1624 iFormat = buffer->format;
1626 else if(iFrequency != buffer->frequency ||
1627 iFormat != buffer->format)
1629 alSetError(AL_INVALID_OPERATION);
1630 bBuffersValid = AL_FALSE;
1631 break;
1635 if(bBuffersValid)
1637 ALbuffer *buffer = NULL;
1639 // Change Source Type
1640 ALSource->lSourceType = AL_STREAMING;
1642 if(buffers[0])
1643 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1645 // All buffers are valid - so add them to the list
1646 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1647 ALBufferListStart->buffer = buffer;
1648 ALBufferListStart->bufferstate = PENDING;
1649 ALBufferListStart->flag = 0;
1650 ALBufferListStart->next = NULL;
1652 // Increment reference counter for buffer
1653 if(buffer) buffer->refcount++;
1655 ALBufferList = ALBufferListStart;
1657 for(i = 1; i < n; i++)
1659 if(buffers[i])
1660 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1662 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1663 ALBufferList->next->buffer = buffer;
1664 ALBufferList->next->bufferstate = PENDING;
1665 ALBufferList->next->flag = 0;
1666 ALBufferList->next->next = NULL;
1668 // Increment reference counter for buffer
1669 if(buffer) buffer->refcount++;
1671 ALBufferList = ALBufferList->next;
1674 if(ALSource->queue == NULL)
1676 ALSource->queue = ALBufferListStart;
1677 // Update Current Buffer
1678 ALSource->Buffer = ALBufferListStart->buffer;
1680 else
1682 // Find end of queue
1683 ALBufferList = ALSource->queue;
1684 while(ALBufferList->next != NULL)
1685 ALBufferList = ALBufferList->next;
1687 ALBufferList->next = ALBufferListStart;
1690 // Update number of buffers in queue
1691 ALSource->BuffersInQueue += n;
1694 else
1696 // Invalid Source Type (can't queue on a Static Source)
1697 alSetError(AL_INVALID_OPERATION);
1700 else
1702 // Invalid Source Name
1703 alSetError(AL_INVALID_NAME);
1706 ProcessContext(Context);
1710 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1711 // an array of buffer IDs that are to be filled with the names of the buffers removed
1712 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1714 ALCcontext *Context;
1715 ALsource *ALSource;
1716 ALsizei i;
1717 ALbufferlistitem *ALBufferList;
1718 ALboolean bBuffersProcessed;
1720 if (n == 0)
1721 return;
1723 bBuffersProcessed = AL_TRUE;
1725 Context = GetContextSuspended();
1726 if(!Context) return;
1728 if(alIsSource(source))
1730 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1732 // Check that all 'n' buffers have been processed
1733 ALBufferList = ALSource->queue;
1734 for(i = 0; i < n; i++)
1736 if(ALBufferList != NULL && ALBufferList->bufferstate == PROCESSED)
1738 ALBufferList = ALBufferList->next;
1740 else
1742 bBuffersProcessed = AL_FALSE;
1743 break;
1747 // If all 'n' buffers have been processed, remove them from the queue
1748 if(bBuffersProcessed)
1750 for(i = 0; i < n; i++)
1752 ALBufferList = ALSource->queue;
1754 ALSource->queue = ALBufferList->next;
1755 // Record name of buffer
1756 buffers[i] = ALBufferList->buffer->buffer;
1757 // Decrement buffer reference counter
1758 if(ALBufferList->buffer)
1759 ALBufferList->buffer->refcount--;
1761 // Release memory for buffer list item
1762 free(ALBufferList);
1763 ALSource->BuffersInQueue--;
1766 if(ALSource->state != AL_PLAYING)
1768 if(ALSource->queue)
1769 ALSource->Buffer = ALSource->queue->buffer;
1770 else
1771 ALSource->Buffer = NULL;
1774 if((ALuint)n > ALSource->BuffersPlayed)
1775 ALSource->BuffersPlayed = 0;
1776 else
1777 ALSource->BuffersPlayed -= n;
1779 else
1781 // Some buffers can't be unqueue because they have not been processed
1782 alSetError(AL_INVALID_VALUE);
1785 else
1787 // Invalid Source Name
1788 alSetError(AL_INVALID_NAME);
1791 ProcessContext(Context);
1795 static ALvoid InitSourceParams(ALCcontext *Context, ALsource *pSource)
1797 pSource->flInnerAngle = 360.0f;
1798 pSource->flOuterAngle = 360.0f;
1799 pSource->flPitch = 1.0f;
1800 pSource->vPosition[0] = 0.0f;
1801 pSource->vPosition[1] = 0.0f;
1802 pSource->vPosition[2] = 0.0f;
1803 pSource->vOrientation[0] = 0.0f;
1804 pSource->vOrientation[1] = 0.0f;
1805 pSource->vOrientation[2] = 0.0f;
1806 pSource->vVelocity[0] = 0.0f;
1807 pSource->vVelocity[1] = 0.0f;
1808 pSource->vVelocity[2] = 0.0f;
1809 pSource->flRefDistance = 1.0f;
1810 pSource->flMaxDistance = FLT_MAX;
1811 pSource->flRollOffFactor = 1.0f;
1812 pSource->bLooping = AL_FALSE;
1813 pSource->flGain = 1.0f;
1814 pSource->flMinGain = 0.0f;
1815 pSource->flMaxGain = 1.0f;
1816 pSource->flOuterGain = 0.0f;
1817 pSource->OuterGainHF = 1.0f;
1819 pSource->DryGainHFAuto = AL_TRUE;
1820 pSource->WetGainAuto = AL_TRUE;
1821 pSource->WetGainHFAuto = AL_TRUE;
1822 pSource->AirAbsorptionFactor = 0.0f;
1823 pSource->RoomRolloffFactor = 0.0f;
1824 pSource->DopplerFactor = 1.0f;
1826 pSource->DistanceModel = Context->DistanceModel;
1828 pSource->state = AL_INITIAL;
1829 pSource->lSourceType = AL_UNDETERMINED;
1831 pSource->Buffer = NULL;
1836 GetSourceOffset
1838 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1839 The offset is relative to the start of the queue (not the start of the current buffer)
1841 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize)
1843 ALbufferlistitem *pBufferList;
1844 ALbuffer *pBuffer;
1845 ALfloat flBufferFreq;
1846 ALint lChannels;
1847 ALint readPos, writePos;
1848 ALenum eOriginalFormat;
1849 ALboolean bReturn = AL_TRUE;
1850 ALint lTotalBufferDataSize;
1852 if((pSource->state == AL_PLAYING || pSource->state == AL_PAUSED) && pSource->Buffer)
1854 pBuffer = pSource->Buffer;
1855 // Get Current Buffer Size and frequency (in milliseconds)
1856 flBufferFreq = (ALfloat)pBuffer->frequency;
1857 eOriginalFormat = pBuffer->eOriginalFormat;
1858 lChannels = aluChannelsFromFormat(pBuffer->format);
1860 // Get Current BytesPlayed
1861 readPos = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
1862 // Add byte length of any processed buffers in the queue
1863 pBufferList = pSource->queue;
1864 while(pBufferList && pBufferList->bufferstate == PROCESSED)
1866 readPos += pBufferList->buffer->size;
1867 pBufferList = pBufferList->next;
1870 if(pSource->state == AL_PLAYING)
1871 writePos = readPos + (updateSize * lChannels * 2);
1872 else
1873 writePos = readPos;
1875 lTotalBufferDataSize = 0;
1876 pBufferList = pSource->queue;
1877 while (pBufferList)
1879 if (pBufferList->buffer)
1880 lTotalBufferDataSize += pBufferList->buffer->size;
1881 pBufferList = pBufferList->next;
1884 if (pSource->bLooping)
1886 if(readPos < 0)
1887 readPos = 0;
1888 else
1889 readPos %= lTotalBufferDataSize;
1890 if(writePos < 0)
1891 writePos = 0;
1892 else
1893 writePos %= lTotalBufferDataSize;
1895 else
1897 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1898 if(readPos < 0)
1899 readPos = 0;
1900 else if(readPos > lTotalBufferDataSize)
1901 readPos = lTotalBufferDataSize;
1902 if(writePos < 0)
1903 writePos = 0;
1904 else if(writePos > lTotalBufferDataSize)
1905 writePos = lTotalBufferDataSize;
1908 switch (eName)
1910 case AL_SEC_OFFSET:
1911 case AL_SEC_RW_OFFSETS_EXT:
1912 pflOffset[0] = (ALfloat)readPos / (lChannels * 2.0f * flBufferFreq);
1913 pflOffset[1] = (ALfloat)writePos / (lChannels * 2.0f * flBufferFreq);
1914 break;
1915 case AL_SAMPLE_OFFSET:
1916 case AL_SAMPLE_RW_OFFSETS_EXT:
1917 pflOffset[0] = (ALfloat)(readPos / (lChannels * 2));
1918 pflOffset[1] = (ALfloat)(writePos / (lChannels * 2));
1919 break;
1920 case AL_BYTE_OFFSET:
1921 case AL_BYTE_RW_OFFSETS_EXT:
1922 // Take into account the original format of the Buffer
1923 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
1924 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1926 // Round down to nearest ADPCM block
1927 pflOffset[0] = (ALfloat)((readPos / (65 * 2 * lChannels)) * 36 * lChannels);
1928 if(pSource->state == AL_PLAYING)
1930 // Round up to nearest ADPCM block
1931 pflOffset[1] = (ALfloat)(((writePos + (65 * 2 * lChannels) - 1) / (65 * 2 * lChannels)) * 36 * lChannels);
1933 else
1934 pflOffset[1] = pflOffset[0];
1936 else if (eOriginalFormat == AL_FORMAT_REAR8)
1938 pflOffset[0] = (ALfloat)(readPos >> 2);
1939 pflOffset[1] = (ALfloat)(writePos >> 2);
1941 else if (eOriginalFormat == AL_FORMAT_REAR16)
1943 pflOffset[0] = (ALfloat)(readPos >> 1);
1944 pflOffset[1] = (ALfloat)(writePos >> 1);
1946 else if (aluBytesFromFormat(eOriginalFormat) == 1)
1948 pflOffset[0] = (ALfloat)(readPos >> 1);
1949 pflOffset[1] = (ALfloat)(writePos >> 1);
1951 else if (aluBytesFromFormat(eOriginalFormat) == 4)
1953 pflOffset[0] = (ALfloat)(readPos << 1);
1954 pflOffset[1] = (ALfloat)(writePos << 1);
1956 else
1958 pflOffset[0] = (ALfloat)readPos;
1959 pflOffset[1] = (ALfloat)writePos;
1961 break;
1964 else
1966 pflOffset[0] = 0.0f;
1967 pflOffset[1] = 0.0f;
1970 return bReturn;
1975 ApplyOffset
1977 Apply a playback offset to the Source. This function will update the queue (to correctly
1978 mark buffers as 'pending' or 'processed' depending upon the new offset.
1980 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
1982 ALbufferlistitem *pBufferList;
1983 ALbuffer *pBuffer;
1984 ALint lBufferSize, lTotalBufferSize;
1985 ALint lByteOffset;
1987 // Get true byte offset
1988 lByteOffset = GetByteOffset(pSource);
1990 // If this is a valid offset apply it
1991 if (lByteOffset != -1)
1993 // Sort out the queue (pending and processed states)
1994 pBufferList = pSource->queue;
1995 lTotalBufferSize = 0;
1996 pSource->BuffersPlayed = 0;
1997 while (pBufferList)
1999 pBuffer = pBufferList->buffer;
2000 lBufferSize = pBuffer ? pBuffer->size : 0;
2002 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2004 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2005 // update the state to PROCESSED
2006 pSource->BuffersPlayed++;
2008 if (!pSource->bLooping)
2009 pBufferList->bufferstate = PROCESSED;
2011 else if (lTotalBufferSize <= lByteOffset)
2013 // Offset is within this buffer
2014 pBufferList->bufferstate = PENDING;
2016 // Set Current Buffer
2017 pSource->Buffer = pBufferList->buffer;
2019 // SW Mixer Positions are in Samples
2020 pSource->position = (lByteOffset - lTotalBufferSize) /
2021 aluBytesFromFormat(pBuffer->format) /
2022 aluChannelsFromFormat(pBuffer->format);
2024 else
2026 // Offset is before this buffer, so mark as pending
2027 pBufferList->bufferstate = PENDING;
2030 // Increment the TotalBufferSize
2031 lTotalBufferSize += lBufferSize;
2033 // Move on to next buffer in the Queue
2034 pBufferList = pBufferList->next;
2037 else
2039 if (bUpdateContext)
2040 alSetError(AL_INVALID_VALUE);
2043 // Clear Offset
2044 pSource->lOffset = 0;
2049 GetByteOffset
2051 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2052 offset supplied by the application). This takes into account the fact that the buffer format
2053 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2055 static ALint GetByteOffset(ALsource *pSource)
2057 ALbuffer *pBuffer = NULL;
2058 ALbufferlistitem *pBufferList;
2059 ALfloat flBufferFreq;
2060 ALint lChannels;
2061 ALint lByteOffset = -1;
2062 ALint lTotalBufferDataSize;
2064 // Find the first non-NULL Buffer in the Queue
2065 pBufferList = pSource->queue;
2066 while (pBufferList)
2068 if (pBufferList->buffer)
2070 pBuffer = pBufferList->buffer;
2071 break;
2073 pBufferList = pBufferList->next;
2076 if (pBuffer)
2078 flBufferFreq = ((ALfloat)pBuffer->frequency);
2079 lChannels = aluChannelsFromFormat(pBuffer->format);
2081 // Determine the ByteOffset (and ensure it is block aligned)
2082 switch (pSource->lOffsetType)
2084 case AL_BYTE_OFFSET:
2085 // Take into consideration the original format
2086 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2087 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2089 // Round down to nearest ADPCM block
2090 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2091 // Multiply by compression rate
2092 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2093 lByteOffset -= (lByteOffset % (lChannels * 2));
2095 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2097 lByteOffset = pSource->lOffset * 4;
2098 lByteOffset -= (lByteOffset % (lChannels * 2));
2100 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2102 lByteOffset = pSource->lOffset * 2;
2103 lByteOffset -= (lByteOffset % (lChannels * 2));
2105 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2107 lByteOffset = pSource->lOffset * 2;
2108 lByteOffset -= (lByteOffset % (lChannels * 2));
2110 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2112 lByteOffset = pSource->lOffset / 2;
2113 lByteOffset -= (lByteOffset % (lChannels * 2));
2115 else
2117 lByteOffset = pSource->lOffset;
2118 lByteOffset -= (lByteOffset % (lChannels * 2));
2120 break;
2122 case AL_SAMPLE_OFFSET:
2123 lByteOffset = pSource->lOffset * lChannels * 2;
2124 break;
2126 case AL_SEC_OFFSET:
2127 // Note - lOffset is internally stored as Milliseconds
2128 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2129 lByteOffset -= (lByteOffset % (lChannels * 2));
2130 break;
2133 lTotalBufferDataSize = 0;
2134 pBufferList = pSource->queue;
2135 while (pBufferList)
2137 if (pBufferList->buffer)
2138 lTotalBufferDataSize += pBufferList->buffer->size;
2139 pBufferList = pBufferList->next;
2142 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2143 if (lByteOffset >= lTotalBufferDataSize)
2144 lByteOffset = -1;
2147 return lByteOffset;
2151 ALvoid ReleaseALSources(ALCcontext *Context)
2153 while(Context->Source)
2155 ALsource *temp = Context->Source;
2156 Context->Source = Context->Source->next;
2158 // Release source structure
2159 ALTHUNK_REMOVEENTRY(temp->source);
2160 memset(temp, 0, sizeof(ALsource));
2161 free(temp);
2163 Context->SourceCount = 0;