Mark the source for updating when setting a buffer on it
[openal-soft/openal-hmr.git] / OpenAL32 / alSource.c
blob5ffc503c6bab5fc89f82cfae1120c29f7de53a89
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, 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(*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;
233 pSource->NeedsUpdate = AL_TRUE;
235 else
236 alSetError(AL_INVALID_VALUE);
237 break;
239 case AL_CONE_INNER_ANGLE:
240 if(flValue >= 0.0f && flValue <= 360.0f)
242 pSource->flInnerAngle = flValue;
243 pSource->NeedsUpdate = AL_TRUE;
245 else
246 alSetError(AL_INVALID_VALUE);
247 break;
249 case AL_CONE_OUTER_ANGLE:
250 if(flValue >= 0.0f && flValue <= 360.0f)
252 pSource->flOuterAngle = flValue;
253 pSource->NeedsUpdate = AL_TRUE;
255 else
256 alSetError(AL_INVALID_VALUE);
257 break;
259 case AL_GAIN:
260 if(flValue >= 0.0f)
262 pSource->flGain = flValue;
263 pSource->NeedsUpdate = AL_TRUE;
265 else
266 alSetError(AL_INVALID_VALUE);
267 break;
269 case AL_MAX_DISTANCE:
270 if(flValue >= 0.0f)
272 pSource->flMaxDistance = flValue;
273 pSource->NeedsUpdate = AL_TRUE;
275 else
276 alSetError(AL_INVALID_VALUE);
277 break;
279 case AL_ROLLOFF_FACTOR:
280 if(flValue >= 0.0f)
282 pSource->flRollOffFactor = flValue;
283 pSource->NeedsUpdate = AL_TRUE;
285 else
286 alSetError(AL_INVALID_VALUE);
287 break;
289 case AL_REFERENCE_DISTANCE:
290 if(flValue >= 0.0f)
292 pSource->flRefDistance = flValue;
293 pSource->NeedsUpdate = AL_TRUE;
295 else
296 alSetError(AL_INVALID_VALUE);
297 break;
299 case AL_MIN_GAIN:
300 if(flValue >= 0.0f && flValue <= 1.0f)
302 pSource->flMinGain = flValue;
303 pSource->NeedsUpdate = AL_TRUE;
305 else
306 alSetError(AL_INVALID_VALUE);
307 break;
309 case AL_MAX_GAIN:
310 if(flValue >= 0.0f && flValue <= 1.0f)
312 pSource->flMaxGain = flValue;
313 pSource->NeedsUpdate = AL_TRUE;
315 else
316 alSetError(AL_INVALID_VALUE);
317 break;
319 case AL_CONE_OUTER_GAIN:
320 if(flValue >= 0.0f && flValue <= 1.0f)
322 pSource->flOuterGain = flValue;
323 pSource->NeedsUpdate = AL_TRUE;
325 else
326 alSetError(AL_INVALID_VALUE);
327 break;
329 case AL_CONE_OUTER_GAINHF:
330 if(flValue >= 0.0f && flValue <= 1.0f)
332 pSource->OuterGainHF = flValue;
333 pSource->NeedsUpdate = AL_TRUE;
335 else
336 alSetError(AL_INVALID_VALUE);
337 break;
339 case AL_AIR_ABSORPTION_FACTOR:
340 if(flValue >= 0.0f && flValue <= 10.0f)
342 pSource->AirAbsorptionFactor = flValue;
343 pSource->NeedsUpdate = AL_TRUE;
345 else
346 alSetError(AL_INVALID_VALUE);
347 break;
349 case AL_ROOM_ROLLOFF_FACTOR:
350 if(flValue >= 0.0f && flValue <= 10.0f)
352 pSource->RoomRolloffFactor = flValue;
353 pSource->NeedsUpdate = AL_TRUE;
355 else
356 alSetError(AL_INVALID_VALUE);
357 break;
359 case AL_DOPPLER_FACTOR:
360 if(flValue >= 0.0f && flValue <= 1.0f)
362 pSource->DopplerFactor = flValue;
363 pSource->NeedsUpdate = AL_TRUE;
365 else
366 alSetError(AL_INVALID_VALUE);
367 break;
369 case AL_SEC_OFFSET:
370 case AL_SAMPLE_OFFSET:
371 case AL_BYTE_OFFSET:
372 if(flValue >= 0.0f)
374 pSource->lOffsetType = eParam;
376 // Store Offset (convert Seconds into Milliseconds)
377 if(eParam == AL_SEC_OFFSET)
378 pSource->lOffset = (ALint)(flValue * 1000.0f);
379 else
380 pSource->lOffset = (ALint)flValue;
382 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
383 ApplyOffset(pSource, AL_TRUE);
385 else
386 alSetError(AL_INVALID_VALUE);
387 break;
389 default:
390 alSetError(AL_INVALID_ENUM);
391 break;
394 else
396 // Invalid Source Name
397 alSetError(AL_INVALID_NAME);
400 ProcessContext(pContext);
404 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
406 ALCcontext *pContext;
407 ALsource *pSource;
409 pContext = GetContextSuspended();
410 if(!pContext) return;
412 if(alIsSource(source))
414 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
415 switch(eParam)
417 case AL_POSITION:
418 pSource->vPosition[0] = flValue1;
419 pSource->vPosition[1] = flValue2;
420 pSource->vPosition[2] = flValue3;
421 pSource->NeedsUpdate = AL_TRUE;
422 break;
424 case AL_VELOCITY:
425 pSource->vVelocity[0] = flValue1;
426 pSource->vVelocity[1] = flValue2;
427 pSource->vVelocity[2] = flValue3;
428 pSource->NeedsUpdate = AL_TRUE;
429 break;
431 case AL_DIRECTION:
432 pSource->vOrientation[0] = flValue1;
433 pSource->vOrientation[1] = flValue2;
434 pSource->vOrientation[2] = flValue3;
435 pSource->NeedsUpdate = AL_TRUE;
436 break;
438 default:
439 alSetError(AL_INVALID_ENUM);
440 break;
443 else
444 alSetError(AL_INVALID_NAME);
446 ProcessContext(pContext);
450 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
452 ALCcontext *pContext;
454 pContext = GetContextSuspended();
455 if(!pContext) return;
457 if(pflValues)
459 if(alIsSource(source))
461 switch(eParam)
463 case AL_PITCH:
464 case AL_CONE_INNER_ANGLE:
465 case AL_CONE_OUTER_ANGLE:
466 case AL_GAIN:
467 case AL_MAX_DISTANCE:
468 case AL_ROLLOFF_FACTOR:
469 case AL_REFERENCE_DISTANCE:
470 case AL_MIN_GAIN:
471 case AL_MAX_GAIN:
472 case AL_CONE_OUTER_GAIN:
473 case AL_CONE_OUTER_GAINHF:
474 case AL_SEC_OFFSET:
475 case AL_SAMPLE_OFFSET:
476 case AL_BYTE_OFFSET:
477 case AL_AIR_ABSORPTION_FACTOR:
478 case AL_ROOM_ROLLOFF_FACTOR:
479 alSourcef(source, eParam, pflValues[0]);
480 break;
482 case AL_POSITION:
483 case AL_VELOCITY:
484 case AL_DIRECTION:
485 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
486 break;
488 default:
489 alSetError(AL_INVALID_ENUM);
490 break;
493 else
494 alSetError(AL_INVALID_NAME);
496 else
497 alSetError(AL_INVALID_VALUE);
499 ProcessContext(pContext);
503 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
505 ALCcontext *pContext;
506 ALsource *pSource;
507 ALbufferlistitem *pALBufferListItem;
509 pContext = GetContextSuspended();
510 if(!pContext) return;
512 if(alIsSource(source))
514 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
516 switch(eParam)
518 case AL_MAX_DISTANCE:
519 case AL_ROLLOFF_FACTOR:
520 case AL_REFERENCE_DISTANCE:
521 alSourcef(source, eParam, (ALfloat)lValue);
522 break;
524 case AL_SOURCE_RELATIVE:
525 if(lValue == AL_FALSE || lValue == AL_TRUE)
527 pSource->bHeadRelative = (ALboolean)lValue;
528 pSource->NeedsUpdate = AL_TRUE;
530 else
531 alSetError(AL_INVALID_VALUE);
532 break;
534 case AL_CONE_INNER_ANGLE:
535 if(lValue >= 0 && lValue <= 360)
537 pSource->flInnerAngle = (float)lValue;
538 pSource->NeedsUpdate = AL_TRUE;
540 else
541 alSetError(AL_INVALID_VALUE);
542 break;
544 case AL_CONE_OUTER_ANGLE:
545 if(lValue >= 0 && lValue <= 360)
547 pSource->flOuterAngle = (float)lValue;
548 pSource->NeedsUpdate = AL_TRUE;
550 else
551 alSetError(AL_INVALID_VALUE);
552 break;
554 case AL_LOOPING:
555 if(lValue == AL_FALSE || lValue == AL_TRUE)
556 pSource->bLooping = (ALboolean)lValue;
557 else
558 alSetError(AL_INVALID_VALUE);
559 break;
561 case AL_BUFFER:
562 if(pSource->state == AL_STOPPED || pSource->state == AL_INITIAL)
564 if(alIsBuffer(lValue))
566 ALbuffer *buffer = NULL;
568 // Remove all elements in the queue
569 while(pSource->queue != NULL)
571 pALBufferListItem = pSource->queue;
572 pSource->queue = pALBufferListItem->next;
573 // Decrement reference counter for buffer
574 if(pALBufferListItem->buffer)
575 pALBufferListItem->buffer->refcount--;
576 // Release memory for buffer list item
577 free(pALBufferListItem);
578 // Decrement the number of buffers in the queue
579 pSource->BuffersInQueue--;
582 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
583 if(lValue != 0)
585 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue);
587 // Source is now in STATIC mode
588 pSource->lSourceType = AL_STATIC;
590 // Add the selected buffer to the queue
591 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
592 pALBufferListItem->buffer = buffer;
593 pALBufferListItem->next = NULL;
595 pSource->queue = pALBufferListItem;
596 pSource->BuffersInQueue = 1;
598 // Increment reference counter for buffer
599 buffer->refcount++;
601 else
603 // Source is now in UNDETERMINED mode
604 pSource->lSourceType = AL_UNDETERMINED;
605 pSource->BuffersPlayed = 0;
608 // Update AL_BUFFER parameter
609 pSource->Buffer = buffer;
610 pSource->NeedsUpdate = AL_TRUE;
612 else
613 alSetError(AL_INVALID_VALUE);
615 else
616 alSetError(AL_INVALID_OPERATION);
617 break;
619 case AL_SOURCE_STATE:
620 // Query only
621 alSetError(AL_INVALID_OPERATION);
622 break;
624 case AL_SEC_OFFSET:
625 case AL_SAMPLE_OFFSET:
626 case AL_BYTE_OFFSET:
627 if(lValue >= 0)
629 pSource->lOffsetType = eParam;
631 // Store Offset (convert Seconds into Milliseconds)
632 if(eParam == AL_SEC_OFFSET)
633 pSource->lOffset = lValue * 1000;
634 else
635 pSource->lOffset = lValue;
637 if(pSource->state == AL_PLAYING || pSource->state == AL_PAUSED)
638 ApplyOffset(pSource, AL_TRUE);
640 else
641 alSetError(AL_INVALID_VALUE);
642 break;
644 case AL_DIRECT_FILTER:
645 if(alIsFilter(lValue))
647 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
648 if(!filter)
650 pSource->DirectFilter.type = AL_FILTER_NULL;
651 pSource->DirectFilter.filter = 0;
653 else
654 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
655 pSource->NeedsUpdate = AL_TRUE;
657 else
658 alSetError(AL_INVALID_VALUE);
659 break;
661 case AL_DIRECT_FILTER_GAINHF_AUTO:
662 if(lValue == AL_TRUE || lValue == AL_FALSE)
664 pSource->DryGainHFAuto = lValue;
665 pSource->NeedsUpdate = AL_TRUE;
667 else
668 alSetError(AL_INVALID_VALUE);
669 break;
671 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
672 if(lValue == AL_TRUE || lValue == AL_FALSE)
674 pSource->WetGainAuto = lValue;
675 pSource->NeedsUpdate = AL_TRUE;
677 else
678 alSetError(AL_INVALID_VALUE);
679 break;
681 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
682 if(lValue == AL_TRUE || lValue == AL_FALSE)
684 pSource->WetGainHFAuto = lValue;
685 pSource->NeedsUpdate = AL_TRUE;
687 else
688 alSetError(AL_INVALID_VALUE);
689 break;
691 case AL_DISTANCE_MODEL:
692 if(lValue == AL_NONE ||
693 lValue == AL_INVERSE_DISTANCE ||
694 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
695 lValue == AL_LINEAR_DISTANCE ||
696 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
697 lValue == AL_EXPONENT_DISTANCE ||
698 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
700 pSource->DistanceModel = lValue;
701 if(pContext->SourceDistanceModel)
702 pSource->NeedsUpdate = AL_TRUE;
704 else
705 alSetError(AL_INVALID_VALUE);
706 break;
708 default:
709 alSetError(AL_INVALID_ENUM);
710 break;
713 else
714 alSetError(AL_INVALID_NAME);
716 ProcessContext(pContext);
720 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
722 ALCcontext *pContext;
724 pContext = GetContextSuspended();
725 if(!pContext) return;
727 if(alIsSource(source))
729 ALsource *pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
730 ALCdevice *Device = pContext->Device;
732 switch (eParam)
734 case AL_POSITION:
735 case AL_VELOCITY:
736 case AL_DIRECTION:
737 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
738 break;
740 case AL_AUXILIARY_SEND_FILTER:
741 if((ALuint)lValue2 < Device->NumAuxSends &&
742 (lValue1 == 0 || alIsAuxiliaryEffectSlot(lValue1)) &&
743 alIsFilter(lValue3))
745 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
746 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
748 /* Release refcount on the previous slot, and add one for
749 * the new slot */
750 if(pSource->Send[lValue2].Slot)
751 pSource->Send[lValue2].Slot->refcount--;
752 pSource->Send[lValue2].Slot = ALEffectSlot;
753 if(pSource->Send[lValue2].Slot)
754 pSource->Send[lValue2].Slot->refcount++;
756 if(!ALFilter)
758 /* Disable filter */
759 pSource->Send[lValue2].WetFilter.type = 0;
760 pSource->Send[lValue2].WetFilter.filter = 0;
762 else
763 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
764 pSource->NeedsUpdate = AL_TRUE;
766 else
767 alSetError(AL_INVALID_VALUE);
768 break;
770 default:
771 alSetError(AL_INVALID_ENUM);
772 break;
775 else
776 alSetError(AL_INVALID_NAME);
778 ProcessContext(pContext);
782 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
784 ALCcontext *pContext;
786 pContext = GetContextSuspended();
787 if(!pContext) return;
789 if(plValues)
791 if(alIsSource(source))
793 switch(eParam)
795 case AL_SOURCE_RELATIVE:
796 case AL_CONE_INNER_ANGLE:
797 case AL_CONE_OUTER_ANGLE:
798 case AL_LOOPING:
799 case AL_BUFFER:
800 case AL_SOURCE_STATE:
801 case AL_SEC_OFFSET:
802 case AL_SAMPLE_OFFSET:
803 case AL_BYTE_OFFSET:
804 case AL_MAX_DISTANCE:
805 case AL_ROLLOFF_FACTOR:
806 case AL_REFERENCE_DISTANCE:
807 case AL_DIRECT_FILTER:
808 case AL_DIRECT_FILTER_GAINHF_AUTO:
809 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
810 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
811 case AL_DISTANCE_MODEL:
812 alSourcei(source, eParam, plValues[0]);
813 break;
815 case AL_POSITION:
816 case AL_VELOCITY:
817 case AL_DIRECTION:
818 case AL_AUXILIARY_SEND_FILTER:
819 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
820 break;
822 default:
823 alSetError(AL_INVALID_ENUM);
824 break;
827 else
828 alSetError(AL_INVALID_NAME);
830 else
831 alSetError(AL_INVALID_VALUE);
833 ProcessContext(pContext);
837 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
839 ALCcontext *pContext;
840 ALsource *pSource;
841 ALfloat flOffset[2];
843 pContext = GetContextSuspended();
844 if(!pContext) return;
846 if(pflValue)
848 if(alIsSource(source))
850 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
852 switch(eParam)
854 case AL_PITCH:
855 *pflValue = pSource->flPitch;
856 break;
858 case AL_GAIN:
859 *pflValue = pSource->flGain;
860 break;
862 case AL_MIN_GAIN:
863 *pflValue = pSource->flMinGain;
864 break;
866 case AL_MAX_GAIN:
867 *pflValue = pSource->flMaxGain;
868 break;
870 case AL_MAX_DISTANCE:
871 *pflValue = pSource->flMaxDistance;
872 break;
874 case AL_ROLLOFF_FACTOR:
875 *pflValue = pSource->flRollOffFactor;
876 break;
878 case AL_CONE_OUTER_GAIN:
879 *pflValue = pSource->flOuterGain;
880 break;
882 case AL_CONE_OUTER_GAINHF:
883 *pflValue = pSource->OuterGainHF;
884 break;
886 case AL_SEC_OFFSET:
887 case AL_SAMPLE_OFFSET:
888 case AL_BYTE_OFFSET:
889 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
890 *pflValue = flOffset[0];
891 else
892 alSetError(AL_INVALID_OPERATION);
893 break;
895 case AL_SEC_RW_OFFSETS_EXT:
896 case AL_SAMPLE_RW_OFFSETS_EXT:
897 case AL_BYTE_RW_OFFSETS_EXT:
898 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
900 pflValue[0] = flOffset[0];
901 pflValue[1] = flOffset[1];
903 else
904 alSetError(AL_INVALID_OPERATION);
905 break;
907 case AL_CONE_INNER_ANGLE:
908 *pflValue = pSource->flInnerAngle;
909 break;
911 case AL_CONE_OUTER_ANGLE:
912 *pflValue = pSource->flOuterAngle;
913 break;
915 case AL_REFERENCE_DISTANCE:
916 *pflValue = pSource->flRefDistance;
917 break;
919 case AL_AIR_ABSORPTION_FACTOR:
920 *pflValue = pSource->AirAbsorptionFactor;
921 break;
923 case AL_ROOM_ROLLOFF_FACTOR:
924 *pflValue = pSource->RoomRolloffFactor;
925 break;
927 case AL_DOPPLER_FACTOR:
928 *pflValue = pSource->DopplerFactor;
929 break;
931 default:
932 alSetError(AL_INVALID_ENUM);
933 break;
936 else
937 alSetError(AL_INVALID_NAME);
939 else
940 alSetError(AL_INVALID_VALUE);
942 ProcessContext(pContext);
946 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
948 ALCcontext *pContext;
949 ALsource *pSource;
951 pContext = GetContextSuspended();
952 if(!pContext) return;
954 if(pflValue1 && pflValue2 && pflValue3)
956 if(alIsSource(source))
958 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
960 switch(eParam)
962 case AL_POSITION:
963 *pflValue1 = pSource->vPosition[0];
964 *pflValue2 = pSource->vPosition[1];
965 *pflValue3 = pSource->vPosition[2];
966 break;
968 case AL_VELOCITY:
969 *pflValue1 = pSource->vVelocity[0];
970 *pflValue2 = pSource->vVelocity[1];
971 *pflValue3 = pSource->vVelocity[2];
972 break;
974 case AL_DIRECTION:
975 *pflValue1 = pSource->vOrientation[0];
976 *pflValue2 = pSource->vOrientation[1];
977 *pflValue3 = pSource->vOrientation[2];
978 break;
980 default:
981 alSetError(AL_INVALID_ENUM);
982 break;
985 else
986 alSetError(AL_INVALID_NAME);
988 else
989 alSetError(AL_INVALID_VALUE);
991 ProcessContext(pContext);
995 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
997 ALCcontext *pContext;
998 ALsource *pSource;
1000 pContext = GetContextSuspended();
1001 if(!pContext) return;
1003 if(pflValues)
1005 if(alIsSource(source))
1007 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1009 switch(eParam)
1011 case AL_PITCH:
1012 case AL_GAIN:
1013 case AL_MIN_GAIN:
1014 case AL_MAX_GAIN:
1015 case AL_MAX_DISTANCE:
1016 case AL_ROLLOFF_FACTOR:
1017 case AL_DOPPLER_FACTOR:
1018 case AL_CONE_OUTER_GAIN:
1019 case AL_SEC_OFFSET:
1020 case AL_SAMPLE_OFFSET:
1021 case AL_BYTE_OFFSET:
1022 case AL_CONE_INNER_ANGLE:
1023 case AL_CONE_OUTER_ANGLE:
1024 case AL_REFERENCE_DISTANCE:
1025 case AL_CONE_OUTER_GAINHF:
1026 case AL_AIR_ABSORPTION_FACTOR:
1027 case AL_ROOM_ROLLOFF_FACTOR:
1028 alGetSourcef(source, eParam, pflValues);
1029 break;
1031 case AL_POSITION:
1032 pflValues[0] = pSource->vPosition[0];
1033 pflValues[1] = pSource->vPosition[1];
1034 pflValues[2] = pSource->vPosition[2];
1035 break;
1037 case AL_VELOCITY:
1038 pflValues[0] = pSource->vVelocity[0];
1039 pflValues[1] = pSource->vVelocity[1];
1040 pflValues[2] = pSource->vVelocity[2];
1041 break;
1043 case AL_DIRECTION:
1044 pflValues[0] = pSource->vOrientation[0];
1045 pflValues[1] = pSource->vOrientation[1];
1046 pflValues[2] = pSource->vOrientation[2];
1047 break;
1049 default:
1050 alSetError(AL_INVALID_ENUM);
1051 break;
1054 else
1055 alSetError(AL_INVALID_NAME);
1057 else
1058 alSetError(AL_INVALID_VALUE);
1060 ProcessContext(pContext);
1064 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1066 ALCcontext *pContext;
1067 ALsource *pSource;
1068 ALfloat flOffset[2];
1070 pContext = GetContextSuspended();
1071 if(!pContext) return;
1073 if(plValue)
1075 if(alIsSource(source))
1077 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1079 switch(eParam)
1081 case AL_MAX_DISTANCE:
1082 *plValue = (ALint)pSource->flMaxDistance;
1083 break;
1085 case AL_ROLLOFF_FACTOR:
1086 *plValue = (ALint)pSource->flRollOffFactor;
1087 break;
1089 case AL_REFERENCE_DISTANCE:
1090 *plValue = (ALint)pSource->flRefDistance;
1091 break;
1093 case AL_SOURCE_RELATIVE:
1094 *plValue = pSource->bHeadRelative;
1095 break;
1097 case AL_CONE_INNER_ANGLE:
1098 *plValue = (ALint)pSource->flInnerAngle;
1099 break;
1101 case AL_CONE_OUTER_ANGLE:
1102 *plValue = (ALint)pSource->flOuterAngle;
1103 break;
1105 case AL_LOOPING:
1106 *plValue = pSource->bLooping;
1107 break;
1109 case AL_BUFFER:
1110 *plValue = (pSource->Buffer ? pSource->Buffer->buffer : 0);
1111 break;
1113 case AL_SOURCE_STATE:
1114 *plValue = pSource->state;
1115 break;
1117 case AL_BUFFERS_QUEUED:
1118 *plValue = pSource->BuffersInQueue;
1119 break;
1121 case AL_BUFFERS_PROCESSED:
1122 if(pSource->bLooping)
1124 /* Buffers on a looping source are in a perpetual state
1125 * of PENDING, so don't report any as PROCESSED */
1126 *plValue = 0;
1128 else
1129 *plValue = pSource->BuffersPlayed;
1130 break;
1132 case AL_SOURCE_TYPE:
1133 *plValue = pSource->lSourceType;
1134 break;
1136 case AL_SEC_OFFSET:
1137 case AL_SAMPLE_OFFSET:
1138 case AL_BYTE_OFFSET:
1139 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1140 *plValue = (ALint)flOffset[0];
1141 else
1142 alSetError(AL_INVALID_OPERATION);
1143 break;
1145 case AL_SEC_RW_OFFSETS_EXT:
1146 case AL_SAMPLE_RW_OFFSETS_EXT:
1147 case AL_BYTE_RW_OFFSETS_EXT:
1148 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1150 plValue[0] = (ALint)flOffset[0];
1151 plValue[1] = (ALint)flOffset[1];
1153 else
1154 alSetError(AL_INVALID_OPERATION);
1155 break;
1157 case AL_DIRECT_FILTER:
1158 *plValue = pSource->DirectFilter.filter;
1159 break;
1161 case AL_DIRECT_FILTER_GAINHF_AUTO:
1162 *plValue = pSource->DryGainHFAuto;
1163 break;
1165 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1166 *plValue = pSource->WetGainAuto;
1167 break;
1169 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1170 *plValue = pSource->WetGainHFAuto;
1171 break;
1173 case AL_DOPPLER_FACTOR:
1174 *plValue = (ALint)pSource->DopplerFactor;
1175 break;
1177 case AL_DISTANCE_MODEL:
1178 *plValue = pSource->DistanceModel;
1179 break;
1181 default:
1182 alSetError(AL_INVALID_ENUM);
1183 break;
1186 else
1187 alSetError(AL_INVALID_NAME);
1189 else
1190 alSetError(AL_INVALID_VALUE);
1192 ProcessContext(pContext);
1196 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1198 ALCcontext *pContext;
1199 ALsource *pSource;
1201 pContext = GetContextSuspended();
1202 if(!pContext) return;
1204 if(plValue1 && plValue2 && plValue3)
1206 if(alIsSource(source))
1208 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1210 switch(eParam)
1212 case AL_POSITION:
1213 *plValue1 = (ALint)pSource->vPosition[0];
1214 *plValue2 = (ALint)pSource->vPosition[1];
1215 *plValue3 = (ALint)pSource->vPosition[2];
1216 break;
1218 case AL_VELOCITY:
1219 *plValue1 = (ALint)pSource->vVelocity[0];
1220 *plValue2 = (ALint)pSource->vVelocity[1];
1221 *plValue3 = (ALint)pSource->vVelocity[2];
1222 break;
1224 case AL_DIRECTION:
1225 *plValue1 = (ALint)pSource->vOrientation[0];
1226 *plValue2 = (ALint)pSource->vOrientation[1];
1227 *plValue3 = (ALint)pSource->vOrientation[2];
1228 break;
1230 default:
1231 alSetError(AL_INVALID_ENUM);
1232 break;
1235 else
1236 alSetError(AL_INVALID_NAME);
1238 else
1239 alSetError(AL_INVALID_VALUE);
1241 ProcessContext(pContext);
1245 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1247 ALCcontext *pContext;
1248 ALsource *pSource;
1250 pContext = GetContextSuspended();
1251 if(!pContext) return;
1253 if(plValues)
1255 if(alIsSource(source))
1257 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1259 switch(eParam)
1261 case AL_SOURCE_RELATIVE:
1262 case AL_CONE_INNER_ANGLE:
1263 case AL_CONE_OUTER_ANGLE:
1264 case AL_LOOPING:
1265 case AL_BUFFER:
1266 case AL_SOURCE_STATE:
1267 case AL_BUFFERS_QUEUED:
1268 case AL_BUFFERS_PROCESSED:
1269 case AL_SEC_OFFSET:
1270 case AL_SAMPLE_OFFSET:
1271 case AL_BYTE_OFFSET:
1272 case AL_MAX_DISTANCE:
1273 case AL_ROLLOFF_FACTOR:
1274 case AL_DOPPLER_FACTOR:
1275 case AL_REFERENCE_DISTANCE:
1276 case AL_SOURCE_TYPE:
1277 case AL_DIRECT_FILTER:
1278 case AL_DIRECT_FILTER_GAINHF_AUTO:
1279 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1280 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1281 case AL_DISTANCE_MODEL:
1282 alGetSourcei(source, eParam, plValues);
1283 break;
1285 case AL_POSITION:
1286 plValues[0] = (ALint)pSource->vPosition[0];
1287 plValues[1] = (ALint)pSource->vPosition[1];
1288 plValues[2] = (ALint)pSource->vPosition[2];
1289 break;
1291 case AL_VELOCITY:
1292 plValues[0] = (ALint)pSource->vVelocity[0];
1293 plValues[1] = (ALint)pSource->vVelocity[1];
1294 plValues[2] = (ALint)pSource->vVelocity[2];
1295 break;
1297 case AL_DIRECTION:
1298 plValues[0] = (ALint)pSource->vOrientation[0];
1299 plValues[1] = (ALint)pSource->vOrientation[1];
1300 plValues[2] = (ALint)pSource->vOrientation[2];
1301 break;
1303 default:
1304 alSetError(AL_INVALID_ENUM);
1305 break;
1308 else
1309 alSetError(AL_INVALID_NAME);
1311 else
1312 alSetError(AL_INVALID_VALUE);
1314 ProcessContext(pContext);
1318 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1320 alSourcePlayv(1, &source);
1323 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1325 ALCcontext *pContext;
1326 ALsource *pSource;
1327 ALbufferlistitem *ALBufferList;
1328 ALboolean bSourcesValid = AL_TRUE;
1329 ALboolean bPlay;
1330 ALsizei i, j;
1332 pContext = GetContextSuspended();
1333 if(!pContext) return;
1335 if(pSourceList)
1337 // Check that all the Sources are valid
1338 for(i = 0; i < n; i++)
1340 if(!alIsSource(pSourceList[i]))
1342 alSetError(AL_INVALID_NAME);
1343 bSourcesValid = AL_FALSE;
1344 break;
1348 if(bSourcesValid)
1350 for(i = 0; i < n; i++)
1352 // Assume Source won't need to play
1353 bPlay = AL_FALSE;
1355 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]);
1357 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1358 ALBufferList = pSource->queue;
1359 while(ALBufferList)
1361 if(ALBufferList->buffer != NULL && ALBufferList->buffer->size)
1363 bPlay = AL_TRUE;
1364 break;
1366 ALBufferList = ALBufferList->next;
1369 if (bPlay)
1371 for(j = 0;j < OUTPUTCHANNELS;j++)
1372 pSource->DryGains[j] = 0.0f;
1373 for(j = 0;j < MAX_SENDS;j++)
1374 pSource->WetGains[j] = 0.0f;
1376 if(pSource->state != AL_PAUSED)
1378 pSource->state = AL_PLAYING;
1379 pSource->position = 0;
1380 pSource->position_fraction = 0;
1381 pSource->BuffersPlayed = 0;
1383 pSource->Buffer = pSource->queue->buffer;
1385 else
1386 pSource->state = AL_PLAYING;
1388 // Check if an Offset has been set
1389 if(pSource->lOffset)
1390 ApplyOffset(pSource, AL_FALSE);
1392 if(pSource->BuffersPlayed == 0 && pSource->position == 0 &&
1393 pSource->position_fraction == 0)
1394 pSource->FirstStart = AL_TRUE;
1395 else
1396 pSource->FirstStart = AL_FALSE;
1398 // If device is disconnected, go right to stopped
1399 if(!pContext->Device->Connected)
1401 pSource->state = AL_STOPPED;
1402 pSource->BuffersPlayed = pSource->BuffersInQueue;
1403 pSource->position = 0;
1404 pSource->position_fraction = 0;
1407 else
1408 pSource->BuffersPlayed = pSource->BuffersInQueue;
1412 else
1414 // sources is a NULL pointer
1415 alSetError(AL_INVALID_VALUE);
1418 ProcessContext(pContext);
1421 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1423 alSourcePausev(1, &source);
1426 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1428 ALCcontext *Context;
1429 ALsource *Source;
1430 ALsizei i;
1431 ALboolean bSourcesValid = AL_TRUE;
1433 Context = GetContextSuspended();
1434 if(!Context) return;
1436 if(sources)
1438 // Check all the Sources are valid
1439 for(i=0;i<n;i++)
1441 if(!alIsSource(sources[i]))
1443 alSetError(AL_INVALID_NAME);
1444 bSourcesValid = AL_FALSE;
1445 break;
1449 if(bSourcesValid)
1451 for(i = 0;i < n;i++)
1453 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1454 if(Source->state == AL_PLAYING)
1455 Source->state = AL_PAUSED;
1459 else
1461 // sources is a NULL pointer
1462 alSetError(AL_INVALID_VALUE);
1465 ProcessContext(Context);
1468 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1470 alSourceStopv(1, &source);
1473 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1475 ALCcontext *Context;
1476 ALsource *Source;
1477 ALsizei i;
1478 ALboolean bSourcesValid = AL_TRUE;
1480 Context = GetContextSuspended();
1481 if(!Context) return;
1483 if(sources)
1485 // Check all the Sources are valid
1486 for(i = 0;i < n;i++)
1488 if(!alIsSource(sources[i]))
1490 alSetError(AL_INVALID_NAME);
1491 bSourcesValid = AL_FALSE;
1492 break;
1496 if(bSourcesValid)
1498 for(i = 0;i < n;i++)
1500 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1501 if(Source->state != AL_INITIAL)
1503 Source->state = AL_STOPPED;
1504 Source->BuffersPlayed = Source->BuffersInQueue;
1506 Source->lOffset = 0;
1510 else
1512 // sources is a NULL pointer
1513 alSetError(AL_INVALID_VALUE);
1516 ProcessContext(Context);
1519 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1521 alSourceRewindv(1, &source);
1524 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1526 ALCcontext *Context;
1527 ALsource *Source;
1528 ALsizei i;
1529 ALboolean bSourcesValid = AL_TRUE;
1531 Context = GetContextSuspended();
1532 if(!Context) return;
1534 if(sources)
1536 // Check all the Sources are valid
1537 for(i = 0;i < n;i++)
1539 if(!alIsSource(sources[i]))
1541 alSetError(AL_INVALID_NAME);
1542 bSourcesValid = AL_FALSE;
1543 break;
1547 if(bSourcesValid)
1549 for(i = 0;i < n;i++)
1551 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1552 if(Source->state != AL_INITIAL)
1554 Source->state = AL_INITIAL;
1555 Source->position = 0;
1556 Source->position_fraction = 0;
1557 Source->BuffersPlayed = 0;
1558 if(Source->queue)
1559 Source->Buffer = Source->queue->buffer;
1561 Source->lOffset = 0;
1565 else
1567 // sources is a NULL pointer
1568 alSetError(AL_INVALID_VALUE);
1571 ProcessContext(Context);
1575 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1577 ALCcontext *Context;
1578 ALsource *ALSource;
1579 ALsizei i;
1580 ALbufferlistitem *ALBufferList;
1581 ALbufferlistitem *ALBufferListStart;
1582 ALint iFrequency;
1583 ALint iFormat;
1584 ALboolean bBuffersValid = AL_TRUE;
1585 ALboolean hadFormat = AL_FALSE;
1587 if (n == 0)
1588 return;
1590 Context = GetContextSuspended();
1591 if(!Context) return;
1593 // Check that all buffers are valid or zero and that the source is valid
1595 // Check that this is a valid source
1596 if(alIsSource(source))
1598 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1600 // Check that this is not a STATIC Source
1601 if(ALSource->lSourceType != AL_STATIC)
1603 iFrequency = -1;
1604 iFormat = -1;
1606 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1607 ALBufferList = ALSource->queue;
1608 while(ALBufferList)
1610 if (ALBufferList->buffer)
1612 iFrequency = ALBufferList->buffer->frequency;
1613 iFormat = ALBufferList->buffer->format;
1614 hadFormat = AL_TRUE;
1615 break;
1617 ALBufferList = ALBufferList->next;
1620 for(i = 0; i < n; i++)
1622 ALbuffer *buffer;
1624 if(!alIsBuffer(buffers[i]))
1626 alSetError(AL_INVALID_NAME);
1627 bBuffersValid = AL_FALSE;
1628 break;
1630 if(!buffers[i])
1631 continue;
1633 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1634 if(iFrequency == -1 && iFormat == -1)
1636 iFrequency = buffer->frequency;
1637 iFormat = buffer->format;
1639 else if(iFrequency != buffer->frequency ||
1640 iFormat != buffer->format)
1642 alSetError(AL_INVALID_OPERATION);
1643 bBuffersValid = AL_FALSE;
1644 break;
1648 if(bBuffersValid)
1650 ALbuffer *buffer = NULL;
1652 // Change Source Type
1653 ALSource->lSourceType = AL_STREAMING;
1655 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1657 // All buffers are valid - so add them to the list
1658 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1659 ALBufferListStart->buffer = buffer;
1660 ALBufferListStart->next = NULL;
1662 // Increment reference counter for buffer
1663 if(buffer) buffer->refcount++;
1665 ALBufferList = ALBufferListStart;
1667 for(i = 1; i < n; i++)
1669 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1671 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1672 ALBufferList->next->buffer = buffer;
1673 ALBufferList->next->next = NULL;
1675 // Increment reference counter for buffer
1676 if(buffer) buffer->refcount++;
1678 ALBufferList = ALBufferList->next;
1681 if(ALSource->queue == NULL)
1683 ALSource->queue = ALBufferListStart;
1684 // Update Current Buffer
1685 ALSource->Buffer = ALBufferListStart->buffer;
1687 else
1689 // Find end of queue
1690 ALBufferList = ALSource->queue;
1691 while(ALBufferList->next != NULL)
1692 ALBufferList = ALBufferList->next;
1694 ALBufferList->next = ALBufferListStart;
1697 // Update number of buffers in queue
1698 ALSource->BuffersInQueue += n;
1699 // If no previous format, mark the source dirty now that it may
1700 // have one
1701 if(!hadFormat)
1702 ALSource->NeedsUpdate = AL_TRUE;
1705 else
1707 // Invalid Source Type (can't queue on a Static Source)
1708 alSetError(AL_INVALID_OPERATION);
1711 else
1713 // Invalid Source Name
1714 alSetError(AL_INVALID_NAME);
1717 ProcessContext(Context);
1721 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1722 // an array of buffer IDs that are to be filled with the names of the buffers removed
1723 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1725 ALCcontext *Context;
1726 ALsource *ALSource;
1727 ALsizei i;
1728 ALbufferlistitem *ALBufferList;
1729 ALboolean bBuffersProcessed;
1731 if (n == 0)
1732 return;
1734 bBuffersProcessed = AL_TRUE;
1736 Context = GetContextSuspended();
1737 if(!Context) return;
1739 if(alIsSource(source))
1741 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1743 // If all 'n' buffers have been processed, remove them from the queue
1744 if(!ALSource->bLooping && (ALuint)n <= ALSource->BuffersPlayed)
1746 for(i = 0; i < n; i++)
1748 ALBufferList = ALSource->queue;
1750 ALSource->queue = ALBufferList->next;
1751 // Record name of buffer
1752 buffers[i] = ALBufferList->buffer->buffer;
1753 // Decrement buffer reference counter
1754 if(ALBufferList->buffer)
1755 ALBufferList->buffer->refcount--;
1757 // Release memory for buffer list item
1758 free(ALBufferList);
1759 ALSource->BuffersInQueue--;
1762 if(ALSource->state != AL_PLAYING)
1764 if(ALSource->queue)
1765 ALSource->Buffer = ALSource->queue->buffer;
1766 else
1767 ALSource->Buffer = NULL;
1770 ALSource->BuffersPlayed -= n;
1772 else
1774 // Some buffers can't be unqueue because they have not been processed
1775 alSetError(AL_INVALID_VALUE);
1778 else
1780 // Invalid Source Name
1781 alSetError(AL_INVALID_NAME);
1784 ProcessContext(Context);
1788 static ALvoid InitSourceParams(ALsource *pSource)
1790 pSource->flInnerAngle = 360.0f;
1791 pSource->flOuterAngle = 360.0f;
1792 pSource->flPitch = 1.0f;
1793 pSource->vPosition[0] = 0.0f;
1794 pSource->vPosition[1] = 0.0f;
1795 pSource->vPosition[2] = 0.0f;
1796 pSource->vOrientation[0] = 0.0f;
1797 pSource->vOrientation[1] = 0.0f;
1798 pSource->vOrientation[2] = 0.0f;
1799 pSource->vVelocity[0] = 0.0f;
1800 pSource->vVelocity[1] = 0.0f;
1801 pSource->vVelocity[2] = 0.0f;
1802 pSource->flRefDistance = 1.0f;
1803 pSource->flMaxDistance = FLT_MAX;
1804 pSource->flRollOffFactor = 1.0f;
1805 pSource->bLooping = AL_FALSE;
1806 pSource->flGain = 1.0f;
1807 pSource->flMinGain = 0.0f;
1808 pSource->flMaxGain = 1.0f;
1809 pSource->flOuterGain = 0.0f;
1810 pSource->OuterGainHF = 1.0f;
1812 pSource->DryGainHFAuto = AL_TRUE;
1813 pSource->WetGainAuto = AL_TRUE;
1814 pSource->WetGainHFAuto = AL_TRUE;
1815 pSource->AirAbsorptionFactor = 0.0f;
1816 pSource->RoomRolloffFactor = 0.0f;
1817 pSource->DopplerFactor = 1.0f;
1819 pSource->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1821 pSource->state = AL_INITIAL;
1822 pSource->lSourceType = AL_UNDETERMINED;
1824 pSource->NeedsUpdate = AL_TRUE;
1826 pSource->Buffer = NULL;
1831 GetSourceOffset
1833 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1834 The offset is relative to the start of the queue (not the start of the current buffer)
1836 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize)
1838 ALbufferlistitem *pBufferList;
1839 ALbuffer *pBuffer;
1840 ALfloat flBufferFreq;
1841 ALint lChannels, lBytes;
1842 ALint readPos, writePos;
1843 ALenum eOriginalFormat;
1844 ALboolean bReturn = AL_TRUE;
1845 ALint lTotalBufferDataSize;
1846 ALuint i;
1848 if((pSource->state == AL_PLAYING || pSource->state == AL_PAUSED) && pSource->Buffer)
1850 pBuffer = pSource->Buffer;
1851 // Get Current Buffer Size and frequency (in milliseconds)
1852 flBufferFreq = (ALfloat)pBuffer->frequency;
1853 eOriginalFormat = pBuffer->eOriginalFormat;
1854 lChannels = aluChannelsFromFormat(pBuffer->format);
1855 lBytes = aluBytesFromFormat(pBuffer->format);
1857 // Get Current BytesPlayed
1858 readPos = pSource->position * lChannels * lBytes; // NOTE : This is the byte offset into the *current* buffer
1859 // Add byte length of any processed buffers in the queue
1860 pBufferList = pSource->queue;
1861 for(i = 0;i < pSource->BuffersPlayed && pBufferList;i++)
1863 readPos += pBufferList->buffer->size;
1864 pBufferList = pBufferList->next;
1867 if(pSource->state == AL_PLAYING)
1868 writePos = readPos + (updateSize * lChannels * lBytes);
1869 else
1870 writePos = readPos;
1872 lTotalBufferDataSize = 0;
1873 pBufferList = pSource->queue;
1874 while (pBufferList)
1876 if (pBufferList->buffer)
1877 lTotalBufferDataSize += pBufferList->buffer->size;
1878 pBufferList = pBufferList->next;
1881 if (pSource->bLooping)
1883 if(readPos < 0)
1884 readPos = 0;
1885 else
1886 readPos %= lTotalBufferDataSize;
1887 if(writePos < 0)
1888 writePos = 0;
1889 else
1890 writePos %= lTotalBufferDataSize;
1892 else
1894 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1895 if(readPos < 0)
1896 readPos = 0;
1897 else if(readPos > lTotalBufferDataSize)
1898 readPos = lTotalBufferDataSize;
1899 if(writePos < 0)
1900 writePos = 0;
1901 else if(writePos > lTotalBufferDataSize)
1902 writePos = lTotalBufferDataSize;
1905 switch (eName)
1907 case AL_SEC_OFFSET:
1908 case AL_SEC_RW_OFFSETS_EXT:
1909 pflOffset[0] = (ALfloat)readPos / (lChannels * lBytes * flBufferFreq);
1910 pflOffset[1] = (ALfloat)writePos / (lChannels * lBytes * flBufferFreq);
1911 break;
1912 case AL_SAMPLE_OFFSET:
1913 case AL_SAMPLE_RW_OFFSETS_EXT:
1914 pflOffset[0] = (ALfloat)(readPos / (lChannels * lBytes));
1915 pflOffset[1] = (ALfloat)(writePos / (lChannels * lBytes));
1916 break;
1917 case AL_BYTE_OFFSET:
1918 case AL_BYTE_RW_OFFSETS_EXT:
1919 // Take into account the original format of the Buffer
1920 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
1921 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1923 // Round down to nearest ADPCM block
1924 pflOffset[0] = (ALfloat)((readPos / (65 * lBytes * lChannels)) * 36 * lChannels);
1925 if(pSource->state == AL_PLAYING)
1927 // Round up to nearest ADPCM block
1928 pflOffset[1] = (ALfloat)(((writePos + (65 * lBytes * lChannels) - 1) / (65 * lBytes * lChannels)) * 36 * lChannels);
1930 else
1931 pflOffset[1] = pflOffset[0];
1933 else if (eOriginalFormat == AL_FORMAT_REAR8)
1935 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 1);
1936 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 1);
1938 else if (eOriginalFormat == AL_FORMAT_REAR16)
1940 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 2);
1941 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 2);
1943 else if (eOriginalFormat == AL_FORMAT_REAR32)
1945 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 4);
1946 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 4);
1948 else if (aluBytesFromFormat(eOriginalFormat) == 1)
1950 pflOffset[0] = (ALfloat)(readPos / lBytes * 1);
1951 pflOffset[1] = (ALfloat)(writePos / lBytes * 1);
1953 else if (aluBytesFromFormat(eOriginalFormat) == 2)
1955 pflOffset[0] = (ALfloat)(readPos / lBytes * 2);
1956 pflOffset[1] = (ALfloat)(writePos / lBytes * 2);
1958 else if (aluBytesFromFormat(eOriginalFormat) == 4)
1960 pflOffset[0] = (ALfloat)(readPos / lBytes * 4);
1961 pflOffset[1] = (ALfloat)(writePos / lBytes * 4);
1963 else
1965 pflOffset[0] = (ALfloat)readPos;
1966 pflOffset[1] = (ALfloat)writePos;
1968 break;
1971 else
1973 pflOffset[0] = 0.0f;
1974 pflOffset[1] = 0.0f;
1977 return bReturn;
1982 ApplyOffset
1984 Apply a playback offset to the Source. This function will update the queue (to correctly
1985 mark buffers as 'pending' or 'processed' depending upon the new offset.
1987 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
1989 ALbufferlistitem *pBufferList;
1990 ALbuffer *pBuffer;
1991 ALint lBufferSize, lTotalBufferSize;
1992 ALint lByteOffset;
1994 // Get true byte offset
1995 lByteOffset = GetByteOffset(pSource);
1997 // If this is a valid offset apply it
1998 if (lByteOffset != -1)
2000 // Sort out the queue (pending and processed states)
2001 pBufferList = pSource->queue;
2002 lTotalBufferSize = 0;
2003 pSource->BuffersPlayed = 0;
2004 while (pBufferList)
2006 pBuffer = pBufferList->buffer;
2007 lBufferSize = pBuffer ? pBuffer->size : 0;
2009 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2011 // Offset is past this buffer so increment BuffersPlayed
2012 pSource->BuffersPlayed++;
2014 else if (lTotalBufferSize <= lByteOffset)
2016 // Offset is within this buffer
2017 // Set Current Buffer
2018 pSource->Buffer = pBufferList->buffer;
2020 // SW Mixer Positions are in Samples
2021 pSource->position = (lByteOffset - lTotalBufferSize) /
2022 aluBytesFromFormat(pBuffer->format) /
2023 aluChannelsFromFormat(pBuffer->format);
2026 // Increment the TotalBufferSize
2027 lTotalBufferSize += lBufferSize;
2029 // Move on to next buffer in the Queue
2030 pBufferList = pBufferList->next;
2033 else
2035 if (bUpdateContext)
2036 alSetError(AL_INVALID_VALUE);
2039 // Clear Offset
2040 pSource->lOffset = 0;
2045 GetByteOffset
2047 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2048 offset supplied by the application). This takes into account the fact that the buffer format
2049 may have been modifed by AL (e.g 8bit samples are converted to float)
2051 static ALint GetByteOffset(ALsource *pSource)
2053 ALbuffer *pBuffer = NULL;
2054 ALbufferlistitem *pBufferList;
2055 ALfloat flBufferFreq;
2056 ALint lChannels, lBytes;
2057 ALint lByteOffset = -1;
2058 ALint lTotalBufferDataSize;
2060 // Find the first non-NULL Buffer in the Queue
2061 pBufferList = pSource->queue;
2062 while (pBufferList)
2064 if (pBufferList->buffer)
2066 pBuffer = pBufferList->buffer;
2067 break;
2069 pBufferList = pBufferList->next;
2072 if (pBuffer)
2074 flBufferFreq = ((ALfloat)pBuffer->frequency);
2075 lChannels = aluChannelsFromFormat(pBuffer->format);
2076 lBytes = aluBytesFromFormat(pBuffer->format);
2078 // Determine the ByteOffset (and ensure it is block aligned)
2079 switch (pSource->lOffsetType)
2081 case AL_BYTE_OFFSET:
2082 // Take into consideration the original format
2083 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2084 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2086 // Round down to nearest ADPCM block
2087 lByteOffset = pSource->lOffset / (36 * lChannels);
2088 // Multiply by compression rate
2089 lByteOffset = lByteOffset * 65 * lChannels * lBytes;
2090 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2092 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2094 lByteOffset = pSource->lOffset / 1 * lBytes * 2;
2095 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2097 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2099 lByteOffset = pSource->lOffset / 2 * lBytes * 2;
2100 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2102 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR32)
2104 lByteOffset = pSource->lOffset / 4 * lBytes * 2;
2105 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2107 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2109 lByteOffset = pSource->lOffset / 1 * lBytes;
2110 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2112 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 2)
2114 lByteOffset = pSource->lOffset / 2 * lBytes;
2115 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2117 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2119 lByteOffset = pSource->lOffset / 4 * lBytes;
2120 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2122 else
2124 lByteOffset = pSource->lOffset;
2125 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2127 break;
2129 case AL_SAMPLE_OFFSET:
2130 lByteOffset = pSource->lOffset * lChannels * lBytes;
2131 break;
2133 case AL_SEC_OFFSET:
2134 // Note - lOffset is internally stored as Milliseconds
2135 lByteOffset = (ALint)(pSource->lOffset * lChannels * lBytes * flBufferFreq / 1000.0f);
2136 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2137 break;
2140 lTotalBufferDataSize = 0;
2141 pBufferList = pSource->queue;
2142 while (pBufferList)
2144 if (pBufferList->buffer)
2145 lTotalBufferDataSize += pBufferList->buffer->size;
2146 pBufferList = pBufferList->next;
2149 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2150 if (lByteOffset >= lTotalBufferDataSize)
2151 lByteOffset = -1;
2154 return lByteOffset;
2158 ALvoid ReleaseALSources(ALCcontext *Context)
2160 ALuint j;
2162 while(Context->Source)
2164 ALsource *temp = Context->Source;
2165 Context->Source = temp->next;
2167 // For each buffer in the source's queue, decrement its reference counter and remove it
2168 while(temp->queue != NULL)
2170 ALbufferlistitem *ALBufferList = temp->queue;
2171 // Decrement buffer's reference counter
2172 if(ALBufferList->buffer != NULL)
2173 ALBufferList->buffer->refcount--;
2174 // Update queue to point to next element in list
2175 temp->queue = ALBufferList->next;
2176 // Release memory allocated for buffer list item
2177 free(ALBufferList);
2180 for(j = 0;j < MAX_SENDS;++j)
2182 if(temp->Send[j].Slot)
2183 temp->Send[j].Slot->refcount--;
2186 // Release source structure
2187 ALTHUNK_REMOVEENTRY(temp->source);
2188 memset(temp, 0, sizeof(ALsource));
2189 free(temp);
2191 Context->SourceCount = 0;