Modify some context checks
[openal-soft.git] / OpenAL32 / alSource.c
blobde85451cbba33081689255808460604009544ef4
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);
675 switch (eParam)
677 case AL_POSITION:
678 case AL_VELOCITY:
679 case AL_DIRECTION:
680 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
681 break;
683 case AL_AUXILIARY_SEND_FILTER:
684 if(lValue2 >= 0 && lValue2 < MAX_SENDS &&
685 (alIsAuxiliaryEffectSlot(lValue1) || lValue1 == 0) &&
686 alIsFilter(lValue3))
688 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
689 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
691 /* Release refcount on the previous slot, and add one for
692 * the new slot */
693 if(pSource->Send[lValue2].Slot)
694 pSource->Send[lValue2].Slot->refcount--;
695 pSource->Send[lValue2].Slot = ALEffectSlot;
696 if(pSource->Send[lValue2].Slot)
697 pSource->Send[lValue2].Slot->refcount++;
699 if(!ALFilter)
701 /* Disable filter */
702 pSource->Send[lValue2].WetFilter.type = 0;
703 pSource->Send[lValue2].WetFilter.filter = 0;
705 else
706 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
708 else
709 alSetError(AL_INVALID_VALUE);
710 break;
712 default:
713 alSetError(AL_INVALID_ENUM);
714 break;
717 else
718 alSetError(AL_INVALID_NAME);
720 ProcessContext(pContext);
724 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
726 ALCcontext *pContext;
728 pContext = GetContextSuspended();
729 if(!pContext) return;
731 if(plValues)
733 if(alIsSource(source))
735 switch(eParam)
737 case AL_SOURCE_RELATIVE:
738 case AL_CONE_INNER_ANGLE:
739 case AL_CONE_OUTER_ANGLE:
740 case AL_LOOPING:
741 case AL_BUFFER:
742 case AL_SOURCE_STATE:
743 case AL_SEC_OFFSET:
744 case AL_SAMPLE_OFFSET:
745 case AL_BYTE_OFFSET:
746 case AL_MAX_DISTANCE:
747 case AL_ROLLOFF_FACTOR:
748 case AL_REFERENCE_DISTANCE:
749 case AL_DIRECT_FILTER:
750 case AL_DIRECT_FILTER_GAINHF_AUTO:
751 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
752 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
753 case AL_DISTANCE_MODEL:
754 alSourcei(source, eParam, plValues[0]);
755 break;
757 case AL_POSITION:
758 case AL_VELOCITY:
759 case AL_DIRECTION:
760 case AL_AUXILIARY_SEND_FILTER:
761 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
762 break;
764 default:
765 alSetError(AL_INVALID_ENUM);
766 break;
769 else
770 alSetError(AL_INVALID_NAME);
772 else
773 alSetError(AL_INVALID_VALUE);
775 ProcessContext(pContext);
779 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
781 ALCcontext *pContext;
782 ALsource *pSource;
783 ALfloat flOffset[2];
785 pContext = GetContextSuspended();
786 if(!pContext) return;
788 if(pflValue)
790 if(alIsSource(source))
792 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
794 switch(eParam)
796 case AL_PITCH:
797 *pflValue = pSource->flPitch;
798 break;
800 case AL_GAIN:
801 *pflValue = pSource->flGain;
802 break;
804 case AL_MIN_GAIN:
805 *pflValue = pSource->flMinGain;
806 break;
808 case AL_MAX_GAIN:
809 *pflValue = pSource->flMaxGain;
810 break;
812 case AL_MAX_DISTANCE:
813 *pflValue = pSource->flMaxDistance;
814 break;
816 case AL_ROLLOFF_FACTOR:
817 *pflValue = pSource->flRollOffFactor;
818 break;
820 case AL_CONE_OUTER_GAIN:
821 *pflValue = pSource->flOuterGain;
822 break;
824 case AL_CONE_OUTER_GAINHF:
825 *pflValue = pSource->OuterGainHF;
826 break;
828 case AL_SEC_OFFSET:
829 case AL_SAMPLE_OFFSET:
830 case AL_BYTE_OFFSET:
831 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
832 *pflValue = flOffset[0];
833 else
834 alSetError(AL_INVALID_OPERATION);
835 break;
837 case AL_SEC_RW_OFFSETS_EXT:
838 case AL_SAMPLE_RW_OFFSETS_EXT:
839 case AL_BYTE_RW_OFFSETS_EXT:
840 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
842 pflValue[0] = flOffset[0];
843 pflValue[1] = flOffset[1];
845 else
846 alSetError(AL_INVALID_OPERATION);
847 break;
849 case AL_CONE_INNER_ANGLE:
850 *pflValue = pSource->flInnerAngle;
851 break;
853 case AL_CONE_OUTER_ANGLE:
854 *pflValue = pSource->flOuterAngle;
855 break;
857 case AL_REFERENCE_DISTANCE:
858 *pflValue = pSource->flRefDistance;
859 break;
861 case AL_AIR_ABSORPTION_FACTOR:
862 *pflValue = pSource->AirAbsorptionFactor;
863 break;
865 case AL_ROOM_ROLLOFF_FACTOR:
866 *pflValue = pSource->RoomRolloffFactor;
867 break;
869 case AL_DOPPLER_FACTOR:
870 *pflValue = pSource->DopplerFactor;
871 break;
873 default:
874 alSetError(AL_INVALID_ENUM);
875 break;
878 else
879 alSetError(AL_INVALID_NAME);
881 else
882 alSetError(AL_INVALID_VALUE);
884 ProcessContext(pContext);
888 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
890 ALCcontext *pContext;
891 ALsource *pSource;
893 pContext = GetContextSuspended();
894 if(!pContext) return;
896 if(pflValue1 && pflValue2 && pflValue3)
898 if(alIsSource(source))
900 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
902 switch(eParam)
904 case AL_POSITION:
905 *pflValue1 = pSource->vPosition[0];
906 *pflValue2 = pSource->vPosition[1];
907 *pflValue3 = pSource->vPosition[2];
908 break;
910 case AL_VELOCITY:
911 *pflValue1 = pSource->vVelocity[0];
912 *pflValue2 = pSource->vVelocity[1];
913 *pflValue3 = pSource->vVelocity[2];
914 break;
916 case AL_DIRECTION:
917 *pflValue1 = pSource->vOrientation[0];
918 *pflValue2 = pSource->vOrientation[1];
919 *pflValue3 = pSource->vOrientation[2];
920 break;
922 default:
923 alSetError(AL_INVALID_ENUM);
924 break;
927 else
928 alSetError(AL_INVALID_NAME);
930 else
931 alSetError(AL_INVALID_VALUE);
933 ProcessContext(pContext);
937 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
939 ALCcontext *pContext;
940 ALsource *pSource;
942 pContext = GetContextSuspended();
943 if(!pContext) return;
945 if(pflValues)
947 if(alIsSource(source))
949 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
951 switch(eParam)
953 case AL_PITCH:
954 case AL_GAIN:
955 case AL_MIN_GAIN:
956 case AL_MAX_GAIN:
957 case AL_MAX_DISTANCE:
958 case AL_ROLLOFF_FACTOR:
959 case AL_DOPPLER_FACTOR:
960 case AL_CONE_OUTER_GAIN:
961 case AL_SEC_OFFSET:
962 case AL_SAMPLE_OFFSET:
963 case AL_BYTE_OFFSET:
964 case AL_CONE_INNER_ANGLE:
965 case AL_CONE_OUTER_ANGLE:
966 case AL_REFERENCE_DISTANCE:
967 case AL_CONE_OUTER_GAINHF:
968 case AL_AIR_ABSORPTION_FACTOR:
969 case AL_ROOM_ROLLOFF_FACTOR:
970 alGetSourcef(source, eParam, pflValues);
971 break;
973 case AL_POSITION:
974 pflValues[0] = pSource->vPosition[0];
975 pflValues[1] = pSource->vPosition[1];
976 pflValues[2] = pSource->vPosition[2];
977 break;
979 case AL_VELOCITY:
980 pflValues[0] = pSource->vVelocity[0];
981 pflValues[1] = pSource->vVelocity[1];
982 pflValues[2] = pSource->vVelocity[2];
983 break;
985 case AL_DIRECTION:
986 pflValues[0] = pSource->vOrientation[0];
987 pflValues[1] = pSource->vOrientation[1];
988 pflValues[2] = 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 alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1008 ALCcontext *pContext;
1009 ALsource *pSource;
1010 ALfloat flOffset[2];
1012 pContext = GetContextSuspended();
1013 if(!pContext) return;
1015 if(plValue)
1017 if(alIsSource(source))
1019 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1021 switch(eParam)
1023 case AL_MAX_DISTANCE:
1024 *plValue = (ALint)pSource->flMaxDistance;
1025 break;
1027 case AL_ROLLOFF_FACTOR:
1028 *plValue = (ALint)pSource->flRollOffFactor;
1029 break;
1031 case AL_REFERENCE_DISTANCE:
1032 *plValue = (ALint)pSource->flRefDistance;
1033 break;
1035 case AL_SOURCE_RELATIVE:
1036 *plValue = pSource->bHeadRelative;
1037 break;
1039 case AL_CONE_INNER_ANGLE:
1040 *plValue = (ALint)pSource->flInnerAngle;
1041 break;
1043 case AL_CONE_OUTER_ANGLE:
1044 *plValue = (ALint)pSource->flOuterAngle;
1045 break;
1047 case AL_LOOPING:
1048 *plValue = pSource->bLooping;
1049 break;
1051 case AL_BUFFER:
1052 *plValue = pSource->ulBufferID;
1053 break;
1055 case AL_SOURCE_STATE:
1056 *plValue = pSource->state;
1057 break;
1059 case AL_BUFFERS_QUEUED:
1060 *plValue = pSource->BuffersInQueue;
1061 break;
1063 case AL_BUFFERS_PROCESSED:
1064 if(pSource->bLooping)
1066 /* Buffers on a looping source are in a perpetual state
1067 * of PENDING, so don't report any as PROCESSED */
1068 *plValue = 0;
1070 else
1071 *plValue = pSource->BuffersPlayed;
1072 break;
1074 case AL_SOURCE_TYPE:
1075 *plValue = pSource->lSourceType;
1076 break;
1078 case AL_SEC_OFFSET:
1079 case AL_SAMPLE_OFFSET:
1080 case AL_BYTE_OFFSET:
1081 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1082 *plValue = (ALint)flOffset[0];
1083 else
1084 alSetError(AL_INVALID_OPERATION);
1085 break;
1087 case AL_SEC_RW_OFFSETS_EXT:
1088 case AL_SAMPLE_RW_OFFSETS_EXT:
1089 case AL_BYTE_RW_OFFSETS_EXT:
1090 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1092 plValue[0] = (ALint)flOffset[0];
1093 plValue[1] = (ALint)flOffset[1];
1095 else
1096 alSetError(AL_INVALID_OPERATION);
1097 break;
1099 case AL_DIRECT_FILTER:
1100 *plValue = pSource->DirectFilter.filter;
1101 break;
1103 case AL_DIRECT_FILTER_GAINHF_AUTO:
1104 *plValue = pSource->DryGainHFAuto;
1105 break;
1107 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1108 *plValue = pSource->WetGainAuto;
1109 break;
1111 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1112 *plValue = pSource->WetGainHFAuto;
1113 break;
1115 case AL_DOPPLER_FACTOR:
1116 *plValue = (ALint)pSource->DopplerFactor;
1117 break;
1119 case AL_DISTANCE_MODEL:
1120 *plValue = pSource->DistanceModel;
1121 break;
1123 default:
1124 alSetError(AL_INVALID_ENUM);
1125 break;
1128 else
1129 alSetError(AL_INVALID_NAME);
1131 else
1132 alSetError(AL_INVALID_VALUE);
1134 ProcessContext(pContext);
1138 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1140 ALCcontext *pContext;
1141 ALsource *pSource;
1143 pContext = GetContextSuspended();
1144 if(!pContext) return;
1146 if(plValue1 && plValue2 && plValue3)
1148 if(alIsSource(source))
1150 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1152 switch(eParam)
1154 case AL_POSITION:
1155 *plValue1 = (ALint)pSource->vPosition[0];
1156 *plValue2 = (ALint)pSource->vPosition[1];
1157 *plValue3 = (ALint)pSource->vPosition[2];
1158 break;
1160 case AL_VELOCITY:
1161 *plValue1 = (ALint)pSource->vVelocity[0];
1162 *plValue2 = (ALint)pSource->vVelocity[1];
1163 *plValue3 = (ALint)pSource->vVelocity[2];
1164 break;
1166 case AL_DIRECTION:
1167 *plValue1 = (ALint)pSource->vOrientation[0];
1168 *plValue2 = (ALint)pSource->vOrientation[1];
1169 *plValue3 = (ALint)pSource->vOrientation[2];
1170 break;
1172 default:
1173 alSetError(AL_INVALID_ENUM);
1174 break;
1177 else
1178 alSetError(AL_INVALID_NAME);
1180 else
1181 alSetError(AL_INVALID_VALUE);
1183 ProcessContext(pContext);
1187 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1189 ALCcontext *pContext;
1190 ALsource *pSource;
1192 pContext = GetContextSuspended();
1193 if(!pContext) return;
1195 if(plValues)
1197 if(alIsSource(source))
1199 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1201 switch(eParam)
1203 case AL_SOURCE_RELATIVE:
1204 case AL_CONE_INNER_ANGLE:
1205 case AL_CONE_OUTER_ANGLE:
1206 case AL_LOOPING:
1207 case AL_BUFFER:
1208 case AL_SOURCE_STATE:
1209 case AL_BUFFERS_QUEUED:
1210 case AL_BUFFERS_PROCESSED:
1211 case AL_SEC_OFFSET:
1212 case AL_SAMPLE_OFFSET:
1213 case AL_BYTE_OFFSET:
1214 case AL_MAX_DISTANCE:
1215 case AL_ROLLOFF_FACTOR:
1216 case AL_DOPPLER_FACTOR:
1217 case AL_REFERENCE_DISTANCE:
1218 case AL_SOURCE_TYPE:
1219 case AL_DIRECT_FILTER:
1220 case AL_DIRECT_FILTER_GAINHF_AUTO:
1221 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1222 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1223 case AL_DISTANCE_MODEL:
1224 alGetSourcei(source, eParam, plValues);
1225 break;
1227 case AL_POSITION:
1228 plValues[0] = (ALint)pSource->vPosition[0];
1229 plValues[1] = (ALint)pSource->vPosition[1];
1230 plValues[2] = (ALint)pSource->vPosition[2];
1231 break;
1233 case AL_VELOCITY:
1234 plValues[0] = (ALint)pSource->vVelocity[0];
1235 plValues[1] = (ALint)pSource->vVelocity[1];
1236 plValues[2] = (ALint)pSource->vVelocity[2];
1237 break;
1239 case AL_DIRECTION:
1240 plValues[0] = (ALint)pSource->vOrientation[0];
1241 plValues[1] = (ALint)pSource->vOrientation[1];
1242 plValues[2] = (ALint)pSource->vOrientation[2];
1243 break;
1245 default:
1246 alSetError(AL_INVALID_ENUM);
1247 break;
1250 else
1251 alSetError(AL_INVALID_NAME);
1253 else
1254 alSetError(AL_INVALID_VALUE);
1256 ProcessContext(pContext);
1260 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1262 alSourcePlayv(1, &source);
1263 return;
1266 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1268 ALCcontext *pContext;
1269 ALsource *pSource;
1270 ALbufferlistitem *ALBufferList;
1271 ALboolean bSourcesValid = AL_TRUE;
1272 ALboolean bPlay;
1273 ALsizei i, j;
1275 pContext = GetContextSuspended();
1276 if(!pContext) return;
1278 if(pSourceList)
1280 // Check that all the Sources are valid
1281 for(i = 0; i < n; i++)
1283 if(!alIsSource(pSourceList[i]))
1285 alSetError(AL_INVALID_NAME);
1286 bSourcesValid = AL_FALSE;
1287 break;
1291 if(bSourcesValid)
1293 for(i = 0; i < n; i++)
1295 // Assume Source won't need to play
1296 bPlay = AL_FALSE;
1298 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]);
1300 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1301 ALBufferList = pSource->queue;
1302 while(ALBufferList)
1304 if(ALBufferList->buffer != 0 && ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size)
1306 bPlay = AL_TRUE;
1307 break;
1309 ALBufferList = ALBufferList->next;
1312 if (bPlay)
1314 for(j = 0;j < OUTPUTCHANNELS;j++)
1315 pSource->DryGains[j] = 0.0f;
1316 for(j = 0;j < MAX_SENDS;j++)
1317 pSource->WetGains[j] = 0.0f;
1319 if(pSource->state != AL_PAUSED)
1321 pSource->state = AL_PLAYING;
1322 pSource->inuse = AL_TRUE;
1323 pSource->play = AL_TRUE;
1324 pSource->position = 0;
1325 pSource->position_fraction = 0;
1326 pSource->BuffersPlayed = 0;
1327 pSource->FirstStart = AL_TRUE;
1329 pSource->ulBufferID = pSource->queue->buffer;
1331 // Make sure all the Buffers in the queue are marked as PENDING
1332 ALBufferList = pSource->queue;
1333 while(ALBufferList)
1335 ALBufferList->bufferstate = PENDING;
1336 ALBufferList = ALBufferList->next;
1339 else
1341 pSource->state = AL_PLAYING;
1342 pSource->inuse = AL_TRUE;
1343 pSource->play = AL_TRUE;
1344 pSource->FirstStart = AL_FALSE;
1347 // Check if an Offset has been set
1348 if(pSource->lOffset)
1349 ApplyOffset(pSource, AL_FALSE);
1351 else
1353 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1354 ALBufferList = pSource->queue;
1355 while(ALBufferList)
1357 ALBufferList->bufferstate = PROCESSED;
1358 ALBufferList = ALBufferList->next;
1361 pSource->BuffersPlayed = pSource->BuffersInQueue;
1366 else
1368 // sources is a NULL pointer
1369 alSetError(AL_INVALID_VALUE);
1372 ProcessContext(pContext);
1375 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1377 alSourcePausev(1, &source);
1378 return;
1381 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1383 ALCcontext *Context;
1384 ALsource *Source;
1385 ALsizei i;
1386 ALboolean bSourcesValid = AL_TRUE;
1388 Context = GetContextSuspended();
1389 if(!Context) return;
1391 if(sources)
1393 // Check all the Sources are valid
1394 for(i=0;i<n;i++)
1396 if(!alIsSource(sources[i]))
1398 alSetError(AL_INVALID_NAME);
1399 bSourcesValid = AL_FALSE;
1400 break;
1404 if(bSourcesValid)
1406 for(i = 0;i < n;i++)
1408 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1409 if(Source->state == AL_PLAYING)
1411 Source->state = AL_PAUSED;
1412 Source->inuse = AL_FALSE;
1417 else
1419 // sources is a NULL pointer
1420 alSetError(AL_INVALID_VALUE);
1423 ProcessContext(Context);
1426 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1428 alSourceStopv(1, &source);
1429 return;
1432 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1434 ALCcontext *Context;
1435 ALsource *Source;
1436 ALsizei i;
1437 ALbufferlistitem *ALBufferListItem;
1438 ALboolean bSourcesValid = AL_TRUE;
1440 Context = GetContextSuspended();
1441 if(!Context) return;
1443 if(sources)
1445 // Check all the Sources are valid
1446 for(i = 0;i < n;i++)
1448 if(!alIsSource(sources[i]))
1450 alSetError(AL_INVALID_NAME);
1451 bSourcesValid = AL_FALSE;
1452 break;
1456 if(bSourcesValid)
1458 for(i = 0;i < n;i++)
1460 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1461 if(Source->state != AL_INITIAL)
1463 Source->state = AL_STOPPED;
1464 Source->inuse = AL_FALSE;
1465 Source->BuffersPlayed = Source->BuffersInQueue;
1466 ALBufferListItem = Source->queue;
1467 while(ALBufferListItem != NULL)
1469 ALBufferListItem->bufferstate = PROCESSED;
1470 ALBufferListItem = ALBufferListItem->next;
1473 Source->lOffset = 0;
1477 else
1479 // sources is a NULL pointer
1480 alSetError(AL_INVALID_VALUE);
1483 ProcessContext(Context);
1486 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1488 alSourceRewindv(1, &source);
1489 return;
1492 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1494 ALCcontext *Context;
1495 ALsource *Source;
1496 ALsizei i;
1497 ALbufferlistitem *ALBufferListItem;
1498 ALboolean bSourcesValid = AL_TRUE;
1500 Context = GetContextSuspended();
1501 if(!Context) return;
1503 if(sources)
1505 // Check all the Sources are valid
1506 for(i = 0;i < n;i++)
1508 if(!alIsSource(sources[i]))
1510 alSetError(AL_INVALID_NAME);
1511 bSourcesValid = AL_FALSE;
1512 break;
1516 if(bSourcesValid)
1518 for(i = 0;i < n;i++)
1520 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1521 if(Source->state != AL_INITIAL)
1523 Source->state = AL_INITIAL;
1524 Source->inuse = AL_FALSE;
1525 Source->position = 0;
1526 Source->position_fraction = 0;
1527 Source->BuffersPlayed = 0;
1528 ALBufferListItem = Source->queue;
1529 while(ALBufferListItem != NULL)
1531 ALBufferListItem->bufferstate = PENDING;
1532 ALBufferListItem = ALBufferListItem->next;
1534 if(Source->queue)
1535 Source->ulBufferID = Source->queue->buffer;
1537 Source->lOffset = 0;
1541 else
1543 // sources is a NULL pointer
1544 alSetError(AL_INVALID_VALUE);
1547 ProcessContext(Context);
1551 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1553 ALCcontext *Context;
1554 ALsource *ALSource;
1555 ALsizei i;
1556 ALbufferlistitem *ALBufferList;
1557 ALbufferlistitem *ALBufferListStart;
1558 ALint iFrequency;
1559 ALint iFormat;
1560 ALboolean bBuffersValid = AL_TRUE;
1562 if (n == 0)
1563 return;
1565 Context = GetContextSuspended();
1566 if(!Context) return;
1568 // Check that all buffers are valid or zero and that the source is valid
1570 // Check that this is a valid source
1571 if(alIsSource(source))
1573 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1575 // Check that this is not a STATIC Source
1576 if(ALSource->lSourceType != AL_STATIC)
1578 iFrequency = -1;
1579 iFormat = -1;
1581 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1582 ALBufferList = ALSource->queue;
1583 while(ALBufferList)
1585 if (ALBufferList->buffer)
1587 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1588 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1589 break;
1591 ALBufferList = ALBufferList->next;
1594 for(i = 0; i < n; i++)
1596 if(alIsBuffer(buffers[i]))
1598 if(buffers[i])
1600 if((iFrequency == -1) && (iFormat == -1))
1602 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1603 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1605 else
1607 if((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1608 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1610 alSetError(AL_INVALID_OPERATION);
1611 bBuffersValid = AL_FALSE;
1612 break;
1617 else
1619 alSetError(AL_INVALID_NAME);
1620 bBuffersValid = AL_FALSE;
1621 break;
1625 if(bBuffersValid)
1627 // Change Source Type
1628 ALSource->lSourceType = AL_STREAMING;
1630 // All buffers are valid - so add them to the list
1631 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1632 ALBufferListStart->buffer = buffers[0];
1633 ALBufferListStart->bufferstate = PENDING;
1634 ALBufferListStart->flag = 0;
1635 ALBufferListStart->next = NULL;
1637 // Increment reference counter for buffer
1638 if(buffers[0])
1639 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1641 ALBufferList = ALBufferListStart;
1643 for(i = 1; i < n; i++)
1645 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1646 ALBufferList->next->buffer = buffers[i];
1647 ALBufferList->next->bufferstate = PENDING;
1648 ALBufferList->next->flag = 0;
1649 ALBufferList->next->next = NULL;
1651 // Increment reference counter for buffer
1652 if(buffers[i])
1653 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1655 ALBufferList = ALBufferList->next;
1658 if(ALSource->queue == NULL)
1660 ALSource->queue = ALBufferListStart;
1661 // Update Current Buffer
1662 ALSource->ulBufferID = ALBufferListStart->buffer;
1664 else
1666 // Find end of queue
1667 ALBufferList = ALSource->queue;
1668 while(ALBufferList->next != NULL)
1669 ALBufferList = ALBufferList->next;
1671 ALBufferList->next = ALBufferListStart;
1674 // Update number of buffers in queue
1675 ALSource->BuffersInQueue += n;
1678 else
1680 // Invalid Source Type (can't queue on a Static Source)
1681 alSetError(AL_INVALID_OPERATION);
1684 else
1686 // Invalid Source Name
1687 alSetError(AL_INVALID_NAME);
1690 ProcessContext(Context);
1694 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1695 // an array of buffer IDs that are to be filled with the names of the buffers removed
1696 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1698 ALCcontext *Context;
1699 ALsource *ALSource;
1700 ALsizei i;
1701 ALbufferlistitem *ALBufferList;
1702 ALuint BufferID;
1703 ALboolean bBuffersProcessed;
1705 if (n == 0)
1706 return;
1708 bBuffersProcessed = AL_TRUE;
1710 Context = GetContextSuspended();
1711 if(!Context) return;
1713 if(alIsSource(source))
1715 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1717 // Check that all 'n' buffers have been processed
1718 ALBufferList = ALSource->queue;
1719 for(i = 0; i < n; i++)
1721 if(ALBufferList != NULL && ALBufferList->bufferstate == PROCESSED)
1723 ALBufferList = ALBufferList->next;
1725 else
1727 bBuffersProcessed = AL_FALSE;
1728 break;
1732 // If all 'n' buffers have been processed, remove them from the queue
1733 if(bBuffersProcessed)
1735 for(i = 0; i < n; i++)
1737 ALBufferList = ALSource->queue;
1739 ALSource->queue = ALBufferList->next;
1740 // Record name of buffer
1741 buffers[i] = ALBufferList->buffer;
1742 // Decrement buffer reference counter
1743 if(ALBufferList->buffer)
1744 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1746 // Release memory for buffer list item
1747 free(ALBufferList);
1748 ALSource->BuffersInQueue--;
1751 if(ALSource->state != AL_PLAYING)
1753 if (ALSource->queue)
1754 BufferID = ALSource->queue->buffer;
1755 else
1756 BufferID = 0;
1758 ALSource->ulBufferID = BufferID;
1761 if((ALuint)n > ALSource->BuffersPlayed)
1762 ALSource->BuffersPlayed = 0;
1763 else
1764 ALSource->BuffersPlayed -= n;
1766 else
1768 // Some buffers can't be unqueue because they have not been processed
1769 alSetError(AL_INVALID_VALUE);
1772 else
1774 // Invalid Source Name
1775 alSetError(AL_INVALID_NAME);
1778 ProcessContext(Context);
1782 static ALvoid InitSourceParams(ALCcontext *Context, ALsource *pSource)
1784 pSource->flInnerAngle = 360.0f;
1785 pSource->flOuterAngle = 360.0f;
1786 pSource->flPitch = 1.0f;
1787 pSource->vPosition[0] = 0.0f;
1788 pSource->vPosition[1] = 0.0f;
1789 pSource->vPosition[2] = 0.0f;
1790 pSource->vOrientation[0] = 0.0f;
1791 pSource->vOrientation[1] = 0.0f;
1792 pSource->vOrientation[2] = 0.0f;
1793 pSource->vVelocity[0] = 0.0f;
1794 pSource->vVelocity[1] = 0.0f;
1795 pSource->vVelocity[2] = 0.0f;
1796 pSource->flRefDistance = 1.0f;
1797 pSource->flMaxDistance = FLT_MAX;
1798 pSource->flRollOffFactor = 1.0f;
1799 pSource->bLooping = AL_FALSE;
1800 pSource->flGain = 1.0f;
1801 pSource->flMinGain = 0.0f;
1802 pSource->flMaxGain = 1.0f;
1803 pSource->flOuterGain = 0.0f;
1804 pSource->OuterGainHF = 1.0f;
1806 pSource->DryGainHFAuto = AL_TRUE;
1807 pSource->WetGainAuto = AL_TRUE;
1808 pSource->WetGainHFAuto = AL_TRUE;
1809 pSource->AirAbsorptionFactor = 0.0f;
1810 pSource->RoomRolloffFactor = 0.0f;
1811 pSource->DopplerFactor = 1.0f;
1813 pSource->DistanceModel = Context->DistanceModel;
1815 pSource->state = AL_INITIAL;
1816 pSource->lSourceType = AL_UNDETERMINED;
1818 pSource->ulBufferID= 0;
1823 GetSourceOffset
1825 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1826 The offset is relative to the start of the queue (not the start of the current buffer)
1828 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize)
1830 ALbufferlistitem *pBufferList;
1831 ALbuffer *pBuffer;
1832 ALfloat flBufferFreq;
1833 ALint lChannels;
1834 ALint readPos, writePos;
1835 ALenum eOriginalFormat;
1836 ALboolean bReturn = AL_TRUE;
1837 ALint lTotalBufferDataSize;
1839 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
1841 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
1842 // Get Current Buffer Size and frequency (in milliseconds)
1843 flBufferFreq = (ALfloat)pBuffer->frequency;
1844 eOriginalFormat = pBuffer->eOriginalFormat;
1845 lChannels = aluChannelsFromFormat(pBuffer->format);
1847 // Get Current BytesPlayed
1848 readPos = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
1849 // Add byte length of any processed buffers in the queue
1850 pBufferList = pSource->queue;
1851 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
1853 readPos += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
1854 pBufferList = pBufferList->next;
1857 if(pSource->state == AL_PLAYING)
1858 writePos = readPos + (updateSize * lChannels * 2);
1859 else
1860 writePos = readPos;
1862 lTotalBufferDataSize = 0;
1863 pBufferList = pSource->queue;
1864 while (pBufferList)
1866 if (pBufferList->buffer)
1867 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
1868 pBufferList = pBufferList->next;
1871 if (pSource->bLooping)
1873 if(readPos < 0)
1874 readPos = 0;
1875 else
1876 readPos %= lTotalBufferDataSize;
1877 if(writePos < 0)
1878 writePos = 0;
1879 else
1880 writePos %= lTotalBufferDataSize;
1882 else
1884 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1885 if(readPos < 0)
1886 readPos = 0;
1887 else if(readPos > lTotalBufferDataSize)
1888 readPos = lTotalBufferDataSize;
1889 if(writePos < 0)
1890 writePos = 0;
1891 else if(writePos > lTotalBufferDataSize)
1892 writePos = lTotalBufferDataSize;
1895 switch (eName)
1897 case AL_SEC_OFFSET:
1898 case AL_SEC_RW_OFFSETS_EXT:
1899 pflOffset[0] = (ALfloat)readPos / (lChannels * 2.0f * flBufferFreq);
1900 pflOffset[1] = (ALfloat)writePos / (lChannels * 2.0f * flBufferFreq);
1901 break;
1902 case AL_SAMPLE_OFFSET:
1903 case AL_SAMPLE_RW_OFFSETS_EXT:
1904 pflOffset[0] = (ALfloat)(readPos / (lChannels * 2));
1905 pflOffset[1] = (ALfloat)(writePos / (lChannels * 2));
1906 break;
1907 case AL_BYTE_OFFSET:
1908 case AL_BYTE_RW_OFFSETS_EXT:
1909 // Take into account the original format of the Buffer
1910 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
1911 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1913 // Round down to nearest ADPCM block
1914 pflOffset[0] = (ALfloat)((readPos / (65 * 2 * lChannels)) * 36 * lChannels);
1915 if(pSource->state == AL_PLAYING)
1917 // Round up to nearest ADPCM block
1918 pflOffset[1] = (ALfloat)(((writePos + (65 * 2 * lChannels) - 1) / (65 * 2 * lChannels)) * 36 * lChannels);
1920 else
1921 pflOffset[1] = pflOffset[0];
1923 else if (eOriginalFormat == AL_FORMAT_REAR8)
1925 pflOffset[0] = (ALfloat)(readPos >> 2);
1926 pflOffset[1] = (ALfloat)(writePos >> 2);
1928 else if (eOriginalFormat == AL_FORMAT_REAR16)
1930 pflOffset[0] = (ALfloat)(readPos >> 1);
1931 pflOffset[1] = (ALfloat)(writePos >> 1);
1933 else if (aluBytesFromFormat(eOriginalFormat) == 1)
1935 pflOffset[0] = (ALfloat)(readPos >> 1);
1936 pflOffset[1] = (ALfloat)(writePos >> 1);
1938 else if (aluBytesFromFormat(eOriginalFormat) == 4)
1940 pflOffset[0] = (ALfloat)(readPos << 1);
1941 pflOffset[1] = (ALfloat)(writePos << 1);
1943 else
1945 pflOffset[0] = (ALfloat)readPos;
1946 pflOffset[1] = (ALfloat)writePos;
1948 break;
1951 else
1953 pflOffset[0] = 0.0f;
1954 pflOffset[1] = 0.0f;
1957 return bReturn;
1962 ApplyOffset
1964 Apply a playback offset to the Source. This function will update the queue (to correctly
1965 mark buffers as 'pending' or 'processed' depending upon the new offset.
1967 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
1969 ALbufferlistitem *pBufferList;
1970 ALbuffer *pBuffer;
1971 ALint lBufferSize, lTotalBufferSize;
1972 ALint lByteOffset;
1974 // Get true byte offset
1975 lByteOffset = GetByteOffset(pSource);
1977 // If this is a valid offset apply it
1978 if (lByteOffset != -1)
1980 // Sort out the queue (pending and processed states)
1981 pBufferList = pSource->queue;
1982 lTotalBufferSize = 0;
1983 pSource->BuffersPlayed = 0;
1984 while (pBufferList)
1986 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
1987 lBufferSize = pBuffer ? pBuffer->size : 0;
1989 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
1991 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
1992 // update the state to PROCESSED
1993 pSource->BuffersPlayed++;
1995 if (!pSource->bLooping)
1996 pBufferList->bufferstate = PROCESSED;
1998 else if (lTotalBufferSize <= lByteOffset)
2000 // Offset is within this buffer
2001 pBufferList->bufferstate = PENDING;
2003 // Set Current Buffer ID
2004 pSource->ulBufferID = pBufferList->buffer;
2006 // SW Mixer Positions are in Samples
2007 pSource->position = (lByteOffset - lTotalBufferSize) /
2008 aluBytesFromFormat(pBuffer->format) /
2009 aluChannelsFromFormat(pBuffer->format);
2011 else
2013 // Offset is before this buffer, so mark as pending
2014 pBufferList->bufferstate = PENDING;
2017 // Increment the TotalBufferSize
2018 lTotalBufferSize += lBufferSize;
2020 // Move on to next buffer in the Queue
2021 pBufferList = pBufferList->next;
2024 else
2026 if (bUpdateContext)
2027 alSetError(AL_INVALID_VALUE);
2030 // Clear Offset
2031 pSource->lOffset = 0;
2036 GetByteOffset
2038 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2039 offset supplied by the application). This takes into account the fact that the buffer format
2040 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2042 static ALint GetByteOffset(ALsource *pSource)
2044 ALbuffer *pBuffer = NULL;
2045 ALbufferlistitem *pBufferList;
2046 ALfloat flBufferFreq;
2047 ALint lChannels;
2048 ALint lByteOffset = -1;
2049 ALint lTotalBufferDataSize;
2051 // Find the first non-NULL Buffer in the Queue
2052 pBufferList = pSource->queue;
2053 while (pBufferList)
2055 if (pBufferList->buffer)
2057 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2058 break;
2060 pBufferList = pBufferList->next;
2063 if (pBuffer)
2065 flBufferFreq = ((ALfloat)pBuffer->frequency);
2066 lChannels = aluChannelsFromFormat(pBuffer->format);
2068 // Determine the ByteOffset (and ensure it is block aligned)
2069 switch (pSource->lOffsetType)
2071 case AL_BYTE_OFFSET:
2072 // Take into consideration the original format
2073 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2074 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2076 // Round down to nearest ADPCM block
2077 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2078 // Multiply by compression rate
2079 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2080 lByteOffset -= (lByteOffset % (lChannels * 2));
2082 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2084 lByteOffset = pSource->lOffset * 4;
2085 lByteOffset -= (lByteOffset % (lChannels * 2));
2087 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2089 lByteOffset = pSource->lOffset * 2;
2090 lByteOffset -= (lByteOffset % (lChannels * 2));
2092 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2094 lByteOffset = pSource->lOffset * 2;
2095 lByteOffset -= (lByteOffset % (lChannels * 2));
2097 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2099 lByteOffset = pSource->lOffset / 2;
2100 lByteOffset -= (lByteOffset % (lChannels * 2));
2102 else
2104 lByteOffset = pSource->lOffset;
2105 lByteOffset -= (lByteOffset % (lChannels * 2));
2107 break;
2109 case AL_SAMPLE_OFFSET:
2110 lByteOffset = pSource->lOffset * lChannels * 2;
2111 break;
2113 case AL_SEC_OFFSET:
2114 // Note - lOffset is internally stored as Milliseconds
2115 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2116 lByteOffset -= (lByteOffset % (lChannels * 2));
2117 break;
2120 lTotalBufferDataSize = 0;
2121 pBufferList = pSource->queue;
2122 while (pBufferList)
2124 if (pBufferList->buffer)
2125 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2126 pBufferList = pBufferList->next;
2129 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2130 if (lByteOffset >= lTotalBufferDataSize)
2131 lByteOffset = -1;
2134 return lByteOffset;
2138 ALvoid ReleaseALSources(ALCcontext *Context)
2140 #ifdef _DEBUG
2141 if(Context->SourceCount > 0)
2142 AL_PRINT("alcDestroyContext(): deleting %d Source(s)\n", Context->SourceCount);
2143 #endif
2145 while(Context->Source)
2147 ALsource *temp = Context->Source;
2148 Context->Source = Context->Source->next;
2150 // Release source structure
2151 ALTHUNK_REMOVEENTRY(temp->source);
2152 memset(temp, 0, sizeof(ALsource));
2153 free(temp);
2155 Context->SourceCount = 0;