Consolidate some source offset handling code
[openal-soft.git] / OpenAL32 / alSource.c
blobe34976386352821791abfeb8e1ee1eef8518eb89
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 ALboolean ApplyOffset(ALsource *pSource);
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))
384 if(ApplyOffset(pSource) == AL_FALSE)
385 alSetError(AL_INVALID_VALUE);
388 else
389 alSetError(AL_INVALID_VALUE);
390 break;
392 default:
393 alSetError(AL_INVALID_ENUM);
394 break;
397 else
399 // Invalid Source Name
400 alSetError(AL_INVALID_NAME);
403 ProcessContext(pContext);
407 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
409 ALCcontext *pContext;
410 ALsource *pSource;
412 pContext = GetContextSuspended();
413 if(!pContext) return;
415 if(alIsSource(source))
417 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
418 switch(eParam)
420 case AL_POSITION:
421 pSource->vPosition[0] = flValue1;
422 pSource->vPosition[1] = flValue2;
423 pSource->vPosition[2] = flValue3;
424 pSource->NeedsUpdate = AL_TRUE;
425 break;
427 case AL_VELOCITY:
428 pSource->vVelocity[0] = flValue1;
429 pSource->vVelocity[1] = flValue2;
430 pSource->vVelocity[2] = flValue3;
431 pSource->NeedsUpdate = AL_TRUE;
432 break;
434 case AL_DIRECTION:
435 pSource->vOrientation[0] = flValue1;
436 pSource->vOrientation[1] = flValue2;
437 pSource->vOrientation[2] = flValue3;
438 pSource->NeedsUpdate = AL_TRUE;
439 break;
441 default:
442 alSetError(AL_INVALID_ENUM);
443 break;
446 else
447 alSetError(AL_INVALID_NAME);
449 ProcessContext(pContext);
453 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
455 ALCcontext *pContext;
457 pContext = GetContextSuspended();
458 if(!pContext) return;
460 if(pflValues)
462 if(alIsSource(source))
464 switch(eParam)
466 case AL_PITCH:
467 case AL_CONE_INNER_ANGLE:
468 case AL_CONE_OUTER_ANGLE:
469 case AL_GAIN:
470 case AL_MAX_DISTANCE:
471 case AL_ROLLOFF_FACTOR:
472 case AL_REFERENCE_DISTANCE:
473 case AL_MIN_GAIN:
474 case AL_MAX_GAIN:
475 case AL_CONE_OUTER_GAIN:
476 case AL_CONE_OUTER_GAINHF:
477 case AL_SEC_OFFSET:
478 case AL_SAMPLE_OFFSET:
479 case AL_BYTE_OFFSET:
480 case AL_AIR_ABSORPTION_FACTOR:
481 case AL_ROOM_ROLLOFF_FACTOR:
482 alSourcef(source, eParam, pflValues[0]);
483 break;
485 case AL_POSITION:
486 case AL_VELOCITY:
487 case AL_DIRECTION:
488 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
489 break;
491 default:
492 alSetError(AL_INVALID_ENUM);
493 break;
496 else
497 alSetError(AL_INVALID_NAME);
499 else
500 alSetError(AL_INVALID_VALUE);
502 ProcessContext(pContext);
506 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
508 ALCcontext *pContext;
509 ALsource *pSource;
510 ALbufferlistitem *pALBufferListItem;
512 pContext = GetContextSuspended();
513 if(!pContext) return;
515 if(alIsSource(source))
517 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
519 switch(eParam)
521 case AL_MAX_DISTANCE:
522 case AL_ROLLOFF_FACTOR:
523 case AL_REFERENCE_DISTANCE:
524 alSourcef(source, eParam, (ALfloat)lValue);
525 break;
527 case AL_SOURCE_RELATIVE:
528 if(lValue == AL_FALSE || lValue == AL_TRUE)
530 pSource->bHeadRelative = (ALboolean)lValue;
531 pSource->NeedsUpdate = AL_TRUE;
533 else
534 alSetError(AL_INVALID_VALUE);
535 break;
537 case AL_CONE_INNER_ANGLE:
538 if(lValue >= 0 && lValue <= 360)
540 pSource->flInnerAngle = (float)lValue;
541 pSource->NeedsUpdate = AL_TRUE;
543 else
544 alSetError(AL_INVALID_VALUE);
545 break;
547 case AL_CONE_OUTER_ANGLE:
548 if(lValue >= 0 && lValue <= 360)
550 pSource->flOuterAngle = (float)lValue;
551 pSource->NeedsUpdate = AL_TRUE;
553 else
554 alSetError(AL_INVALID_VALUE);
555 break;
557 case AL_LOOPING:
558 if(lValue == AL_FALSE || lValue == AL_TRUE)
559 pSource->bLooping = (ALboolean)lValue;
560 else
561 alSetError(AL_INVALID_VALUE);
562 break;
564 case AL_BUFFER:
565 if(pSource->state == AL_STOPPED || pSource->state == AL_INITIAL)
567 if(alIsBuffer(lValue))
569 ALbuffer *buffer = NULL;
571 // Remove all elements in the queue
572 while(pSource->queue != NULL)
574 pALBufferListItem = pSource->queue;
575 pSource->queue = pALBufferListItem->next;
576 // Decrement reference counter for buffer
577 if(pALBufferListItem->buffer)
578 pALBufferListItem->buffer->refcount--;
579 // Release memory for buffer list item
580 free(pALBufferListItem);
581 // Decrement the number of buffers in the queue
582 pSource->BuffersInQueue--;
585 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
586 if(lValue != 0)
588 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue);
590 // Source is now in STATIC mode
591 pSource->lSourceType = AL_STATIC;
593 // Add the selected buffer to the queue
594 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
595 pALBufferListItem->buffer = buffer;
596 pALBufferListItem->next = NULL;
598 pSource->queue = pALBufferListItem;
599 pSource->BuffersInQueue = 1;
601 // Increment reference counter for buffer
602 buffer->refcount++;
604 else
606 // Source is now in UNDETERMINED mode
607 pSource->lSourceType = AL_UNDETERMINED;
608 pSource->BuffersPlayed = 0;
611 // Update AL_BUFFER parameter
612 pSource->Buffer = buffer;
613 pSource->NeedsUpdate = AL_TRUE;
615 else
616 alSetError(AL_INVALID_VALUE);
618 else
619 alSetError(AL_INVALID_OPERATION);
620 break;
622 case AL_SOURCE_STATE:
623 // Query only
624 alSetError(AL_INVALID_OPERATION);
625 break;
627 case AL_SEC_OFFSET:
628 case AL_SAMPLE_OFFSET:
629 case AL_BYTE_OFFSET:
630 if(lValue >= 0)
632 pSource->lOffsetType = eParam;
634 // Store Offset (convert Seconds into Milliseconds)
635 if(eParam == AL_SEC_OFFSET)
636 pSource->lOffset = lValue * 1000;
637 else
638 pSource->lOffset = lValue;
640 if(pSource->state == AL_PLAYING || pSource->state == AL_PAUSED)
642 if(ApplyOffset(pSource) == AL_FALSE)
643 alSetError(AL_INVALID_VALUE);
646 else
647 alSetError(AL_INVALID_VALUE);
648 break;
650 case AL_DIRECT_FILTER:
651 if(alIsFilter(lValue))
653 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
654 if(!filter)
656 pSource->DirectFilter.type = AL_FILTER_NULL;
657 pSource->DirectFilter.filter = 0;
659 else
660 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
661 pSource->NeedsUpdate = AL_TRUE;
663 else
664 alSetError(AL_INVALID_VALUE);
665 break;
667 case AL_DIRECT_FILTER_GAINHF_AUTO:
668 if(lValue == AL_TRUE || lValue == AL_FALSE)
670 pSource->DryGainHFAuto = lValue;
671 pSource->NeedsUpdate = AL_TRUE;
673 else
674 alSetError(AL_INVALID_VALUE);
675 break;
677 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
678 if(lValue == AL_TRUE || lValue == AL_FALSE)
680 pSource->WetGainAuto = lValue;
681 pSource->NeedsUpdate = AL_TRUE;
683 else
684 alSetError(AL_INVALID_VALUE);
685 break;
687 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
688 if(lValue == AL_TRUE || lValue == AL_FALSE)
690 pSource->WetGainHFAuto = lValue;
691 pSource->NeedsUpdate = AL_TRUE;
693 else
694 alSetError(AL_INVALID_VALUE);
695 break;
697 case AL_DISTANCE_MODEL:
698 if(lValue == AL_NONE ||
699 lValue == AL_INVERSE_DISTANCE ||
700 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
701 lValue == AL_LINEAR_DISTANCE ||
702 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
703 lValue == AL_EXPONENT_DISTANCE ||
704 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
706 pSource->DistanceModel = lValue;
707 if(pContext->SourceDistanceModel)
708 pSource->NeedsUpdate = AL_TRUE;
710 else
711 alSetError(AL_INVALID_VALUE);
712 break;
714 default:
715 alSetError(AL_INVALID_ENUM);
716 break;
719 else
720 alSetError(AL_INVALID_NAME);
722 ProcessContext(pContext);
726 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
728 ALCcontext *pContext;
730 pContext = GetContextSuspended();
731 if(!pContext) return;
733 if(alIsSource(source))
735 ALsource *pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
736 ALCdevice *Device = pContext->Device;
738 switch (eParam)
740 case AL_POSITION:
741 case AL_VELOCITY:
742 case AL_DIRECTION:
743 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
744 break;
746 case AL_AUXILIARY_SEND_FILTER:
747 if((ALuint)lValue2 < Device->NumAuxSends &&
748 (lValue1 == 0 || alIsAuxiliaryEffectSlot(lValue1)) &&
749 alIsFilter(lValue3))
751 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
752 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
754 /* Release refcount on the previous slot, and add one for
755 * the new slot */
756 if(pSource->Send[lValue2].Slot)
757 pSource->Send[lValue2].Slot->refcount--;
758 pSource->Send[lValue2].Slot = ALEffectSlot;
759 if(pSource->Send[lValue2].Slot)
760 pSource->Send[lValue2].Slot->refcount++;
762 if(!ALFilter)
764 /* Disable filter */
765 pSource->Send[lValue2].WetFilter.type = 0;
766 pSource->Send[lValue2].WetFilter.filter = 0;
768 else
769 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
770 pSource->NeedsUpdate = AL_TRUE;
772 else
773 alSetError(AL_INVALID_VALUE);
774 break;
776 default:
777 alSetError(AL_INVALID_ENUM);
778 break;
781 else
782 alSetError(AL_INVALID_NAME);
784 ProcessContext(pContext);
788 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
790 ALCcontext *pContext;
792 pContext = GetContextSuspended();
793 if(!pContext) return;
795 if(plValues)
797 if(alIsSource(source))
799 switch(eParam)
801 case AL_SOURCE_RELATIVE:
802 case AL_CONE_INNER_ANGLE:
803 case AL_CONE_OUTER_ANGLE:
804 case AL_LOOPING:
805 case AL_BUFFER:
806 case AL_SOURCE_STATE:
807 case AL_SEC_OFFSET:
808 case AL_SAMPLE_OFFSET:
809 case AL_BYTE_OFFSET:
810 case AL_MAX_DISTANCE:
811 case AL_ROLLOFF_FACTOR:
812 case AL_REFERENCE_DISTANCE:
813 case AL_DIRECT_FILTER:
814 case AL_DIRECT_FILTER_GAINHF_AUTO:
815 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
816 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
817 case AL_DISTANCE_MODEL:
818 alSourcei(source, eParam, plValues[0]);
819 break;
821 case AL_POSITION:
822 case AL_VELOCITY:
823 case AL_DIRECTION:
824 case AL_AUXILIARY_SEND_FILTER:
825 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
826 break;
828 default:
829 alSetError(AL_INVALID_ENUM);
830 break;
833 else
834 alSetError(AL_INVALID_NAME);
836 else
837 alSetError(AL_INVALID_VALUE);
839 ProcessContext(pContext);
843 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
845 ALCcontext *pContext;
846 ALsource *pSource;
847 ALfloat flOffset[2];
849 pContext = GetContextSuspended();
850 if(!pContext) return;
852 if(pflValue)
854 if(alIsSource(source))
856 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
858 switch(eParam)
860 case AL_PITCH:
861 *pflValue = pSource->flPitch;
862 break;
864 case AL_GAIN:
865 *pflValue = pSource->flGain;
866 break;
868 case AL_MIN_GAIN:
869 *pflValue = pSource->flMinGain;
870 break;
872 case AL_MAX_GAIN:
873 *pflValue = pSource->flMaxGain;
874 break;
876 case AL_MAX_DISTANCE:
877 *pflValue = pSource->flMaxDistance;
878 break;
880 case AL_ROLLOFF_FACTOR:
881 *pflValue = pSource->flRollOffFactor;
882 break;
884 case AL_CONE_OUTER_GAIN:
885 *pflValue = pSource->flOuterGain;
886 break;
888 case AL_CONE_OUTER_GAINHF:
889 *pflValue = pSource->OuterGainHF;
890 break;
892 case AL_SEC_OFFSET:
893 case AL_SAMPLE_OFFSET:
894 case AL_BYTE_OFFSET:
895 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
896 *pflValue = flOffset[0];
897 else
898 alSetError(AL_INVALID_OPERATION);
899 break;
901 case AL_SEC_RW_OFFSETS_EXT:
902 case AL_SAMPLE_RW_OFFSETS_EXT:
903 case AL_BYTE_RW_OFFSETS_EXT:
904 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
906 pflValue[0] = flOffset[0];
907 pflValue[1] = flOffset[1];
909 else
910 alSetError(AL_INVALID_OPERATION);
911 break;
913 case AL_CONE_INNER_ANGLE:
914 *pflValue = pSource->flInnerAngle;
915 break;
917 case AL_CONE_OUTER_ANGLE:
918 *pflValue = pSource->flOuterAngle;
919 break;
921 case AL_REFERENCE_DISTANCE:
922 *pflValue = pSource->flRefDistance;
923 break;
925 case AL_AIR_ABSORPTION_FACTOR:
926 *pflValue = pSource->AirAbsorptionFactor;
927 break;
929 case AL_ROOM_ROLLOFF_FACTOR:
930 *pflValue = pSource->RoomRolloffFactor;
931 break;
933 case AL_DOPPLER_FACTOR:
934 *pflValue = pSource->DopplerFactor;
935 break;
937 default:
938 alSetError(AL_INVALID_ENUM);
939 break;
942 else
943 alSetError(AL_INVALID_NAME);
945 else
946 alSetError(AL_INVALID_VALUE);
948 ProcessContext(pContext);
952 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
954 ALCcontext *pContext;
955 ALsource *pSource;
957 pContext = GetContextSuspended();
958 if(!pContext) return;
960 if(pflValue1 && pflValue2 && pflValue3)
962 if(alIsSource(source))
964 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
966 switch(eParam)
968 case AL_POSITION:
969 *pflValue1 = pSource->vPosition[0];
970 *pflValue2 = pSource->vPosition[1];
971 *pflValue3 = pSource->vPosition[2];
972 break;
974 case AL_VELOCITY:
975 *pflValue1 = pSource->vVelocity[0];
976 *pflValue2 = pSource->vVelocity[1];
977 *pflValue3 = pSource->vVelocity[2];
978 break;
980 case AL_DIRECTION:
981 *pflValue1 = pSource->vOrientation[0];
982 *pflValue2 = pSource->vOrientation[1];
983 *pflValue3 = pSource->vOrientation[2];
984 break;
986 default:
987 alSetError(AL_INVALID_ENUM);
988 break;
991 else
992 alSetError(AL_INVALID_NAME);
994 else
995 alSetError(AL_INVALID_VALUE);
997 ProcessContext(pContext);
1001 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1003 ALCcontext *pContext;
1004 ALsource *pSource;
1006 pContext = GetContextSuspended();
1007 if(!pContext) return;
1009 if(pflValues)
1011 if(alIsSource(source))
1013 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1015 switch(eParam)
1017 case AL_PITCH:
1018 case AL_GAIN:
1019 case AL_MIN_GAIN:
1020 case AL_MAX_GAIN:
1021 case AL_MAX_DISTANCE:
1022 case AL_ROLLOFF_FACTOR:
1023 case AL_DOPPLER_FACTOR:
1024 case AL_CONE_OUTER_GAIN:
1025 case AL_SEC_OFFSET:
1026 case AL_SAMPLE_OFFSET:
1027 case AL_BYTE_OFFSET:
1028 case AL_CONE_INNER_ANGLE:
1029 case AL_CONE_OUTER_ANGLE:
1030 case AL_REFERENCE_DISTANCE:
1031 case AL_CONE_OUTER_GAINHF:
1032 case AL_AIR_ABSORPTION_FACTOR:
1033 case AL_ROOM_ROLLOFF_FACTOR:
1034 alGetSourcef(source, eParam, pflValues);
1035 break;
1037 case AL_POSITION:
1038 pflValues[0] = pSource->vPosition[0];
1039 pflValues[1] = pSource->vPosition[1];
1040 pflValues[2] = pSource->vPosition[2];
1041 break;
1043 case AL_VELOCITY:
1044 pflValues[0] = pSource->vVelocity[0];
1045 pflValues[1] = pSource->vVelocity[1];
1046 pflValues[2] = pSource->vVelocity[2];
1047 break;
1049 case AL_DIRECTION:
1050 pflValues[0] = pSource->vOrientation[0];
1051 pflValues[1] = pSource->vOrientation[1];
1052 pflValues[2] = pSource->vOrientation[2];
1053 break;
1055 default:
1056 alSetError(AL_INVALID_ENUM);
1057 break;
1060 else
1061 alSetError(AL_INVALID_NAME);
1063 else
1064 alSetError(AL_INVALID_VALUE);
1066 ProcessContext(pContext);
1070 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1072 ALCcontext *pContext;
1073 ALsource *pSource;
1074 ALfloat flOffset[2];
1076 pContext = GetContextSuspended();
1077 if(!pContext) return;
1079 if(plValue)
1081 if(alIsSource(source))
1083 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1085 switch(eParam)
1087 case AL_MAX_DISTANCE:
1088 *plValue = (ALint)pSource->flMaxDistance;
1089 break;
1091 case AL_ROLLOFF_FACTOR:
1092 *plValue = (ALint)pSource->flRollOffFactor;
1093 break;
1095 case AL_REFERENCE_DISTANCE:
1096 *plValue = (ALint)pSource->flRefDistance;
1097 break;
1099 case AL_SOURCE_RELATIVE:
1100 *plValue = pSource->bHeadRelative;
1101 break;
1103 case AL_CONE_INNER_ANGLE:
1104 *plValue = (ALint)pSource->flInnerAngle;
1105 break;
1107 case AL_CONE_OUTER_ANGLE:
1108 *plValue = (ALint)pSource->flOuterAngle;
1109 break;
1111 case AL_LOOPING:
1112 *plValue = pSource->bLooping;
1113 break;
1115 case AL_BUFFER:
1116 *plValue = (pSource->Buffer ? pSource->Buffer->buffer : 0);
1117 break;
1119 case AL_SOURCE_STATE:
1120 *plValue = pSource->state;
1121 break;
1123 case AL_BUFFERS_QUEUED:
1124 *plValue = pSource->BuffersInQueue;
1125 break;
1127 case AL_BUFFERS_PROCESSED:
1128 if(pSource->bLooping)
1130 /* Buffers on a looping source are in a perpetual state
1131 * of PENDING, so don't report any as PROCESSED */
1132 *plValue = 0;
1134 else
1135 *plValue = pSource->BuffersPlayed;
1136 break;
1138 case AL_SOURCE_TYPE:
1139 *plValue = pSource->lSourceType;
1140 break;
1142 case AL_SEC_OFFSET:
1143 case AL_SAMPLE_OFFSET:
1144 case AL_BYTE_OFFSET:
1145 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1146 *plValue = (ALint)flOffset[0];
1147 else
1148 alSetError(AL_INVALID_OPERATION);
1149 break;
1151 case AL_SEC_RW_OFFSETS_EXT:
1152 case AL_SAMPLE_RW_OFFSETS_EXT:
1153 case AL_BYTE_RW_OFFSETS_EXT:
1154 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1156 plValue[0] = (ALint)flOffset[0];
1157 plValue[1] = (ALint)flOffset[1];
1159 else
1160 alSetError(AL_INVALID_OPERATION);
1161 break;
1163 case AL_DIRECT_FILTER:
1164 *plValue = pSource->DirectFilter.filter;
1165 break;
1167 case AL_DIRECT_FILTER_GAINHF_AUTO:
1168 *plValue = pSource->DryGainHFAuto;
1169 break;
1171 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1172 *plValue = pSource->WetGainAuto;
1173 break;
1175 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1176 *plValue = pSource->WetGainHFAuto;
1177 break;
1179 case AL_DOPPLER_FACTOR:
1180 *plValue = (ALint)pSource->DopplerFactor;
1181 break;
1183 case AL_DISTANCE_MODEL:
1184 *plValue = pSource->DistanceModel;
1185 break;
1187 default:
1188 alSetError(AL_INVALID_ENUM);
1189 break;
1192 else
1193 alSetError(AL_INVALID_NAME);
1195 else
1196 alSetError(AL_INVALID_VALUE);
1198 ProcessContext(pContext);
1202 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1204 ALCcontext *pContext;
1205 ALsource *pSource;
1207 pContext = GetContextSuspended();
1208 if(!pContext) return;
1210 if(plValue1 && plValue2 && plValue3)
1212 if(alIsSource(source))
1214 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1216 switch(eParam)
1218 case AL_POSITION:
1219 *plValue1 = (ALint)pSource->vPosition[0];
1220 *plValue2 = (ALint)pSource->vPosition[1];
1221 *plValue3 = (ALint)pSource->vPosition[2];
1222 break;
1224 case AL_VELOCITY:
1225 *plValue1 = (ALint)pSource->vVelocity[0];
1226 *plValue2 = (ALint)pSource->vVelocity[1];
1227 *plValue3 = (ALint)pSource->vVelocity[2];
1228 break;
1230 case AL_DIRECTION:
1231 *plValue1 = (ALint)pSource->vOrientation[0];
1232 *plValue2 = (ALint)pSource->vOrientation[1];
1233 *plValue3 = (ALint)pSource->vOrientation[2];
1234 break;
1236 default:
1237 alSetError(AL_INVALID_ENUM);
1238 break;
1241 else
1242 alSetError(AL_INVALID_NAME);
1244 else
1245 alSetError(AL_INVALID_VALUE);
1247 ProcessContext(pContext);
1251 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1253 ALCcontext *pContext;
1254 ALsource *pSource;
1256 pContext = GetContextSuspended();
1257 if(!pContext) return;
1259 if(plValues)
1261 if(alIsSource(source))
1263 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1265 switch(eParam)
1267 case AL_SOURCE_RELATIVE:
1268 case AL_CONE_INNER_ANGLE:
1269 case AL_CONE_OUTER_ANGLE:
1270 case AL_LOOPING:
1271 case AL_BUFFER:
1272 case AL_SOURCE_STATE:
1273 case AL_BUFFERS_QUEUED:
1274 case AL_BUFFERS_PROCESSED:
1275 case AL_SEC_OFFSET:
1276 case AL_SAMPLE_OFFSET:
1277 case AL_BYTE_OFFSET:
1278 case AL_MAX_DISTANCE:
1279 case AL_ROLLOFF_FACTOR:
1280 case AL_DOPPLER_FACTOR:
1281 case AL_REFERENCE_DISTANCE:
1282 case AL_SOURCE_TYPE:
1283 case AL_DIRECT_FILTER:
1284 case AL_DIRECT_FILTER_GAINHF_AUTO:
1285 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1286 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1287 case AL_DISTANCE_MODEL:
1288 alGetSourcei(source, eParam, plValues);
1289 break;
1291 case AL_POSITION:
1292 plValues[0] = (ALint)pSource->vPosition[0];
1293 plValues[1] = (ALint)pSource->vPosition[1];
1294 plValues[2] = (ALint)pSource->vPosition[2];
1295 break;
1297 case AL_VELOCITY:
1298 plValues[0] = (ALint)pSource->vVelocity[0];
1299 plValues[1] = (ALint)pSource->vVelocity[1];
1300 plValues[2] = (ALint)pSource->vVelocity[2];
1301 break;
1303 case AL_DIRECTION:
1304 plValues[0] = (ALint)pSource->vOrientation[0];
1305 plValues[1] = (ALint)pSource->vOrientation[1];
1306 plValues[2] = (ALint)pSource->vOrientation[2];
1307 break;
1309 default:
1310 alSetError(AL_INVALID_ENUM);
1311 break;
1314 else
1315 alSetError(AL_INVALID_NAME);
1317 else
1318 alSetError(AL_INVALID_VALUE);
1320 ProcessContext(pContext);
1324 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1326 alSourcePlayv(1, &source);
1329 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1331 ALCcontext *pContext;
1332 ALsource *pSource;
1333 ALbufferlistitem *ALBufferList;
1334 ALboolean bSourcesValid = AL_TRUE;
1335 ALboolean bPlay;
1336 ALsizei i, j;
1338 pContext = GetContextSuspended();
1339 if(!pContext) return;
1341 if(pSourceList)
1343 // Check that all the Sources are valid
1344 for(i = 0; i < n; i++)
1346 if(!alIsSource(pSourceList[i]))
1348 alSetError(AL_INVALID_NAME);
1349 bSourcesValid = AL_FALSE;
1350 break;
1354 if(bSourcesValid)
1356 for(i = 0; i < n; i++)
1358 // Assume Source won't need to play
1359 bPlay = AL_FALSE;
1361 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]);
1363 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1364 ALBufferList = pSource->queue;
1365 while(ALBufferList)
1367 if(ALBufferList->buffer != NULL && ALBufferList->buffer->size)
1369 bPlay = AL_TRUE;
1370 break;
1372 ALBufferList = ALBufferList->next;
1375 if (bPlay)
1377 for(j = 0;j < OUTPUTCHANNELS;j++)
1378 pSource->DryGains[j] = 0.0f;
1379 for(j = 0;j < MAX_SENDS;j++)
1380 pSource->WetGains[j] = 0.0f;
1382 if(pSource->state != AL_PAUSED)
1384 pSource->state = AL_PLAYING;
1385 pSource->position = 0;
1386 pSource->position_fraction = 0;
1387 pSource->BuffersPlayed = 0;
1389 pSource->Buffer = pSource->queue->buffer;
1391 else
1392 pSource->state = AL_PLAYING;
1394 // Check if an Offset has been set
1395 if(pSource->lOffset)
1396 ApplyOffset(pSource);
1398 if(pSource->BuffersPlayed == 0 && pSource->position == 0 &&
1399 pSource->position_fraction == 0)
1400 pSource->FirstStart = AL_TRUE;
1401 else
1402 pSource->FirstStart = AL_FALSE;
1404 // If device is disconnected, go right to stopped
1405 if(!pContext->Device->Connected)
1407 pSource->state = AL_STOPPED;
1408 pSource->BuffersPlayed = pSource->BuffersInQueue;
1409 pSource->position = 0;
1410 pSource->position_fraction = 0;
1413 else
1414 pSource->BuffersPlayed = pSource->BuffersInQueue;
1418 else
1420 // sources is a NULL pointer
1421 alSetError(AL_INVALID_VALUE);
1424 ProcessContext(pContext);
1427 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1429 alSourcePausev(1, &source);
1432 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1434 ALCcontext *Context;
1435 ALsource *Source;
1436 ALsizei i;
1437 ALboolean bSourcesValid = AL_TRUE;
1439 Context = GetContextSuspended();
1440 if(!Context) return;
1442 if(sources)
1444 // Check all the Sources are valid
1445 for(i=0;i<n;i++)
1447 if(!alIsSource(sources[i]))
1449 alSetError(AL_INVALID_NAME);
1450 bSourcesValid = AL_FALSE;
1451 break;
1455 if(bSourcesValid)
1457 for(i = 0;i < n;i++)
1459 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1460 if(Source->state == AL_PLAYING)
1461 Source->state = AL_PAUSED;
1465 else
1467 // sources is a NULL pointer
1468 alSetError(AL_INVALID_VALUE);
1471 ProcessContext(Context);
1474 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1476 alSourceStopv(1, &source);
1479 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1481 ALCcontext *Context;
1482 ALsource *Source;
1483 ALsizei i;
1484 ALboolean bSourcesValid = AL_TRUE;
1486 Context = GetContextSuspended();
1487 if(!Context) return;
1489 if(sources)
1491 // Check all the Sources are valid
1492 for(i = 0;i < n;i++)
1494 if(!alIsSource(sources[i]))
1496 alSetError(AL_INVALID_NAME);
1497 bSourcesValid = AL_FALSE;
1498 break;
1502 if(bSourcesValid)
1504 for(i = 0;i < n;i++)
1506 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1507 if(Source->state != AL_INITIAL)
1509 Source->state = AL_STOPPED;
1510 Source->BuffersPlayed = Source->BuffersInQueue;
1512 Source->lOffset = 0;
1516 else
1518 // sources is a NULL pointer
1519 alSetError(AL_INVALID_VALUE);
1522 ProcessContext(Context);
1525 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1527 alSourceRewindv(1, &source);
1530 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1532 ALCcontext *Context;
1533 ALsource *Source;
1534 ALsizei i;
1535 ALboolean bSourcesValid = AL_TRUE;
1537 Context = GetContextSuspended();
1538 if(!Context) return;
1540 if(sources)
1542 // Check all the Sources are valid
1543 for(i = 0;i < n;i++)
1545 if(!alIsSource(sources[i]))
1547 alSetError(AL_INVALID_NAME);
1548 bSourcesValid = AL_FALSE;
1549 break;
1553 if(bSourcesValid)
1555 for(i = 0;i < n;i++)
1557 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1558 if(Source->state != AL_INITIAL)
1560 Source->state = AL_INITIAL;
1561 Source->position = 0;
1562 Source->position_fraction = 0;
1563 Source->BuffersPlayed = 0;
1564 if(Source->queue)
1565 Source->Buffer = Source->queue->buffer;
1567 Source->lOffset = 0;
1571 else
1573 // sources is a NULL pointer
1574 alSetError(AL_INVALID_VALUE);
1577 ProcessContext(Context);
1581 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1583 ALCcontext *Context;
1584 ALsource *ALSource;
1585 ALsizei i;
1586 ALbufferlistitem *ALBufferList;
1587 ALbufferlistitem *ALBufferListStart;
1588 ALint iFrequency;
1589 ALint iFormat;
1590 ALboolean bBuffersValid = AL_TRUE;
1591 ALboolean hadFormat = AL_FALSE;
1593 if (n == 0)
1594 return;
1596 Context = GetContextSuspended();
1597 if(!Context) return;
1599 // Check that all buffers are valid or zero and that the source is valid
1601 // Check that this is a valid source
1602 if(alIsSource(source))
1604 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1606 // Check that this is not a STATIC Source
1607 if(ALSource->lSourceType != AL_STATIC)
1609 iFrequency = -1;
1610 iFormat = -1;
1612 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1613 ALBufferList = ALSource->queue;
1614 while(ALBufferList)
1616 if (ALBufferList->buffer)
1618 iFrequency = ALBufferList->buffer->frequency;
1619 iFormat = ALBufferList->buffer->format;
1620 hadFormat = AL_TRUE;
1621 break;
1623 ALBufferList = ALBufferList->next;
1626 for(i = 0; i < n; i++)
1628 ALbuffer *buffer;
1630 if(!alIsBuffer(buffers[i]))
1632 alSetError(AL_INVALID_NAME);
1633 bBuffersValid = AL_FALSE;
1634 break;
1636 if(!buffers[i])
1637 continue;
1639 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1640 if(iFrequency == -1 && iFormat == -1)
1642 iFrequency = buffer->frequency;
1643 iFormat = buffer->format;
1645 else if(iFrequency != buffer->frequency ||
1646 iFormat != buffer->format)
1648 alSetError(AL_INVALID_OPERATION);
1649 bBuffersValid = AL_FALSE;
1650 break;
1654 if(bBuffersValid)
1656 ALbuffer *buffer = NULL;
1658 // Change Source Type
1659 ALSource->lSourceType = AL_STREAMING;
1661 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1663 // All buffers are valid - so add them to the list
1664 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1665 ALBufferListStart->buffer = buffer;
1666 ALBufferListStart->next = NULL;
1668 // Increment reference counter for buffer
1669 if(buffer) buffer->refcount++;
1671 ALBufferList = ALBufferListStart;
1673 for(i = 1; i < n; i++)
1675 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1677 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1678 ALBufferList->next->buffer = buffer;
1679 ALBufferList->next->next = NULL;
1681 // Increment reference counter for buffer
1682 if(buffer) buffer->refcount++;
1684 ALBufferList = ALBufferList->next;
1687 if(ALSource->queue == NULL)
1689 ALSource->queue = ALBufferListStart;
1690 // Update Current Buffer
1691 ALSource->Buffer = ALBufferListStart->buffer;
1693 else
1695 // Find end of queue
1696 ALBufferList = ALSource->queue;
1697 while(ALBufferList->next != NULL)
1698 ALBufferList = ALBufferList->next;
1700 ALBufferList->next = ALBufferListStart;
1703 // Update number of buffers in queue
1704 ALSource->BuffersInQueue += n;
1705 // If no previous format, mark the source dirty now that it may
1706 // have one
1707 if(!hadFormat)
1708 ALSource->NeedsUpdate = AL_TRUE;
1711 else
1713 // Invalid Source Type (can't queue on a Static Source)
1714 alSetError(AL_INVALID_OPERATION);
1717 else
1719 // Invalid Source Name
1720 alSetError(AL_INVALID_NAME);
1723 ProcessContext(Context);
1727 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1728 // an array of buffer IDs that are to be filled with the names of the buffers removed
1729 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1731 ALCcontext *Context;
1732 ALsource *ALSource;
1733 ALsizei i;
1734 ALbufferlistitem *ALBufferList;
1735 ALboolean bBuffersProcessed;
1737 if (n == 0)
1738 return;
1740 bBuffersProcessed = AL_TRUE;
1742 Context = GetContextSuspended();
1743 if(!Context) return;
1745 if(alIsSource(source))
1747 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1749 // If all 'n' buffers have been processed, remove them from the queue
1750 if(!ALSource->bLooping && (ALuint)n <= ALSource->BuffersPlayed)
1752 for(i = 0; i < n; i++)
1754 ALBufferList = ALSource->queue;
1756 ALSource->queue = ALBufferList->next;
1757 // Record name of buffer
1758 buffers[i] = ALBufferList->buffer->buffer;
1759 // Decrement buffer reference counter
1760 if(ALBufferList->buffer)
1761 ALBufferList->buffer->refcount--;
1763 // Release memory for buffer list item
1764 free(ALBufferList);
1765 ALSource->BuffersInQueue--;
1768 if(ALSource->state != AL_PLAYING)
1770 if(ALSource->queue)
1771 ALSource->Buffer = ALSource->queue->buffer;
1772 else
1773 ALSource->Buffer = NULL;
1776 ALSource->BuffersPlayed -= n;
1778 else
1780 // Some buffers can't be unqueue because they have not been processed
1781 alSetError(AL_INVALID_VALUE);
1784 else
1786 // Invalid Source Name
1787 alSetError(AL_INVALID_NAME);
1790 ProcessContext(Context);
1794 static ALvoid InitSourceParams(ALsource *pSource)
1796 pSource->flInnerAngle = 360.0f;
1797 pSource->flOuterAngle = 360.0f;
1798 pSource->flPitch = 1.0f;
1799 pSource->vPosition[0] = 0.0f;
1800 pSource->vPosition[1] = 0.0f;
1801 pSource->vPosition[2] = 0.0f;
1802 pSource->vOrientation[0] = 0.0f;
1803 pSource->vOrientation[1] = 0.0f;
1804 pSource->vOrientation[2] = 0.0f;
1805 pSource->vVelocity[0] = 0.0f;
1806 pSource->vVelocity[1] = 0.0f;
1807 pSource->vVelocity[2] = 0.0f;
1808 pSource->flRefDistance = 1.0f;
1809 pSource->flMaxDistance = FLT_MAX;
1810 pSource->flRollOffFactor = 1.0f;
1811 pSource->bLooping = AL_FALSE;
1812 pSource->flGain = 1.0f;
1813 pSource->flMinGain = 0.0f;
1814 pSource->flMaxGain = 1.0f;
1815 pSource->flOuterGain = 0.0f;
1816 pSource->OuterGainHF = 1.0f;
1818 pSource->DryGainHFAuto = AL_TRUE;
1819 pSource->WetGainAuto = AL_TRUE;
1820 pSource->WetGainHFAuto = AL_TRUE;
1821 pSource->AirAbsorptionFactor = 0.0f;
1822 pSource->RoomRolloffFactor = 0.0f;
1823 pSource->DopplerFactor = 1.0f;
1825 pSource->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1827 pSource->Resampler = DefaultResampler;
1829 pSource->state = AL_INITIAL;
1830 pSource->lSourceType = AL_UNDETERMINED;
1832 pSource->NeedsUpdate = AL_TRUE;
1834 pSource->Buffer = NULL;
1839 GetSourceOffset
1841 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1842 The offset is relative to the start of the queue (not the start of the current buffer)
1844 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize)
1846 ALbufferlistitem *pBufferList;
1847 ALbuffer *pBuffer;
1848 ALfloat flBufferFreq;
1849 ALint lChannels, lBytes;
1850 ALint readPos, writePos;
1851 ALenum eOriginalFormat;
1852 ALboolean bReturn = AL_TRUE;
1853 ALint lTotalBufferDataSize;
1854 ALuint i;
1856 if((pSource->state == AL_PLAYING || pSource->state == AL_PAUSED) && pSource->Buffer)
1858 pBuffer = pSource->Buffer;
1859 // Get Current Buffer Size and frequency (in milliseconds)
1860 flBufferFreq = (ALfloat)pBuffer->frequency;
1861 eOriginalFormat = pBuffer->eOriginalFormat;
1862 lChannels = aluChannelsFromFormat(pBuffer->format);
1863 lBytes = aluBytesFromFormat(pBuffer->format);
1865 // Get Current BytesPlayed
1866 readPos = pSource->position * lChannels * lBytes; // NOTE : This is the byte offset into the *current* buffer
1867 // Add byte length of any processed buffers in the queue
1868 pBufferList = pSource->queue;
1869 for(i = 0;i < pSource->BuffersPlayed && pBufferList;i++)
1871 readPos += pBufferList->buffer->size;
1872 pBufferList = pBufferList->next;
1875 if(pSource->state == AL_PLAYING)
1876 writePos = readPos + (updateSize * lChannels * lBytes);
1877 else
1878 writePos = readPos;
1880 lTotalBufferDataSize = 0;
1881 pBufferList = pSource->queue;
1882 while (pBufferList)
1884 if (pBufferList->buffer)
1885 lTotalBufferDataSize += pBufferList->buffer->size;
1886 pBufferList = pBufferList->next;
1889 if (pSource->bLooping)
1891 if(readPos < 0)
1892 readPos = 0;
1893 else
1894 readPos %= lTotalBufferDataSize;
1895 if(writePos < 0)
1896 writePos = 0;
1897 else
1898 writePos %= lTotalBufferDataSize;
1900 else
1902 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1903 if(readPos < 0)
1904 readPos = 0;
1905 else if(readPos > lTotalBufferDataSize)
1906 readPos = lTotalBufferDataSize;
1907 if(writePos < 0)
1908 writePos = 0;
1909 else if(writePos > lTotalBufferDataSize)
1910 writePos = lTotalBufferDataSize;
1913 switch (eName)
1915 case AL_SEC_OFFSET:
1916 case AL_SEC_RW_OFFSETS_EXT:
1917 pflOffset[0] = (ALfloat)readPos / (lChannels * lBytes * flBufferFreq);
1918 pflOffset[1] = (ALfloat)writePos / (lChannels * lBytes * flBufferFreq);
1919 break;
1920 case AL_SAMPLE_OFFSET:
1921 case AL_SAMPLE_RW_OFFSETS_EXT:
1922 pflOffset[0] = (ALfloat)(readPos / (lChannels * lBytes));
1923 pflOffset[1] = (ALfloat)(writePos / (lChannels * lBytes));
1924 break;
1925 case AL_BYTE_OFFSET:
1926 case AL_BYTE_RW_OFFSETS_EXT:
1927 // Take into account the original format of the Buffer
1928 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
1929 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1931 // Round down to nearest ADPCM block
1932 pflOffset[0] = (ALfloat)((readPos / (65 * lBytes * lChannels)) * 36 * lChannels);
1933 if(pSource->state == AL_PLAYING)
1935 // Round up to nearest ADPCM block
1936 pflOffset[1] = (ALfloat)(((writePos + (65 * lBytes * lChannels) - 1) / (65 * lBytes * lChannels)) * 36 * lChannels);
1938 else
1939 pflOffset[1] = pflOffset[0];
1941 else if (eOriginalFormat == AL_FORMAT_REAR8)
1943 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 1);
1944 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 1);
1946 else if (eOriginalFormat == AL_FORMAT_REAR16)
1948 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 2);
1949 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 2);
1951 else if (eOriginalFormat == AL_FORMAT_REAR32)
1953 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 4);
1954 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 4);
1956 else
1958 ALuint OrigBytes = aluBytesFromFormat(eOriginalFormat);
1959 pflOffset[0] = (ALfloat)(readPos / lBytes * OrigBytes);
1960 pflOffset[1] = (ALfloat)(writePos / lBytes * OrigBytes);
1962 break;
1965 else
1967 pflOffset[0] = 0.0f;
1968 pflOffset[1] = 0.0f;
1971 return bReturn;
1976 ApplyOffset
1978 Apply a playback offset to the Source. This function will update the queue (to correctly
1979 mark buffers as 'pending' or 'processed' depending upon the new offset.
1981 static ALboolean ApplyOffset(ALsource *pSource)
1983 ALbufferlistitem *pBufferList;
1984 ALbuffer *pBuffer;
1985 ALint lBufferSize, lTotalBufferSize;
1986 ALint lByteOffset;
1988 // Get true byte offset
1989 lByteOffset = GetByteOffset(pSource);
1991 // If the offset is invalid, don't apply it
1992 if(lByteOffset == -1)
1993 return AL_FALSE;
1995 // Sort out the queue (pending and processed states)
1996 pBufferList = pSource->queue;
1997 lTotalBufferSize = 0;
1998 pSource->BuffersPlayed = 0;
2000 while(pBufferList)
2002 pBuffer = pBufferList->buffer;
2003 lBufferSize = pBuffer ? pBuffer->size : 0;
2005 if(lTotalBufferSize+lBufferSize <= lByteOffset)
2007 // Offset is past this buffer so increment BuffersPlayed
2008 pSource->BuffersPlayed++;
2010 else if(lTotalBufferSize <= lByteOffset)
2012 // Offset is within this buffer
2013 // Set Current Buffer
2014 pSource->Buffer = pBufferList->buffer;
2016 // SW Mixer Positions are in Samples
2017 pSource->position = (lByteOffset - lTotalBufferSize) /
2018 aluBytesFromFormat(pBuffer->format) /
2019 aluChannelsFromFormat(pBuffer->format);
2020 break;
2023 // Increment the TotalBufferSize
2024 lTotalBufferSize += lBufferSize;
2026 // Move on to next buffer in the Queue
2027 pBufferList = pBufferList->next;
2030 return AL_TRUE;
2035 GetByteOffset
2037 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2038 offset supplied by the application). This takes into account the fact that the buffer format
2039 may have been modifed by AL (e.g 8bit samples are converted to float)
2041 static ALint GetByteOffset(ALsource *pSource)
2043 ALbuffer *pBuffer = NULL;
2044 ALbufferlistitem *pBufferList;
2045 ALfloat flBufferFreq;
2046 ALint lChannels, lBytes;
2047 ALint lByteOffset = -1;
2048 ALint lTotalBufferDataSize;
2049 ALenum OriginalFormat;
2051 // Find the first non-NULL Buffer in the Queue
2052 pBufferList = pSource->queue;
2053 while (pBufferList)
2055 if (pBufferList->buffer)
2057 pBuffer = pBufferList->buffer;
2058 break;
2060 pBufferList = pBufferList->next;
2063 if (pBuffer)
2065 flBufferFreq = ((ALfloat)pBuffer->frequency);
2066 lChannels = aluChannelsFromFormat(pBuffer->format);
2067 lBytes = aluBytesFromFormat(pBuffer->format);
2068 OriginalFormat = pBuffer->eOriginalFormat;
2070 // Determine the ByteOffset (and ensure it is block aligned)
2071 switch (pSource->lOffsetType)
2073 case AL_BYTE_OFFSET:
2074 // Take into consideration the original format
2075 if(OriginalFormat == AL_FORMAT_MONO_IMA4 ||
2076 OriginalFormat == AL_FORMAT_STEREO_IMA4)
2078 // Round down to nearest ADPCM block
2079 lByteOffset = pSource->lOffset / (36 * lChannels);
2080 // Multiply by compression rate
2081 lByteOffset = lByteOffset * 65 * lChannels * lBytes;
2082 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2084 else if(OriginalFormat == AL_FORMAT_REAR8)
2086 lByteOffset = pSource->lOffset / 1 * lBytes * 2;
2087 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2089 else if(OriginalFormat == AL_FORMAT_REAR16)
2091 lByteOffset = pSource->lOffset / 2 * lBytes * 2;
2092 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2094 else if(OriginalFormat == AL_FORMAT_REAR32)
2096 lByteOffset = pSource->lOffset / 4 * lBytes * 2;
2097 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2099 else
2101 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
2102 lByteOffset = pSource->lOffset / OrigBytes * lBytes;
2103 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2105 break;
2107 case AL_SAMPLE_OFFSET:
2108 lByteOffset = pSource->lOffset * lChannels * lBytes;
2109 break;
2111 case AL_SEC_OFFSET:
2112 // Note - lOffset is internally stored as Milliseconds
2113 lByteOffset = (ALint)(pSource->lOffset / 1000.0f * flBufferFreq);
2114 lByteOffset *= lChannels * lBytes;
2115 break;
2118 lTotalBufferDataSize = 0;
2119 pBufferList = pSource->queue;
2120 while (pBufferList)
2122 if (pBufferList->buffer)
2123 lTotalBufferDataSize += pBufferList->buffer->size;
2124 pBufferList = pBufferList->next;
2127 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2128 if (lByteOffset >= lTotalBufferDataSize)
2129 lByteOffset = -1;
2132 // Clear Offset
2133 pSource->lOffset = 0;
2135 return lByteOffset;
2139 ALvoid ReleaseALSources(ALCcontext *Context)
2141 ALuint j;
2143 while(Context->Source)
2145 ALsource *temp = Context->Source;
2146 Context->Source = temp->next;
2148 // For each buffer in the source's queue, decrement its reference counter and remove it
2149 while(temp->queue != NULL)
2151 ALbufferlistitem *ALBufferList = temp->queue;
2152 // Decrement buffer's reference counter
2153 if(ALBufferList->buffer != NULL)
2154 ALBufferList->buffer->refcount--;
2155 // Update queue to point to next element in list
2156 temp->queue = ALBufferList->next;
2157 // Release memory allocated for buffer list item
2158 free(ALBufferList);
2161 for(j = 0;j < MAX_SENDS;++j)
2163 if(temp->Send[j].Slot)
2164 temp->Send[j].Slot->refcount--;
2167 // Release source structure
2168 ALTHUNK_REMOVEENTRY(temp->source);
2169 memset(temp, 0, sizeof(ALsource));
2170 free(temp);
2172 Context->SourceCount = 0;