Get rid of unnecessary messages from pulseaudio
[openal-soft.git] / OpenAL32 / alSource.c
blob74591ff2cdef8e4f02d4dd7b56172e33984c0ead
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <math.h>
25 #include <float.h>
26 #include "alMain.h"
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alError.h"
30 #include "alSource.h"
31 #include "alBuffer.h"
32 #include "alThunk.h"
33 #include "alAuxEffectSlot.h"
35 static ALvoid InitSourceParams(ALCcontext *Context, ALsource *pSource);
36 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize);
37 static ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext);
38 static ALint GetByteOffset(ALsource *pSource);
40 ALAPI ALvoid ALAPIENTRY alGenSources(ALsizei n,ALuint *sources)
42 ALCcontext *Context;
43 ALCdevice *Device;
44 ALsizei i=0;
46 Context = GetContextSuspended();
47 if(!Context) return;
49 if(n > 0)
51 Device = Context->Device;
53 // Check that enough memory has been allocted in the 'sources' array for n Sources
54 if(!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
56 // Check that the requested number of sources can be generated
57 if((Context->SourceCount + n) <= Device->MaxNoOfSources)
59 ALsource **list = &Context->Source;
60 while(*list)
61 list = &(*list)->next;
63 // Add additional sources to the list (Source->next points to the location for the next Source structure)
64 while(i < n)
66 *list = calloc(1, sizeof(ALsource));
67 if(!(*list))
69 alDeleteSources(i, sources);
70 alSetError(AL_OUT_OF_MEMORY);
71 break;
74 sources[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
75 (*list)->source = sources[i];
77 InitSourceParams(Context, *list);
78 Context->SourceCount++;
79 i++;
81 list = &(*list)->next;
84 else
86 // Not enough resources to create the Sources
87 alSetError(AL_INVALID_VALUE);
90 else
92 // Bad pointer
93 alSetError(AL_INVALID_VALUE);
97 ProcessContext(Context);
101 ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
103 ALCcontext *Context;
104 ALCdevice *Device;
105 ALsource *ALSource;
106 ALsource **list;
107 ALsizei i, j;
108 ALbufferlistitem *ALBufferList;
109 ALboolean bSourcesValid = AL_TRUE;
111 Context = GetContextSuspended();
112 if(!Context) return;
114 if(n >= 0)
116 Device = Context->Device;
118 // Check that all Sources are valid (and can therefore be deleted)
119 for (i = 0; i < n; i++)
121 if (!alIsSource(sources[i]))
123 alSetError(AL_INVALID_NAME);
124 bSourcesValid = AL_FALSE;
125 break;
129 if(bSourcesValid)
131 // All Sources are valid, and can be deleted
132 for(i = 0; i < n; i++)
134 // Recheck that the Source is valid, because there could be duplicated Source names
135 if(alIsSource(sources[i]))
137 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
138 alSourceStop((ALuint)ALSource->source);
140 // For each buffer in the source's queue, decrement its reference counter and remove it
141 while (ALSource->queue != NULL)
143 ALBufferList = ALSource->queue;
144 // Decrement buffer's reference counter
145 if(ALBufferList->buffer != 0)
146 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
147 // Update queue to point to next element in list
148 ALSource->queue = ALBufferList->next;
149 // Release memory allocated for buffer list item
150 free(ALBufferList);
153 for(j = 0;j < MAX_SENDS;++j)
155 if(ALSource->Send[j].Slot)
156 ALSource->Send[j].Slot->refcount--;
157 ALSource->Send[j].Slot = NULL;
160 // Decrement Source count
161 Context->SourceCount--;
163 // Remove Source from list of Sources
164 list = &Context->Source;
165 while(*list && *list != ALSource)
166 list = &(*list)->next;
168 if(*list)
169 *list = (*list)->next;
170 ALTHUNK_REMOVEENTRY(ALSource->source);
172 memset(ALSource,0,sizeof(ALsource));
173 free(ALSource);
178 else
179 alSetError(AL_INVALID_VALUE);
181 ProcessContext(Context);
185 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
187 ALboolean result=AL_FALSE;
188 ALCcontext *Context;
189 ALsource *Source;
191 Context = GetContextSuspended();
192 if(!Context) return AL_FALSE;
194 // To determine if this is a valid Source name, look through the list of generated Sources
195 Source = Context->Source;
196 while(Source)
198 if(Source->source == source)
200 result = AL_TRUE;
201 break;
204 Source = Source->next;
207 ProcessContext(Context);
209 return result;
213 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
215 ALCcontext *pContext;
216 ALsource *pSource;
218 pContext = GetContextSuspended();
219 if(!pContext) return;
221 if(alIsSource(source))
223 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
225 switch(eParam)
227 case AL_PITCH:
228 if(flValue >= 0.0f)
230 pSource->flPitch = flValue;
231 if(pSource->flPitch < 0.001f)
232 pSource->flPitch = 0.001f;
234 else
235 alSetError(AL_INVALID_VALUE);
236 break;
238 case AL_CONE_INNER_ANGLE:
239 if(flValue >= 0.0f && flValue <= 360.0f)
240 pSource->flInnerAngle = flValue;
241 else
242 alSetError(AL_INVALID_VALUE);
243 break;
245 case AL_CONE_OUTER_ANGLE:
246 if(flValue >= 0.0f && flValue <= 360.0f)
247 pSource->flOuterAngle = flValue;
248 else
249 alSetError(AL_INVALID_VALUE);
250 break;
252 case AL_GAIN:
253 if(flValue >= 0.0f)
254 pSource->flGain = flValue;
255 else
256 alSetError(AL_INVALID_VALUE);
257 break;
259 case AL_MAX_DISTANCE:
260 if(flValue >= 0.0f)
261 pSource->flMaxDistance = flValue;
262 else
263 alSetError(AL_INVALID_VALUE);
264 break;
266 case AL_ROLLOFF_FACTOR:
267 if(flValue >= 0.0f)
268 pSource->flRollOffFactor = flValue;
269 else
270 alSetError(AL_INVALID_VALUE);
271 break;
273 case AL_REFERENCE_DISTANCE:
274 if(flValue >= 0.0f)
275 pSource->flRefDistance = flValue;
276 else
277 alSetError(AL_INVALID_VALUE);
278 break;
280 case AL_MIN_GAIN:
281 if(flValue >= 0.0f && flValue <= 1.0f)
282 pSource->flMinGain = flValue;
283 else
284 alSetError(AL_INVALID_VALUE);
285 break;
287 case AL_MAX_GAIN:
288 if(flValue >= 0.0f && flValue <= 1.0f)
289 pSource->flMaxGain = flValue;
290 else
291 alSetError(AL_INVALID_VALUE);
292 break;
294 case AL_CONE_OUTER_GAIN:
295 if(flValue >= 0.0f && flValue <= 1.0f)
296 pSource->flOuterGain = flValue;
297 else
298 alSetError(AL_INVALID_VALUE);
299 break;
301 case AL_CONE_OUTER_GAINHF:
302 if(flValue >= 0.0f && flValue <= 1.0f)
303 pSource->OuterGainHF = flValue;
304 else
305 alSetError(AL_INVALID_VALUE);
306 break;
308 case AL_AIR_ABSORPTION_FACTOR:
309 if(flValue >= 0.0f && flValue <= 10.0f)
310 pSource->AirAbsorptionFactor = flValue;
311 else
312 alSetError(AL_INVALID_VALUE);
313 break;
315 case AL_ROOM_ROLLOFF_FACTOR:
316 if(flValue >= 0.0f && flValue <= 10.0f)
317 pSource->RoomRolloffFactor = flValue;
318 else
319 alSetError(AL_INVALID_VALUE);
320 break;
322 case AL_DOPPLER_FACTOR:
323 if(flValue >= 0.0f && flValue <= 1.0f)
324 pSource->DopplerFactor = flValue;
325 else
326 alSetError(AL_INVALID_VALUE);
327 break;
329 case AL_SEC_OFFSET:
330 case AL_SAMPLE_OFFSET:
331 case AL_BYTE_OFFSET:
332 if(flValue >= 0.0f)
334 pSource->lOffsetType = eParam;
336 // Store Offset (convert Seconds into Milliseconds)
337 if(eParam == AL_SEC_OFFSET)
338 pSource->lOffset = (ALint)(flValue * 1000.0f);
339 else
340 pSource->lOffset = (ALint)flValue;
342 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
343 ApplyOffset(pSource, AL_TRUE);
345 else
346 alSetError(AL_INVALID_VALUE);
347 break;
349 default:
350 alSetError(AL_INVALID_ENUM);
351 break;
354 else
356 // Invalid Source Name
357 alSetError(AL_INVALID_NAME);
360 ProcessContext(pContext);
364 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
366 ALCcontext *pContext;
367 ALsource *pSource;
369 pContext = GetContextSuspended();
370 if(!pContext) return;
372 if(alIsSource(source))
374 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
375 switch(eParam)
377 case AL_POSITION:
378 pSource->vPosition[0] = flValue1;
379 pSource->vPosition[1] = flValue2;
380 pSource->vPosition[2] = flValue3;
381 break;
383 case AL_VELOCITY:
384 pSource->vVelocity[0] = flValue1;
385 pSource->vVelocity[1] = flValue2;
386 pSource->vVelocity[2] = flValue3;
387 break;
389 case AL_DIRECTION:
390 pSource->vOrientation[0] = flValue1;
391 pSource->vOrientation[1] = flValue2;
392 pSource->vOrientation[2] = flValue3;
393 break;
395 default:
396 alSetError(AL_INVALID_ENUM);
397 break;
400 else
401 alSetError(AL_INVALID_NAME);
403 ProcessContext(pContext);
407 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
409 ALCcontext *pContext;
411 pContext = GetContextSuspended();
412 if(!pContext) return;
414 if(pflValues)
416 if(alIsSource(source))
418 switch(eParam)
420 case AL_PITCH:
421 case AL_CONE_INNER_ANGLE:
422 case AL_CONE_OUTER_ANGLE:
423 case AL_GAIN:
424 case AL_MAX_DISTANCE:
425 case AL_ROLLOFF_FACTOR:
426 case AL_REFERENCE_DISTANCE:
427 case AL_MIN_GAIN:
428 case AL_MAX_GAIN:
429 case AL_CONE_OUTER_GAIN:
430 case AL_CONE_OUTER_GAINHF:
431 case AL_SEC_OFFSET:
432 case AL_SAMPLE_OFFSET:
433 case AL_BYTE_OFFSET:
434 case AL_AIR_ABSORPTION_FACTOR:
435 case AL_ROOM_ROLLOFF_FACTOR:
436 alSourcef(source, eParam, pflValues[0]);
437 break;
439 case AL_POSITION:
440 case AL_VELOCITY:
441 case AL_DIRECTION:
442 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
443 break;
445 default:
446 alSetError(AL_INVALID_ENUM);
447 break;
450 else
451 alSetError(AL_INVALID_NAME);
453 else
454 alSetError(AL_INVALID_VALUE);
456 ProcessContext(pContext);
460 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
462 ALCcontext *pContext;
463 ALsource *pSource;
464 ALbufferlistitem *pALBufferListItem;
465 ALuint i;
467 pContext = GetContextSuspended();
468 if(!pContext) return;
470 if(alIsSource(source))
472 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
474 switch(eParam)
476 case AL_MAX_DISTANCE:
477 case AL_ROLLOFF_FACTOR:
478 case AL_REFERENCE_DISTANCE:
479 alSourcef(source, eParam, (ALfloat)lValue);
480 break;
482 case AL_SOURCE_RELATIVE:
483 if(lValue == AL_FALSE || lValue == AL_TRUE)
484 pSource->bHeadRelative = (ALboolean)lValue;
485 else
486 alSetError(AL_INVALID_VALUE);
487 break;
489 case AL_CONE_INNER_ANGLE:
490 if(lValue >= 0 && lValue <= 360)
491 pSource->flInnerAngle = (float)lValue;
492 else
493 alSetError(AL_INVALID_VALUE);
494 break;
496 case AL_CONE_OUTER_ANGLE:
497 if(lValue >= 0 && lValue <= 360)
498 pSource->flOuterAngle = (float)lValue;
499 else
500 alSetError(AL_INVALID_VALUE);
501 break;
503 case AL_LOOPING:
504 if(lValue == AL_FALSE || lValue == AL_TRUE)
506 pSource->bLooping = (ALboolean)lValue;
508 pALBufferListItem = pSource->queue;
509 for(i = 0;pALBufferListItem != NULL;i++)
511 if(lValue == AL_FALSE && i <= pSource->BuffersPlayed)
512 pALBufferListItem->bufferstate = PROCESSED;
513 else
514 pALBufferListItem->bufferstate = PENDING;
515 pALBufferListItem = pALBufferListItem->next;
518 else
519 alSetError(AL_INVALID_VALUE);
520 break;
522 case AL_BUFFER:
523 if(pSource->state == AL_STOPPED || pSource->state == AL_INITIAL)
525 if(alIsBuffer(lValue))
527 // Remove all elements in the queue
528 while(pSource->queue != NULL)
530 pALBufferListItem = pSource->queue;
531 pSource->queue = pALBufferListItem->next;
532 // Decrement reference counter for buffer
533 if (pALBufferListItem->buffer)
534 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
535 // Release memory for buffer list item
536 free(pALBufferListItem);
537 // Decrement the number of buffers in the queue
538 pSource->BuffersInQueue--;
541 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
542 if(lValue != 0)
544 // Source is now in STATIC mode
545 pSource->lSourceType = AL_STATIC;
547 // Add the selected buffer to the queue
548 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
549 pALBufferListItem->buffer = lValue;
550 pALBufferListItem->bufferstate = PENDING;
551 pALBufferListItem->flag = 0;
552 pALBufferListItem->next = NULL;
554 pSource->queue = pALBufferListItem;
555 pSource->BuffersInQueue = 1;
557 // Increment reference counter for buffer
558 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
560 else
562 // Source is now in UNDETERMINED mode
563 pSource->lSourceType = AL_UNDETERMINED;
564 pSource->BuffersPlayed = 0;
567 // Update AL_BUFFER parameter
568 pSource->ulBufferID = lValue;
570 else
571 alSetError(AL_INVALID_VALUE);
573 else
574 alSetError(AL_INVALID_OPERATION);
575 break;
577 case AL_SOURCE_STATE:
578 // Query only
579 alSetError(AL_INVALID_OPERATION);
580 break;
582 case AL_SEC_OFFSET:
583 case AL_SAMPLE_OFFSET:
584 case AL_BYTE_OFFSET:
585 if(lValue >= 0)
587 pSource->lOffsetType = eParam;
589 // Store Offset (convert Seconds into Milliseconds)
590 if(eParam == AL_SEC_OFFSET)
591 pSource->lOffset = lValue * 1000;
592 else
593 pSource->lOffset = lValue;
595 if(pSource->state == AL_PLAYING || pSource->state == AL_PAUSED)
596 ApplyOffset(pSource, AL_TRUE);
598 else
599 alSetError(AL_INVALID_VALUE);
600 break;
602 case AL_DIRECT_FILTER:
603 if(alIsFilter(lValue))
605 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
606 if(!filter)
608 pSource->DirectFilter.type = AL_FILTER_NULL;
609 pSource->DirectFilter.filter = 0;
611 else
612 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
614 else
615 alSetError(AL_INVALID_VALUE);
616 break;
618 case AL_DIRECT_FILTER_GAINHF_AUTO:
619 if(lValue == AL_TRUE || lValue == AL_FALSE)
620 pSource->DryGainHFAuto = lValue;
621 else
622 alSetError(AL_INVALID_VALUE);
623 break;
625 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
626 if(lValue == AL_TRUE || lValue == AL_FALSE)
627 pSource->WetGainAuto = lValue;
628 else
629 alSetError(AL_INVALID_VALUE);
630 break;
632 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
633 if(lValue == AL_TRUE || lValue == AL_FALSE)
634 pSource->WetGainHFAuto = lValue;
635 else
636 alSetError(AL_INVALID_VALUE);
637 break;
639 case AL_DISTANCE_MODEL:
640 if(lValue == AL_NONE ||
641 lValue == AL_INVERSE_DISTANCE ||
642 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
643 lValue == AL_LINEAR_DISTANCE ||
644 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
645 lValue == AL_EXPONENT_DISTANCE ||
646 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
647 pSource->DistanceModel = lValue;
648 else
649 alSetError(AL_INVALID_VALUE);
650 break;
652 default:
653 alSetError(AL_INVALID_ENUM);
654 break;
657 else
658 alSetError(AL_INVALID_NAME);
660 ProcessContext(pContext);
664 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
666 ALCcontext *pContext;
668 pContext = GetContextSuspended();
669 if(!pContext) return;
671 if(alIsSource(source))
673 ALsource *pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
674 ALCdevice *Device = pContext->Device;
676 switch (eParam)
678 case AL_POSITION:
679 case AL_VELOCITY:
680 case AL_DIRECTION:
681 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
682 break;
684 case AL_AUXILIARY_SEND_FILTER:
685 if((ALuint)lValue2 < Device->NumAuxSends &&
686 (lValue1 == 0 || alIsAuxiliaryEffectSlot(lValue1)) &&
687 alIsFilter(lValue3))
689 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
690 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
692 /* Release refcount on the previous slot, and add one for
693 * the new slot */
694 if(pSource->Send[lValue2].Slot)
695 pSource->Send[lValue2].Slot->refcount--;
696 pSource->Send[lValue2].Slot = ALEffectSlot;
697 if(pSource->Send[lValue2].Slot)
698 pSource->Send[lValue2].Slot->refcount++;
700 if(!ALFilter)
702 /* Disable filter */
703 pSource->Send[lValue2].WetFilter.type = 0;
704 pSource->Send[lValue2].WetFilter.filter = 0;
706 else
707 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
709 else
710 alSetError(AL_INVALID_VALUE);
711 break;
713 default:
714 alSetError(AL_INVALID_ENUM);
715 break;
718 else
719 alSetError(AL_INVALID_NAME);
721 ProcessContext(pContext);
725 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
727 ALCcontext *pContext;
729 pContext = GetContextSuspended();
730 if(!pContext) return;
732 if(plValues)
734 if(alIsSource(source))
736 switch(eParam)
738 case AL_SOURCE_RELATIVE:
739 case AL_CONE_INNER_ANGLE:
740 case AL_CONE_OUTER_ANGLE:
741 case AL_LOOPING:
742 case AL_BUFFER:
743 case AL_SOURCE_STATE:
744 case AL_SEC_OFFSET:
745 case AL_SAMPLE_OFFSET:
746 case AL_BYTE_OFFSET:
747 case AL_MAX_DISTANCE:
748 case AL_ROLLOFF_FACTOR:
749 case AL_REFERENCE_DISTANCE:
750 case AL_DIRECT_FILTER:
751 case AL_DIRECT_FILTER_GAINHF_AUTO:
752 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
753 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
754 case AL_DISTANCE_MODEL:
755 alSourcei(source, eParam, plValues[0]);
756 break;
758 case AL_POSITION:
759 case AL_VELOCITY:
760 case AL_DIRECTION:
761 case AL_AUXILIARY_SEND_FILTER:
762 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
763 break;
765 default:
766 alSetError(AL_INVALID_ENUM);
767 break;
770 else
771 alSetError(AL_INVALID_NAME);
773 else
774 alSetError(AL_INVALID_VALUE);
776 ProcessContext(pContext);
780 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
782 ALCcontext *pContext;
783 ALsource *pSource;
784 ALfloat flOffset[2];
786 pContext = GetContextSuspended();
787 if(!pContext) return;
789 if(pflValue)
791 if(alIsSource(source))
793 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
795 switch(eParam)
797 case AL_PITCH:
798 *pflValue = pSource->flPitch;
799 break;
801 case AL_GAIN:
802 *pflValue = pSource->flGain;
803 break;
805 case AL_MIN_GAIN:
806 *pflValue = pSource->flMinGain;
807 break;
809 case AL_MAX_GAIN:
810 *pflValue = pSource->flMaxGain;
811 break;
813 case AL_MAX_DISTANCE:
814 *pflValue = pSource->flMaxDistance;
815 break;
817 case AL_ROLLOFF_FACTOR:
818 *pflValue = pSource->flRollOffFactor;
819 break;
821 case AL_CONE_OUTER_GAIN:
822 *pflValue = pSource->flOuterGain;
823 break;
825 case AL_CONE_OUTER_GAINHF:
826 *pflValue = pSource->OuterGainHF;
827 break;
829 case AL_SEC_OFFSET:
830 case AL_SAMPLE_OFFSET:
831 case AL_BYTE_OFFSET:
832 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
833 *pflValue = flOffset[0];
834 else
835 alSetError(AL_INVALID_OPERATION);
836 break;
838 case AL_SEC_RW_OFFSETS_EXT:
839 case AL_SAMPLE_RW_OFFSETS_EXT:
840 case AL_BYTE_RW_OFFSETS_EXT:
841 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
843 pflValue[0] = flOffset[0];
844 pflValue[1] = flOffset[1];
846 else
847 alSetError(AL_INVALID_OPERATION);
848 break;
850 case AL_CONE_INNER_ANGLE:
851 *pflValue = pSource->flInnerAngle;
852 break;
854 case AL_CONE_OUTER_ANGLE:
855 *pflValue = pSource->flOuterAngle;
856 break;
858 case AL_REFERENCE_DISTANCE:
859 *pflValue = pSource->flRefDistance;
860 break;
862 case AL_AIR_ABSORPTION_FACTOR:
863 *pflValue = pSource->AirAbsorptionFactor;
864 break;
866 case AL_ROOM_ROLLOFF_FACTOR:
867 *pflValue = pSource->RoomRolloffFactor;
868 break;
870 case AL_DOPPLER_FACTOR:
871 *pflValue = pSource->DopplerFactor;
872 break;
874 default:
875 alSetError(AL_INVALID_ENUM);
876 break;
879 else
880 alSetError(AL_INVALID_NAME);
882 else
883 alSetError(AL_INVALID_VALUE);
885 ProcessContext(pContext);
889 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
891 ALCcontext *pContext;
892 ALsource *pSource;
894 pContext = GetContextSuspended();
895 if(!pContext) return;
897 if(pflValue1 && pflValue2 && pflValue3)
899 if(alIsSource(source))
901 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
903 switch(eParam)
905 case AL_POSITION:
906 *pflValue1 = pSource->vPosition[0];
907 *pflValue2 = pSource->vPosition[1];
908 *pflValue3 = pSource->vPosition[2];
909 break;
911 case AL_VELOCITY:
912 *pflValue1 = pSource->vVelocity[0];
913 *pflValue2 = pSource->vVelocity[1];
914 *pflValue3 = pSource->vVelocity[2];
915 break;
917 case AL_DIRECTION:
918 *pflValue1 = pSource->vOrientation[0];
919 *pflValue2 = pSource->vOrientation[1];
920 *pflValue3 = pSource->vOrientation[2];
921 break;
923 default:
924 alSetError(AL_INVALID_ENUM);
925 break;
928 else
929 alSetError(AL_INVALID_NAME);
931 else
932 alSetError(AL_INVALID_VALUE);
934 ProcessContext(pContext);
938 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
940 ALCcontext *pContext;
941 ALsource *pSource;
943 pContext = GetContextSuspended();
944 if(!pContext) return;
946 if(pflValues)
948 if(alIsSource(source))
950 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
952 switch(eParam)
954 case AL_PITCH:
955 case AL_GAIN:
956 case AL_MIN_GAIN:
957 case AL_MAX_GAIN:
958 case AL_MAX_DISTANCE:
959 case AL_ROLLOFF_FACTOR:
960 case AL_DOPPLER_FACTOR:
961 case AL_CONE_OUTER_GAIN:
962 case AL_SEC_OFFSET:
963 case AL_SAMPLE_OFFSET:
964 case AL_BYTE_OFFSET:
965 case AL_CONE_INNER_ANGLE:
966 case AL_CONE_OUTER_ANGLE:
967 case AL_REFERENCE_DISTANCE:
968 case AL_CONE_OUTER_GAINHF:
969 case AL_AIR_ABSORPTION_FACTOR:
970 case AL_ROOM_ROLLOFF_FACTOR:
971 alGetSourcef(source, eParam, pflValues);
972 break;
974 case AL_POSITION:
975 pflValues[0] = pSource->vPosition[0];
976 pflValues[1] = pSource->vPosition[1];
977 pflValues[2] = pSource->vPosition[2];
978 break;
980 case AL_VELOCITY:
981 pflValues[0] = pSource->vVelocity[0];
982 pflValues[1] = pSource->vVelocity[1];
983 pflValues[2] = pSource->vVelocity[2];
984 break;
986 case AL_DIRECTION:
987 pflValues[0] = pSource->vOrientation[0];
988 pflValues[1] = pSource->vOrientation[1];
989 pflValues[2] = pSource->vOrientation[2];
990 break;
992 default:
993 alSetError(AL_INVALID_ENUM);
994 break;
997 else
998 alSetError(AL_INVALID_NAME);
1000 else
1001 alSetError(AL_INVALID_VALUE);
1003 ProcessContext(pContext);
1007 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1009 ALCcontext *pContext;
1010 ALsource *pSource;
1011 ALfloat flOffset[2];
1013 pContext = GetContextSuspended();
1014 if(!pContext) return;
1016 if(plValue)
1018 if(alIsSource(source))
1020 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1022 switch(eParam)
1024 case AL_MAX_DISTANCE:
1025 *plValue = (ALint)pSource->flMaxDistance;
1026 break;
1028 case AL_ROLLOFF_FACTOR:
1029 *plValue = (ALint)pSource->flRollOffFactor;
1030 break;
1032 case AL_REFERENCE_DISTANCE:
1033 *plValue = (ALint)pSource->flRefDistance;
1034 break;
1036 case AL_SOURCE_RELATIVE:
1037 *plValue = pSource->bHeadRelative;
1038 break;
1040 case AL_CONE_INNER_ANGLE:
1041 *plValue = (ALint)pSource->flInnerAngle;
1042 break;
1044 case AL_CONE_OUTER_ANGLE:
1045 *plValue = (ALint)pSource->flOuterAngle;
1046 break;
1048 case AL_LOOPING:
1049 *plValue = pSource->bLooping;
1050 break;
1052 case AL_BUFFER:
1053 *plValue = pSource->ulBufferID;
1054 break;
1056 case AL_SOURCE_STATE:
1057 *plValue = pSource->state;
1058 break;
1060 case AL_BUFFERS_QUEUED:
1061 *plValue = pSource->BuffersInQueue;
1062 break;
1064 case AL_BUFFERS_PROCESSED:
1065 if(pSource->bLooping)
1067 /* Buffers on a looping source are in a perpetual state
1068 * of PENDING, so don't report any as PROCESSED */
1069 *plValue = 0;
1071 else
1072 *plValue = pSource->BuffersPlayed;
1073 break;
1075 case AL_SOURCE_TYPE:
1076 *plValue = pSource->lSourceType;
1077 break;
1079 case AL_SEC_OFFSET:
1080 case AL_SAMPLE_OFFSET:
1081 case AL_BYTE_OFFSET:
1082 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1083 *plValue = (ALint)flOffset[0];
1084 else
1085 alSetError(AL_INVALID_OPERATION);
1086 break;
1088 case AL_SEC_RW_OFFSETS_EXT:
1089 case AL_SAMPLE_RW_OFFSETS_EXT:
1090 case AL_BYTE_RW_OFFSETS_EXT:
1091 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1093 plValue[0] = (ALint)flOffset[0];
1094 plValue[1] = (ALint)flOffset[1];
1096 else
1097 alSetError(AL_INVALID_OPERATION);
1098 break;
1100 case AL_DIRECT_FILTER:
1101 *plValue = pSource->DirectFilter.filter;
1102 break;
1104 case AL_DIRECT_FILTER_GAINHF_AUTO:
1105 *plValue = pSource->DryGainHFAuto;
1106 break;
1108 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1109 *plValue = pSource->WetGainAuto;
1110 break;
1112 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1113 *plValue = pSource->WetGainHFAuto;
1114 break;
1116 case AL_DOPPLER_FACTOR:
1117 *plValue = (ALint)pSource->DopplerFactor;
1118 break;
1120 case AL_DISTANCE_MODEL:
1121 *plValue = pSource->DistanceModel;
1122 break;
1124 default:
1125 alSetError(AL_INVALID_ENUM);
1126 break;
1129 else
1130 alSetError(AL_INVALID_NAME);
1132 else
1133 alSetError(AL_INVALID_VALUE);
1135 ProcessContext(pContext);
1139 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1141 ALCcontext *pContext;
1142 ALsource *pSource;
1144 pContext = GetContextSuspended();
1145 if(!pContext) return;
1147 if(plValue1 && plValue2 && plValue3)
1149 if(alIsSource(source))
1151 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1153 switch(eParam)
1155 case AL_POSITION:
1156 *plValue1 = (ALint)pSource->vPosition[0];
1157 *plValue2 = (ALint)pSource->vPosition[1];
1158 *plValue3 = (ALint)pSource->vPosition[2];
1159 break;
1161 case AL_VELOCITY:
1162 *plValue1 = (ALint)pSource->vVelocity[0];
1163 *plValue2 = (ALint)pSource->vVelocity[1];
1164 *plValue3 = (ALint)pSource->vVelocity[2];
1165 break;
1167 case AL_DIRECTION:
1168 *plValue1 = (ALint)pSource->vOrientation[0];
1169 *plValue2 = (ALint)pSource->vOrientation[1];
1170 *plValue3 = (ALint)pSource->vOrientation[2];
1171 break;
1173 default:
1174 alSetError(AL_INVALID_ENUM);
1175 break;
1178 else
1179 alSetError(AL_INVALID_NAME);
1181 else
1182 alSetError(AL_INVALID_VALUE);
1184 ProcessContext(pContext);
1188 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1190 ALCcontext *pContext;
1191 ALsource *pSource;
1193 pContext = GetContextSuspended();
1194 if(!pContext) return;
1196 if(plValues)
1198 if(alIsSource(source))
1200 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1202 switch(eParam)
1204 case AL_SOURCE_RELATIVE:
1205 case AL_CONE_INNER_ANGLE:
1206 case AL_CONE_OUTER_ANGLE:
1207 case AL_LOOPING:
1208 case AL_BUFFER:
1209 case AL_SOURCE_STATE:
1210 case AL_BUFFERS_QUEUED:
1211 case AL_BUFFERS_PROCESSED:
1212 case AL_SEC_OFFSET:
1213 case AL_SAMPLE_OFFSET:
1214 case AL_BYTE_OFFSET:
1215 case AL_MAX_DISTANCE:
1216 case AL_ROLLOFF_FACTOR:
1217 case AL_DOPPLER_FACTOR:
1218 case AL_REFERENCE_DISTANCE:
1219 case AL_SOURCE_TYPE:
1220 case AL_DIRECT_FILTER:
1221 case AL_DIRECT_FILTER_GAINHF_AUTO:
1222 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1223 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1224 case AL_DISTANCE_MODEL:
1225 alGetSourcei(source, eParam, plValues);
1226 break;
1228 case AL_POSITION:
1229 plValues[0] = (ALint)pSource->vPosition[0];
1230 plValues[1] = (ALint)pSource->vPosition[1];
1231 plValues[2] = (ALint)pSource->vPosition[2];
1232 break;
1234 case AL_VELOCITY:
1235 plValues[0] = (ALint)pSource->vVelocity[0];
1236 plValues[1] = (ALint)pSource->vVelocity[1];
1237 plValues[2] = (ALint)pSource->vVelocity[2];
1238 break;
1240 case AL_DIRECTION:
1241 plValues[0] = (ALint)pSource->vOrientation[0];
1242 plValues[1] = (ALint)pSource->vOrientation[1];
1243 plValues[2] = (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 ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1263 alSourcePlayv(1, &source);
1264 return;
1267 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1269 ALCcontext *pContext;
1270 ALsource *pSource;
1271 ALbufferlistitem *ALBufferList;
1272 ALboolean bSourcesValid = AL_TRUE;
1273 ALboolean bPlay;
1274 ALsizei i, j;
1276 pContext = GetContextSuspended();
1277 if(!pContext) return;
1279 if(pSourceList)
1281 // Check that all the Sources are valid
1282 for(i = 0; i < n; i++)
1284 if(!alIsSource(pSourceList[i]))
1286 alSetError(AL_INVALID_NAME);
1287 bSourcesValid = AL_FALSE;
1288 break;
1292 if(bSourcesValid)
1294 for(i = 0; i < n; i++)
1296 // Assume Source won't need to play
1297 bPlay = AL_FALSE;
1299 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]);
1301 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1302 ALBufferList = pSource->queue;
1303 while(ALBufferList)
1305 if(ALBufferList->buffer != 0 && ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size)
1307 bPlay = AL_TRUE;
1308 break;
1310 ALBufferList = ALBufferList->next;
1313 if (bPlay)
1315 for(j = 0;j < OUTPUTCHANNELS;j++)
1316 pSource->DryGains[j] = 0.0f;
1317 for(j = 0;j < MAX_SENDS;j++)
1318 pSource->WetGains[j] = 0.0f;
1320 if(pSource->state != AL_PAUSED)
1322 pSource->state = AL_PLAYING;
1323 pSource->inuse = AL_TRUE;
1324 pSource->play = AL_TRUE;
1325 pSource->position = 0;
1326 pSource->position_fraction = 0;
1327 pSource->BuffersPlayed = 0;
1328 pSource->FirstStart = AL_TRUE;
1330 pSource->ulBufferID = pSource->queue->buffer;
1332 // Make sure all the Buffers in the queue are marked as PENDING
1333 ALBufferList = pSource->queue;
1334 while(ALBufferList)
1336 ALBufferList->bufferstate = PENDING;
1337 ALBufferList = ALBufferList->next;
1340 else
1342 pSource->state = AL_PLAYING;
1343 pSource->inuse = AL_TRUE;
1344 pSource->play = AL_TRUE;
1345 pSource->FirstStart = AL_FALSE;
1348 // Check if an Offset has been set
1349 if(pSource->lOffset)
1350 ApplyOffset(pSource, AL_FALSE);
1352 // If device is disconnected, go right to stopped
1353 if(!pContext->Device->Connected)
1355 pSource->state = AL_STOPPED;
1356 pSource->inuse = AL_FALSE;
1357 pSource->BuffersPlayed = pSource->BuffersInQueue;
1358 ALBufferList = pSource->queue;
1359 while(ALBufferList != NULL)
1361 ALBufferList->bufferstate = PROCESSED;
1362 ALBufferList = ALBufferList->next;
1364 pSource->position = 0;
1365 pSource->position_fraction = 0;
1368 else
1370 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1371 ALBufferList = pSource->queue;
1372 while(ALBufferList)
1374 ALBufferList->bufferstate = PROCESSED;
1375 ALBufferList = ALBufferList->next;
1378 pSource->BuffersPlayed = pSource->BuffersInQueue;
1383 else
1385 // sources is a NULL pointer
1386 alSetError(AL_INVALID_VALUE);
1389 ProcessContext(pContext);
1392 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1394 alSourcePausev(1, &source);
1395 return;
1398 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1400 ALCcontext *Context;
1401 ALsource *Source;
1402 ALsizei i;
1403 ALboolean bSourcesValid = AL_TRUE;
1405 Context = GetContextSuspended();
1406 if(!Context) return;
1408 if(sources)
1410 // Check all the Sources are valid
1411 for(i=0;i<n;i++)
1413 if(!alIsSource(sources[i]))
1415 alSetError(AL_INVALID_NAME);
1416 bSourcesValid = AL_FALSE;
1417 break;
1421 if(bSourcesValid)
1423 for(i = 0;i < n;i++)
1425 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1426 if(Source->state == AL_PLAYING)
1428 Source->state = AL_PAUSED;
1429 Source->inuse = AL_FALSE;
1434 else
1436 // sources is a NULL pointer
1437 alSetError(AL_INVALID_VALUE);
1440 ProcessContext(Context);
1443 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1445 alSourceStopv(1, &source);
1446 return;
1449 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1451 ALCcontext *Context;
1452 ALsource *Source;
1453 ALsizei i;
1454 ALbufferlistitem *ALBufferListItem;
1455 ALboolean bSourcesValid = AL_TRUE;
1457 Context = GetContextSuspended();
1458 if(!Context) return;
1460 if(sources)
1462 // Check all the Sources are valid
1463 for(i = 0;i < n;i++)
1465 if(!alIsSource(sources[i]))
1467 alSetError(AL_INVALID_NAME);
1468 bSourcesValid = AL_FALSE;
1469 break;
1473 if(bSourcesValid)
1475 for(i = 0;i < n;i++)
1477 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1478 if(Source->state != AL_INITIAL)
1480 Source->state = AL_STOPPED;
1481 Source->inuse = AL_FALSE;
1482 Source->BuffersPlayed = Source->BuffersInQueue;
1483 ALBufferListItem = Source->queue;
1484 while(ALBufferListItem != NULL)
1486 ALBufferListItem->bufferstate = PROCESSED;
1487 ALBufferListItem = ALBufferListItem->next;
1490 Source->lOffset = 0;
1494 else
1496 // sources is a NULL pointer
1497 alSetError(AL_INVALID_VALUE);
1500 ProcessContext(Context);
1503 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1505 alSourceRewindv(1, &source);
1506 return;
1509 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1511 ALCcontext *Context;
1512 ALsource *Source;
1513 ALsizei i;
1514 ALbufferlistitem *ALBufferListItem;
1515 ALboolean bSourcesValid = AL_TRUE;
1517 Context = GetContextSuspended();
1518 if(!Context) return;
1520 if(sources)
1522 // Check all the Sources are valid
1523 for(i = 0;i < n;i++)
1525 if(!alIsSource(sources[i]))
1527 alSetError(AL_INVALID_NAME);
1528 bSourcesValid = AL_FALSE;
1529 break;
1533 if(bSourcesValid)
1535 for(i = 0;i < n;i++)
1537 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1538 if(Source->state != AL_INITIAL)
1540 Source->state = AL_INITIAL;
1541 Source->inuse = AL_FALSE;
1542 Source->position = 0;
1543 Source->position_fraction = 0;
1544 Source->BuffersPlayed = 0;
1545 ALBufferListItem = Source->queue;
1546 while(ALBufferListItem != NULL)
1548 ALBufferListItem->bufferstate = PENDING;
1549 ALBufferListItem = ALBufferListItem->next;
1551 if(Source->queue)
1552 Source->ulBufferID = Source->queue->buffer;
1554 Source->lOffset = 0;
1558 else
1560 // sources is a NULL pointer
1561 alSetError(AL_INVALID_VALUE);
1564 ProcessContext(Context);
1568 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1570 ALCcontext *Context;
1571 ALsource *ALSource;
1572 ALsizei i;
1573 ALbufferlistitem *ALBufferList;
1574 ALbufferlistitem *ALBufferListStart;
1575 ALint iFrequency;
1576 ALint iFormat;
1577 ALboolean bBuffersValid = AL_TRUE;
1579 if (n == 0)
1580 return;
1582 Context = GetContextSuspended();
1583 if(!Context) return;
1585 // Check that all buffers are valid or zero and that the source is valid
1587 // Check that this is a valid source
1588 if(alIsSource(source))
1590 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1592 // Check that this is not a STATIC Source
1593 if(ALSource->lSourceType != AL_STATIC)
1595 iFrequency = -1;
1596 iFormat = -1;
1598 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1599 ALBufferList = ALSource->queue;
1600 while(ALBufferList)
1602 if (ALBufferList->buffer)
1604 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1605 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1606 break;
1608 ALBufferList = ALBufferList->next;
1611 for(i = 0; i < n; i++)
1613 if(alIsBuffer(buffers[i]))
1615 if(buffers[i])
1617 if((iFrequency == -1) && (iFormat == -1))
1619 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1620 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1622 else
1624 if((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1625 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1627 alSetError(AL_INVALID_OPERATION);
1628 bBuffersValid = AL_FALSE;
1629 break;
1634 else
1636 alSetError(AL_INVALID_NAME);
1637 bBuffersValid = AL_FALSE;
1638 break;
1642 if(bBuffersValid)
1644 // Change Source Type
1645 ALSource->lSourceType = AL_STREAMING;
1647 // All buffers are valid - so add them to the list
1648 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1649 ALBufferListStart->buffer = buffers[0];
1650 ALBufferListStart->bufferstate = PENDING;
1651 ALBufferListStart->flag = 0;
1652 ALBufferListStart->next = NULL;
1654 // Increment reference counter for buffer
1655 if(buffers[0])
1656 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1658 ALBufferList = ALBufferListStart;
1660 for(i = 1; i < n; i++)
1662 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1663 ALBufferList->next->buffer = buffers[i];
1664 ALBufferList->next->bufferstate = PENDING;
1665 ALBufferList->next->flag = 0;
1666 ALBufferList->next->next = NULL;
1668 // Increment reference counter for buffer
1669 if(buffers[i])
1670 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1672 ALBufferList = ALBufferList->next;
1675 if(ALSource->queue == NULL)
1677 ALSource->queue = ALBufferListStart;
1678 // Update Current Buffer
1679 ALSource->ulBufferID = ALBufferListStart->buffer;
1681 else
1683 // Find end of queue
1684 ALBufferList = ALSource->queue;
1685 while(ALBufferList->next != NULL)
1686 ALBufferList = ALBufferList->next;
1688 ALBufferList->next = ALBufferListStart;
1691 // Update number of buffers in queue
1692 ALSource->BuffersInQueue += n;
1695 else
1697 // Invalid Source Type (can't queue on a Static Source)
1698 alSetError(AL_INVALID_OPERATION);
1701 else
1703 // Invalid Source Name
1704 alSetError(AL_INVALID_NAME);
1707 ProcessContext(Context);
1711 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1712 // an array of buffer IDs that are to be filled with the names of the buffers removed
1713 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1715 ALCcontext *Context;
1716 ALsource *ALSource;
1717 ALsizei i;
1718 ALbufferlistitem *ALBufferList;
1719 ALuint BufferID;
1720 ALboolean bBuffersProcessed;
1722 if (n == 0)
1723 return;
1725 bBuffersProcessed = AL_TRUE;
1727 Context = GetContextSuspended();
1728 if(!Context) return;
1730 if(alIsSource(source))
1732 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1734 // Check that all 'n' buffers have been processed
1735 ALBufferList = ALSource->queue;
1736 for(i = 0; i < n; i++)
1738 if(ALBufferList != NULL && ALBufferList->bufferstate == PROCESSED)
1740 ALBufferList = ALBufferList->next;
1742 else
1744 bBuffersProcessed = AL_FALSE;
1745 break;
1749 // If all 'n' buffers have been processed, remove them from the queue
1750 if(bBuffersProcessed)
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;
1759 // Decrement buffer reference counter
1760 if(ALBufferList->buffer)
1761 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(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 BufferID = ALSource->queue->buffer;
1772 else
1773 BufferID = 0;
1775 ALSource->ulBufferID = BufferID;
1778 if((ALuint)n > ALSource->BuffersPlayed)
1779 ALSource->BuffersPlayed = 0;
1780 else
1781 ALSource->BuffersPlayed -= n;
1783 else
1785 // Some buffers can't be unqueue because they have not been processed
1786 alSetError(AL_INVALID_VALUE);
1789 else
1791 // Invalid Source Name
1792 alSetError(AL_INVALID_NAME);
1795 ProcessContext(Context);
1799 static ALvoid InitSourceParams(ALCcontext *Context, ALsource *pSource)
1801 pSource->flInnerAngle = 360.0f;
1802 pSource->flOuterAngle = 360.0f;
1803 pSource->flPitch = 1.0f;
1804 pSource->vPosition[0] = 0.0f;
1805 pSource->vPosition[1] = 0.0f;
1806 pSource->vPosition[2] = 0.0f;
1807 pSource->vOrientation[0] = 0.0f;
1808 pSource->vOrientation[1] = 0.0f;
1809 pSource->vOrientation[2] = 0.0f;
1810 pSource->vVelocity[0] = 0.0f;
1811 pSource->vVelocity[1] = 0.0f;
1812 pSource->vVelocity[2] = 0.0f;
1813 pSource->flRefDistance = 1.0f;
1814 pSource->flMaxDistance = FLT_MAX;
1815 pSource->flRollOffFactor = 1.0f;
1816 pSource->bLooping = AL_FALSE;
1817 pSource->flGain = 1.0f;
1818 pSource->flMinGain = 0.0f;
1819 pSource->flMaxGain = 1.0f;
1820 pSource->flOuterGain = 0.0f;
1821 pSource->OuterGainHF = 1.0f;
1823 pSource->DryGainHFAuto = AL_TRUE;
1824 pSource->WetGainAuto = AL_TRUE;
1825 pSource->WetGainHFAuto = AL_TRUE;
1826 pSource->AirAbsorptionFactor = 0.0f;
1827 pSource->RoomRolloffFactor = 0.0f;
1828 pSource->DopplerFactor = 1.0f;
1830 pSource->DistanceModel = Context->DistanceModel;
1832 pSource->state = AL_INITIAL;
1833 pSource->lSourceType = AL_UNDETERMINED;
1835 pSource->ulBufferID= 0;
1840 GetSourceOffset
1842 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1843 The offset is relative to the start of the queue (not the start of the current buffer)
1845 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize)
1847 ALbufferlistitem *pBufferList;
1848 ALbuffer *pBuffer;
1849 ALfloat flBufferFreq;
1850 ALint lChannels;
1851 ALint readPos, writePos;
1852 ALenum eOriginalFormat;
1853 ALboolean bReturn = AL_TRUE;
1854 ALint lTotalBufferDataSize;
1856 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
1858 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
1859 // Get Current Buffer Size and frequency (in milliseconds)
1860 flBufferFreq = (ALfloat)pBuffer->frequency;
1861 eOriginalFormat = pBuffer->eOriginalFormat;
1862 lChannels = aluChannelsFromFormat(pBuffer->format);
1864 // Get Current BytesPlayed
1865 readPos = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
1866 // Add byte length of any processed buffers in the queue
1867 pBufferList = pSource->queue;
1868 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
1870 readPos += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
1871 pBufferList = pBufferList->next;
1874 if(pSource->state == AL_PLAYING)
1875 writePos = readPos + (updateSize * lChannels * 2);
1876 else
1877 writePos = readPos;
1879 lTotalBufferDataSize = 0;
1880 pBufferList = pSource->queue;
1881 while (pBufferList)
1883 if (pBufferList->buffer)
1884 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
1885 pBufferList = pBufferList->next;
1888 if (pSource->bLooping)
1890 if(readPos < 0)
1891 readPos = 0;
1892 else
1893 readPos %= lTotalBufferDataSize;
1894 if(writePos < 0)
1895 writePos = 0;
1896 else
1897 writePos %= lTotalBufferDataSize;
1899 else
1901 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1902 if(readPos < 0)
1903 readPos = 0;
1904 else if(readPos > lTotalBufferDataSize)
1905 readPos = lTotalBufferDataSize;
1906 if(writePos < 0)
1907 writePos = 0;
1908 else if(writePos > lTotalBufferDataSize)
1909 writePos = lTotalBufferDataSize;
1912 switch (eName)
1914 case AL_SEC_OFFSET:
1915 case AL_SEC_RW_OFFSETS_EXT:
1916 pflOffset[0] = (ALfloat)readPos / (lChannels * 2.0f * flBufferFreq);
1917 pflOffset[1] = (ALfloat)writePos / (lChannels * 2.0f * flBufferFreq);
1918 break;
1919 case AL_SAMPLE_OFFSET:
1920 case AL_SAMPLE_RW_OFFSETS_EXT:
1921 pflOffset[0] = (ALfloat)(readPos / (lChannels * 2));
1922 pflOffset[1] = (ALfloat)(writePos / (lChannels * 2));
1923 break;
1924 case AL_BYTE_OFFSET:
1925 case AL_BYTE_RW_OFFSETS_EXT:
1926 // Take into account the original format of the Buffer
1927 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
1928 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1930 // Round down to nearest ADPCM block
1931 pflOffset[0] = (ALfloat)((readPos / (65 * 2 * lChannels)) * 36 * lChannels);
1932 if(pSource->state == AL_PLAYING)
1934 // Round up to nearest ADPCM block
1935 pflOffset[1] = (ALfloat)(((writePos + (65 * 2 * lChannels) - 1) / (65 * 2 * lChannels)) * 36 * lChannels);
1937 else
1938 pflOffset[1] = pflOffset[0];
1940 else if (eOriginalFormat == AL_FORMAT_REAR8)
1942 pflOffset[0] = (ALfloat)(readPos >> 2);
1943 pflOffset[1] = (ALfloat)(writePos >> 2);
1945 else if (eOriginalFormat == AL_FORMAT_REAR16)
1947 pflOffset[0] = (ALfloat)(readPos >> 1);
1948 pflOffset[1] = (ALfloat)(writePos >> 1);
1950 else if (aluBytesFromFormat(eOriginalFormat) == 1)
1952 pflOffset[0] = (ALfloat)(readPos >> 1);
1953 pflOffset[1] = (ALfloat)(writePos >> 1);
1955 else if (aluBytesFromFormat(eOriginalFormat) == 4)
1957 pflOffset[0] = (ALfloat)(readPos << 1);
1958 pflOffset[1] = (ALfloat)(writePos << 1);
1960 else
1962 pflOffset[0] = (ALfloat)readPos;
1963 pflOffset[1] = (ALfloat)writePos;
1965 break;
1968 else
1970 pflOffset[0] = 0.0f;
1971 pflOffset[1] = 0.0f;
1974 return bReturn;
1979 ApplyOffset
1981 Apply a playback offset to the Source. This function will update the queue (to correctly
1982 mark buffers as 'pending' or 'processed' depending upon the new offset.
1984 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
1986 ALbufferlistitem *pBufferList;
1987 ALbuffer *pBuffer;
1988 ALint lBufferSize, lTotalBufferSize;
1989 ALint lByteOffset;
1991 // Get true byte offset
1992 lByteOffset = GetByteOffset(pSource);
1994 // If this is a valid offset apply it
1995 if (lByteOffset != -1)
1997 // Sort out the queue (pending and processed states)
1998 pBufferList = pSource->queue;
1999 lTotalBufferSize = 0;
2000 pSource->BuffersPlayed = 0;
2001 while (pBufferList)
2003 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2004 lBufferSize = pBuffer ? pBuffer->size : 0;
2006 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2008 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2009 // update the state to PROCESSED
2010 pSource->BuffersPlayed++;
2012 if (!pSource->bLooping)
2013 pBufferList->bufferstate = PROCESSED;
2015 else if (lTotalBufferSize <= lByteOffset)
2017 // Offset is within this buffer
2018 pBufferList->bufferstate = PENDING;
2020 // Set Current Buffer ID
2021 pSource->ulBufferID = pBufferList->buffer;
2023 // SW Mixer Positions are in Samples
2024 pSource->position = (lByteOffset - lTotalBufferSize) /
2025 aluBytesFromFormat(pBuffer->format) /
2026 aluChannelsFromFormat(pBuffer->format);
2028 else
2030 // Offset is before this buffer, so mark as pending
2031 pBufferList->bufferstate = PENDING;
2034 // Increment the TotalBufferSize
2035 lTotalBufferSize += lBufferSize;
2037 // Move on to next buffer in the Queue
2038 pBufferList = pBufferList->next;
2041 else
2043 if (bUpdateContext)
2044 alSetError(AL_INVALID_VALUE);
2047 // Clear Offset
2048 pSource->lOffset = 0;
2053 GetByteOffset
2055 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2056 offset supplied by the application). This takes into account the fact that the buffer format
2057 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2059 static ALint GetByteOffset(ALsource *pSource)
2061 ALbuffer *pBuffer = NULL;
2062 ALbufferlistitem *pBufferList;
2063 ALfloat flBufferFreq;
2064 ALint lChannels;
2065 ALint lByteOffset = -1;
2066 ALint lTotalBufferDataSize;
2068 // Find the first non-NULL Buffer in the Queue
2069 pBufferList = pSource->queue;
2070 while (pBufferList)
2072 if (pBufferList->buffer)
2074 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2075 break;
2077 pBufferList = pBufferList->next;
2080 if (pBuffer)
2082 flBufferFreq = ((ALfloat)pBuffer->frequency);
2083 lChannels = aluChannelsFromFormat(pBuffer->format);
2085 // Determine the ByteOffset (and ensure it is block aligned)
2086 switch (pSource->lOffsetType)
2088 case AL_BYTE_OFFSET:
2089 // Take into consideration the original format
2090 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2091 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2093 // Round down to nearest ADPCM block
2094 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2095 // Multiply by compression rate
2096 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2097 lByteOffset -= (lByteOffset % (lChannels * 2));
2099 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2101 lByteOffset = pSource->lOffset * 4;
2102 lByteOffset -= (lByteOffset % (lChannels * 2));
2104 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2106 lByteOffset = pSource->lOffset * 2;
2107 lByteOffset -= (lByteOffset % (lChannels * 2));
2109 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2111 lByteOffset = pSource->lOffset * 2;
2112 lByteOffset -= (lByteOffset % (lChannels * 2));
2114 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2116 lByteOffset = pSource->lOffset / 2;
2117 lByteOffset -= (lByteOffset % (lChannels * 2));
2119 else
2121 lByteOffset = pSource->lOffset;
2122 lByteOffset -= (lByteOffset % (lChannels * 2));
2124 break;
2126 case AL_SAMPLE_OFFSET:
2127 lByteOffset = pSource->lOffset * lChannels * 2;
2128 break;
2130 case AL_SEC_OFFSET:
2131 // Note - lOffset is internally stored as Milliseconds
2132 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2133 lByteOffset -= (lByteOffset % (lChannels * 2));
2134 break;
2137 lTotalBufferDataSize = 0;
2138 pBufferList = pSource->queue;
2139 while (pBufferList)
2141 if (pBufferList->buffer)
2142 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2143 pBufferList = pBufferList->next;
2146 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2147 if (lByteOffset >= lTotalBufferDataSize)
2148 lByteOffset = -1;
2151 return lByteOffset;
2155 ALvoid ReleaseALSources(ALCcontext *Context)
2157 while(Context->Source)
2159 ALsource *temp = Context->Source;
2160 Context->Source = Context->Source->next;
2162 // Release source structure
2163 ALTHUNK_REMOVEENTRY(temp->source);
2164 memset(temp, 0, sizeof(ALsource));
2165 free(temp);
2167 Context->SourceCount = 0;