Store the buffer format and frequency in the source when updated
[openal-soft.git] / OpenAL32 / alSource.c
blob85b9c9669f1bcf6f2297fdc93e63fcb93cbd2bca
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 pSource->Format = buffer->format;
539 pSource->Frequency = buffer->frequency;
541 // Add the selected buffer to the queue
542 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
543 pALBufferListItem->buffer = buffer;
544 pALBufferListItem->next = NULL;
546 pSource->queue = pALBufferListItem;
547 pSource->BuffersInQueue = 1;
549 // Increment reference counter for buffer
550 buffer->refcount++;
552 else
554 // Source is now in UNDETERMINED mode
555 pSource->lSourceType = AL_UNDETERMINED;
556 pSource->BuffersPlayed = 0;
559 // Update AL_BUFFER parameter
560 pSource->Buffer = buffer;
562 else
563 alSetError(AL_INVALID_VALUE);
565 else
566 alSetError(AL_INVALID_OPERATION);
567 break;
569 case AL_SOURCE_STATE:
570 // Query only
571 alSetError(AL_INVALID_OPERATION);
572 break;
574 case AL_SEC_OFFSET:
575 case AL_SAMPLE_OFFSET:
576 case AL_BYTE_OFFSET:
577 if(lValue >= 0)
579 pSource->lOffsetType = eParam;
581 // Store Offset (convert Seconds into Milliseconds)
582 if(eParam == AL_SEC_OFFSET)
583 pSource->lOffset = lValue * 1000;
584 else
585 pSource->lOffset = lValue;
587 if(pSource->state == AL_PLAYING || pSource->state == AL_PAUSED)
588 ApplyOffset(pSource, AL_TRUE);
590 else
591 alSetError(AL_INVALID_VALUE);
592 break;
594 case AL_DIRECT_FILTER:
595 if(alIsFilter(lValue))
597 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
598 if(!filter)
600 pSource->DirectFilter.type = AL_FILTER_NULL;
601 pSource->DirectFilter.filter = 0;
603 else
604 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
606 else
607 alSetError(AL_INVALID_VALUE);
608 break;
610 case AL_DIRECT_FILTER_GAINHF_AUTO:
611 if(lValue == AL_TRUE || lValue == AL_FALSE)
612 pSource->DryGainHFAuto = lValue;
613 else
614 alSetError(AL_INVALID_VALUE);
615 break;
617 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
618 if(lValue == AL_TRUE || lValue == AL_FALSE)
619 pSource->WetGainAuto = lValue;
620 else
621 alSetError(AL_INVALID_VALUE);
622 break;
624 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
625 if(lValue == AL_TRUE || lValue == AL_FALSE)
626 pSource->WetGainHFAuto = lValue;
627 else
628 alSetError(AL_INVALID_VALUE);
629 break;
631 case AL_DISTANCE_MODEL:
632 if(lValue == AL_NONE ||
633 lValue == AL_INVERSE_DISTANCE ||
634 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
635 lValue == AL_LINEAR_DISTANCE ||
636 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
637 lValue == AL_EXPONENT_DISTANCE ||
638 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
639 pSource->DistanceModel = lValue;
640 else
641 alSetError(AL_INVALID_VALUE);
642 break;
644 default:
645 alSetError(AL_INVALID_ENUM);
646 break;
649 else
650 alSetError(AL_INVALID_NAME);
652 ProcessContext(pContext);
656 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
658 ALCcontext *pContext;
660 pContext = GetContextSuspended();
661 if(!pContext) return;
663 if(alIsSource(source))
665 ALsource *pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
666 ALCdevice *Device = pContext->Device;
668 switch (eParam)
670 case AL_POSITION:
671 case AL_VELOCITY:
672 case AL_DIRECTION:
673 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
674 break;
676 case AL_AUXILIARY_SEND_FILTER:
677 if((ALuint)lValue2 < Device->NumAuxSends &&
678 (lValue1 == 0 || alIsAuxiliaryEffectSlot(lValue1)) &&
679 alIsFilter(lValue3))
681 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
682 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
684 /* Release refcount on the previous slot, and add one for
685 * the new slot */
686 if(pSource->Send[lValue2].Slot)
687 pSource->Send[lValue2].Slot->refcount--;
688 pSource->Send[lValue2].Slot = ALEffectSlot;
689 if(pSource->Send[lValue2].Slot)
690 pSource->Send[lValue2].Slot->refcount++;
692 if(!ALFilter)
694 /* Disable filter */
695 pSource->Send[lValue2].WetFilter.type = 0;
696 pSource->Send[lValue2].WetFilter.filter = 0;
698 else
699 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
701 else
702 alSetError(AL_INVALID_VALUE);
703 break;
705 default:
706 alSetError(AL_INVALID_ENUM);
707 break;
710 else
711 alSetError(AL_INVALID_NAME);
713 ProcessContext(pContext);
717 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
719 ALCcontext *pContext;
721 pContext = GetContextSuspended();
722 if(!pContext) return;
724 if(plValues)
726 if(alIsSource(source))
728 switch(eParam)
730 case AL_SOURCE_RELATIVE:
731 case AL_CONE_INNER_ANGLE:
732 case AL_CONE_OUTER_ANGLE:
733 case AL_LOOPING:
734 case AL_BUFFER:
735 case AL_SOURCE_STATE:
736 case AL_SEC_OFFSET:
737 case AL_SAMPLE_OFFSET:
738 case AL_BYTE_OFFSET:
739 case AL_MAX_DISTANCE:
740 case AL_ROLLOFF_FACTOR:
741 case AL_REFERENCE_DISTANCE:
742 case AL_DIRECT_FILTER:
743 case AL_DIRECT_FILTER_GAINHF_AUTO:
744 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
745 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
746 case AL_DISTANCE_MODEL:
747 alSourcei(source, eParam, plValues[0]);
748 break;
750 case AL_POSITION:
751 case AL_VELOCITY:
752 case AL_DIRECTION:
753 case AL_AUXILIARY_SEND_FILTER:
754 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
755 break;
757 default:
758 alSetError(AL_INVALID_ENUM);
759 break;
762 else
763 alSetError(AL_INVALID_NAME);
765 else
766 alSetError(AL_INVALID_VALUE);
768 ProcessContext(pContext);
772 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
774 ALCcontext *pContext;
775 ALsource *pSource;
776 ALfloat flOffset[2];
778 pContext = GetContextSuspended();
779 if(!pContext) return;
781 if(pflValue)
783 if(alIsSource(source))
785 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
787 switch(eParam)
789 case AL_PITCH:
790 *pflValue = pSource->flPitch;
791 break;
793 case AL_GAIN:
794 *pflValue = pSource->flGain;
795 break;
797 case AL_MIN_GAIN:
798 *pflValue = pSource->flMinGain;
799 break;
801 case AL_MAX_GAIN:
802 *pflValue = pSource->flMaxGain;
803 break;
805 case AL_MAX_DISTANCE:
806 *pflValue = pSource->flMaxDistance;
807 break;
809 case AL_ROLLOFF_FACTOR:
810 *pflValue = pSource->flRollOffFactor;
811 break;
813 case AL_CONE_OUTER_GAIN:
814 *pflValue = pSource->flOuterGain;
815 break;
817 case AL_CONE_OUTER_GAINHF:
818 *pflValue = pSource->OuterGainHF;
819 break;
821 case AL_SEC_OFFSET:
822 case AL_SAMPLE_OFFSET:
823 case AL_BYTE_OFFSET:
824 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
825 *pflValue = flOffset[0];
826 else
827 alSetError(AL_INVALID_OPERATION);
828 break;
830 case AL_SEC_RW_OFFSETS_EXT:
831 case AL_SAMPLE_RW_OFFSETS_EXT:
832 case AL_BYTE_RW_OFFSETS_EXT:
833 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
835 pflValue[0] = flOffset[0];
836 pflValue[1] = flOffset[1];
838 else
839 alSetError(AL_INVALID_OPERATION);
840 break;
842 case AL_CONE_INNER_ANGLE:
843 *pflValue = pSource->flInnerAngle;
844 break;
846 case AL_CONE_OUTER_ANGLE:
847 *pflValue = pSource->flOuterAngle;
848 break;
850 case AL_REFERENCE_DISTANCE:
851 *pflValue = pSource->flRefDistance;
852 break;
854 case AL_AIR_ABSORPTION_FACTOR:
855 *pflValue = pSource->AirAbsorptionFactor;
856 break;
858 case AL_ROOM_ROLLOFF_FACTOR:
859 *pflValue = pSource->RoomRolloffFactor;
860 break;
862 case AL_DOPPLER_FACTOR:
863 *pflValue = pSource->DopplerFactor;
864 break;
866 default:
867 alSetError(AL_INVALID_ENUM);
868 break;
871 else
872 alSetError(AL_INVALID_NAME);
874 else
875 alSetError(AL_INVALID_VALUE);
877 ProcessContext(pContext);
881 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
883 ALCcontext *pContext;
884 ALsource *pSource;
886 pContext = GetContextSuspended();
887 if(!pContext) return;
889 if(pflValue1 && pflValue2 && pflValue3)
891 if(alIsSource(source))
893 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
895 switch(eParam)
897 case AL_POSITION:
898 *pflValue1 = pSource->vPosition[0];
899 *pflValue2 = pSource->vPosition[1];
900 *pflValue3 = pSource->vPosition[2];
901 break;
903 case AL_VELOCITY:
904 *pflValue1 = pSource->vVelocity[0];
905 *pflValue2 = pSource->vVelocity[1];
906 *pflValue3 = pSource->vVelocity[2];
907 break;
909 case AL_DIRECTION:
910 *pflValue1 = pSource->vOrientation[0];
911 *pflValue2 = pSource->vOrientation[1];
912 *pflValue3 = pSource->vOrientation[2];
913 break;
915 default:
916 alSetError(AL_INVALID_ENUM);
917 break;
920 else
921 alSetError(AL_INVALID_NAME);
923 else
924 alSetError(AL_INVALID_VALUE);
926 ProcessContext(pContext);
930 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
932 ALCcontext *pContext;
933 ALsource *pSource;
935 pContext = GetContextSuspended();
936 if(!pContext) return;
938 if(pflValues)
940 if(alIsSource(source))
942 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
944 switch(eParam)
946 case AL_PITCH:
947 case AL_GAIN:
948 case AL_MIN_GAIN:
949 case AL_MAX_GAIN:
950 case AL_MAX_DISTANCE:
951 case AL_ROLLOFF_FACTOR:
952 case AL_DOPPLER_FACTOR:
953 case AL_CONE_OUTER_GAIN:
954 case AL_SEC_OFFSET:
955 case AL_SAMPLE_OFFSET:
956 case AL_BYTE_OFFSET:
957 case AL_CONE_INNER_ANGLE:
958 case AL_CONE_OUTER_ANGLE:
959 case AL_REFERENCE_DISTANCE:
960 case AL_CONE_OUTER_GAINHF:
961 case AL_AIR_ABSORPTION_FACTOR:
962 case AL_ROOM_ROLLOFF_FACTOR:
963 alGetSourcef(source, eParam, pflValues);
964 break;
966 case AL_POSITION:
967 pflValues[0] = pSource->vPosition[0];
968 pflValues[1] = pSource->vPosition[1];
969 pflValues[2] = pSource->vPosition[2];
970 break;
972 case AL_VELOCITY:
973 pflValues[0] = pSource->vVelocity[0];
974 pflValues[1] = pSource->vVelocity[1];
975 pflValues[2] = pSource->vVelocity[2];
976 break;
978 case AL_DIRECTION:
979 pflValues[0] = pSource->vOrientation[0];
980 pflValues[1] = pSource->vOrientation[1];
981 pflValues[2] = pSource->vOrientation[2];
982 break;
984 default:
985 alSetError(AL_INVALID_ENUM);
986 break;
989 else
990 alSetError(AL_INVALID_NAME);
992 else
993 alSetError(AL_INVALID_VALUE);
995 ProcessContext(pContext);
999 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1001 ALCcontext *pContext;
1002 ALsource *pSource;
1003 ALfloat flOffset[2];
1005 pContext = GetContextSuspended();
1006 if(!pContext) return;
1008 if(plValue)
1010 if(alIsSource(source))
1012 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1014 switch(eParam)
1016 case AL_MAX_DISTANCE:
1017 *plValue = (ALint)pSource->flMaxDistance;
1018 break;
1020 case AL_ROLLOFF_FACTOR:
1021 *plValue = (ALint)pSource->flRollOffFactor;
1022 break;
1024 case AL_REFERENCE_DISTANCE:
1025 *plValue = (ALint)pSource->flRefDistance;
1026 break;
1028 case AL_SOURCE_RELATIVE:
1029 *plValue = pSource->bHeadRelative;
1030 break;
1032 case AL_CONE_INNER_ANGLE:
1033 *plValue = (ALint)pSource->flInnerAngle;
1034 break;
1036 case AL_CONE_OUTER_ANGLE:
1037 *plValue = (ALint)pSource->flOuterAngle;
1038 break;
1040 case AL_LOOPING:
1041 *plValue = pSource->bLooping;
1042 break;
1044 case AL_BUFFER:
1045 *plValue = (pSource->Buffer ? pSource->Buffer->buffer : 0);
1046 break;
1048 case AL_SOURCE_STATE:
1049 *plValue = pSource->state;
1050 break;
1052 case AL_BUFFERS_QUEUED:
1053 *plValue = pSource->BuffersInQueue;
1054 break;
1056 case AL_BUFFERS_PROCESSED:
1057 if(pSource->bLooping)
1059 /* Buffers on a looping source are in a perpetual state
1060 * of PENDING, so don't report any as PROCESSED */
1061 *plValue = 0;
1063 else
1064 *plValue = pSource->BuffersPlayed;
1065 break;
1067 case AL_SOURCE_TYPE:
1068 *plValue = pSource->lSourceType;
1069 break;
1071 case AL_SEC_OFFSET:
1072 case AL_SAMPLE_OFFSET:
1073 case AL_BYTE_OFFSET:
1074 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1075 *plValue = (ALint)flOffset[0];
1076 else
1077 alSetError(AL_INVALID_OPERATION);
1078 break;
1080 case AL_SEC_RW_OFFSETS_EXT:
1081 case AL_SAMPLE_RW_OFFSETS_EXT:
1082 case AL_BYTE_RW_OFFSETS_EXT:
1083 if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
1085 plValue[0] = (ALint)flOffset[0];
1086 plValue[1] = (ALint)flOffset[1];
1088 else
1089 alSetError(AL_INVALID_OPERATION);
1090 break;
1092 case AL_DIRECT_FILTER:
1093 *plValue = pSource->DirectFilter.filter;
1094 break;
1096 case AL_DIRECT_FILTER_GAINHF_AUTO:
1097 *plValue = pSource->DryGainHFAuto;
1098 break;
1100 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1101 *plValue = pSource->WetGainAuto;
1102 break;
1104 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1105 *plValue = pSource->WetGainHFAuto;
1106 break;
1108 case AL_DOPPLER_FACTOR:
1109 *plValue = (ALint)pSource->DopplerFactor;
1110 break;
1112 case AL_DISTANCE_MODEL:
1113 *plValue = pSource->DistanceModel;
1114 break;
1116 default:
1117 alSetError(AL_INVALID_ENUM);
1118 break;
1121 else
1122 alSetError(AL_INVALID_NAME);
1124 else
1125 alSetError(AL_INVALID_VALUE);
1127 ProcessContext(pContext);
1131 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1133 ALCcontext *pContext;
1134 ALsource *pSource;
1136 pContext = GetContextSuspended();
1137 if(!pContext) return;
1139 if(plValue1 && plValue2 && plValue3)
1141 if(alIsSource(source))
1143 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1145 switch(eParam)
1147 case AL_POSITION:
1148 *plValue1 = (ALint)pSource->vPosition[0];
1149 *plValue2 = (ALint)pSource->vPosition[1];
1150 *plValue3 = (ALint)pSource->vPosition[2];
1151 break;
1153 case AL_VELOCITY:
1154 *plValue1 = (ALint)pSource->vVelocity[0];
1155 *plValue2 = (ALint)pSource->vVelocity[1];
1156 *plValue3 = (ALint)pSource->vVelocity[2];
1157 break;
1159 case AL_DIRECTION:
1160 *plValue1 = (ALint)pSource->vOrientation[0];
1161 *plValue2 = (ALint)pSource->vOrientation[1];
1162 *plValue3 = (ALint)pSource->vOrientation[2];
1163 break;
1165 default:
1166 alSetError(AL_INVALID_ENUM);
1167 break;
1170 else
1171 alSetError(AL_INVALID_NAME);
1173 else
1174 alSetError(AL_INVALID_VALUE);
1176 ProcessContext(pContext);
1180 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1182 ALCcontext *pContext;
1183 ALsource *pSource;
1185 pContext = GetContextSuspended();
1186 if(!pContext) return;
1188 if(plValues)
1190 if(alIsSource(source))
1192 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1194 switch(eParam)
1196 case AL_SOURCE_RELATIVE:
1197 case AL_CONE_INNER_ANGLE:
1198 case AL_CONE_OUTER_ANGLE:
1199 case AL_LOOPING:
1200 case AL_BUFFER:
1201 case AL_SOURCE_STATE:
1202 case AL_BUFFERS_QUEUED:
1203 case AL_BUFFERS_PROCESSED:
1204 case AL_SEC_OFFSET:
1205 case AL_SAMPLE_OFFSET:
1206 case AL_BYTE_OFFSET:
1207 case AL_MAX_DISTANCE:
1208 case AL_ROLLOFF_FACTOR:
1209 case AL_DOPPLER_FACTOR:
1210 case AL_REFERENCE_DISTANCE:
1211 case AL_SOURCE_TYPE:
1212 case AL_DIRECT_FILTER:
1213 case AL_DIRECT_FILTER_GAINHF_AUTO:
1214 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1215 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1216 case AL_DISTANCE_MODEL:
1217 alGetSourcei(source, eParam, plValues);
1218 break;
1220 case AL_POSITION:
1221 plValues[0] = (ALint)pSource->vPosition[0];
1222 plValues[1] = (ALint)pSource->vPosition[1];
1223 plValues[2] = (ALint)pSource->vPosition[2];
1224 break;
1226 case AL_VELOCITY:
1227 plValues[0] = (ALint)pSource->vVelocity[0];
1228 plValues[1] = (ALint)pSource->vVelocity[1];
1229 plValues[2] = (ALint)pSource->vVelocity[2];
1230 break;
1232 case AL_DIRECTION:
1233 plValues[0] = (ALint)pSource->vOrientation[0];
1234 plValues[1] = (ALint)pSource->vOrientation[1];
1235 plValues[2] = (ALint)pSource->vOrientation[2];
1236 break;
1238 default:
1239 alSetError(AL_INVALID_ENUM);
1240 break;
1243 else
1244 alSetError(AL_INVALID_NAME);
1246 else
1247 alSetError(AL_INVALID_VALUE);
1249 ProcessContext(pContext);
1253 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1255 alSourcePlayv(1, &source);
1256 return;
1259 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1261 ALCcontext *pContext;
1262 ALsource *pSource;
1263 ALbufferlistitem *ALBufferList;
1264 ALboolean bSourcesValid = AL_TRUE;
1265 ALboolean bPlay;
1266 ALsizei i, j;
1268 pContext = GetContextSuspended();
1269 if(!pContext) return;
1271 if(pSourceList)
1273 // Check that all the Sources are valid
1274 for(i = 0; i < n; i++)
1276 if(!alIsSource(pSourceList[i]))
1278 alSetError(AL_INVALID_NAME);
1279 bSourcesValid = AL_FALSE;
1280 break;
1284 if(bSourcesValid)
1286 for(i = 0; i < n; i++)
1288 // Assume Source won't need to play
1289 bPlay = AL_FALSE;
1291 pSource = (ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]);
1293 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1294 ALBufferList = pSource->queue;
1295 while(ALBufferList)
1297 if(ALBufferList->buffer != NULL && ALBufferList->buffer->size)
1299 bPlay = AL_TRUE;
1300 break;
1302 ALBufferList = ALBufferList->next;
1305 if (bPlay)
1307 for(j = 0;j < OUTPUTCHANNELS;j++)
1308 pSource->DryGains[j] = 0.0f;
1309 for(j = 0;j < MAX_SENDS;j++)
1310 pSource->WetGains[j] = 0.0f;
1312 if(pSource->state != AL_PAUSED)
1314 pSource->state = AL_PLAYING;
1315 pSource->position = 0;
1316 pSource->position_fraction = 0;
1317 pSource->BuffersPlayed = 0;
1319 pSource->Buffer = pSource->queue->buffer;
1321 else
1322 pSource->state = AL_PLAYING;
1324 // Check if an Offset has been set
1325 if(pSource->lOffset)
1326 ApplyOffset(pSource, AL_FALSE);
1328 if(pSource->BuffersPlayed == 0 && pSource->position == 0 &&
1329 pSource->position_fraction == 0)
1330 pSource->FirstStart = AL_TRUE;
1331 else
1332 pSource->FirstStart = AL_FALSE;
1334 // If device is disconnected, go right to stopped
1335 if(!pContext->Device->Connected)
1337 pSource->state = AL_STOPPED;
1338 pSource->BuffersPlayed = pSource->BuffersInQueue;
1339 pSource->position = 0;
1340 pSource->position_fraction = 0;
1343 else
1344 pSource->BuffersPlayed = pSource->BuffersInQueue;
1348 else
1350 // sources is a NULL pointer
1351 alSetError(AL_INVALID_VALUE);
1354 ProcessContext(pContext);
1357 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1359 alSourcePausev(1, &source);
1360 return;
1363 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1365 ALCcontext *Context;
1366 ALsource *Source;
1367 ALsizei i;
1368 ALboolean bSourcesValid = AL_TRUE;
1370 Context = GetContextSuspended();
1371 if(!Context) return;
1373 if(sources)
1375 // Check all the Sources are valid
1376 for(i=0;i<n;i++)
1378 if(!alIsSource(sources[i]))
1380 alSetError(AL_INVALID_NAME);
1381 bSourcesValid = AL_FALSE;
1382 break;
1386 if(bSourcesValid)
1388 for(i = 0;i < n;i++)
1390 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1391 if(Source->state == AL_PLAYING)
1392 Source->state = AL_PAUSED;
1396 else
1398 // sources is a NULL pointer
1399 alSetError(AL_INVALID_VALUE);
1402 ProcessContext(Context);
1405 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1407 alSourceStopv(1, &source);
1408 return;
1411 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1413 ALCcontext *Context;
1414 ALsource *Source;
1415 ALsizei i;
1416 ALboolean bSourcesValid = AL_TRUE;
1418 Context = GetContextSuspended();
1419 if(!Context) return;
1421 if(sources)
1423 // Check all the Sources are valid
1424 for(i = 0;i < n;i++)
1426 if(!alIsSource(sources[i]))
1428 alSetError(AL_INVALID_NAME);
1429 bSourcesValid = AL_FALSE;
1430 break;
1434 if(bSourcesValid)
1436 for(i = 0;i < n;i++)
1438 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1439 if(Source->state != AL_INITIAL)
1441 Source->state = AL_STOPPED;
1442 Source->BuffersPlayed = Source->BuffersInQueue;
1444 Source->lOffset = 0;
1448 else
1450 // sources is a NULL pointer
1451 alSetError(AL_INVALID_VALUE);
1454 ProcessContext(Context);
1457 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1459 alSourceRewindv(1, &source);
1460 return;
1463 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1465 ALCcontext *Context;
1466 ALsource *Source;
1467 ALsizei i;
1468 ALboolean bSourcesValid = AL_TRUE;
1470 Context = GetContextSuspended();
1471 if(!Context) return;
1473 if(sources)
1475 // Check all the Sources are valid
1476 for(i = 0;i < n;i++)
1478 if(!alIsSource(sources[i]))
1480 alSetError(AL_INVALID_NAME);
1481 bSourcesValid = AL_FALSE;
1482 break;
1486 if(bSourcesValid)
1488 for(i = 0;i < n;i++)
1490 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1491 if(Source->state != AL_INITIAL)
1493 Source->state = AL_INITIAL;
1494 Source->position = 0;
1495 Source->position_fraction = 0;
1496 Source->BuffersPlayed = 0;
1497 if(Source->queue)
1498 Source->Buffer = Source->queue->buffer;
1500 Source->lOffset = 0;
1504 else
1506 // sources is a NULL pointer
1507 alSetError(AL_INVALID_VALUE);
1510 ProcessContext(Context);
1514 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1516 ALCcontext *Context;
1517 ALsource *ALSource;
1518 ALsizei i;
1519 ALbufferlistitem *ALBufferList;
1520 ALbufferlistitem *ALBufferListStart;
1521 ALint iFrequency;
1522 ALint iFormat;
1523 ALboolean bBuffersValid = AL_TRUE;
1525 if (n == 0)
1526 return;
1528 Context = GetContextSuspended();
1529 if(!Context) return;
1531 // Check that all buffers are valid or zero and that the source is valid
1533 // Check that this is a valid source
1534 if(alIsSource(source))
1536 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1538 // Check that this is not a STATIC Source
1539 if(ALSource->lSourceType != AL_STATIC)
1541 iFrequency = -1;
1542 iFormat = -1;
1544 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1545 ALBufferList = ALSource->queue;
1546 while(ALBufferList)
1548 if (ALBufferList->buffer)
1550 iFrequency = ALBufferList->buffer->frequency;
1551 iFormat = ALBufferList->buffer->format;
1552 break;
1554 ALBufferList = ALBufferList->next;
1557 for(i = 0; i < n; i++)
1559 ALbuffer *buffer;
1561 if(!alIsBuffer(buffers[i]))
1563 alSetError(AL_INVALID_NAME);
1564 bBuffersValid = AL_FALSE;
1565 break;
1567 if(!buffers[i])
1568 continue;
1570 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1571 if(iFrequency == -1 && iFormat == -1)
1573 iFrequency = buffer->frequency;
1574 iFormat = buffer->format;
1576 else if(iFrequency != buffer->frequency ||
1577 iFormat != buffer->format)
1579 alSetError(AL_INVALID_OPERATION);
1580 bBuffersValid = AL_FALSE;
1581 break;
1585 if(bBuffersValid)
1587 ALbuffer *buffer = NULL;
1589 // Change Source Type
1590 ALSource->lSourceType = AL_STREAMING;
1592 ALSource->Format = iFormat;
1593 ALSource->Frequency = iFrequency;
1595 if(buffers[0])
1596 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1598 // All buffers are valid - so add them to the list
1599 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1600 ALBufferListStart->buffer = buffer;
1601 ALBufferListStart->next = NULL;
1603 // Increment reference counter for buffer
1604 if(buffer) buffer->refcount++;
1606 ALBufferList = ALBufferListStart;
1608 for(i = 1; i < n; i++)
1610 if(buffers[i])
1611 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1613 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1614 ALBufferList->next->buffer = buffer;
1615 ALBufferList->next->next = NULL;
1617 // Increment reference counter for buffer
1618 if(buffer) buffer->refcount++;
1620 ALBufferList = ALBufferList->next;
1623 if(ALSource->queue == NULL)
1625 ALSource->queue = ALBufferListStart;
1626 // Update Current Buffer
1627 ALSource->Buffer = ALBufferListStart->buffer;
1629 else
1631 // Find end of queue
1632 ALBufferList = ALSource->queue;
1633 while(ALBufferList->next != NULL)
1634 ALBufferList = ALBufferList->next;
1636 ALBufferList->next = ALBufferListStart;
1639 // Update number of buffers in queue
1640 ALSource->BuffersInQueue += n;
1643 else
1645 // Invalid Source Type (can't queue on a Static Source)
1646 alSetError(AL_INVALID_OPERATION);
1649 else
1651 // Invalid Source Name
1652 alSetError(AL_INVALID_NAME);
1655 ProcessContext(Context);
1659 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1660 // an array of buffer IDs that are to be filled with the names of the buffers removed
1661 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1663 ALCcontext *Context;
1664 ALsource *ALSource;
1665 ALsizei i;
1666 ALbufferlistitem *ALBufferList;
1667 ALboolean bBuffersProcessed;
1669 if (n == 0)
1670 return;
1672 bBuffersProcessed = AL_TRUE;
1674 Context = GetContextSuspended();
1675 if(!Context) return;
1677 if(alIsSource(source))
1679 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1681 // If all 'n' buffers have been processed, remove them from the queue
1682 if(!ALSource->bLooping && (ALuint)n <= ALSource->BuffersPlayed)
1684 for(i = 0; i < n; i++)
1686 ALBufferList = ALSource->queue;
1688 ALSource->queue = ALBufferList->next;
1689 // Record name of buffer
1690 buffers[i] = ALBufferList->buffer->buffer;
1691 // Decrement buffer reference counter
1692 if(ALBufferList->buffer)
1693 ALBufferList->buffer->refcount--;
1695 // Release memory for buffer list item
1696 free(ALBufferList);
1697 ALSource->BuffersInQueue--;
1700 if(ALSource->state != AL_PLAYING)
1702 if(ALSource->queue)
1703 ALSource->Buffer = ALSource->queue->buffer;
1704 else
1705 ALSource->Buffer = NULL;
1708 ALSource->BuffersPlayed -= n;
1710 else
1712 // Some buffers can't be unqueue because they have not been processed
1713 alSetError(AL_INVALID_VALUE);
1716 else
1718 // Invalid Source Name
1719 alSetError(AL_INVALID_NAME);
1722 ProcessContext(Context);
1726 static ALvoid InitSourceParams(ALCcontext *Context, ALsource *pSource)
1728 pSource->flInnerAngle = 360.0f;
1729 pSource->flOuterAngle = 360.0f;
1730 pSource->flPitch = 1.0f;
1731 pSource->vPosition[0] = 0.0f;
1732 pSource->vPosition[1] = 0.0f;
1733 pSource->vPosition[2] = 0.0f;
1734 pSource->vOrientation[0] = 0.0f;
1735 pSource->vOrientation[1] = 0.0f;
1736 pSource->vOrientation[2] = 0.0f;
1737 pSource->vVelocity[0] = 0.0f;
1738 pSource->vVelocity[1] = 0.0f;
1739 pSource->vVelocity[2] = 0.0f;
1740 pSource->flRefDistance = 1.0f;
1741 pSource->flMaxDistance = FLT_MAX;
1742 pSource->flRollOffFactor = 1.0f;
1743 pSource->bLooping = AL_FALSE;
1744 pSource->flGain = 1.0f;
1745 pSource->flMinGain = 0.0f;
1746 pSource->flMaxGain = 1.0f;
1747 pSource->flOuterGain = 0.0f;
1748 pSource->OuterGainHF = 1.0f;
1750 pSource->DryGainHFAuto = AL_TRUE;
1751 pSource->WetGainAuto = AL_TRUE;
1752 pSource->WetGainHFAuto = AL_TRUE;
1753 pSource->AirAbsorptionFactor = 0.0f;
1754 pSource->RoomRolloffFactor = 0.0f;
1755 pSource->DopplerFactor = 1.0f;
1757 pSource->DistanceModel = Context->DistanceModel;
1759 pSource->state = AL_INITIAL;
1760 pSource->lSourceType = AL_UNDETERMINED;
1762 pSource->Buffer = NULL;
1767 GetSourceOffset
1769 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1770 The offset is relative to the start of the queue (not the start of the current buffer)
1772 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize)
1774 ALbufferlistitem *pBufferList;
1775 ALbuffer *pBuffer;
1776 ALfloat flBufferFreq;
1777 ALint lChannels;
1778 ALint readPos, writePos;
1779 ALenum eOriginalFormat;
1780 ALboolean bReturn = AL_TRUE;
1781 ALint lTotalBufferDataSize;
1782 ALuint i;
1784 if((pSource->state == AL_PLAYING || pSource->state == AL_PAUSED) && pSource->Buffer)
1786 pBuffer = pSource->Buffer;
1787 // Get Current Buffer Size and frequency (in milliseconds)
1788 flBufferFreq = (ALfloat)pBuffer->frequency;
1789 eOriginalFormat = pBuffer->eOriginalFormat;
1790 lChannels = aluChannelsFromFormat(pBuffer->format);
1792 // Get Current BytesPlayed
1793 readPos = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
1794 // Add byte length of any processed buffers in the queue
1795 pBufferList = pSource->queue;
1796 for(i = 0;i < pSource->BuffersPlayed && pBufferList;i++)
1798 readPos += pBufferList->buffer->size;
1799 pBufferList = pBufferList->next;
1802 if(pSource->state == AL_PLAYING)
1803 writePos = readPos + (updateSize * lChannels * 2);
1804 else
1805 writePos = readPos;
1807 lTotalBufferDataSize = 0;
1808 pBufferList = pSource->queue;
1809 while (pBufferList)
1811 if (pBufferList->buffer)
1812 lTotalBufferDataSize += pBufferList->buffer->size;
1813 pBufferList = pBufferList->next;
1816 if (pSource->bLooping)
1818 if(readPos < 0)
1819 readPos = 0;
1820 else
1821 readPos %= lTotalBufferDataSize;
1822 if(writePos < 0)
1823 writePos = 0;
1824 else
1825 writePos %= lTotalBufferDataSize;
1827 else
1829 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1830 if(readPos < 0)
1831 readPos = 0;
1832 else if(readPos > lTotalBufferDataSize)
1833 readPos = lTotalBufferDataSize;
1834 if(writePos < 0)
1835 writePos = 0;
1836 else if(writePos > lTotalBufferDataSize)
1837 writePos = lTotalBufferDataSize;
1840 switch (eName)
1842 case AL_SEC_OFFSET:
1843 case AL_SEC_RW_OFFSETS_EXT:
1844 pflOffset[0] = (ALfloat)readPos / (lChannels * 2.0f * flBufferFreq);
1845 pflOffset[1] = (ALfloat)writePos / (lChannels * 2.0f * flBufferFreq);
1846 break;
1847 case AL_SAMPLE_OFFSET:
1848 case AL_SAMPLE_RW_OFFSETS_EXT:
1849 pflOffset[0] = (ALfloat)(readPos / (lChannels * 2));
1850 pflOffset[1] = (ALfloat)(writePos / (lChannels * 2));
1851 break;
1852 case AL_BYTE_OFFSET:
1853 case AL_BYTE_RW_OFFSETS_EXT:
1854 // Take into account the original format of the Buffer
1855 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
1856 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
1858 // Round down to nearest ADPCM block
1859 pflOffset[0] = (ALfloat)((readPos / (65 * 2 * lChannels)) * 36 * lChannels);
1860 if(pSource->state == AL_PLAYING)
1862 // Round up to nearest ADPCM block
1863 pflOffset[1] = (ALfloat)(((writePos + (65 * 2 * lChannels) - 1) / (65 * 2 * lChannels)) * 36 * lChannels);
1865 else
1866 pflOffset[1] = pflOffset[0];
1868 else if (eOriginalFormat == AL_FORMAT_REAR8)
1870 pflOffset[0] = (ALfloat)(readPos >> 2);
1871 pflOffset[1] = (ALfloat)(writePos >> 2);
1873 else if (eOriginalFormat == AL_FORMAT_REAR16)
1875 pflOffset[0] = (ALfloat)(readPos >> 1);
1876 pflOffset[1] = (ALfloat)(writePos >> 1);
1878 else if (aluBytesFromFormat(eOriginalFormat) == 1)
1880 pflOffset[0] = (ALfloat)(readPos >> 1);
1881 pflOffset[1] = (ALfloat)(writePos >> 1);
1883 else if (aluBytesFromFormat(eOriginalFormat) == 4)
1885 pflOffset[0] = (ALfloat)(readPos << 1);
1886 pflOffset[1] = (ALfloat)(writePos << 1);
1888 else
1890 pflOffset[0] = (ALfloat)readPos;
1891 pflOffset[1] = (ALfloat)writePos;
1893 break;
1896 else
1898 pflOffset[0] = 0.0f;
1899 pflOffset[1] = 0.0f;
1902 return bReturn;
1907 ApplyOffset
1909 Apply a playback offset to the Source. This function will update the queue (to correctly
1910 mark buffers as 'pending' or 'processed' depending upon the new offset.
1912 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
1914 ALbufferlistitem *pBufferList;
1915 ALbuffer *pBuffer;
1916 ALint lBufferSize, lTotalBufferSize;
1917 ALint lByteOffset;
1919 // Get true byte offset
1920 lByteOffset = GetByteOffset(pSource);
1922 // If this is a valid offset apply it
1923 if (lByteOffset != -1)
1925 // Sort out the queue (pending and processed states)
1926 pBufferList = pSource->queue;
1927 lTotalBufferSize = 0;
1928 pSource->BuffersPlayed = 0;
1929 while (pBufferList)
1931 pBuffer = pBufferList->buffer;
1932 lBufferSize = pBuffer ? pBuffer->size : 0;
1934 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
1936 // Offset is past this buffer so increment BuffersPlayed
1937 pSource->BuffersPlayed++;
1939 else if (lTotalBufferSize <= lByteOffset)
1941 // Offset is within this buffer
1942 // Set Current Buffer
1943 pSource->Buffer = pBufferList->buffer;
1945 // SW Mixer Positions are in Samples
1946 pSource->position = (lByteOffset - lTotalBufferSize) /
1947 aluBytesFromFormat(pBuffer->format) /
1948 aluChannelsFromFormat(pBuffer->format);
1951 // Increment the TotalBufferSize
1952 lTotalBufferSize += lBufferSize;
1954 // Move on to next buffer in the Queue
1955 pBufferList = pBufferList->next;
1958 else
1960 if (bUpdateContext)
1961 alSetError(AL_INVALID_VALUE);
1964 // Clear Offset
1965 pSource->lOffset = 0;
1970 GetByteOffset
1972 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1973 offset supplied by the application). This takes into account the fact that the buffer format
1974 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
1976 static ALint GetByteOffset(ALsource *pSource)
1978 ALbuffer *pBuffer = NULL;
1979 ALbufferlistitem *pBufferList;
1980 ALfloat flBufferFreq;
1981 ALint lChannels;
1982 ALint lByteOffset = -1;
1983 ALint lTotalBufferDataSize;
1985 // Find the first non-NULL Buffer in the Queue
1986 pBufferList = pSource->queue;
1987 while (pBufferList)
1989 if (pBufferList->buffer)
1991 pBuffer = pBufferList->buffer;
1992 break;
1994 pBufferList = pBufferList->next;
1997 if (pBuffer)
1999 flBufferFreq = ((ALfloat)pBuffer->frequency);
2000 lChannels = aluChannelsFromFormat(pBuffer->format);
2002 // Determine the ByteOffset (and ensure it is block aligned)
2003 switch (pSource->lOffsetType)
2005 case AL_BYTE_OFFSET:
2006 // Take into consideration the original format
2007 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2008 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2010 // Round down to nearest ADPCM block
2011 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2012 // Multiply by compression rate
2013 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2014 lByteOffset -= (lByteOffset % (lChannels * 2));
2016 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2018 lByteOffset = pSource->lOffset * 4;
2019 lByteOffset -= (lByteOffset % (lChannels * 2));
2021 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2023 lByteOffset = pSource->lOffset * 2;
2024 lByteOffset -= (lByteOffset % (lChannels * 2));
2026 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2028 lByteOffset = pSource->lOffset * 2;
2029 lByteOffset -= (lByteOffset % (lChannels * 2));
2031 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2033 lByteOffset = pSource->lOffset / 2;
2034 lByteOffset -= (lByteOffset % (lChannels * 2));
2036 else
2038 lByteOffset = pSource->lOffset;
2039 lByteOffset -= (lByteOffset % (lChannels * 2));
2041 break;
2043 case AL_SAMPLE_OFFSET:
2044 lByteOffset = pSource->lOffset * lChannels * 2;
2045 break;
2047 case AL_SEC_OFFSET:
2048 // Note - lOffset is internally stored as Milliseconds
2049 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2050 lByteOffset -= (lByteOffset % (lChannels * 2));
2051 break;
2054 lTotalBufferDataSize = 0;
2055 pBufferList = pSource->queue;
2056 while (pBufferList)
2058 if (pBufferList->buffer)
2059 lTotalBufferDataSize += pBufferList->buffer->size;
2060 pBufferList = pBufferList->next;
2063 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2064 if (lByteOffset >= lTotalBufferDataSize)
2065 lByteOffset = -1;
2068 return lByteOffset;
2072 ALvoid ReleaseALSources(ALCcontext *Context)
2074 ALuint j;
2076 while(Context->Source)
2078 ALsource *temp = Context->Source;
2079 Context->Source = temp->next;
2081 // For each buffer in the source's queue, decrement its reference counter and remove it
2082 while(temp->queue != NULL)
2084 ALbufferlistitem *ALBufferList = temp->queue;
2085 // Decrement buffer's reference counter
2086 if(ALBufferList->buffer != NULL)
2087 ALBufferList->buffer->refcount--;
2088 // Update queue to point to next element in list
2089 temp->queue = ALBufferList->next;
2090 // Release memory allocated for buffer list item
2091 free(ALBufferList);
2094 for(j = 0;j < MAX_SENDS;++j)
2096 if(temp->Send[j].Slot)
2097 temp->Send[j].Slot->refcount--;
2100 // Release source structure
2101 ALTHUNK_REMOVEENTRY(temp->source);
2102 memset(temp, 0, sizeof(ALsource));
2103 free(temp);
2105 Context->SourceCount = 0;