ALCAPIENTRY is deprecated in favor of ALC_APIENTRY
[openal-soft.git] / OpenAL32 / alSource.c
blob2e7250815e926d80e0d447a15e94b3235181d2f8
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 != NULL)
146 ALBufferList->buffer->refcount--;
147 // Update queue to point to next element in list
148 ALSource->queue = ALBufferList->next;
149 // Release memory allocated for buffer list item
150 free(ALBufferList);
153 for(j = 0;j < MAX_SENDS;++j)
155 if(ALSource->Send[j].Slot)
156 ALSource->Send[j].Slot->refcount--;
157 ALSource->Send[j].Slot = NULL;
160 // Decrement Source count
161 Context->SourceCount--;
163 // Remove Source from list of Sources
164 list = &Context->Source;
165 while(*list && *list != ALSource)
166 list = &(*list)->next;
168 if(*list)
169 *list = (*list)->next;
170 ALTHUNK_REMOVEENTRY(ALSource->source);
172 memset(ALSource,0,sizeof(ALsource));
173 free(ALSource);
178 else
179 alSetError(AL_INVALID_VALUE);
181 ProcessContext(Context);
185 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
187 ALboolean result=AL_FALSE;
188 ALCcontext *Context;
189 ALsource *Source;
191 Context = GetContextSuspended();
192 if(!Context) return AL_FALSE;
194 // To determine if this is a valid Source name, look through the list of generated Sources
195 Source = Context->Source;
196 while(Source)
198 if(Source->source == source)
200 result = AL_TRUE;
201 break;
204 Source = Source->next;
207 ProcessContext(Context);
209 return result;
213 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
215 ALCcontext *pContext;
216 ALsource *pSource;
218 pContext = GetContextSuspended();
219 if(!pContext) return;
221 if(alIsSource(source))
223 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
225 switch(eParam)
227 case AL_PITCH:
228 if(flValue >= 0.0f)
230 pSource->flPitch = flValue;
231 if(pSource->flPitch < 0.001f)
232 pSource->flPitch = 0.001f;
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;
466 pContext = GetContextSuspended();
467 if(!pContext) return;
469 if(alIsSource(source))
471 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
473 switch(eParam)
475 case AL_MAX_DISTANCE:
476 case AL_ROLLOFF_FACTOR:
477 case AL_REFERENCE_DISTANCE:
478 alSourcef(source, eParam, (ALfloat)lValue);
479 break;
481 case AL_SOURCE_RELATIVE:
482 if(lValue == AL_FALSE || lValue == AL_TRUE)
483 pSource->bHeadRelative = (ALboolean)lValue;
484 else
485 alSetError(AL_INVALID_VALUE);
486 break;
488 case AL_CONE_INNER_ANGLE:
489 if(lValue >= 0 && lValue <= 360)
490 pSource->flInnerAngle = (float)lValue;
491 else
492 alSetError(AL_INVALID_VALUE);
493 break;
495 case AL_CONE_OUTER_ANGLE:
496 if(lValue >= 0 && lValue <= 360)
497 pSource->flOuterAngle = (float)lValue;
498 else
499 alSetError(AL_INVALID_VALUE);
500 break;
502 case AL_LOOPING:
503 if(lValue == AL_FALSE || lValue == AL_TRUE)
504 pSource->bLooping = (ALboolean)lValue;
505 else
506 alSetError(AL_INVALID_VALUE);
507 break;
509 case AL_BUFFER:
510 if(pSource->state == AL_STOPPED || pSource->state == AL_INITIAL)
512 if(alIsBuffer(lValue))
514 ALbuffer *buffer = NULL;
516 // Remove all elements in the queue
517 while(pSource->queue != NULL)
519 pALBufferListItem = pSource->queue;
520 pSource->queue = pALBufferListItem->next;
521 // Decrement reference counter for buffer
522 if(pALBufferListItem->buffer)
523 pALBufferListItem->buffer->refcount--;
524 // Release memory for buffer list item
525 free(pALBufferListItem);
526 // Decrement the number of buffers in the queue
527 pSource->BuffersInQueue--;
530 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
531 if(lValue != 0)
533 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue);
535 // Source is now in STATIC mode
536 pSource->lSourceType = AL_STATIC;
538 // Add the selected buffer to the queue
539 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
540 pALBufferListItem->buffer = buffer;
541 pALBufferListItem->next = NULL;
543 pSource->queue = pALBufferListItem;
544 pSource->BuffersInQueue = 1;
546 // Increment reference counter for buffer
547 buffer->refcount++;
549 else
551 // Source is now in UNDETERMINED mode
552 pSource->lSourceType = AL_UNDETERMINED;
553 pSource->BuffersPlayed = 0;
556 // Update AL_BUFFER parameter
557 pSource->Buffer = buffer;
559 else
560 alSetError(AL_INVALID_VALUE);
562 else
563 alSetError(AL_INVALID_OPERATION);
564 break;
566 case AL_SOURCE_STATE:
567 // Query only
568 alSetError(AL_INVALID_OPERATION);
569 break;
571 case AL_SEC_OFFSET:
572 case AL_SAMPLE_OFFSET:
573 case AL_BYTE_OFFSET:
574 if(lValue >= 0)
576 pSource->lOffsetType = eParam;
578 // Store Offset (convert Seconds into Milliseconds)
579 if(eParam == AL_SEC_OFFSET)
580 pSource->lOffset = lValue * 1000;
581 else
582 pSource->lOffset = lValue;
584 if(pSource->state == AL_PLAYING || pSource->state == AL_PAUSED)
585 ApplyOffset(pSource, AL_TRUE);
587 else
588 alSetError(AL_INVALID_VALUE);
589 break;
591 case AL_DIRECT_FILTER:
592 if(alIsFilter(lValue))
594 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
595 if(!filter)
597 pSource->DirectFilter.type = AL_FILTER_NULL;
598 pSource->DirectFilter.filter = 0;
600 else
601 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
603 else
604 alSetError(AL_INVALID_VALUE);
605 break;
607 case AL_DIRECT_FILTER_GAINHF_AUTO:
608 if(lValue == AL_TRUE || lValue == AL_FALSE)
609 pSource->DryGainHFAuto = lValue;
610 else
611 alSetError(AL_INVALID_VALUE);
612 break;
614 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
615 if(lValue == AL_TRUE || lValue == AL_FALSE)
616 pSource->WetGainAuto = lValue;
617 else
618 alSetError(AL_INVALID_VALUE);
619 break;
621 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
622 if(lValue == AL_TRUE || lValue == AL_FALSE)
623 pSource->WetGainHFAuto = lValue;
624 else
625 alSetError(AL_INVALID_VALUE);
626 break;
628 case AL_DISTANCE_MODEL:
629 if(lValue == AL_NONE ||
630 lValue == AL_INVERSE_DISTANCE ||
631 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
632 lValue == AL_LINEAR_DISTANCE ||
633 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
634 lValue == AL_EXPONENT_DISTANCE ||
635 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
636 pSource->DistanceModel = lValue;
637 else
638 alSetError(AL_INVALID_VALUE);
639 break;
641 default:
642 alSetError(AL_INVALID_ENUM);
643 break;
646 else
647 alSetError(AL_INVALID_NAME);
649 ProcessContext(pContext);
653 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
655 ALCcontext *pContext;
657 pContext = GetContextSuspended();
658 if(!pContext) return;
660 if(alIsSource(source))
662 ALsource *pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
663 ALCdevice *Device = pContext->Device;
665 switch (eParam)
667 case AL_POSITION:
668 case AL_VELOCITY:
669 case AL_DIRECTION:
670 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
671 break;
673 case AL_AUXILIARY_SEND_FILTER:
674 if((ALuint)lValue2 < Device->NumAuxSends &&
675 (lValue1 == 0 || alIsAuxiliaryEffectSlot(lValue1)) &&
676 alIsFilter(lValue3))
678 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
679 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
681 /* Release refcount on the previous slot, and add one for
682 * the new slot */
683 if(pSource->Send[lValue2].Slot)
684 pSource->Send[lValue2].Slot->refcount--;
685 pSource->Send[lValue2].Slot = ALEffectSlot;
686 if(pSource->Send[lValue2].Slot)
687 pSource->Send[lValue2].Slot->refcount++;
689 if(!ALFilter)
691 /* Disable filter */
692 pSource->Send[lValue2].WetFilter.type = 0;
693 pSource->Send[lValue2].WetFilter.filter = 0;
695 else
696 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
698 else
699 alSetError(AL_INVALID_VALUE);
700 break;
702 default:
703 alSetError(AL_INVALID_ENUM);
704 break;
707 else
708 alSetError(AL_INVALID_NAME);
710 ProcessContext(pContext);
714 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
716 ALCcontext *pContext;
718 pContext = GetContextSuspended();
719 if(!pContext) return;
721 if(plValues)
723 if(alIsSource(source))
725 switch(eParam)
727 case AL_SOURCE_RELATIVE:
728 case AL_CONE_INNER_ANGLE:
729 case AL_CONE_OUTER_ANGLE:
730 case AL_LOOPING:
731 case AL_BUFFER:
732 case AL_SOURCE_STATE:
733 case AL_SEC_OFFSET:
734 case AL_SAMPLE_OFFSET:
735 case AL_BYTE_OFFSET:
736 case AL_MAX_DISTANCE:
737 case AL_ROLLOFF_FACTOR:
738 case AL_REFERENCE_DISTANCE:
739 case AL_DIRECT_FILTER:
740 case AL_DIRECT_FILTER_GAINHF_AUTO:
741 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
742 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
743 case AL_DISTANCE_MODEL:
744 alSourcei(source, eParam, plValues[0]);
745 break;
747 case AL_POSITION:
748 case AL_VELOCITY:
749 case AL_DIRECTION:
750 case AL_AUXILIARY_SEND_FILTER:
751 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
752 break;
754 default:
755 alSetError(AL_INVALID_ENUM);
756 break;
759 else
760 alSetError(AL_INVALID_NAME);
762 else
763 alSetError(AL_INVALID_VALUE);
765 ProcessContext(pContext);
769 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
771 ALCcontext *pContext;
772 ALsource *pSource;
773 ALfloat flOffset[2];
775 pContext = GetContextSuspended();
776 if(!pContext) return;
778 if(pflValue)
780 if(alIsSource(source))
782 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
784 switch(eParam)
786 case AL_PITCH:
787 *pflValue = pSource->flPitch;
788 break;
790 case AL_GAIN:
791 *pflValue = pSource->flGain;
792 break;
794 case AL_MIN_GAIN:
795 *pflValue = pSource->flMinGain;
796 break;
798 case AL_MAX_GAIN:
799 *pflValue = pSource->flMaxGain;
800 break;
802 case AL_MAX_DISTANCE:
803 *pflValue = pSource->flMaxDistance;
804 break;
806 case AL_ROLLOFF_FACTOR:
807 *pflValue = pSource->flRollOffFactor;
808 break;
810 case AL_CONE_OUTER_GAIN:
811 *pflValue = pSource->flOuterGain;
812 break;
814 case AL_CONE_OUTER_GAINHF:
815 *pflValue = pSource->OuterGainHF;
816 break;
818 case AL_SEC_OFFSET:
819 case AL_SAMPLE_OFFSET:
820 case AL_BYTE_OFFSET:
821 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
822 *pflValue = flOffset[0];
823 else
824 alSetError(AL_INVALID_OPERATION);
825 break;
827 case AL_SEC_RW_OFFSETS_EXT:
828 case AL_SAMPLE_RW_OFFSETS_EXT:
829 case AL_BYTE_RW_OFFSETS_EXT:
830 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
832 pflValue[0] = flOffset[0];
833 pflValue[1] = flOffset[1];
835 else
836 alSetError(AL_INVALID_OPERATION);
837 break;
839 case AL_CONE_INNER_ANGLE:
840 *pflValue = pSource->flInnerAngle;
841 break;
843 case AL_CONE_OUTER_ANGLE:
844 *pflValue = pSource->flOuterAngle;
845 break;
847 case AL_REFERENCE_DISTANCE:
848 *pflValue = pSource->flRefDistance;
849 break;
851 case AL_AIR_ABSORPTION_FACTOR:
852 *pflValue = pSource->AirAbsorptionFactor;
853 break;
855 case AL_ROOM_ROLLOFF_FACTOR:
856 *pflValue = pSource->RoomRolloffFactor;
857 break;
859 case AL_DOPPLER_FACTOR:
860 *pflValue = pSource->DopplerFactor;
861 break;
863 default:
864 alSetError(AL_INVALID_ENUM);
865 break;
868 else
869 alSetError(AL_INVALID_NAME);
871 else
872 alSetError(AL_INVALID_VALUE);
874 ProcessContext(pContext);
878 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
880 ALCcontext *pContext;
881 ALsource *pSource;
883 pContext = GetContextSuspended();
884 if(!pContext) return;
886 if(pflValue1 && pflValue2 && pflValue3)
888 if(alIsSource(source))
890 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
892 switch(eParam)
894 case AL_POSITION:
895 *pflValue1 = pSource->vPosition[0];
896 *pflValue2 = pSource->vPosition[1];
897 *pflValue3 = pSource->vPosition[2];
898 break;
900 case AL_VELOCITY:
901 *pflValue1 = pSource->vVelocity[0];
902 *pflValue2 = pSource->vVelocity[1];
903 *pflValue3 = pSource->vVelocity[2];
904 break;
906 case AL_DIRECTION:
907 *pflValue1 = pSource->vOrientation[0];
908 *pflValue2 = pSource->vOrientation[1];
909 *pflValue3 = pSource->vOrientation[2];
910 break;
912 default:
913 alSetError(AL_INVALID_ENUM);
914 break;
917 else
918 alSetError(AL_INVALID_NAME);
920 else
921 alSetError(AL_INVALID_VALUE);
923 ProcessContext(pContext);
927 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
929 ALCcontext *pContext;
930 ALsource *pSource;
932 pContext = GetContextSuspended();
933 if(!pContext) return;
935 if(pflValues)
937 if(alIsSource(source))
939 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
941 switch(eParam)
943 case AL_PITCH:
944 case AL_GAIN:
945 case AL_MIN_GAIN:
946 case AL_MAX_GAIN:
947 case AL_MAX_DISTANCE:
948 case AL_ROLLOFF_FACTOR:
949 case AL_DOPPLER_FACTOR:
950 case AL_CONE_OUTER_GAIN:
951 case AL_SEC_OFFSET:
952 case AL_SAMPLE_OFFSET:
953 case AL_BYTE_OFFSET:
954 case AL_CONE_INNER_ANGLE:
955 case AL_CONE_OUTER_ANGLE:
956 case AL_REFERENCE_DISTANCE:
957 case AL_CONE_OUTER_GAINHF:
958 case AL_AIR_ABSORPTION_FACTOR:
959 case AL_ROOM_ROLLOFF_FACTOR:
960 alGetSourcef(source, eParam, pflValues);
961 break;
963 case AL_POSITION:
964 pflValues[0] = pSource->vPosition[0];
965 pflValues[1] = pSource->vPosition[1];
966 pflValues[2] = pSource->vPosition[2];
967 break;
969 case AL_VELOCITY:
970 pflValues[0] = pSource->vVelocity[0];
971 pflValues[1] = pSource->vVelocity[1];
972 pflValues[2] = pSource->vVelocity[2];
973 break;
975 case AL_DIRECTION:
976 pflValues[0] = pSource->vOrientation[0];
977 pflValues[1] = pSource->vOrientation[1];
978 pflValues[2] = pSource->vOrientation[2];
979 break;
981 default:
982 alSetError(AL_INVALID_ENUM);
983 break;
986 else
987 alSetError(AL_INVALID_NAME);
989 else
990 alSetError(AL_INVALID_VALUE);
992 ProcessContext(pContext);
996 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
998 ALCcontext *pContext;
999 ALsource *pSource;
1000 ALfloat flOffset[2];
1002 pContext = GetContextSuspended();
1003 if(!pContext) return;
1005 if(plValue)
1007 if(alIsSource(source))
1009 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1011 switch(eParam)
1013 case AL_MAX_DISTANCE:
1014 *plValue = (ALint)pSource->flMaxDistance;
1015 break;
1017 case AL_ROLLOFF_FACTOR:
1018 *plValue = (ALint)pSource->flRollOffFactor;
1019 break;
1021 case AL_REFERENCE_DISTANCE:
1022 *plValue = (ALint)pSource->flRefDistance;
1023 break;
1025 case AL_SOURCE_RELATIVE:
1026 *plValue = pSource->bHeadRelative;
1027 break;
1029 case AL_CONE_INNER_ANGLE:
1030 *plValue = (ALint)pSource->flInnerAngle;
1031 break;
1033 case AL_CONE_OUTER_ANGLE:
1034 *plValue = (ALint)pSource->flOuterAngle;
1035 break;
1037 case AL_LOOPING:
1038 *plValue = pSource->bLooping;
1039 break;
1041 case AL_BUFFER:
1042 *plValue = (pSource->Buffer ? pSource->Buffer->buffer : 0);
1043 break;
1045 case AL_SOURCE_STATE:
1046 *plValue = pSource->state;
1047 break;
1049 case AL_BUFFERS_QUEUED:
1050 *plValue = pSource->BuffersInQueue;
1051 break;
1053 case AL_BUFFERS_PROCESSED:
1054 if(pSource->bLooping)
1056 /* Buffers on a looping source are in a perpetual state
1057 * of PENDING, so don't report any as PROCESSED */
1058 *plValue = 0;
1060 else
1061 *plValue = pSource->BuffersPlayed;
1062 break;
1064 case AL_SOURCE_TYPE:
1065 *plValue = pSource->lSourceType;
1066 break;
1068 case AL_SEC_OFFSET:
1069 case AL_SAMPLE_OFFSET:
1070 case AL_BYTE_OFFSET:
1071 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1072 *plValue = (ALint)flOffset[0];
1073 else
1074 alSetError(AL_INVALID_OPERATION);
1075 break;
1077 case AL_SEC_RW_OFFSETS_EXT:
1078 case AL_SAMPLE_RW_OFFSETS_EXT:
1079 case AL_BYTE_RW_OFFSETS_EXT:
1080 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1082 plValue[0] = (ALint)flOffset[0];
1083 plValue[1] = (ALint)flOffset[1];
1085 else
1086 alSetError(AL_INVALID_OPERATION);
1087 break;
1089 case AL_DIRECT_FILTER:
1090 *plValue = pSource->DirectFilter.filter;
1091 break;
1093 case AL_DIRECT_FILTER_GAINHF_AUTO:
1094 *plValue = pSource->DryGainHFAuto;
1095 break;
1097 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1098 *plValue = pSource->WetGainAuto;
1099 break;
1101 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1102 *plValue = pSource->WetGainHFAuto;
1103 break;
1105 case AL_DOPPLER_FACTOR:
1106 *plValue = (ALint)pSource->DopplerFactor;
1107 break;
1109 case AL_DISTANCE_MODEL:
1110 *plValue = pSource->DistanceModel;
1111 break;
1113 default:
1114 alSetError(AL_INVALID_ENUM);
1115 break;
1118 else
1119 alSetError(AL_INVALID_NAME);
1121 else
1122 alSetError(AL_INVALID_VALUE);
1124 ProcessContext(pContext);
1128 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1130 ALCcontext *pContext;
1131 ALsource *pSource;
1133 pContext = GetContextSuspended();
1134 if(!pContext) return;
1136 if(plValue1 && plValue2 && plValue3)
1138 if(alIsSource(source))
1140 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1142 switch(eParam)
1144 case AL_POSITION:
1145 *plValue1 = (ALint)pSource->vPosition[0];
1146 *plValue2 = (ALint)pSource->vPosition[1];
1147 *plValue3 = (ALint)pSource->vPosition[2];
1148 break;
1150 case AL_VELOCITY:
1151 *plValue1 = (ALint)pSource->vVelocity[0];
1152 *plValue2 = (ALint)pSource->vVelocity[1];
1153 *plValue3 = (ALint)pSource->vVelocity[2];
1154 break;
1156 case AL_DIRECTION:
1157 *plValue1 = (ALint)pSource->vOrientation[0];
1158 *plValue2 = (ALint)pSource->vOrientation[1];
1159 *plValue3 = (ALint)pSource->vOrientation[2];
1160 break;
1162 default:
1163 alSetError(AL_INVALID_ENUM);
1164 break;
1167 else
1168 alSetError(AL_INVALID_NAME);
1170 else
1171 alSetError(AL_INVALID_VALUE);
1173 ProcessContext(pContext);
1177 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1179 ALCcontext *pContext;
1180 ALsource *pSource;
1182 pContext = GetContextSuspended();
1183 if(!pContext) return;
1185 if(plValues)
1187 if(alIsSource(source))
1189 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1191 switch(eParam)
1193 case AL_SOURCE_RELATIVE:
1194 case AL_CONE_INNER_ANGLE:
1195 case AL_CONE_OUTER_ANGLE:
1196 case AL_LOOPING:
1197 case AL_BUFFER:
1198 case AL_SOURCE_STATE:
1199 case AL_BUFFERS_QUEUED:
1200 case AL_BUFFERS_PROCESSED:
1201 case AL_SEC_OFFSET:
1202 case AL_SAMPLE_OFFSET:
1203 case AL_BYTE_OFFSET:
1204 case AL_MAX_DISTANCE:
1205 case AL_ROLLOFF_FACTOR:
1206 case AL_DOPPLER_FACTOR:
1207 case AL_REFERENCE_DISTANCE:
1208 case AL_SOURCE_TYPE:
1209 case AL_DIRECT_FILTER:
1210 case AL_DIRECT_FILTER_GAINHF_AUTO:
1211 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1212 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1213 case AL_DISTANCE_MODEL:
1214 alGetSourcei(source, eParam, plValues);
1215 break;
1217 case AL_POSITION:
1218 plValues[0] = (ALint)pSource->vPosition[0];
1219 plValues[1] = (ALint)pSource->vPosition[1];
1220 plValues[2] = (ALint)pSource->vPosition[2];
1221 break;
1223 case AL_VELOCITY:
1224 plValues[0] = (ALint)pSource->vVelocity[0];
1225 plValues[1] = (ALint)pSource->vVelocity[1];
1226 plValues[2] = (ALint)pSource->vVelocity[2];
1227 break;
1229 case AL_DIRECTION:
1230 plValues[0] = (ALint)pSource->vOrientation[0];
1231 plValues[1] = (ALint)pSource->vOrientation[1];
1232 plValues[2] = (ALint)pSource->vOrientation[2];
1233 break;
1235 default:
1236 alSetError(AL_INVALID_ENUM);
1237 break;
1240 else
1241 alSetError(AL_INVALID_NAME);
1243 else
1244 alSetError(AL_INVALID_VALUE);
1246 ProcessContext(pContext);
1250 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1252 alSourcePlayv(1, &source);
1253 return;
1256 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1258 ALCcontext *pContext;
1259 ALsource *pSource;
1260 ALbufferlistitem *ALBufferList;
1261 ALboolean bSourcesValid = AL_TRUE;
1262 ALboolean bPlay;
1263 ALsizei i, j;
1265 pContext = GetContextSuspended();
1266 if(!pContext) return;
1268 if(pSourceList)
1270 // Check that all the Sources are valid
1271 for(i = 0; i < n; i++)
1273 if(!alIsSource(pSourceList[i]))
1275 alSetError(AL_INVALID_NAME);
1276 bSourcesValid = AL_FALSE;
1277 break;
1281 if(bSourcesValid)
1283 for(i = 0; i < n; i++)
1285 // Assume Source won't need to play
1286 bPlay = AL_FALSE;
1288 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]);
1290 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1291 ALBufferList = pSource->queue;
1292 while(ALBufferList)
1294 if(ALBufferList->buffer != NULL && ALBufferList->buffer->size)
1296 bPlay = AL_TRUE;
1297 break;
1299 ALBufferList = ALBufferList->next;
1302 if (bPlay)
1304 for(j = 0;j < OUTPUTCHANNELS;j++)
1305 pSource->DryGains[j] = 0.0f;
1306 for(j = 0;j < MAX_SENDS;j++)
1307 pSource->WetGains[j] = 0.0f;
1309 if(pSource->state != AL_PAUSED)
1311 pSource->state = AL_PLAYING;
1312 pSource->position = 0;
1313 pSource->position_fraction = 0;
1314 pSource->BuffersPlayed = 0;
1316 pSource->Buffer = pSource->queue->buffer;
1318 else
1319 pSource->state = AL_PLAYING;
1321 // Check if an Offset has been set
1322 if(pSource->lOffset)
1323 ApplyOffset(pSource, AL_FALSE);
1325 if(pSource->BuffersPlayed == 0 && pSource->position == 0 &&
1326 pSource->position_fraction == 0)
1327 pSource->FirstStart = AL_TRUE;
1328 else
1329 pSource->FirstStart = AL_FALSE;
1331 // If device is disconnected, go right to stopped
1332 if(!pContext->Device->Connected)
1334 pSource->state = AL_STOPPED;
1335 pSource->BuffersPlayed = pSource->BuffersInQueue;
1336 pSource->position = 0;
1337 pSource->position_fraction = 0;
1340 else
1341 pSource->BuffersPlayed = pSource->BuffersInQueue;
1345 else
1347 // sources is a NULL pointer
1348 alSetError(AL_INVALID_VALUE);
1351 ProcessContext(pContext);
1354 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1356 alSourcePausev(1, &source);
1357 return;
1360 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1362 ALCcontext *Context;
1363 ALsource *Source;
1364 ALsizei i;
1365 ALboolean bSourcesValid = AL_TRUE;
1367 Context = GetContextSuspended();
1368 if(!Context) return;
1370 if(sources)
1372 // Check all the Sources are valid
1373 for(i=0;i<n;i++)
1375 if(!alIsSource(sources[i]))
1377 alSetError(AL_INVALID_NAME);
1378 bSourcesValid = AL_FALSE;
1379 break;
1383 if(bSourcesValid)
1385 for(i = 0;i < n;i++)
1387 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1388 if(Source->state == AL_PLAYING)
1389 Source->state = AL_PAUSED;
1393 else
1395 // sources is a NULL pointer
1396 alSetError(AL_INVALID_VALUE);
1399 ProcessContext(Context);
1402 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1404 alSourceStopv(1, &source);
1405 return;
1408 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1410 ALCcontext *Context;
1411 ALsource *Source;
1412 ALsizei i;
1413 ALboolean bSourcesValid = AL_TRUE;
1415 Context = GetContextSuspended();
1416 if(!Context) return;
1418 if(sources)
1420 // Check all the Sources are valid
1421 for(i = 0;i < n;i++)
1423 if(!alIsSource(sources[i]))
1425 alSetError(AL_INVALID_NAME);
1426 bSourcesValid = AL_FALSE;
1427 break;
1431 if(bSourcesValid)
1433 for(i = 0;i < n;i++)
1435 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1436 if(Source->state != AL_INITIAL)
1438 Source->state = AL_STOPPED;
1439 Source->BuffersPlayed = Source->BuffersInQueue;
1441 Source->lOffset = 0;
1445 else
1447 // sources is a NULL pointer
1448 alSetError(AL_INVALID_VALUE);
1451 ProcessContext(Context);
1454 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1456 alSourceRewindv(1, &source);
1457 return;
1460 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1462 ALCcontext *Context;
1463 ALsource *Source;
1464 ALsizei i;
1465 ALboolean bSourcesValid = AL_TRUE;
1467 Context = GetContextSuspended();
1468 if(!Context) return;
1470 if(sources)
1472 // Check all the Sources are valid
1473 for(i = 0;i < n;i++)
1475 if(!alIsSource(sources[i]))
1477 alSetError(AL_INVALID_NAME);
1478 bSourcesValid = AL_FALSE;
1479 break;
1483 if(bSourcesValid)
1485 for(i = 0;i < n;i++)
1487 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1488 if(Source->state != AL_INITIAL)
1490 Source->state = AL_INITIAL;
1491 Source->position = 0;
1492 Source->position_fraction = 0;
1493 Source->BuffersPlayed = 0;
1494 if(Source->queue)
1495 Source->Buffer = Source->queue->buffer;
1497 Source->lOffset = 0;
1501 else
1503 // sources is a NULL pointer
1504 alSetError(AL_INVALID_VALUE);
1507 ProcessContext(Context);
1511 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1513 ALCcontext *Context;
1514 ALsource *ALSource;
1515 ALsizei i;
1516 ALbufferlistitem *ALBufferList;
1517 ALbufferlistitem *ALBufferListStart;
1518 ALint iFrequency;
1519 ALint iFormat;
1520 ALboolean bBuffersValid = AL_TRUE;
1522 if (n == 0)
1523 return;
1525 Context = GetContextSuspended();
1526 if(!Context) return;
1528 // Check that all buffers are valid or zero and that the source is valid
1530 // Check that this is a valid source
1531 if(alIsSource(source))
1533 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1535 // Check that this is not a STATIC Source
1536 if(ALSource->lSourceType != AL_STATIC)
1538 iFrequency = -1;
1539 iFormat = -1;
1541 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1542 ALBufferList = ALSource->queue;
1543 while(ALBufferList)
1545 if (ALBufferList->buffer)
1547 iFrequency = ALBufferList->buffer->frequency;
1548 iFormat = ALBufferList->buffer->format;
1549 break;
1551 ALBufferList = ALBufferList->next;
1554 for(i = 0; i < n; i++)
1556 ALbuffer *buffer;
1558 if(!alIsBuffer(buffers[i]))
1560 alSetError(AL_INVALID_NAME);
1561 bBuffersValid = AL_FALSE;
1562 break;
1564 if(!buffers[i])
1565 continue;
1567 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1568 if(iFrequency == -1 && iFormat == -1)
1570 iFrequency = buffer->frequency;
1571 iFormat = buffer->format;
1573 else if(iFrequency != buffer->frequency ||
1574 iFormat != buffer->format)
1576 alSetError(AL_INVALID_OPERATION);
1577 bBuffersValid = AL_FALSE;
1578 break;
1582 if(bBuffersValid)
1584 ALbuffer *buffer = NULL;
1586 // Change Source Type
1587 ALSource->lSourceType = AL_STREAMING;
1589 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1591 // All buffers are valid - so add them to the list
1592 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1593 ALBufferListStart->buffer = buffer;
1594 ALBufferListStart->next = NULL;
1596 // Increment reference counter for buffer
1597 if(buffer) buffer->refcount++;
1599 ALBufferList = ALBufferListStart;
1601 for(i = 1; i < n; i++)
1603 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1605 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1606 ALBufferList->next->buffer = buffer;
1607 ALBufferList->next->next = NULL;
1609 // Increment reference counter for buffer
1610 if(buffer) buffer->refcount++;
1612 ALBufferList = ALBufferList->next;
1615 if(ALSource->queue == NULL)
1617 ALSource->queue = ALBufferListStart;
1618 // Update Current Buffer
1619 ALSource->Buffer = ALBufferListStart->buffer;
1621 else
1623 // Find end of queue
1624 ALBufferList = ALSource->queue;
1625 while(ALBufferList->next != NULL)
1626 ALBufferList = ALBufferList->next;
1628 ALBufferList->next = ALBufferListStart;
1631 // Update number of buffers in queue
1632 ALSource->BuffersInQueue += n;
1635 else
1637 // Invalid Source Type (can't queue on a Static Source)
1638 alSetError(AL_INVALID_OPERATION);
1641 else
1643 // Invalid Source Name
1644 alSetError(AL_INVALID_NAME);
1647 ProcessContext(Context);
1651 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1652 // an array of buffer IDs that are to be filled with the names of the buffers removed
1653 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1655 ALCcontext *Context;
1656 ALsource *ALSource;
1657 ALsizei i;
1658 ALbufferlistitem *ALBufferList;
1659 ALboolean bBuffersProcessed;
1661 if (n == 0)
1662 return;
1664 bBuffersProcessed = AL_TRUE;
1666 Context = GetContextSuspended();
1667 if(!Context) return;
1669 if(alIsSource(source))
1671 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1673 // If all 'n' buffers have been processed, remove them from the queue
1674 if(!ALSource->bLooping && (ALuint)n <= ALSource->BuffersPlayed)
1676 for(i = 0; i < n; i++)
1678 ALBufferList = ALSource->queue;
1680 ALSource->queue = ALBufferList->next;
1681 // Record name of buffer
1682 buffers[i] = ALBufferList->buffer->buffer;
1683 // Decrement buffer reference counter
1684 if(ALBufferList->buffer)
1685 ALBufferList->buffer->refcount--;
1687 // Release memory for buffer list item
1688 free(ALBufferList);
1689 ALSource->BuffersInQueue--;
1692 if(ALSource->state != AL_PLAYING)
1694 if(ALSource->queue)
1695 ALSource->Buffer = ALSource->queue->buffer;
1696 else
1697 ALSource->Buffer = NULL;
1700 ALSource->BuffersPlayed -= n;
1702 else
1704 // Some buffers can't be unqueue because they have not been processed
1705 alSetError(AL_INVALID_VALUE);
1708 else
1710 // Invalid Source Name
1711 alSetError(AL_INVALID_NAME);
1714 ProcessContext(Context);
1718 static ALvoid InitSourceParams(ALCcontext *Context, ALsource *pSource)
1720 pSource->flInnerAngle = 360.0f;
1721 pSource->flOuterAngle = 360.0f;
1722 pSource->flPitch = 1.0f;
1723 pSource->vPosition[0] = 0.0f;
1724 pSource->vPosition[1] = 0.0f;
1725 pSource->vPosition[2] = 0.0f;
1726 pSource->vOrientation[0] = 0.0f;
1727 pSource->vOrientation[1] = 0.0f;
1728 pSource->vOrientation[2] = 0.0f;
1729 pSource->vVelocity[0] = 0.0f;
1730 pSource->vVelocity[1] = 0.0f;
1731 pSource->vVelocity[2] = 0.0f;
1732 pSource->flRefDistance = 1.0f;
1733 pSource->flMaxDistance = FLT_MAX;
1734 pSource->flRollOffFactor = 1.0f;
1735 pSource->bLooping = AL_FALSE;
1736 pSource->flGain = 1.0f;
1737 pSource->flMinGain = 0.0f;
1738 pSource->flMaxGain = 1.0f;
1739 pSource->flOuterGain = 0.0f;
1740 pSource->OuterGainHF = 1.0f;
1742 pSource->DryGainHFAuto = AL_TRUE;
1743 pSource->WetGainAuto = AL_TRUE;
1744 pSource->WetGainHFAuto = AL_TRUE;
1745 pSource->AirAbsorptionFactor = 0.0f;
1746 pSource->RoomRolloffFactor = 0.0f;
1747 pSource->DopplerFactor = 1.0f;
1749 pSource->DistanceModel = Context->DistanceModel;
1751 pSource->state = AL_INITIAL;
1752 pSource->lSourceType = AL_UNDETERMINED;
1754 pSource->Buffer = NULL;
1759 GetSourceOffset
1761 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1762 The offset is relative to the start of the queue (not the start of the current buffer)
1764 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize)
1766 ALbufferlistitem *pBufferList;
1767 ALbuffer *pBuffer;
1768 ALfloat flBufferFreq;
1769 ALint lChannels;
1770 ALint readPos, writePos;
1771 ALenum eOriginalFormat;
1772 ALboolean bReturn = AL_TRUE;
1773 ALint lTotalBufferDataSize;
1774 ALuint i;
1776 if((pSource->state == AL_PLAYING || pSource->state == AL_PAUSED) && pSource->Buffer)
1778 pBuffer = pSource->Buffer;
1779 // Get Current Buffer Size and frequency (in milliseconds)
1780 flBufferFreq = (ALfloat)pBuffer->frequency;
1781 eOriginalFormat = pBuffer->eOriginalFormat;
1782 lChannels = aluChannelsFromFormat(pBuffer->format);
1784 // Get Current BytesPlayed
1785 readPos = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
1786 // Add byte length of any processed buffers in the queue
1787 pBufferList = pSource->queue;
1788 for(i = 0;i < pSource->BuffersPlayed && pBufferList;i++)
1790 readPos += pBufferList->buffer->size;
1791 pBufferList = pBufferList->next;
1794 if(pSource->state == AL_PLAYING)
1795 writePos = readPos + (updateSize * lChannels * 2);
1796 else
1797 writePos = readPos;
1799 lTotalBufferDataSize = 0;
1800 pBufferList = pSource->queue;
1801 while (pBufferList)
1803 if (pBufferList->buffer)
1804 lTotalBufferDataSize += pBufferList->buffer->size;
1805 pBufferList = pBufferList->next;
1808 if (pSource->bLooping)
1810 if(readPos < 0)
1811 readPos = 0;
1812 else
1813 readPos %= lTotalBufferDataSize;
1814 if(writePos < 0)
1815 writePos = 0;
1816 else
1817 writePos %= lTotalBufferDataSize;
1819 else
1821 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1822 if(readPos < 0)
1823 readPos = 0;
1824 else if(readPos > lTotalBufferDataSize)
1825 readPos = lTotalBufferDataSize;
1826 if(writePos < 0)
1827 writePos = 0;
1828 else if(writePos > lTotalBufferDataSize)
1829 writePos = lTotalBufferDataSize;
1832 switch (eName)
1834 case AL_SEC_OFFSET:
1835 case AL_SEC_RW_OFFSETS_EXT:
1836 pflOffset[0] = (ALfloat)readPos / (lChannels * 2.0f * flBufferFreq);
1837 pflOffset[1] = (ALfloat)writePos / (lChannels * 2.0f * flBufferFreq);
1838 break;
1839 case AL_SAMPLE_OFFSET:
1840 case AL_SAMPLE_RW_OFFSETS_EXT:
1841 pflOffset[0] = (ALfloat)(readPos / (lChannels * 2));
1842 pflOffset[1] = (ALfloat)(writePos / (lChannels * 2));
1843 break;
1844 case AL_BYTE_OFFSET:
1845 case AL_BYTE_RW_OFFSETS_EXT:
1846 // Take into account the original format of the Buffer
1847 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
1848 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1850 // Round down to nearest ADPCM block
1851 pflOffset[0] = (ALfloat)((readPos / (65 * 2 * lChannels)) * 36 * lChannels);
1852 if(pSource->state == AL_PLAYING)
1854 // Round up to nearest ADPCM block
1855 pflOffset[1] = (ALfloat)(((writePos + (65 * 2 * lChannels) - 1) / (65 * 2 * lChannels)) * 36 * lChannels);
1857 else
1858 pflOffset[1] = pflOffset[0];
1860 else if (eOriginalFormat == AL_FORMAT_REAR8)
1862 pflOffset[0] = (ALfloat)(readPos >> 2);
1863 pflOffset[1] = (ALfloat)(writePos >> 2);
1865 else if (eOriginalFormat == AL_FORMAT_REAR16)
1867 pflOffset[0] = (ALfloat)(readPos >> 1);
1868 pflOffset[1] = (ALfloat)(writePos >> 1);
1870 else if (aluBytesFromFormat(eOriginalFormat) == 1)
1872 pflOffset[0] = (ALfloat)(readPos >> 1);
1873 pflOffset[1] = (ALfloat)(writePos >> 1);
1875 else if (aluBytesFromFormat(eOriginalFormat) == 4)
1877 pflOffset[0] = (ALfloat)(readPos << 1);
1878 pflOffset[1] = (ALfloat)(writePos << 1);
1880 else
1882 pflOffset[0] = (ALfloat)readPos;
1883 pflOffset[1] = (ALfloat)writePos;
1885 break;
1888 else
1890 pflOffset[0] = 0.0f;
1891 pflOffset[1] = 0.0f;
1894 return bReturn;
1899 ApplyOffset
1901 Apply a playback offset to the Source. This function will update the queue (to correctly
1902 mark buffers as 'pending' or 'processed' depending upon the new offset.
1904 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
1906 ALbufferlistitem *pBufferList;
1907 ALbuffer *pBuffer;
1908 ALint lBufferSize, lTotalBufferSize;
1909 ALint lByteOffset;
1911 // Get true byte offset
1912 lByteOffset = GetByteOffset(pSource);
1914 // If this is a valid offset apply it
1915 if (lByteOffset != -1)
1917 // Sort out the queue (pending and processed states)
1918 pBufferList = pSource->queue;
1919 lTotalBufferSize = 0;
1920 pSource->BuffersPlayed = 0;
1921 while (pBufferList)
1923 pBuffer = pBufferList->buffer;
1924 lBufferSize = pBuffer ? pBuffer->size : 0;
1926 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
1928 // Offset is past this buffer so increment BuffersPlayed
1929 pSource->BuffersPlayed++;
1931 else if (lTotalBufferSize <= lByteOffset)
1933 // Offset is within this buffer
1934 // Set Current Buffer
1935 pSource->Buffer = pBufferList->buffer;
1937 // SW Mixer Positions are in Samples
1938 pSource->position = (lByteOffset - lTotalBufferSize) /
1939 aluBytesFromFormat(pBuffer->format) /
1940 aluChannelsFromFormat(pBuffer->format);
1943 // Increment the TotalBufferSize
1944 lTotalBufferSize += lBufferSize;
1946 // Move on to next buffer in the Queue
1947 pBufferList = pBufferList->next;
1950 else
1952 if (bUpdateContext)
1953 alSetError(AL_INVALID_VALUE);
1956 // Clear Offset
1957 pSource->lOffset = 0;
1962 GetByteOffset
1964 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1965 offset supplied by the application). This takes into account the fact that the buffer format
1966 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
1968 static ALint GetByteOffset(ALsource *pSource)
1970 ALbuffer *pBuffer = NULL;
1971 ALbufferlistitem *pBufferList;
1972 ALfloat flBufferFreq;
1973 ALint lChannels;
1974 ALint lByteOffset = -1;
1975 ALint lTotalBufferDataSize;
1977 // Find the first non-NULL Buffer in the Queue
1978 pBufferList = pSource->queue;
1979 while (pBufferList)
1981 if (pBufferList->buffer)
1983 pBuffer = pBufferList->buffer;
1984 break;
1986 pBufferList = pBufferList->next;
1989 if (pBuffer)
1991 flBufferFreq = ((ALfloat)pBuffer->frequency);
1992 lChannels = aluChannelsFromFormat(pBuffer->format);
1994 // Determine the ByteOffset (and ensure it is block aligned)
1995 switch (pSource->lOffsetType)
1997 case AL_BYTE_OFFSET:
1998 // Take into consideration the original format
1999 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2000 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2002 // Round down to nearest ADPCM block
2003 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2004 // Multiply by compression rate
2005 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2006 lByteOffset -= (lByteOffset % (lChannels * 2));
2008 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2010 lByteOffset = pSource->lOffset * 4;
2011 lByteOffset -= (lByteOffset % (lChannels * 2));
2013 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2015 lByteOffset = pSource->lOffset * 2;
2016 lByteOffset -= (lByteOffset % (lChannels * 2));
2018 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2020 lByteOffset = pSource->lOffset * 2;
2021 lByteOffset -= (lByteOffset % (lChannels * 2));
2023 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2025 lByteOffset = pSource->lOffset / 2;
2026 lByteOffset -= (lByteOffset % (lChannels * 2));
2028 else
2030 lByteOffset = pSource->lOffset;
2031 lByteOffset -= (lByteOffset % (lChannels * 2));
2033 break;
2035 case AL_SAMPLE_OFFSET:
2036 lByteOffset = pSource->lOffset * lChannels * 2;
2037 break;
2039 case AL_SEC_OFFSET:
2040 // Note - lOffset is internally stored as Milliseconds
2041 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2042 lByteOffset -= (lByteOffset % (lChannels * 2));
2043 break;
2046 lTotalBufferDataSize = 0;
2047 pBufferList = pSource->queue;
2048 while (pBufferList)
2050 if (pBufferList->buffer)
2051 lTotalBufferDataSize += pBufferList->buffer->size;
2052 pBufferList = pBufferList->next;
2055 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2056 if (lByteOffset >= lTotalBufferDataSize)
2057 lByteOffset = -1;
2060 return lByteOffset;
2064 ALvoid ReleaseALSources(ALCcontext *Context)
2066 ALuint j;
2068 while(Context->Source)
2070 ALsource *temp = Context->Source;
2071 Context->Source = temp->next;
2073 // For each buffer in the source's queue, decrement its reference counter and remove it
2074 while(temp->queue != NULL)
2076 ALbufferlistitem *ALBufferList = temp->queue;
2077 // Decrement buffer's reference counter
2078 if(ALBufferList->buffer != NULL)
2079 ALBufferList->buffer->refcount--;
2080 // Update queue to point to next element in list
2081 temp->queue = ALBufferList->next;
2082 // Release memory allocated for buffer list item
2083 free(ALBufferList);
2086 for(j = 0;j < MAX_SENDS;++j)
2088 if(temp->Send[j].Slot)
2089 temp->Send[j].Slot->refcount--;
2092 // Release source structure
2093 ALTHUNK_REMOVEENTRY(temp->source);
2094 memset(temp, 0, sizeof(ALsource));
2095 free(temp);
2097 Context->SourceCount = 0;