Always disable ALSA's resampler for playback
[openal-soft.git] / OpenAL32 / alSource.c
blob2fd1ad15b64a12b510d947dbb918fb6e5a98c0c4
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <math.h>
25 #include <float.h>
26 #include "alMain.h"
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alError.h"
30 #include "alSource.h"
31 #include "alBuffer.h"
32 #include "alThunk.h"
33 #include "alAuxEffectSlot.h"
35 static ALvoid InitSourceParams(ALsource *pSource);
36 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALfloat updateLen);
37 static ALboolean ApplyOffset(ALsource *pSource);
38 static ALint GetByteOffset(ALsource *pSource);
40 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];
848 ALfloat updateLen;
850 pContext = GetContextSuspended();
851 if(!pContext) return;
853 if(pflValue)
855 if(alIsSource(source))
857 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
859 switch(eParam)
861 case AL_PITCH:
862 *pflValue = pSource->flPitch;
863 break;
865 case AL_GAIN:
866 *pflValue = pSource->flGain;
867 break;
869 case AL_MIN_GAIN:
870 *pflValue = pSource->flMinGain;
871 break;
873 case AL_MAX_GAIN:
874 *pflValue = pSource->flMaxGain;
875 break;
877 case AL_MAX_DISTANCE:
878 *pflValue = pSource->flMaxDistance;
879 break;
881 case AL_ROLLOFF_FACTOR:
882 *pflValue = pSource->flRollOffFactor;
883 break;
885 case AL_CONE_OUTER_GAIN:
886 *pflValue = pSource->flOuterGain;
887 break;
889 case AL_CONE_OUTER_GAINHF:
890 *pflValue = pSource->OuterGainHF;
891 break;
893 case AL_SEC_OFFSET:
894 case AL_SAMPLE_OFFSET:
895 case AL_BYTE_OFFSET:
896 updateLen = (ALfloat)pContext->Device->UpdateSize /
897 pContext->Device->Frequency;
898 if(GetSourceOffset(pSource, eParam, flOffset, updateLen))
899 *pflValue = flOffset[0];
900 else
901 alSetError(AL_INVALID_OPERATION);
902 break;
904 case AL_SEC_RW_OFFSETS_EXT:
905 case AL_SAMPLE_RW_OFFSETS_EXT:
906 case AL_BYTE_RW_OFFSETS_EXT:
907 updateLen = (ALfloat)pContext->Device->UpdateSize /
908 pContext->Device->Frequency;
909 if(GetSourceOffset(pSource, eParam, flOffset, updateLen))
911 pflValue[0] = flOffset[0];
912 pflValue[1] = flOffset[1];
914 else
915 alSetError(AL_INVALID_OPERATION);
916 break;
918 case AL_CONE_INNER_ANGLE:
919 *pflValue = pSource->flInnerAngle;
920 break;
922 case AL_CONE_OUTER_ANGLE:
923 *pflValue = pSource->flOuterAngle;
924 break;
926 case AL_REFERENCE_DISTANCE:
927 *pflValue = pSource->flRefDistance;
928 break;
930 case AL_AIR_ABSORPTION_FACTOR:
931 *pflValue = pSource->AirAbsorptionFactor;
932 break;
934 case AL_ROOM_ROLLOFF_FACTOR:
935 *pflValue = pSource->RoomRolloffFactor;
936 break;
938 case AL_DOPPLER_FACTOR:
939 *pflValue = pSource->DopplerFactor;
940 break;
942 default:
943 alSetError(AL_INVALID_ENUM);
944 break;
947 else
948 alSetError(AL_INVALID_NAME);
950 else
951 alSetError(AL_INVALID_VALUE);
953 ProcessContext(pContext);
957 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
959 ALCcontext *pContext;
960 ALsource *pSource;
962 pContext = GetContextSuspended();
963 if(!pContext) return;
965 if(pflValue1 && pflValue2 && pflValue3)
967 if(alIsSource(source))
969 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
971 switch(eParam)
973 case AL_POSITION:
974 *pflValue1 = pSource->vPosition[0];
975 *pflValue2 = pSource->vPosition[1];
976 *pflValue3 = pSource->vPosition[2];
977 break;
979 case AL_VELOCITY:
980 *pflValue1 = pSource->vVelocity[0];
981 *pflValue2 = pSource->vVelocity[1];
982 *pflValue3 = pSource->vVelocity[2];
983 break;
985 case AL_DIRECTION:
986 *pflValue1 = pSource->vOrientation[0];
987 *pflValue2 = pSource->vOrientation[1];
988 *pflValue3 = pSource->vOrientation[2];
989 break;
991 default:
992 alSetError(AL_INVALID_ENUM);
993 break;
996 else
997 alSetError(AL_INVALID_NAME);
999 else
1000 alSetError(AL_INVALID_VALUE);
1002 ProcessContext(pContext);
1006 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1008 ALCcontext *pContext;
1009 ALsource *pSource;
1011 pContext = GetContextSuspended();
1012 if(!pContext) return;
1014 if(pflValues)
1016 if(alIsSource(source))
1018 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1020 switch(eParam)
1022 case AL_PITCH:
1023 case AL_GAIN:
1024 case AL_MIN_GAIN:
1025 case AL_MAX_GAIN:
1026 case AL_MAX_DISTANCE:
1027 case AL_ROLLOFF_FACTOR:
1028 case AL_DOPPLER_FACTOR:
1029 case AL_CONE_OUTER_GAIN:
1030 case AL_SEC_OFFSET:
1031 case AL_SAMPLE_OFFSET:
1032 case AL_BYTE_OFFSET:
1033 case AL_CONE_INNER_ANGLE:
1034 case AL_CONE_OUTER_ANGLE:
1035 case AL_REFERENCE_DISTANCE:
1036 case AL_CONE_OUTER_GAINHF:
1037 case AL_AIR_ABSORPTION_FACTOR:
1038 case AL_ROOM_ROLLOFF_FACTOR:
1039 alGetSourcef(source, eParam, pflValues);
1040 break;
1042 case AL_POSITION:
1043 pflValues[0] = pSource->vPosition[0];
1044 pflValues[1] = pSource->vPosition[1];
1045 pflValues[2] = pSource->vPosition[2];
1046 break;
1048 case AL_VELOCITY:
1049 pflValues[0] = pSource->vVelocity[0];
1050 pflValues[1] = pSource->vVelocity[1];
1051 pflValues[2] = pSource->vVelocity[2];
1052 break;
1054 case AL_DIRECTION:
1055 pflValues[0] = pSource->vOrientation[0];
1056 pflValues[1] = pSource->vOrientation[1];
1057 pflValues[2] = pSource->vOrientation[2];
1058 break;
1060 default:
1061 alSetError(AL_INVALID_ENUM);
1062 break;
1065 else
1066 alSetError(AL_INVALID_NAME);
1068 else
1069 alSetError(AL_INVALID_VALUE);
1071 ProcessContext(pContext);
1075 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1077 ALCcontext *pContext;
1078 ALsource *pSource;
1079 ALfloat flOffset[2];
1080 ALfloat updateLen;
1082 pContext = GetContextSuspended();
1083 if(!pContext) return;
1085 if(plValue)
1087 if(alIsSource(source))
1089 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1091 switch(eParam)
1093 case AL_MAX_DISTANCE:
1094 *plValue = (ALint)pSource->flMaxDistance;
1095 break;
1097 case AL_ROLLOFF_FACTOR:
1098 *plValue = (ALint)pSource->flRollOffFactor;
1099 break;
1101 case AL_REFERENCE_DISTANCE:
1102 *plValue = (ALint)pSource->flRefDistance;
1103 break;
1105 case AL_SOURCE_RELATIVE:
1106 *plValue = pSource->bHeadRelative;
1107 break;
1109 case AL_CONE_INNER_ANGLE:
1110 *plValue = (ALint)pSource->flInnerAngle;
1111 break;
1113 case AL_CONE_OUTER_ANGLE:
1114 *plValue = (ALint)pSource->flOuterAngle;
1115 break;
1117 case AL_LOOPING:
1118 *plValue = pSource->bLooping;
1119 break;
1121 case AL_BUFFER:
1122 *plValue = (pSource->Buffer ? pSource->Buffer->buffer : 0);
1123 break;
1125 case AL_SOURCE_STATE:
1126 *plValue = pSource->state;
1127 break;
1129 case AL_BUFFERS_QUEUED:
1130 *plValue = pSource->BuffersInQueue;
1131 break;
1133 case AL_BUFFERS_PROCESSED:
1134 if(pSource->bLooping)
1136 /* Buffers on a looping source are in a perpetual state
1137 * of PENDING, so don't report any as PROCESSED */
1138 *plValue = 0;
1140 else
1141 *plValue = pSource->BuffersPlayed;
1142 break;
1144 case AL_SOURCE_TYPE:
1145 *plValue = pSource->lSourceType;
1146 break;
1148 case AL_SEC_OFFSET:
1149 case AL_SAMPLE_OFFSET:
1150 case AL_BYTE_OFFSET:
1151 updateLen = (ALfloat)pContext->Device->UpdateSize /
1152 pContext->Device->Frequency;
1153 if(GetSourceOffset(pSource, eParam, flOffset, updateLen))
1154 *plValue = (ALint)flOffset[0];
1155 else
1156 alSetError(AL_INVALID_OPERATION);
1157 break;
1159 case AL_SEC_RW_OFFSETS_EXT:
1160 case AL_SAMPLE_RW_OFFSETS_EXT:
1161 case AL_BYTE_RW_OFFSETS_EXT:
1162 updateLen = (ALfloat)pContext->Device->UpdateSize /
1163 pContext->Device->Frequency;
1164 if(GetSourceOffset(pSource, eParam, flOffset, updateLen))
1166 plValue[0] = (ALint)flOffset[0];
1167 plValue[1] = (ALint)flOffset[1];
1169 else
1170 alSetError(AL_INVALID_OPERATION);
1171 break;
1173 case AL_DIRECT_FILTER:
1174 *plValue = pSource->DirectFilter.filter;
1175 break;
1177 case AL_DIRECT_FILTER_GAINHF_AUTO:
1178 *plValue = pSource->DryGainHFAuto;
1179 break;
1181 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1182 *plValue = pSource->WetGainAuto;
1183 break;
1185 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1186 *plValue = pSource->WetGainHFAuto;
1187 break;
1189 case AL_DOPPLER_FACTOR:
1190 *plValue = (ALint)pSource->DopplerFactor;
1191 break;
1193 case AL_DISTANCE_MODEL:
1194 *plValue = pSource->DistanceModel;
1195 break;
1197 default:
1198 alSetError(AL_INVALID_ENUM);
1199 break;
1202 else
1203 alSetError(AL_INVALID_NAME);
1205 else
1206 alSetError(AL_INVALID_VALUE);
1208 ProcessContext(pContext);
1212 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1214 ALCcontext *pContext;
1215 ALsource *pSource;
1217 pContext = GetContextSuspended();
1218 if(!pContext) return;
1220 if(plValue1 && plValue2 && plValue3)
1222 if(alIsSource(source))
1224 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1226 switch(eParam)
1228 case AL_POSITION:
1229 *plValue1 = (ALint)pSource->vPosition[0];
1230 *plValue2 = (ALint)pSource->vPosition[1];
1231 *plValue3 = (ALint)pSource->vPosition[2];
1232 break;
1234 case AL_VELOCITY:
1235 *plValue1 = (ALint)pSource->vVelocity[0];
1236 *plValue2 = (ALint)pSource->vVelocity[1];
1237 *plValue3 = (ALint)pSource->vVelocity[2];
1238 break;
1240 case AL_DIRECTION:
1241 *plValue1 = (ALint)pSource->vOrientation[0];
1242 *plValue2 = (ALint)pSource->vOrientation[1];
1243 *plValue3 = (ALint)pSource->vOrientation[2];
1244 break;
1246 default:
1247 alSetError(AL_INVALID_ENUM);
1248 break;
1251 else
1252 alSetError(AL_INVALID_NAME);
1254 else
1255 alSetError(AL_INVALID_VALUE);
1257 ProcessContext(pContext);
1261 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1263 ALCcontext *pContext;
1264 ALsource *pSource;
1266 pContext = GetContextSuspended();
1267 if(!pContext) return;
1269 if(plValues)
1271 if(alIsSource(source))
1273 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1275 switch(eParam)
1277 case AL_SOURCE_RELATIVE:
1278 case AL_CONE_INNER_ANGLE:
1279 case AL_CONE_OUTER_ANGLE:
1280 case AL_LOOPING:
1281 case AL_BUFFER:
1282 case AL_SOURCE_STATE:
1283 case AL_BUFFERS_QUEUED:
1284 case AL_BUFFERS_PROCESSED:
1285 case AL_SEC_OFFSET:
1286 case AL_SAMPLE_OFFSET:
1287 case AL_BYTE_OFFSET:
1288 case AL_MAX_DISTANCE:
1289 case AL_ROLLOFF_FACTOR:
1290 case AL_DOPPLER_FACTOR:
1291 case AL_REFERENCE_DISTANCE:
1292 case AL_SOURCE_TYPE:
1293 case AL_DIRECT_FILTER:
1294 case AL_DIRECT_FILTER_GAINHF_AUTO:
1295 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1296 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1297 case AL_DISTANCE_MODEL:
1298 alGetSourcei(source, eParam, plValues);
1299 break;
1301 case AL_POSITION:
1302 plValues[0] = (ALint)pSource->vPosition[0];
1303 plValues[1] = (ALint)pSource->vPosition[1];
1304 plValues[2] = (ALint)pSource->vPosition[2];
1305 break;
1307 case AL_VELOCITY:
1308 plValues[0] = (ALint)pSource->vVelocity[0];
1309 plValues[1] = (ALint)pSource->vVelocity[1];
1310 plValues[2] = (ALint)pSource->vVelocity[2];
1311 break;
1313 case AL_DIRECTION:
1314 plValues[0] = (ALint)pSource->vOrientation[0];
1315 plValues[1] = (ALint)pSource->vOrientation[1];
1316 plValues[2] = (ALint)pSource->vOrientation[2];
1317 break;
1319 default:
1320 alSetError(AL_INVALID_ENUM);
1321 break;
1324 else
1325 alSetError(AL_INVALID_NAME);
1327 else
1328 alSetError(AL_INVALID_VALUE);
1330 ProcessContext(pContext);
1334 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1336 alSourcePlayv(1, &source);
1339 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1341 ALCcontext *pContext;
1342 ALsource *pSource;
1343 ALbufferlistitem *ALBufferList;
1344 ALboolean bSourcesValid = AL_TRUE;
1345 ALboolean bPlay;
1346 ALsizei i, j;
1348 pContext = GetContextSuspended();
1349 if(!pContext) return;
1351 if(pSourceList)
1353 // Check that all the Sources are valid
1354 for(i = 0; i < n; i++)
1356 if(!alIsSource(pSourceList[i]))
1358 alSetError(AL_INVALID_NAME);
1359 bSourcesValid = AL_FALSE;
1360 break;
1364 if(bSourcesValid)
1366 for(i = 0; i < n; i++)
1368 // Assume Source won't need to play
1369 bPlay = AL_FALSE;
1371 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]);
1373 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1374 ALBufferList = pSource->queue;
1375 while(ALBufferList)
1377 if(ALBufferList->buffer != NULL && ALBufferList->buffer->size)
1379 bPlay = AL_TRUE;
1380 break;
1382 ALBufferList = ALBufferList->next;
1385 if (bPlay)
1387 for(j = 0;j < OUTPUTCHANNELS;j++)
1388 pSource->DryGains[j] = 0.0f;
1389 for(j = 0;j < MAX_SENDS;j++)
1390 pSource->WetGains[j] = 0.0f;
1392 if(pSource->state != AL_PAUSED)
1394 pSource->state = AL_PLAYING;
1395 pSource->position = 0;
1396 pSource->position_fraction = 0;
1397 pSource->BuffersPlayed = 0;
1399 pSource->Buffer = pSource->queue->buffer;
1401 else
1402 pSource->state = AL_PLAYING;
1404 // Check if an Offset has been set
1405 if(pSource->lOffset)
1406 ApplyOffset(pSource);
1408 if(pSource->BuffersPlayed == 0 && pSource->position == 0 &&
1409 pSource->position_fraction == 0)
1410 pSource->FirstStart = AL_TRUE;
1411 else
1412 pSource->FirstStart = AL_FALSE;
1414 // If device is disconnected, go right to stopped
1415 if(!pContext->Device->Connected)
1417 pSource->state = AL_STOPPED;
1418 pSource->BuffersPlayed = pSource->BuffersInQueue;
1419 pSource->position = 0;
1420 pSource->position_fraction = 0;
1423 else
1424 pSource->BuffersPlayed = pSource->BuffersInQueue;
1428 else
1430 // sources is a NULL pointer
1431 alSetError(AL_INVALID_VALUE);
1434 ProcessContext(pContext);
1437 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1439 alSourcePausev(1, &source);
1442 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1444 ALCcontext *Context;
1445 ALsource *Source;
1446 ALsizei i;
1447 ALboolean bSourcesValid = AL_TRUE;
1449 Context = GetContextSuspended();
1450 if(!Context) return;
1452 if(sources)
1454 // Check all the Sources are valid
1455 for(i=0;i<n;i++)
1457 if(!alIsSource(sources[i]))
1459 alSetError(AL_INVALID_NAME);
1460 bSourcesValid = AL_FALSE;
1461 break;
1465 if(bSourcesValid)
1467 for(i = 0;i < n;i++)
1469 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1470 if(Source->state == AL_PLAYING)
1471 Source->state = AL_PAUSED;
1475 else
1477 // sources is a NULL pointer
1478 alSetError(AL_INVALID_VALUE);
1481 ProcessContext(Context);
1484 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1486 alSourceStopv(1, &source);
1489 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1491 ALCcontext *Context;
1492 ALsource *Source;
1493 ALsizei i;
1494 ALboolean bSourcesValid = AL_TRUE;
1496 Context = GetContextSuspended();
1497 if(!Context) return;
1499 if(sources)
1501 // Check all the Sources are valid
1502 for(i = 0;i < n;i++)
1504 if(!alIsSource(sources[i]))
1506 alSetError(AL_INVALID_NAME);
1507 bSourcesValid = AL_FALSE;
1508 break;
1512 if(bSourcesValid)
1514 for(i = 0;i < n;i++)
1516 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1517 if(Source->state != AL_INITIAL)
1519 Source->state = AL_STOPPED;
1520 Source->BuffersPlayed = Source->BuffersInQueue;
1522 Source->lOffset = 0;
1526 else
1528 // sources is a NULL pointer
1529 alSetError(AL_INVALID_VALUE);
1532 ProcessContext(Context);
1535 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1537 alSourceRewindv(1, &source);
1540 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1542 ALCcontext *Context;
1543 ALsource *Source;
1544 ALsizei i;
1545 ALboolean bSourcesValid = AL_TRUE;
1547 Context = GetContextSuspended();
1548 if(!Context) return;
1550 if(sources)
1552 // Check all the Sources are valid
1553 for(i = 0;i < n;i++)
1555 if(!alIsSource(sources[i]))
1557 alSetError(AL_INVALID_NAME);
1558 bSourcesValid = AL_FALSE;
1559 break;
1563 if(bSourcesValid)
1565 for(i = 0;i < n;i++)
1567 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1568 if(Source->state != AL_INITIAL)
1570 Source->state = AL_INITIAL;
1571 Source->position = 0;
1572 Source->position_fraction = 0;
1573 Source->BuffersPlayed = 0;
1574 if(Source->queue)
1575 Source->Buffer = Source->queue->buffer;
1577 Source->lOffset = 0;
1581 else
1583 // sources is a NULL pointer
1584 alSetError(AL_INVALID_VALUE);
1587 ProcessContext(Context);
1591 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1593 ALCcontext *Context;
1594 ALsource *ALSource;
1595 ALsizei i;
1596 ALbufferlistitem *ALBufferList;
1597 ALbufferlistitem *ALBufferListStart;
1598 ALint iFrequency;
1599 ALint iFormat;
1600 ALboolean bBuffersValid = AL_TRUE;
1601 ALboolean hadFormat = AL_FALSE;
1603 if (n == 0)
1604 return;
1606 Context = GetContextSuspended();
1607 if(!Context) return;
1609 // Check that all buffers are valid or zero and that the source is valid
1611 // Check that this is a valid source
1612 if(alIsSource(source))
1614 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1616 // Check that this is not a STATIC Source
1617 if(ALSource->lSourceType != AL_STATIC)
1619 iFrequency = -1;
1620 iFormat = -1;
1622 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1623 ALBufferList = ALSource->queue;
1624 while(ALBufferList)
1626 if (ALBufferList->buffer)
1628 iFrequency = ALBufferList->buffer->frequency;
1629 iFormat = ALBufferList->buffer->format;
1630 hadFormat = AL_TRUE;
1631 break;
1633 ALBufferList = ALBufferList->next;
1636 for(i = 0; i < n; i++)
1638 ALbuffer *buffer;
1640 if(!alIsBuffer(buffers[i]))
1642 alSetError(AL_INVALID_NAME);
1643 bBuffersValid = AL_FALSE;
1644 break;
1646 if(!buffers[i])
1647 continue;
1649 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1650 if(iFrequency == -1 && iFormat == -1)
1652 iFrequency = buffer->frequency;
1653 iFormat = buffer->format;
1655 else if(iFrequency != buffer->frequency ||
1656 iFormat != buffer->format)
1658 alSetError(AL_INVALID_OPERATION);
1659 bBuffersValid = AL_FALSE;
1660 break;
1664 if(bBuffersValid)
1666 ALbuffer *buffer = NULL;
1668 // Change Source Type
1669 ALSource->lSourceType = AL_STREAMING;
1671 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1673 // All buffers are valid - so add them to the list
1674 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1675 ALBufferListStart->buffer = buffer;
1676 ALBufferListStart->next = NULL;
1678 // Increment reference counter for buffer
1679 if(buffer) buffer->refcount++;
1681 ALBufferList = ALBufferListStart;
1683 for(i = 1; i < n; i++)
1685 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1687 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1688 ALBufferList->next->buffer = buffer;
1689 ALBufferList->next->next = NULL;
1691 // Increment reference counter for buffer
1692 if(buffer) buffer->refcount++;
1694 ALBufferList = ALBufferList->next;
1697 if(ALSource->queue == NULL)
1699 ALSource->queue = ALBufferListStart;
1700 // Update Current Buffer
1701 ALSource->Buffer = ALBufferListStart->buffer;
1703 else
1705 // Find end of queue
1706 ALBufferList = ALSource->queue;
1707 while(ALBufferList->next != NULL)
1708 ALBufferList = ALBufferList->next;
1710 ALBufferList->next = ALBufferListStart;
1713 // Update number of buffers in queue
1714 ALSource->BuffersInQueue += n;
1715 // If no previous format, mark the source dirty now that it may
1716 // have one
1717 if(!hadFormat)
1718 ALSource->NeedsUpdate = AL_TRUE;
1721 else
1723 // Invalid Source Type (can't queue on a Static Source)
1724 alSetError(AL_INVALID_OPERATION);
1727 else
1729 // Invalid Source Name
1730 alSetError(AL_INVALID_NAME);
1733 ProcessContext(Context);
1737 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1738 // an array of buffer IDs that are to be filled with the names of the buffers removed
1739 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1741 ALCcontext *Context;
1742 ALsource *ALSource;
1743 ALsizei i;
1744 ALbufferlistitem *ALBufferList;
1745 ALboolean bBuffersProcessed;
1747 if (n == 0)
1748 return;
1750 bBuffersProcessed = AL_TRUE;
1752 Context = GetContextSuspended();
1753 if(!Context) return;
1755 if(alIsSource(source))
1757 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1759 // If all 'n' buffers have been processed, remove them from the queue
1760 if(!ALSource->bLooping && (ALuint)n <= ALSource->BuffersPlayed)
1762 for(i = 0; i < n; i++)
1764 ALBufferList = ALSource->queue;
1766 ALSource->queue = ALBufferList->next;
1767 // Record name of buffer
1768 buffers[i] = ALBufferList->buffer->buffer;
1769 // Decrement buffer reference counter
1770 if(ALBufferList->buffer)
1771 ALBufferList->buffer->refcount--;
1773 // Release memory for buffer list item
1774 free(ALBufferList);
1775 ALSource->BuffersInQueue--;
1778 if(ALSource->state != AL_PLAYING)
1780 if(ALSource->queue)
1781 ALSource->Buffer = ALSource->queue->buffer;
1782 else
1783 ALSource->Buffer = NULL;
1786 ALSource->BuffersPlayed -= n;
1788 else
1790 // Some buffers can't be unqueue because they have not been processed
1791 alSetError(AL_INVALID_VALUE);
1794 else
1796 // Invalid Source Name
1797 alSetError(AL_INVALID_NAME);
1800 ProcessContext(Context);
1804 static ALvoid InitSourceParams(ALsource *pSource)
1806 pSource->flInnerAngle = 360.0f;
1807 pSource->flOuterAngle = 360.0f;
1808 pSource->flPitch = 1.0f;
1809 pSource->vPosition[0] = 0.0f;
1810 pSource->vPosition[1] = 0.0f;
1811 pSource->vPosition[2] = 0.0f;
1812 pSource->vOrientation[0] = 0.0f;
1813 pSource->vOrientation[1] = 0.0f;
1814 pSource->vOrientation[2] = 0.0f;
1815 pSource->vVelocity[0] = 0.0f;
1816 pSource->vVelocity[1] = 0.0f;
1817 pSource->vVelocity[2] = 0.0f;
1818 pSource->flRefDistance = 1.0f;
1819 pSource->flMaxDistance = FLT_MAX;
1820 pSource->flRollOffFactor = 1.0f;
1821 pSource->bLooping = AL_FALSE;
1822 pSource->flGain = 1.0f;
1823 pSource->flMinGain = 0.0f;
1824 pSource->flMaxGain = 1.0f;
1825 pSource->flOuterGain = 0.0f;
1826 pSource->OuterGainHF = 1.0f;
1828 pSource->DryGainHFAuto = AL_TRUE;
1829 pSource->WetGainAuto = AL_TRUE;
1830 pSource->WetGainHFAuto = AL_TRUE;
1831 pSource->AirAbsorptionFactor = 0.0f;
1832 pSource->RoomRolloffFactor = 0.0f;
1833 pSource->DopplerFactor = 1.0f;
1835 pSource->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1837 pSource->Resampler = DefaultResampler;
1839 pSource->state = AL_INITIAL;
1840 pSource->lSourceType = AL_UNDETERMINED;
1842 pSource->NeedsUpdate = AL_TRUE;
1844 pSource->Buffer = NULL;
1849 GetSourceOffset
1851 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1852 The offset is relative to the start of the queue (not the start of the current buffer)
1854 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALfloat updateLen)
1856 ALbufferlistitem *pBufferList;
1857 ALbuffer *pBuffer;
1858 ALfloat flBufferFreq;
1859 ALint lChannels, lBytes;
1860 ALint readPos, writePos;
1861 ALenum eOriginalFormat;
1862 ALboolean bReturn = AL_TRUE;
1863 ALint lTotalBufferDataSize;
1864 ALuint i;
1866 if((pSource->state == AL_PLAYING || pSource->state == AL_PAUSED) && pSource->Buffer)
1868 pBuffer = pSource->Buffer;
1869 // Get Current Buffer Size and frequency (in milliseconds)
1870 flBufferFreq = (ALfloat)pBuffer->frequency;
1871 eOriginalFormat = pBuffer->eOriginalFormat;
1872 lChannels = aluChannelsFromFormat(pBuffer->format);
1873 lBytes = aluBytesFromFormat(pBuffer->format);
1875 // Get Current BytesPlayed
1876 readPos = pSource->position * lChannels * lBytes; // NOTE : This is the byte offset into the *current* buffer
1877 // Add byte length of any processed buffers in the queue
1878 pBufferList = pSource->queue;
1879 for(i = 0;i < pSource->BuffersPlayed && pBufferList;i++)
1881 readPos += pBufferList->buffer->size;
1882 pBufferList = pBufferList->next;
1885 if(pSource->state == AL_PLAYING)
1886 writePos = readPos + ((ALuint)(updateLen*flBufferFreq) * lChannels * lBytes);
1887 else
1888 writePos = readPos;
1890 lTotalBufferDataSize = 0;
1891 pBufferList = pSource->queue;
1892 while (pBufferList)
1894 if (pBufferList->buffer)
1895 lTotalBufferDataSize += pBufferList->buffer->size;
1896 pBufferList = pBufferList->next;
1899 if (pSource->bLooping)
1901 if(readPos < 0)
1902 readPos = 0;
1903 else
1904 readPos %= lTotalBufferDataSize;
1905 if(writePos < 0)
1906 writePos = 0;
1907 else
1908 writePos %= lTotalBufferDataSize;
1910 else
1912 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1913 if(readPos < 0)
1914 readPos = 0;
1915 else if(readPos > lTotalBufferDataSize)
1916 readPos = lTotalBufferDataSize;
1917 if(writePos < 0)
1918 writePos = 0;
1919 else if(writePos > lTotalBufferDataSize)
1920 writePos = lTotalBufferDataSize;
1923 switch (eName)
1925 case AL_SEC_OFFSET:
1926 case AL_SEC_RW_OFFSETS_EXT:
1927 pflOffset[0] = (ALfloat)readPos / (lChannels * lBytes * flBufferFreq);
1928 pflOffset[1] = (ALfloat)writePos / (lChannels * lBytes * flBufferFreq);
1929 break;
1930 case AL_SAMPLE_OFFSET:
1931 case AL_SAMPLE_RW_OFFSETS_EXT:
1932 pflOffset[0] = (ALfloat)(readPos / (lChannels * lBytes));
1933 pflOffset[1] = (ALfloat)(writePos / (lChannels * lBytes));
1934 break;
1935 case AL_BYTE_OFFSET:
1936 case AL_BYTE_RW_OFFSETS_EXT:
1937 // Take into account the original format of the Buffer
1938 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
1939 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1941 // Round down to nearest ADPCM block
1942 pflOffset[0] = (ALfloat)((readPos / (65 * lBytes * lChannels)) * 36 * lChannels);
1943 if(pSource->state == AL_PLAYING)
1945 // Round up to nearest ADPCM block
1946 pflOffset[1] = (ALfloat)(((writePos + (65 * lBytes * lChannels) - 1) / (65 * lBytes * lChannels)) * 36 * lChannels);
1948 else
1949 pflOffset[1] = pflOffset[0];
1951 else if (eOriginalFormat == AL_FORMAT_REAR8)
1953 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 1);
1954 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 1);
1956 else if (eOriginalFormat == AL_FORMAT_REAR16)
1958 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 2);
1959 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 2);
1961 else if (eOriginalFormat == AL_FORMAT_REAR32)
1963 pflOffset[0] = (ALfloat)(readPos / 2 / lBytes * 4);
1964 pflOffset[1] = (ALfloat)(writePos / 2 / lBytes * 4);
1966 else
1968 ALuint OrigBytes = aluBytesFromFormat(eOriginalFormat);
1969 pflOffset[0] = (ALfloat)(readPos / lBytes * OrigBytes);
1970 pflOffset[1] = (ALfloat)(writePos / lBytes * OrigBytes);
1972 break;
1975 else
1977 pflOffset[0] = 0.0f;
1978 pflOffset[1] = 0.0f;
1981 return bReturn;
1986 ApplyOffset
1988 Apply a playback offset to the Source. This function will update the queue (to correctly
1989 mark buffers as 'pending' or 'processed' depending upon the new offset.
1991 static ALboolean ApplyOffset(ALsource *pSource)
1993 ALbufferlistitem *pBufferList;
1994 ALbuffer *pBuffer;
1995 ALint lBufferSize, lTotalBufferSize;
1996 ALint lByteOffset;
1998 // Get true byte offset
1999 lByteOffset = GetByteOffset(pSource);
2001 // If the offset is invalid, don't apply it
2002 if(lByteOffset == -1)
2003 return AL_FALSE;
2005 // Sort out the queue (pending and processed states)
2006 pBufferList = pSource->queue;
2007 lTotalBufferSize = 0;
2008 pSource->BuffersPlayed = 0;
2010 while(pBufferList)
2012 pBuffer = pBufferList->buffer;
2013 lBufferSize = pBuffer ? pBuffer->size : 0;
2015 if(lTotalBufferSize+lBufferSize <= lByteOffset)
2017 // Offset is past this buffer so increment BuffersPlayed
2018 pSource->BuffersPlayed++;
2020 else if(lTotalBufferSize <= lByteOffset)
2022 // Offset is within this buffer
2023 // Set Current Buffer
2024 pSource->Buffer = pBufferList->buffer;
2026 // SW Mixer Positions are in Samples
2027 pSource->position = (lByteOffset - lTotalBufferSize) /
2028 aluBytesFromFormat(pBuffer->format) /
2029 aluChannelsFromFormat(pBuffer->format);
2030 break;
2033 // Increment the TotalBufferSize
2034 lTotalBufferSize += lBufferSize;
2036 // Move on to next buffer in the Queue
2037 pBufferList = pBufferList->next;
2040 return AL_TRUE;
2045 GetByteOffset
2047 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2048 offset supplied by the application). This takes into account the fact that the buffer format
2049 may have been modifed by AL (e.g 8bit samples are converted to float)
2051 static ALint GetByteOffset(ALsource *pSource)
2053 ALbuffer *pBuffer = NULL;
2054 ALbufferlistitem *pBufferList;
2055 ALfloat flBufferFreq;
2056 ALint lChannels, lBytes;
2057 ALint lByteOffset = -1;
2058 ALint lTotalBufferDataSize;
2059 ALenum OriginalFormat;
2061 // Find the first non-NULL Buffer in the Queue
2062 pBufferList = pSource->queue;
2063 while (pBufferList)
2065 if (pBufferList->buffer)
2067 pBuffer = pBufferList->buffer;
2068 break;
2070 pBufferList = pBufferList->next;
2073 if (pBuffer)
2075 flBufferFreq = ((ALfloat)pBuffer->frequency);
2076 lChannels = aluChannelsFromFormat(pBuffer->format);
2077 lBytes = aluBytesFromFormat(pBuffer->format);
2078 OriginalFormat = pBuffer->eOriginalFormat;
2080 // Determine the ByteOffset (and ensure it is block aligned)
2081 switch (pSource->lOffsetType)
2083 case AL_BYTE_OFFSET:
2084 // Take into consideration the original format
2085 if(OriginalFormat == AL_FORMAT_MONO_IMA4 ||
2086 OriginalFormat == AL_FORMAT_STEREO_IMA4)
2088 // Round down to nearest ADPCM block
2089 lByteOffset = pSource->lOffset / (36 * lChannels);
2090 // Multiply by compression rate
2091 lByteOffset = lByteOffset * 65 * lChannels * lBytes;
2092 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2094 else if(OriginalFormat == AL_FORMAT_REAR8)
2096 lByteOffset = pSource->lOffset / 1 * lBytes * 2;
2097 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2099 else if(OriginalFormat == AL_FORMAT_REAR16)
2101 lByteOffset = pSource->lOffset / 2 * lBytes * 2;
2102 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2104 else if(OriginalFormat == AL_FORMAT_REAR32)
2106 lByteOffset = pSource->lOffset / 4 * lBytes * 2;
2107 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2109 else
2111 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
2112 lByteOffset = pSource->lOffset / OrigBytes * lBytes;
2113 lByteOffset -= (lByteOffset % (lChannels * lBytes));
2115 break;
2117 case AL_SAMPLE_OFFSET:
2118 lByteOffset = pSource->lOffset * lChannels * lBytes;
2119 break;
2121 case AL_SEC_OFFSET:
2122 // Note - lOffset is internally stored as Milliseconds
2123 lByteOffset = (ALint)(pSource->lOffset / 1000.0f * flBufferFreq);
2124 lByteOffset *= lChannels * lBytes;
2125 break;
2128 lTotalBufferDataSize = 0;
2129 pBufferList = pSource->queue;
2130 while (pBufferList)
2132 if (pBufferList->buffer)
2133 lTotalBufferDataSize += pBufferList->buffer->size;
2134 pBufferList = pBufferList->next;
2137 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2138 if (lByteOffset >= lTotalBufferDataSize)
2139 lByteOffset = -1;
2142 // Clear Offset
2143 pSource->lOffset = 0;
2145 return lByteOffset;
2149 ALvoid ReleaseALSources(ALCcontext *Context)
2151 ALuint j;
2153 while(Context->Source)
2155 ALsource *temp = Context->Source;
2156 Context->Source = temp->next;
2158 // For each buffer in the source's queue, decrement its reference counter and remove it
2159 while(temp->queue != NULL)
2161 ALbufferlistitem *ALBufferList = temp->queue;
2162 // Decrement buffer's reference counter
2163 if(ALBufferList->buffer != NULL)
2164 ALBufferList->buffer->refcount--;
2165 // Update queue to point to next element in list
2166 temp->queue = ALBufferList->next;
2167 // Release memory allocated for buffer list item
2168 free(ALBufferList);
2171 for(j = 0;j < MAX_SENDS;++j)
2173 if(temp->Send[j].Slot)
2174 temp->Send[j].Slot->refcount--;
2177 // Release source structure
2178 ALTHUNK_REMOVEENTRY(temp->source);
2179 memset(temp, 0, sizeof(ALsource));
2180 free(temp);
2182 Context->SourceCount = 0;