Remove some assumptions of 16-bit internal storage
[openal-soft/openal-hmr.git] / OpenAL32 / alSource.c
blob73cde8ffe023d5dedda4979128aaa7ed9ad38454
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;
611 else
612 alSetError(AL_INVALID_VALUE);
614 else
615 alSetError(AL_INVALID_OPERATION);
616 break;
618 case AL_SOURCE_STATE:
619 // Query only
620 alSetError(AL_INVALID_OPERATION);
621 break;
623 case AL_SEC_OFFSET:
624 case AL_SAMPLE_OFFSET:
625 case AL_BYTE_OFFSET:
626 if(lValue >= 0)
628 pSource->lOffsetType = eParam;
630 // Store Offset (convert Seconds into Milliseconds)
631 if(eParam == AL_SEC_OFFSET)
632 pSource->lOffset = lValue * 1000;
633 else
634 pSource->lOffset = lValue;
636 if(pSource->state == AL_PLAYING || pSource->state == AL_PAUSED)
637 ApplyOffset(pSource, AL_TRUE);
639 else
640 alSetError(AL_INVALID_VALUE);
641 break;
643 case AL_DIRECT_FILTER:
644 if(alIsFilter(lValue))
646 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
647 if(!filter)
649 pSource->DirectFilter.type = AL_FILTER_NULL;
650 pSource->DirectFilter.filter = 0;
652 else
653 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
654 pSource->NeedsUpdate = AL_TRUE;
656 else
657 alSetError(AL_INVALID_VALUE);
658 break;
660 case AL_DIRECT_FILTER_GAINHF_AUTO:
661 if(lValue == AL_TRUE || lValue == AL_FALSE)
663 pSource->DryGainHFAuto = lValue;
664 pSource->NeedsUpdate = AL_TRUE;
666 else
667 alSetError(AL_INVALID_VALUE);
668 break;
670 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
671 if(lValue == AL_TRUE || lValue == AL_FALSE)
673 pSource->WetGainAuto = lValue;
674 pSource->NeedsUpdate = AL_TRUE;
676 else
677 alSetError(AL_INVALID_VALUE);
678 break;
680 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
681 if(lValue == AL_TRUE || lValue == AL_FALSE)
683 pSource->WetGainHFAuto = lValue;
684 pSource->NeedsUpdate = AL_TRUE;
686 else
687 alSetError(AL_INVALID_VALUE);
688 break;
690 case AL_DISTANCE_MODEL:
691 if(lValue == AL_NONE ||
692 lValue == AL_INVERSE_DISTANCE ||
693 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
694 lValue == AL_LINEAR_DISTANCE ||
695 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
696 lValue == AL_EXPONENT_DISTANCE ||
697 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
699 pSource->DistanceModel = lValue;
700 if(pContext->SourceDistanceModel)
701 pSource->NeedsUpdate = AL_TRUE;
703 else
704 alSetError(AL_INVALID_VALUE);
705 break;
707 default:
708 alSetError(AL_INVALID_ENUM);
709 break;
712 else
713 alSetError(AL_INVALID_NAME);
715 ProcessContext(pContext);
719 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
721 ALCcontext *pContext;
723 pContext = GetContextSuspended();
724 if(!pContext) return;
726 if(alIsSource(source))
728 ALsource *pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
729 ALCdevice *Device = pContext->Device;
731 switch (eParam)
733 case AL_POSITION:
734 case AL_VELOCITY:
735 case AL_DIRECTION:
736 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
737 break;
739 case AL_AUXILIARY_SEND_FILTER:
740 if((ALuint)lValue2 < Device->NumAuxSends &&
741 (lValue1 == 0 || alIsAuxiliaryEffectSlot(lValue1)) &&
742 alIsFilter(lValue3))
744 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
745 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
747 /* Release refcount on the previous slot, and add one for
748 * the new slot */
749 if(pSource->Send[lValue2].Slot)
750 pSource->Send[lValue2].Slot->refcount--;
751 pSource->Send[lValue2].Slot = ALEffectSlot;
752 if(pSource->Send[lValue2].Slot)
753 pSource->Send[lValue2].Slot->refcount++;
755 if(!ALFilter)
757 /* Disable filter */
758 pSource->Send[lValue2].WetFilter.type = 0;
759 pSource->Send[lValue2].WetFilter.filter = 0;
761 else
762 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
763 pSource->NeedsUpdate = AL_TRUE;
765 else
766 alSetError(AL_INVALID_VALUE);
767 break;
769 default:
770 alSetError(AL_INVALID_ENUM);
771 break;
774 else
775 alSetError(AL_INVALID_NAME);
777 ProcessContext(pContext);
781 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
783 ALCcontext *pContext;
785 pContext = GetContextSuspended();
786 if(!pContext) return;
788 if(plValues)
790 if(alIsSource(source))
792 switch(eParam)
794 case AL_SOURCE_RELATIVE:
795 case AL_CONE_INNER_ANGLE:
796 case AL_CONE_OUTER_ANGLE:
797 case AL_LOOPING:
798 case AL_BUFFER:
799 case AL_SOURCE_STATE:
800 case AL_SEC_OFFSET:
801 case AL_SAMPLE_OFFSET:
802 case AL_BYTE_OFFSET:
803 case AL_MAX_DISTANCE:
804 case AL_ROLLOFF_FACTOR:
805 case AL_REFERENCE_DISTANCE:
806 case AL_DIRECT_FILTER:
807 case AL_DIRECT_FILTER_GAINHF_AUTO:
808 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
809 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
810 case AL_DISTANCE_MODEL:
811 alSourcei(source, eParam, plValues[0]);
812 break;
814 case AL_POSITION:
815 case AL_VELOCITY:
816 case AL_DIRECTION:
817 case AL_AUXILIARY_SEND_FILTER:
818 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
819 break;
821 default:
822 alSetError(AL_INVALID_ENUM);
823 break;
826 else
827 alSetError(AL_INVALID_NAME);
829 else
830 alSetError(AL_INVALID_VALUE);
832 ProcessContext(pContext);
836 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
838 ALCcontext *pContext;
839 ALsource *pSource;
840 ALfloat flOffset[2];
842 pContext = GetContextSuspended();
843 if(!pContext) return;
845 if(pflValue)
847 if(alIsSource(source))
849 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
851 switch(eParam)
853 case AL_PITCH:
854 *pflValue = pSource->flPitch;
855 break;
857 case AL_GAIN:
858 *pflValue = pSource->flGain;
859 break;
861 case AL_MIN_GAIN:
862 *pflValue = pSource->flMinGain;
863 break;
865 case AL_MAX_GAIN:
866 *pflValue = pSource->flMaxGain;
867 break;
869 case AL_MAX_DISTANCE:
870 *pflValue = pSource->flMaxDistance;
871 break;
873 case AL_ROLLOFF_FACTOR:
874 *pflValue = pSource->flRollOffFactor;
875 break;
877 case AL_CONE_OUTER_GAIN:
878 *pflValue = pSource->flOuterGain;
879 break;
881 case AL_CONE_OUTER_GAINHF:
882 *pflValue = pSource->OuterGainHF;
883 break;
885 case AL_SEC_OFFSET:
886 case AL_SAMPLE_OFFSET:
887 case AL_BYTE_OFFSET:
888 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
889 *pflValue = flOffset[0];
890 else
891 alSetError(AL_INVALID_OPERATION);
892 break;
894 case AL_SEC_RW_OFFSETS_EXT:
895 case AL_SAMPLE_RW_OFFSETS_EXT:
896 case AL_BYTE_RW_OFFSETS_EXT:
897 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
899 pflValue[0] = flOffset[0];
900 pflValue[1] = flOffset[1];
902 else
903 alSetError(AL_INVALID_OPERATION);
904 break;
906 case AL_CONE_INNER_ANGLE:
907 *pflValue = pSource->flInnerAngle;
908 break;
910 case AL_CONE_OUTER_ANGLE:
911 *pflValue = pSource->flOuterAngle;
912 break;
914 case AL_REFERENCE_DISTANCE:
915 *pflValue = pSource->flRefDistance;
916 break;
918 case AL_AIR_ABSORPTION_FACTOR:
919 *pflValue = pSource->AirAbsorptionFactor;
920 break;
922 case AL_ROOM_ROLLOFF_FACTOR:
923 *pflValue = pSource->RoomRolloffFactor;
924 break;
926 case AL_DOPPLER_FACTOR:
927 *pflValue = pSource->DopplerFactor;
928 break;
930 default:
931 alSetError(AL_INVALID_ENUM);
932 break;
935 else
936 alSetError(AL_INVALID_NAME);
938 else
939 alSetError(AL_INVALID_VALUE);
941 ProcessContext(pContext);
945 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
947 ALCcontext *pContext;
948 ALsource *pSource;
950 pContext = GetContextSuspended();
951 if(!pContext) return;
953 if(pflValue1 && pflValue2 && pflValue3)
955 if(alIsSource(source))
957 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
959 switch(eParam)
961 case AL_POSITION:
962 *pflValue1 = pSource->vPosition[0];
963 *pflValue2 = pSource->vPosition[1];
964 *pflValue3 = pSource->vPosition[2];
965 break;
967 case AL_VELOCITY:
968 *pflValue1 = pSource->vVelocity[0];
969 *pflValue2 = pSource->vVelocity[1];
970 *pflValue3 = pSource->vVelocity[2];
971 break;
973 case AL_DIRECTION:
974 *pflValue1 = pSource->vOrientation[0];
975 *pflValue2 = pSource->vOrientation[1];
976 *pflValue3 = pSource->vOrientation[2];
977 break;
979 default:
980 alSetError(AL_INVALID_ENUM);
981 break;
984 else
985 alSetError(AL_INVALID_NAME);
987 else
988 alSetError(AL_INVALID_VALUE);
990 ProcessContext(pContext);
994 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
996 ALCcontext *pContext;
997 ALsource *pSource;
999 pContext = GetContextSuspended();
1000 if(!pContext) return;
1002 if(pflValues)
1004 if(alIsSource(source))
1006 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1008 switch(eParam)
1010 case AL_PITCH:
1011 case AL_GAIN:
1012 case AL_MIN_GAIN:
1013 case AL_MAX_GAIN:
1014 case AL_MAX_DISTANCE:
1015 case AL_ROLLOFF_FACTOR:
1016 case AL_DOPPLER_FACTOR:
1017 case AL_CONE_OUTER_GAIN:
1018 case AL_SEC_OFFSET:
1019 case AL_SAMPLE_OFFSET:
1020 case AL_BYTE_OFFSET:
1021 case AL_CONE_INNER_ANGLE:
1022 case AL_CONE_OUTER_ANGLE:
1023 case AL_REFERENCE_DISTANCE:
1024 case AL_CONE_OUTER_GAINHF:
1025 case AL_AIR_ABSORPTION_FACTOR:
1026 case AL_ROOM_ROLLOFF_FACTOR:
1027 alGetSourcef(source, eParam, pflValues);
1028 break;
1030 case AL_POSITION:
1031 pflValues[0] = pSource->vPosition[0];
1032 pflValues[1] = pSource->vPosition[1];
1033 pflValues[2] = pSource->vPosition[2];
1034 break;
1036 case AL_VELOCITY:
1037 pflValues[0] = pSource->vVelocity[0];
1038 pflValues[1] = pSource->vVelocity[1];
1039 pflValues[2] = pSource->vVelocity[2];
1040 break;
1042 case AL_DIRECTION:
1043 pflValues[0] = pSource->vOrientation[0];
1044 pflValues[1] = pSource->vOrientation[1];
1045 pflValues[2] = pSource->vOrientation[2];
1046 break;
1048 default:
1049 alSetError(AL_INVALID_ENUM);
1050 break;
1053 else
1054 alSetError(AL_INVALID_NAME);
1056 else
1057 alSetError(AL_INVALID_VALUE);
1059 ProcessContext(pContext);
1063 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1065 ALCcontext *pContext;
1066 ALsource *pSource;
1067 ALfloat flOffset[2];
1069 pContext = GetContextSuspended();
1070 if(!pContext) return;
1072 if(plValue)
1074 if(alIsSource(source))
1076 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1078 switch(eParam)
1080 case AL_MAX_DISTANCE:
1081 *plValue = (ALint)pSource->flMaxDistance;
1082 break;
1084 case AL_ROLLOFF_FACTOR:
1085 *plValue = (ALint)pSource->flRollOffFactor;
1086 break;
1088 case AL_REFERENCE_DISTANCE:
1089 *plValue = (ALint)pSource->flRefDistance;
1090 break;
1092 case AL_SOURCE_RELATIVE:
1093 *plValue = pSource->bHeadRelative;
1094 break;
1096 case AL_CONE_INNER_ANGLE:
1097 *plValue = (ALint)pSource->flInnerAngle;
1098 break;
1100 case AL_CONE_OUTER_ANGLE:
1101 *plValue = (ALint)pSource->flOuterAngle;
1102 break;
1104 case AL_LOOPING:
1105 *plValue = pSource->bLooping;
1106 break;
1108 case AL_BUFFER:
1109 *plValue = (pSource->Buffer ? pSource->Buffer->buffer : 0);
1110 break;
1112 case AL_SOURCE_STATE:
1113 *plValue = pSource->state;
1114 break;
1116 case AL_BUFFERS_QUEUED:
1117 *plValue = pSource->BuffersInQueue;
1118 break;
1120 case AL_BUFFERS_PROCESSED:
1121 if(pSource->bLooping)
1123 /* Buffers on a looping source are in a perpetual state
1124 * of PENDING, so don't report any as PROCESSED */
1125 *plValue = 0;
1127 else
1128 *plValue = pSource->BuffersPlayed;
1129 break;
1131 case AL_SOURCE_TYPE:
1132 *plValue = pSource->lSourceType;
1133 break;
1135 case AL_SEC_OFFSET:
1136 case AL_SAMPLE_OFFSET:
1137 case AL_BYTE_OFFSET:
1138 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1139 *plValue = (ALint)flOffset[0];
1140 else
1141 alSetError(AL_INVALID_OPERATION);
1142 break;
1144 case AL_SEC_RW_OFFSETS_EXT:
1145 case AL_SAMPLE_RW_OFFSETS_EXT:
1146 case AL_BYTE_RW_OFFSETS_EXT:
1147 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1149 plValue[0] = (ALint)flOffset[0];
1150 plValue[1] = (ALint)flOffset[1];
1152 else
1153 alSetError(AL_INVALID_OPERATION);
1154 break;
1156 case AL_DIRECT_FILTER:
1157 *plValue = pSource->DirectFilter.filter;
1158 break;
1160 case AL_DIRECT_FILTER_GAINHF_AUTO:
1161 *plValue = pSource->DryGainHFAuto;
1162 break;
1164 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1165 *plValue = pSource->WetGainAuto;
1166 break;
1168 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1169 *plValue = pSource->WetGainHFAuto;
1170 break;
1172 case AL_DOPPLER_FACTOR:
1173 *plValue = (ALint)pSource->DopplerFactor;
1174 break;
1176 case AL_DISTANCE_MODEL:
1177 *plValue = pSource->DistanceModel;
1178 break;
1180 default:
1181 alSetError(AL_INVALID_ENUM);
1182 break;
1185 else
1186 alSetError(AL_INVALID_NAME);
1188 else
1189 alSetError(AL_INVALID_VALUE);
1191 ProcessContext(pContext);
1195 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1197 ALCcontext *pContext;
1198 ALsource *pSource;
1200 pContext = GetContextSuspended();
1201 if(!pContext) return;
1203 if(plValue1 && plValue2 && plValue3)
1205 if(alIsSource(source))
1207 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1209 switch(eParam)
1211 case AL_POSITION:
1212 *plValue1 = (ALint)pSource->vPosition[0];
1213 *plValue2 = (ALint)pSource->vPosition[1];
1214 *plValue3 = (ALint)pSource->vPosition[2];
1215 break;
1217 case AL_VELOCITY:
1218 *plValue1 = (ALint)pSource->vVelocity[0];
1219 *plValue2 = (ALint)pSource->vVelocity[1];
1220 *plValue3 = (ALint)pSource->vVelocity[2];
1221 break;
1223 case AL_DIRECTION:
1224 *plValue1 = (ALint)pSource->vOrientation[0];
1225 *plValue2 = (ALint)pSource->vOrientation[1];
1226 *plValue3 = (ALint)pSource->vOrientation[2];
1227 break;
1229 default:
1230 alSetError(AL_INVALID_ENUM);
1231 break;
1234 else
1235 alSetError(AL_INVALID_NAME);
1237 else
1238 alSetError(AL_INVALID_VALUE);
1240 ProcessContext(pContext);
1244 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1246 ALCcontext *pContext;
1247 ALsource *pSource;
1249 pContext = GetContextSuspended();
1250 if(!pContext) return;
1252 if(plValues)
1254 if(alIsSource(source))
1256 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1258 switch(eParam)
1260 case AL_SOURCE_RELATIVE:
1261 case AL_CONE_INNER_ANGLE:
1262 case AL_CONE_OUTER_ANGLE:
1263 case AL_LOOPING:
1264 case AL_BUFFER:
1265 case AL_SOURCE_STATE:
1266 case AL_BUFFERS_QUEUED:
1267 case AL_BUFFERS_PROCESSED:
1268 case AL_SEC_OFFSET:
1269 case AL_SAMPLE_OFFSET:
1270 case AL_BYTE_OFFSET:
1271 case AL_MAX_DISTANCE:
1272 case AL_ROLLOFF_FACTOR:
1273 case AL_DOPPLER_FACTOR:
1274 case AL_REFERENCE_DISTANCE:
1275 case AL_SOURCE_TYPE:
1276 case AL_DIRECT_FILTER:
1277 case AL_DIRECT_FILTER_GAINHF_AUTO:
1278 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1279 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1280 case AL_DISTANCE_MODEL:
1281 alGetSourcei(source, eParam, plValues);
1282 break;
1284 case AL_POSITION:
1285 plValues[0] = (ALint)pSource->vPosition[0];
1286 plValues[1] = (ALint)pSource->vPosition[1];
1287 plValues[2] = (ALint)pSource->vPosition[2];
1288 break;
1290 case AL_VELOCITY:
1291 plValues[0] = (ALint)pSource->vVelocity[0];
1292 plValues[1] = (ALint)pSource->vVelocity[1];
1293 plValues[2] = (ALint)pSource->vVelocity[2];
1294 break;
1296 case AL_DIRECTION:
1297 plValues[0] = (ALint)pSource->vOrientation[0];
1298 plValues[1] = (ALint)pSource->vOrientation[1];
1299 plValues[2] = (ALint)pSource->vOrientation[2];
1300 break;
1302 default:
1303 alSetError(AL_INVALID_ENUM);
1304 break;
1307 else
1308 alSetError(AL_INVALID_NAME);
1310 else
1311 alSetError(AL_INVALID_VALUE);
1313 ProcessContext(pContext);
1317 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1319 alSourcePlayv(1, &source);
1322 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1324 ALCcontext *pContext;
1325 ALsource *pSource;
1326 ALbufferlistitem *ALBufferList;
1327 ALboolean bSourcesValid = AL_TRUE;
1328 ALboolean bPlay;
1329 ALsizei i, j;
1331 pContext = GetContextSuspended();
1332 if(!pContext) return;
1334 if(pSourceList)
1336 // Check that all the Sources are valid
1337 for(i = 0; i < n; i++)
1339 if(!alIsSource(pSourceList[i]))
1341 alSetError(AL_INVALID_NAME);
1342 bSourcesValid = AL_FALSE;
1343 break;
1347 if(bSourcesValid)
1349 for(i = 0; i < n; i++)
1351 // Assume Source won't need to play
1352 bPlay = AL_FALSE;
1354 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]);
1356 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1357 ALBufferList = pSource->queue;
1358 while(ALBufferList)
1360 if(ALBufferList->buffer != NULL && ALBufferList->buffer->size)
1362 bPlay = AL_TRUE;
1363 break;
1365 ALBufferList = ALBufferList->next;
1368 if (bPlay)
1370 for(j = 0;j < OUTPUTCHANNELS;j++)
1371 pSource->DryGains[j] = 0.0f;
1372 for(j = 0;j < MAX_SENDS;j++)
1373 pSource->WetGains[j] = 0.0f;
1375 if(pSource->state != AL_PAUSED)
1377 pSource->state = AL_PLAYING;
1378 pSource->position = 0;
1379 pSource->position_fraction = 0;
1380 pSource->BuffersPlayed = 0;
1382 pSource->Buffer = pSource->queue->buffer;
1384 else
1385 pSource->state = AL_PLAYING;
1387 // Check if an Offset has been set
1388 if(pSource->lOffset)
1389 ApplyOffset(pSource, AL_FALSE);
1391 if(pSource->BuffersPlayed == 0 && pSource->position == 0 &&
1392 pSource->position_fraction == 0)
1393 pSource->FirstStart = AL_TRUE;
1394 else
1395 pSource->FirstStart = AL_FALSE;
1397 // If device is disconnected, go right to stopped
1398 if(!pContext->Device->Connected)
1400 pSource->state = AL_STOPPED;
1401 pSource->BuffersPlayed = pSource->BuffersInQueue;
1402 pSource->position = 0;
1403 pSource->position_fraction = 0;
1406 else
1407 pSource->BuffersPlayed = pSource->BuffersInQueue;
1411 else
1413 // sources is a NULL pointer
1414 alSetError(AL_INVALID_VALUE);
1417 ProcessContext(pContext);
1420 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1422 alSourcePausev(1, &source);
1425 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1427 ALCcontext *Context;
1428 ALsource *Source;
1429 ALsizei i;
1430 ALboolean bSourcesValid = AL_TRUE;
1432 Context = GetContextSuspended();
1433 if(!Context) return;
1435 if(sources)
1437 // Check all the Sources are valid
1438 for(i=0;i<n;i++)
1440 if(!alIsSource(sources[i]))
1442 alSetError(AL_INVALID_NAME);
1443 bSourcesValid = AL_FALSE;
1444 break;
1448 if(bSourcesValid)
1450 for(i = 0;i < n;i++)
1452 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1453 if(Source->state == AL_PLAYING)
1454 Source->state = AL_PAUSED;
1458 else
1460 // sources is a NULL pointer
1461 alSetError(AL_INVALID_VALUE);
1464 ProcessContext(Context);
1467 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1469 alSourceStopv(1, &source);
1472 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1474 ALCcontext *Context;
1475 ALsource *Source;
1476 ALsizei i;
1477 ALboolean bSourcesValid = AL_TRUE;
1479 Context = GetContextSuspended();
1480 if(!Context) return;
1482 if(sources)
1484 // Check all the Sources are valid
1485 for(i = 0;i < n;i++)
1487 if(!alIsSource(sources[i]))
1489 alSetError(AL_INVALID_NAME);
1490 bSourcesValid = AL_FALSE;
1491 break;
1495 if(bSourcesValid)
1497 for(i = 0;i < n;i++)
1499 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1500 if(Source->state != AL_INITIAL)
1502 Source->state = AL_STOPPED;
1503 Source->BuffersPlayed = Source->BuffersInQueue;
1505 Source->lOffset = 0;
1509 else
1511 // sources is a NULL pointer
1512 alSetError(AL_INVALID_VALUE);
1515 ProcessContext(Context);
1518 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1520 alSourceRewindv(1, &source);
1523 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1525 ALCcontext *Context;
1526 ALsource *Source;
1527 ALsizei i;
1528 ALboolean bSourcesValid = AL_TRUE;
1530 Context = GetContextSuspended();
1531 if(!Context) return;
1533 if(sources)
1535 // Check all the Sources are valid
1536 for(i = 0;i < n;i++)
1538 if(!alIsSource(sources[i]))
1540 alSetError(AL_INVALID_NAME);
1541 bSourcesValid = AL_FALSE;
1542 break;
1546 if(bSourcesValid)
1548 for(i = 0;i < n;i++)
1550 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1551 if(Source->state != AL_INITIAL)
1553 Source->state = AL_INITIAL;
1554 Source->position = 0;
1555 Source->position_fraction = 0;
1556 Source->BuffersPlayed = 0;
1557 if(Source->queue)
1558 Source->Buffer = Source->queue->buffer;
1560 Source->lOffset = 0;
1564 else
1566 // sources is a NULL pointer
1567 alSetError(AL_INVALID_VALUE);
1570 ProcessContext(Context);
1574 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1576 ALCcontext *Context;
1577 ALsource *ALSource;
1578 ALsizei i;
1579 ALbufferlistitem *ALBufferList;
1580 ALbufferlistitem *ALBufferListStart;
1581 ALint iFrequency;
1582 ALint iFormat;
1583 ALboolean bBuffersValid = AL_TRUE;
1585 if (n == 0)
1586 return;
1588 Context = GetContextSuspended();
1589 if(!Context) return;
1591 // Check that all buffers are valid or zero and that the source is valid
1593 // Check that this is a valid source
1594 if(alIsSource(source))
1596 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1598 // Check that this is not a STATIC Source
1599 if(ALSource->lSourceType != AL_STATIC)
1601 iFrequency = -1;
1602 iFormat = -1;
1604 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1605 ALBufferList = ALSource->queue;
1606 while(ALBufferList)
1608 if (ALBufferList->buffer)
1610 iFrequency = ALBufferList->buffer->frequency;
1611 iFormat = ALBufferList->buffer->format;
1612 break;
1614 ALBufferList = ALBufferList->next;
1617 for(i = 0; i < n; i++)
1619 ALbuffer *buffer;
1621 if(!alIsBuffer(buffers[i]))
1623 alSetError(AL_INVALID_NAME);
1624 bBuffersValid = AL_FALSE;
1625 break;
1627 if(!buffers[i])
1628 continue;
1630 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1631 if(iFrequency == -1 && iFormat == -1)
1633 iFrequency = buffer->frequency;
1634 iFormat = buffer->format;
1636 else if(iFrequency != buffer->frequency ||
1637 iFormat != buffer->format)
1639 alSetError(AL_INVALID_OPERATION);
1640 bBuffersValid = AL_FALSE;
1641 break;
1645 if(bBuffersValid)
1647 ALbuffer *buffer = NULL;
1649 // Change Source Type
1650 ALSource->lSourceType = AL_STREAMING;
1652 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1654 // All buffers are valid - so add them to the list
1655 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1656 ALBufferListStart->buffer = buffer;
1657 ALBufferListStart->next = NULL;
1659 // Increment reference counter for buffer
1660 if(buffer) buffer->refcount++;
1662 ALBufferList = ALBufferListStart;
1664 for(i = 1; i < n; i++)
1666 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1668 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1669 ALBufferList->next->buffer = buffer;
1670 ALBufferList->next->next = NULL;
1672 // Increment reference counter for buffer
1673 if(buffer) buffer->refcount++;
1675 ALBufferList = ALBufferList->next;
1678 if(ALSource->queue == NULL)
1680 ALSource->queue = ALBufferListStart;
1681 // Update Current Buffer
1682 ALSource->Buffer = ALBufferListStart->buffer;
1684 else
1686 // Find end of queue
1687 ALBufferList = ALSource->queue;
1688 while(ALBufferList->next != NULL)
1689 ALBufferList = ALBufferList->next;
1691 ALBufferList->next = ALBufferListStart;
1694 // Update number of buffers in queue
1695 ALSource->BuffersInQueue += n;
1698 else
1700 // Invalid Source Type (can't queue on a Static Source)
1701 alSetError(AL_INVALID_OPERATION);
1704 else
1706 // Invalid Source Name
1707 alSetError(AL_INVALID_NAME);
1710 ProcessContext(Context);
1714 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1715 // an array of buffer IDs that are to be filled with the names of the buffers removed
1716 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1718 ALCcontext *Context;
1719 ALsource *ALSource;
1720 ALsizei i;
1721 ALbufferlistitem *ALBufferList;
1722 ALboolean bBuffersProcessed;
1724 if (n == 0)
1725 return;
1727 bBuffersProcessed = AL_TRUE;
1729 Context = GetContextSuspended();
1730 if(!Context) return;
1732 if(alIsSource(source))
1734 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1736 // If all 'n' buffers have been processed, remove them from the queue
1737 if(!ALSource->bLooping && (ALuint)n <= ALSource->BuffersPlayed)
1739 for(i = 0; i < n; i++)
1741 ALBufferList = ALSource->queue;
1743 ALSource->queue = ALBufferList->next;
1744 // Record name of buffer
1745 buffers[i] = ALBufferList->buffer->buffer;
1746 // Decrement buffer reference counter
1747 if(ALBufferList->buffer)
1748 ALBufferList->buffer->refcount--;
1750 // Release memory for buffer list item
1751 free(ALBufferList);
1752 ALSource->BuffersInQueue--;
1755 if(ALSource->state != AL_PLAYING)
1757 if(ALSource->queue)
1758 ALSource->Buffer = ALSource->queue->buffer;
1759 else
1760 ALSource->Buffer = NULL;
1763 ALSource->BuffersPlayed -= n;
1765 else
1767 // Some buffers can't be unqueue because they have not been processed
1768 alSetError(AL_INVALID_VALUE);
1771 else
1773 // Invalid Source Name
1774 alSetError(AL_INVALID_NAME);
1777 ProcessContext(Context);
1781 static ALvoid InitSourceParams(ALsource *pSource)
1783 pSource->flInnerAngle = 360.0f;
1784 pSource->flOuterAngle = 360.0f;
1785 pSource->flPitch = 1.0f;
1786 pSource->vPosition[0] = 0.0f;
1787 pSource->vPosition[1] = 0.0f;
1788 pSource->vPosition[2] = 0.0f;
1789 pSource->vOrientation[0] = 0.0f;
1790 pSource->vOrientation[1] = 0.0f;
1791 pSource->vOrientation[2] = 0.0f;
1792 pSource->vVelocity[0] = 0.0f;
1793 pSource->vVelocity[1] = 0.0f;
1794 pSource->vVelocity[2] = 0.0f;
1795 pSource->flRefDistance = 1.0f;
1796 pSource->flMaxDistance = FLT_MAX;
1797 pSource->flRollOffFactor = 1.0f;
1798 pSource->bLooping = AL_FALSE;
1799 pSource->flGain = 1.0f;
1800 pSource->flMinGain = 0.0f;
1801 pSource->flMaxGain = 1.0f;
1802 pSource->flOuterGain = 0.0f;
1803 pSource->OuterGainHF = 1.0f;
1805 pSource->DryGainHFAuto = AL_TRUE;
1806 pSource->WetGainAuto = AL_TRUE;
1807 pSource->WetGainHFAuto = AL_TRUE;
1808 pSource->AirAbsorptionFactor = 0.0f;
1809 pSource->RoomRolloffFactor = 0.0f;
1810 pSource->DopplerFactor = 1.0f;
1812 pSource->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1814 pSource->state = AL_INITIAL;
1815 pSource->lSourceType = AL_UNDETERMINED;
1817 pSource->NeedsUpdate = AL_TRUE;
1819 pSource->Buffer = NULL;
1824 GetSourceOffset
1826 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1827 The offset is relative to the start of the queue (not the start of the current buffer)
1829 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize)
1831 ALbufferlistitem *pBufferList;
1832 ALbuffer *pBuffer;
1833 ALfloat flBufferFreq;
1834 ALint lChannels, lBytes;
1835 ALint readPos, writePos;
1836 ALenum eOriginalFormat;
1837 ALboolean bReturn = AL_TRUE;
1838 ALint lTotalBufferDataSize;
1839 ALuint i;
1841 if((pSource->state == AL_PLAYING || pSource->state == AL_PAUSED) && pSource->Buffer)
1843 pBuffer = pSource->Buffer;
1844 // Get Current Buffer Size and frequency (in milliseconds)
1845 flBufferFreq = (ALfloat)pBuffer->frequency;
1846 eOriginalFormat = pBuffer->eOriginalFormat;
1847 lChannels = aluChannelsFromFormat(pBuffer->format);
1848 lBytes = aluBytesFromFormat(pBuffer->format);
1850 // Get Current BytesPlayed
1851 readPos = pSource->position * lChannels * lBytes; // NOTE : This is the byte offset into the *current* buffer
1852 // Add byte length of any processed buffers in the queue
1853 pBufferList = pSource->queue;
1854 for(i = 0;i < pSource->BuffersPlayed && pBufferList;i++)
1856 readPos += pBufferList->buffer->size;
1857 pBufferList = pBufferList->next;
1860 if(pSource->state == AL_PLAYING)
1861 writePos = readPos + (updateSize * lChannels * lBytes);
1862 else
1863 writePos = readPos;
1865 lTotalBufferDataSize = 0;
1866 pBufferList = pSource->queue;
1867 while (pBufferList)
1869 if (pBufferList->buffer)
1870 lTotalBufferDataSize += pBufferList->buffer->size;
1871 pBufferList = pBufferList->next;
1874 if (pSource->bLooping)
1876 if(readPos < 0)
1877 readPos = 0;
1878 else
1879 readPos %= lTotalBufferDataSize;
1880 if(writePos < 0)
1881 writePos = 0;
1882 else
1883 writePos %= lTotalBufferDataSize;
1885 else
1887 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1888 if(readPos < 0)
1889 readPos = 0;
1890 else if(readPos > lTotalBufferDataSize)
1891 readPos = lTotalBufferDataSize;
1892 if(writePos < 0)
1893 writePos = 0;
1894 else if(writePos > lTotalBufferDataSize)
1895 writePos = lTotalBufferDataSize;
1898 switch (eName)
1900 case AL_SEC_OFFSET:
1901 case AL_SEC_RW_OFFSETS_EXT:
1902 pflOffset[0] = (ALfloat)readPos / (lChannels * lBytes * flBufferFreq);
1903 pflOffset[1] = (ALfloat)writePos / (lChannels * lBytes * flBufferFreq);
1904 break;
1905 case AL_SAMPLE_OFFSET:
1906 case AL_SAMPLE_RW_OFFSETS_EXT:
1907 pflOffset[0] = (ALfloat)(readPos / (lChannels * lBytes));
1908 pflOffset[1] = (ALfloat)(writePos / (lChannels * lBytes));
1909 break;
1910 case AL_BYTE_OFFSET:
1911 case AL_BYTE_RW_OFFSETS_EXT:
1912 // Take into account the original format of the Buffer
1913 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
1914 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1916 // Round down to nearest ADPCM block
1917 pflOffset[0] = (ALfloat)((readPos / (65 * lBytes * lChannels)) * 36 * lChannels);
1918 if(pSource->state == AL_PLAYING)
1920 // Round up to nearest ADPCM block
1921 pflOffset[1] = (ALfloat)(((writePos + (65 * lBytes * lChannels) - 1) / (65 * lBytes * lChannels)) * 36 * lChannels);
1923 else
1924 pflOffset[1] = pflOffset[0];
1926 else if (eOriginalFormat == AL_FORMAT_REAR8)
1928 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 1);
1929 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 1);
1931 else if (eOriginalFormat == AL_FORMAT_REAR16)
1933 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 2);
1934 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 2);
1936 else if (eOriginalFormat == AL_FORMAT_REAR32)
1938 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 4);
1939 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 4);
1941 else if (aluBytesFromFormat(eOriginalFormat) == 1)
1943 pflOffset[0] = (ALfloat)(readPos / lBytes * 1);
1944 pflOffset[1] = (ALfloat)(writePos / lBytes * 1);
1946 else if (aluBytesFromFormat(eOriginalFormat) == 2)
1948 pflOffset[0] = (ALfloat)(readPos / lBytes * 2);
1949 pflOffset[1] = (ALfloat)(writePos / lBytes * 2);
1951 else if (aluBytesFromFormat(eOriginalFormat) == 4)
1953 pflOffset[0] = (ALfloat)(readPos / lBytes * 4);
1954 pflOffset[1] = (ALfloat)(writePos / lBytes * 4);
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
2005 pSource->BuffersPlayed++;
2007 else if (lTotalBufferSize <= lByteOffset)
2009 // Offset is within this buffer
2010 // Set Current Buffer
2011 pSource->Buffer = pBufferList->buffer;
2013 // SW Mixer Positions are in Samples
2014 pSource->position = (lByteOffset - lTotalBufferSize) /
2015 aluBytesFromFormat(pBuffer->format) /
2016 aluChannelsFromFormat(pBuffer->format);
2019 // Increment the TotalBufferSize
2020 lTotalBufferSize += lBufferSize;
2022 // Move on to next buffer in the Queue
2023 pBufferList = pBufferList->next;
2026 else
2028 if (bUpdateContext)
2029 alSetError(AL_INVALID_VALUE);
2032 // Clear Offset
2033 pSource->lOffset = 0;
2038 GetByteOffset
2040 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2041 offset supplied by the application). This takes into account the fact that the buffer format
2042 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2044 static ALint GetByteOffset(ALsource *pSource)
2046 ALbuffer *pBuffer = NULL;
2047 ALbufferlistitem *pBufferList;
2048 ALfloat flBufferFreq;
2049 ALint lChannels, lBytes;
2050 ALint lByteOffset = -1;
2051 ALint lTotalBufferDataSize;
2053 // Find the first non-NULL Buffer in the Queue
2054 pBufferList = pSource->queue;
2055 while (pBufferList)
2057 if (pBufferList->buffer)
2059 pBuffer = pBufferList->buffer;
2060 break;
2062 pBufferList = pBufferList->next;
2065 if (pBuffer)
2067 flBufferFreq = ((ALfloat)pBuffer->frequency);
2068 lChannels = aluChannelsFromFormat(pBuffer->format);
2069 lBytes = aluBytesFromFormat(pBuffer->format);
2071 // Determine the ByteOffset (and ensure it is block aligned)
2072 switch (pSource->lOffsetType)
2074 case AL_BYTE_OFFSET:
2075 // Take into consideration the original format
2076 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2077 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2079 // Round down to nearest ADPCM block
2080 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2081 // Multiply by compression rate
2082 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2083 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2085 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2087 lByteOffset = pSource->lOffset / 1 * lBytes * 2;
2088 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2090 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2092 lByteOffset = pSource->lOffset / 2 * lBytes * 2;
2093 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2095 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR32)
2097 lByteOffset = pSource->lOffset / 4 * lBytes * 2;
2098 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2100 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2102 lByteOffset = pSource->lOffset / 1 * lBytes;
2103 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2105 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 2)
2107 lByteOffset = pSource->lOffset / 2 * lBytes;
2108 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2110 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2112 lByteOffset = pSource->lOffset / 4 * lBytes;
2113 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2115 else
2117 lByteOffset = pSource->lOffset;
2118 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2120 break;
2122 case AL_SAMPLE_OFFSET:
2123 lByteOffset = pSource->lOffset * lChannels * lBytes;
2124 break;
2126 case AL_SEC_OFFSET:
2127 // Note - lOffset is internally stored as Milliseconds
2128 lByteOffset = (ALint)(pSource->lOffset * lChannels * lBytes * flBufferFreq / 1000.0f);
2129 lByteOffset -= (lByteOffset % (lChannels * lBytes));
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 ALuint j;
2155 while(Context->Source)
2157 ALsource *temp = Context->Source;
2158 Context->Source = temp->next;
2160 // For each buffer in the source's queue, decrement its reference counter and remove it
2161 while(temp->queue != NULL)
2163 ALbufferlistitem *ALBufferList = temp->queue;
2164 // Decrement buffer's reference counter
2165 if(ALBufferList->buffer != NULL)
2166 ALBufferList->buffer->refcount--;
2167 // Update queue to point to next element in list
2168 temp->queue = ALBufferList->next;
2169 // Release memory allocated for buffer list item
2170 free(ALBufferList);
2173 for(j = 0;j < MAX_SENDS;++j)
2175 if(temp->Send[j].Slot)
2176 temp->Send[j].Slot->refcount--;
2179 // Release source structure
2180 ALTHUNK_REMOVEENTRY(temp->source);
2181 memset(temp, 0, sizeof(ALsource));
2182 free(temp);
2184 Context->SourceCount = 0;