Implement AL_SOFT_buffer_sub_data using the current AL_EXT_buffer_sub_data spec
[openal-soft.git] / OpenAL32 / alSource.c
blobc9051793e016f5d036f1b3d195414d72ec115a56
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <math.h>
25 #include <float.h>
26 #include "alMain.h"
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alError.h"
30 #include "alSource.h"
31 #include "alBuffer.h"
32 #include "alThunk.h"
33 #include "alAuxEffectSlot.h"
35 static ALvoid InitSourceParams(ALsource *Source);
36 static ALvoid GetSourceOffset(ALsource *Source, ALenum eName, ALdouble *Offsets, ALdouble updateLen);
37 static ALboolean ApplyOffset(ALsource *Source);
38 static ALint GetByteOffset(ALsource *Source);
39 static ALint FramesFromBytes(ALint offset, ALenum format, ALint channels);
41 #define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k)))
42 #define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
43 #define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
44 #define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
46 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources)
48 ALCcontext *Context;
49 ALCdevice *Device;
50 ALsizei i=0;
52 Context = GetContextSuspended();
53 if(!Context) return;
55 if(n < 0)
56 alSetError(Context, AL_INVALID_VALUE);
57 else
59 Device = Context->Device;
61 // Check that enough memory has been allocted in the 'sources' array for n Sources
62 if(!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
64 // Check that the requested number of sources can be generated
65 if((Context->SourceMap.size + n) <= (ALsizei)Device->MaxNoOfSources)
67 ALenum err;
69 // Add additional sources to the list
70 while(i < n)
72 ALsource *source = calloc(1, sizeof(ALsource));
73 if(!source)
75 alSetError(Context, AL_OUT_OF_MEMORY);
76 alDeleteSources(i, sources);
77 break;
80 source->source = (ALuint)ALTHUNK_ADDENTRY(source);
81 err = InsertUIntMapEntry(&Context->SourceMap, source->source,
82 source);
83 if(err != AL_NO_ERROR)
85 ALTHUNK_REMOVEENTRY(source->source);
86 memset(source, 0, sizeof(ALsource));
87 free(source);
89 alSetError(Context, err);
90 alDeleteSources(i, sources);
91 break;
94 sources[i++] = source->source;
95 InitSourceParams(source);
98 else
100 // Not enough resources to create the Sources
101 alSetError(Context, AL_INVALID_VALUE);
104 else
106 // Bad pointer
107 alSetError(Context, AL_INVALID_VALUE);
111 ProcessContext(Context);
115 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
117 ALCcontext *Context;
118 ALCdevice *Device;
119 ALsource *Source;
120 ALsizei i, j;
121 ALbufferlistitem *BufferList;
122 ALboolean bSourcesValid = AL_TRUE;
124 Context = GetContextSuspended();
125 if(!Context) return;
127 if(n < 0)
128 alSetError(Context, AL_INVALID_VALUE);
129 else
131 Device = Context->Device;
133 // Check that all Sources are valid (and can therefore be deleted)
134 for(i = 0;i < n;i++)
136 if(LookupSource(Context->SourceMap, sources[i]) == NULL)
138 alSetError(Context, AL_INVALID_NAME);
139 bSourcesValid = AL_FALSE;
140 break;
144 if(bSourcesValid)
146 // All Sources are valid, and can be deleted
147 for(i = 0;i < n;i++)
149 // Recheck that the Source is valid, because there could be duplicated Source names
150 if((Source=LookupSource(Context->SourceMap, sources[i])) != NULL)
152 for(j = 0;j < Context->ActiveSourceCount;j++)
154 if(Context->ActiveSources[j] == Source)
156 ALsizei end = --(Context->ActiveSourceCount);
157 Context->ActiveSources[j] = Context->ActiveSources[end];
158 break;
162 // For each buffer in the source's queue, decrement its reference counter and remove it
163 while(Source->queue != NULL)
165 BufferList = Source->queue;
166 // Decrement buffer's reference counter
167 if(BufferList->buffer != NULL)
168 BufferList->buffer->refcount--;
169 // Update queue to point to next element in list
170 Source->queue = BufferList->next;
171 // Release memory allocated for buffer list item
172 free(BufferList);
175 for(j = 0;j < MAX_SENDS;++j)
177 if(Source->Send[j].Slot)
178 Source->Send[j].Slot->refcount--;
179 Source->Send[j].Slot = NULL;
182 // Remove Source from list of Sources
183 RemoveUIntMapKey(&Context->SourceMap, Source->source);
184 ALTHUNK_REMOVEENTRY(Source->source);
186 memset(Source,0,sizeof(ALsource));
187 free(Source);
193 ProcessContext(Context);
197 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
199 ALCcontext *Context;
200 ALboolean result;
202 Context = GetContextSuspended();
203 if(!Context) return AL_FALSE;
205 result = (LookupSource(Context->SourceMap, source) ? AL_TRUE : AL_FALSE);
207 ProcessContext(Context);
209 return result;
213 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
215 ALCcontext *pContext;
216 ALsource *Source;
218 pContext = GetContextSuspended();
219 if(!pContext) return;
221 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
223 switch(eParam)
225 case AL_PITCH:
226 if(flValue >= 0.0f)
228 Source->flPitch = flValue;
229 if(Source->flPitch < 0.001f)
230 Source->flPitch = 0.001f;
231 Source->NeedsUpdate = AL_TRUE;
233 else
234 alSetError(pContext, AL_INVALID_VALUE);
235 break;
237 case AL_CONE_INNER_ANGLE:
238 if(flValue >= 0.0f && flValue <= 360.0f)
240 Source->flInnerAngle = flValue;
241 Source->NeedsUpdate = AL_TRUE;
243 else
244 alSetError(pContext, AL_INVALID_VALUE);
245 break;
247 case AL_CONE_OUTER_ANGLE:
248 if(flValue >= 0.0f && flValue <= 360.0f)
250 Source->flOuterAngle = flValue;
251 Source->NeedsUpdate = AL_TRUE;
253 else
254 alSetError(pContext, AL_INVALID_VALUE);
255 break;
257 case AL_GAIN:
258 if(flValue >= 0.0f)
260 Source->flGain = flValue;
261 Source->NeedsUpdate = AL_TRUE;
263 else
264 alSetError(pContext, AL_INVALID_VALUE);
265 break;
267 case AL_MAX_DISTANCE:
268 if(flValue >= 0.0f)
270 Source->flMaxDistance = flValue;
271 Source->NeedsUpdate = AL_TRUE;
273 else
274 alSetError(pContext, AL_INVALID_VALUE);
275 break;
277 case AL_ROLLOFF_FACTOR:
278 if(flValue >= 0.0f)
280 Source->flRollOffFactor = flValue;
281 Source->NeedsUpdate = AL_TRUE;
283 else
284 alSetError(pContext, AL_INVALID_VALUE);
285 break;
287 case AL_REFERENCE_DISTANCE:
288 if(flValue >= 0.0f)
290 Source->flRefDistance = flValue;
291 Source->NeedsUpdate = AL_TRUE;
293 else
294 alSetError(pContext, AL_INVALID_VALUE);
295 break;
297 case AL_MIN_GAIN:
298 if(flValue >= 0.0f && flValue <= 1.0f)
300 Source->flMinGain = flValue;
301 Source->NeedsUpdate = AL_TRUE;
303 else
304 alSetError(pContext, AL_INVALID_VALUE);
305 break;
307 case AL_MAX_GAIN:
308 if(flValue >= 0.0f && flValue <= 1.0f)
310 Source->flMaxGain = flValue;
311 Source->NeedsUpdate = AL_TRUE;
313 else
314 alSetError(pContext, AL_INVALID_VALUE);
315 break;
317 case AL_CONE_OUTER_GAIN:
318 if(flValue >= 0.0f && flValue <= 1.0f)
320 Source->flOuterGain = flValue;
321 Source->NeedsUpdate = AL_TRUE;
323 else
324 alSetError(pContext, AL_INVALID_VALUE);
325 break;
327 case AL_CONE_OUTER_GAINHF:
328 if(flValue >= 0.0f && flValue <= 1.0f)
330 Source->OuterGainHF = flValue;
331 Source->NeedsUpdate = AL_TRUE;
333 else
334 alSetError(pContext, AL_INVALID_VALUE);
335 break;
337 case AL_AIR_ABSORPTION_FACTOR:
338 if(flValue >= 0.0f && flValue <= 10.0f)
340 Source->AirAbsorptionFactor = flValue;
341 Source->NeedsUpdate = AL_TRUE;
343 else
344 alSetError(pContext, AL_INVALID_VALUE);
345 break;
347 case AL_ROOM_ROLLOFF_FACTOR:
348 if(flValue >= 0.0f && flValue <= 10.0f)
350 Source->RoomRolloffFactor = flValue;
351 Source->NeedsUpdate = AL_TRUE;
353 else
354 alSetError(pContext, AL_INVALID_VALUE);
355 break;
357 case AL_DOPPLER_FACTOR:
358 if(flValue >= 0.0f && flValue <= 1.0f)
360 Source->DopplerFactor = flValue;
361 Source->NeedsUpdate = AL_TRUE;
363 else
364 alSetError(pContext, AL_INVALID_VALUE);
365 break;
367 case AL_SEC_OFFSET:
368 case AL_SAMPLE_OFFSET:
369 case AL_BYTE_OFFSET:
370 if(flValue >= 0.0f)
372 Source->lOffsetType = eParam;
374 // Store Offset (convert Seconds into Milliseconds)
375 if(eParam == AL_SEC_OFFSET)
376 Source->lOffset = (ALint)(flValue * 1000.0f);
377 else
378 Source->lOffset = (ALint)flValue;
380 if ((Source->state == AL_PLAYING) || (Source->state == AL_PAUSED))
382 if(ApplyOffset(Source) == AL_FALSE)
383 alSetError(pContext, AL_INVALID_VALUE);
386 else
387 alSetError(pContext, AL_INVALID_VALUE);
388 break;
390 default:
391 alSetError(pContext, AL_INVALID_ENUM);
392 break;
395 else
397 // Invalid Source Name
398 alSetError(pContext, AL_INVALID_NAME);
401 ProcessContext(pContext);
405 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
407 ALCcontext *pContext;
408 ALsource *Source;
410 pContext = GetContextSuspended();
411 if(!pContext) return;
413 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
415 switch(eParam)
417 case AL_POSITION:
418 Source->vPosition[0] = flValue1;
419 Source->vPosition[1] = flValue2;
420 Source->vPosition[2] = flValue3;
421 Source->NeedsUpdate = AL_TRUE;
422 break;
424 case AL_VELOCITY:
425 Source->vVelocity[0] = flValue1;
426 Source->vVelocity[1] = flValue2;
427 Source->vVelocity[2] = flValue3;
428 Source->NeedsUpdate = AL_TRUE;
429 break;
431 case AL_DIRECTION:
432 Source->vOrientation[0] = flValue1;
433 Source->vOrientation[1] = flValue2;
434 Source->vOrientation[2] = flValue3;
435 Source->NeedsUpdate = AL_TRUE;
436 break;
438 default:
439 alSetError(pContext, AL_INVALID_ENUM);
440 break;
443 else
444 alSetError(pContext, AL_INVALID_NAME);
446 ProcessContext(pContext);
450 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
452 ALCcontext *pContext;
454 pContext = GetContextSuspended();
455 if(!pContext) return;
457 if(pflValues)
459 if(LookupSource(pContext->SourceMap, source) != NULL)
461 switch(eParam)
463 case AL_PITCH:
464 case AL_CONE_INNER_ANGLE:
465 case AL_CONE_OUTER_ANGLE:
466 case AL_GAIN:
467 case AL_MAX_DISTANCE:
468 case AL_ROLLOFF_FACTOR:
469 case AL_REFERENCE_DISTANCE:
470 case AL_MIN_GAIN:
471 case AL_MAX_GAIN:
472 case AL_CONE_OUTER_GAIN:
473 case AL_CONE_OUTER_GAINHF:
474 case AL_SEC_OFFSET:
475 case AL_SAMPLE_OFFSET:
476 case AL_BYTE_OFFSET:
477 case AL_AIR_ABSORPTION_FACTOR:
478 case AL_ROOM_ROLLOFF_FACTOR:
479 alSourcef(source, eParam, pflValues[0]);
480 break;
482 case AL_POSITION:
483 case AL_VELOCITY:
484 case AL_DIRECTION:
485 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
486 break;
488 default:
489 alSetError(pContext, AL_INVALID_ENUM);
490 break;
493 else
494 alSetError(pContext, AL_INVALID_NAME);
496 else
497 alSetError(pContext, AL_INVALID_VALUE);
499 ProcessContext(pContext);
503 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
505 ALCcontext *pContext;
506 ALsource *Source;
507 ALbufferlistitem *BufferListItem;
509 pContext = GetContextSuspended();
510 if(!pContext) return;
512 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
514 ALCdevice *device = pContext->Device;
516 switch(eParam)
518 case AL_MAX_DISTANCE:
519 case AL_ROLLOFF_FACTOR:
520 case AL_CONE_INNER_ANGLE:
521 case AL_CONE_OUTER_ANGLE:
522 case AL_REFERENCE_DISTANCE:
523 alSourcef(source, eParam, (ALfloat)lValue);
524 break;
526 case AL_SOURCE_RELATIVE:
527 if(lValue == AL_FALSE || lValue == AL_TRUE)
529 Source->bHeadRelative = (ALboolean)lValue;
530 Source->NeedsUpdate = AL_TRUE;
532 else
533 alSetError(pContext, AL_INVALID_VALUE);
534 break;
536 case AL_LOOPING:
537 if(lValue == AL_FALSE || lValue == AL_TRUE)
538 Source->bLooping = (ALboolean)lValue;
539 else
540 alSetError(pContext, AL_INVALID_VALUE);
541 break;
543 case AL_BUFFER:
544 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
546 ALbuffer *buffer = NULL;
548 if(lValue == 0 ||
549 (buffer=LookupBuffer(device->BufferMap, lValue)) != NULL)
551 // Remove all elements in the queue
552 while(Source->queue != NULL)
554 BufferListItem = Source->queue;
555 Source->queue = BufferListItem->next;
556 // Decrement reference counter for buffer
557 if(BufferListItem->buffer)
558 BufferListItem->buffer->refcount--;
559 // Release memory for buffer list item
560 free(BufferListItem);
561 // Decrement the number of buffers in the queue
562 Source->BuffersInQueue--;
565 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
566 if(lValue != 0)
568 // Source is now in STATIC mode
569 Source->lSourceType = AL_STATIC;
571 // Add the selected buffer to the queue
572 BufferListItem = malloc(sizeof(ALbufferlistitem));
573 BufferListItem->buffer = buffer;
574 BufferListItem->next = NULL;
576 Source->queue = BufferListItem;
577 Source->BuffersInQueue = 1;
579 if(aluChannelsFromFormat(buffer->format) == 1)
580 Source->Update = CalcSourceParams;
581 else
582 Source->Update = CalcNonAttnSourceParams;
584 // Increment reference counter for buffer
585 buffer->refcount++;
587 else
589 // Source is now in UNDETERMINED mode
590 Source->lSourceType = AL_UNDETERMINED;
592 Source->BuffersPlayed = 0;
594 // Update AL_BUFFER parameter
595 Source->Buffer = buffer;
596 Source->NeedsUpdate = AL_TRUE;
598 else
599 alSetError(pContext, AL_INVALID_VALUE);
601 else
602 alSetError(pContext, AL_INVALID_OPERATION);
603 break;
605 case AL_SOURCE_STATE:
606 // Query only
607 alSetError(pContext, AL_INVALID_OPERATION);
608 break;
610 case AL_SEC_OFFSET:
611 case AL_SAMPLE_OFFSET:
612 case AL_BYTE_OFFSET:
613 if(lValue >= 0)
615 Source->lOffsetType = eParam;
617 // Store Offset (convert Seconds into Milliseconds)
618 if(eParam == AL_SEC_OFFSET)
619 Source->lOffset = lValue * 1000;
620 else
621 Source->lOffset = lValue;
623 if(Source->state == AL_PLAYING || Source->state == AL_PAUSED)
625 if(ApplyOffset(Source) == AL_FALSE)
626 alSetError(pContext, AL_INVALID_VALUE);
629 else
630 alSetError(pContext, AL_INVALID_VALUE);
631 break;
633 case AL_DIRECT_FILTER: {
634 ALfilter *filter = NULL;
636 if(lValue == 0 ||
637 (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL)
639 if(!filter)
641 Source->DirectFilter.type = AL_FILTER_NULL;
642 Source->DirectFilter.filter = 0;
644 else
645 memcpy(&Source->DirectFilter, filter, sizeof(*filter));
646 Source->NeedsUpdate = AL_TRUE;
648 else
649 alSetError(pContext, AL_INVALID_VALUE);
650 } break;
652 case AL_DIRECT_FILTER_GAINHF_AUTO:
653 if(lValue == AL_TRUE || lValue == AL_FALSE)
655 Source->DryGainHFAuto = lValue;
656 Source->NeedsUpdate = AL_TRUE;
658 else
659 alSetError(pContext, AL_INVALID_VALUE);
660 break;
662 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
663 if(lValue == AL_TRUE || lValue == AL_FALSE)
665 Source->WetGainAuto = lValue;
666 Source->NeedsUpdate = AL_TRUE;
668 else
669 alSetError(pContext, AL_INVALID_VALUE);
670 break;
672 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
673 if(lValue == AL_TRUE || lValue == AL_FALSE)
675 Source->WetGainHFAuto = lValue;
676 Source->NeedsUpdate = AL_TRUE;
678 else
679 alSetError(pContext, AL_INVALID_VALUE);
680 break;
682 case AL_DISTANCE_MODEL:
683 if(lValue == AL_NONE ||
684 lValue == AL_INVERSE_DISTANCE ||
685 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
686 lValue == AL_LINEAR_DISTANCE ||
687 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
688 lValue == AL_EXPONENT_DISTANCE ||
689 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
691 Source->DistanceModel = lValue;
692 if(pContext->SourceDistanceModel)
693 Source->NeedsUpdate = AL_TRUE;
695 else
696 alSetError(pContext, AL_INVALID_VALUE);
697 break;
699 default:
700 alSetError(pContext, AL_INVALID_ENUM);
701 break;
704 else
705 alSetError(pContext, AL_INVALID_NAME);
707 ProcessContext(pContext);
711 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
713 ALCcontext *pContext;
714 ALsource *Source;
716 pContext = GetContextSuspended();
717 if(!pContext) return;
719 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
721 ALCdevice *device = pContext->Device;
723 switch (eParam)
725 case AL_POSITION:
726 case AL_VELOCITY:
727 case AL_DIRECTION:
728 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
729 break;
731 case AL_AUXILIARY_SEND_FILTER: {
732 ALeffectslot *ALEffectSlot = NULL;
733 ALfilter *ALFilter = NULL;
735 if((ALuint)lValue2 < device->NumAuxSends &&
736 (lValue1 == 0 ||
737 (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
738 (lValue3 == 0 ||
739 (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL))
741 /* Release refcount on the previous slot, and add one for
742 * the new slot */
743 if(Source->Send[lValue2].Slot)
744 Source->Send[lValue2].Slot->refcount--;
745 Source->Send[lValue2].Slot = ALEffectSlot;
746 if(Source->Send[lValue2].Slot)
747 Source->Send[lValue2].Slot->refcount++;
749 if(!ALFilter)
751 /* Disable filter */
752 Source->Send[lValue2].WetFilter.type = 0;
753 Source->Send[lValue2].WetFilter.filter = 0;
755 else
756 memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
757 Source->NeedsUpdate = AL_TRUE;
759 else
760 alSetError(pContext, AL_INVALID_VALUE);
761 } break;
763 default:
764 alSetError(pContext, AL_INVALID_ENUM);
765 break;
768 else
769 alSetError(pContext, AL_INVALID_NAME);
771 ProcessContext(pContext);
775 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
777 ALCcontext *pContext;
779 pContext = GetContextSuspended();
780 if(!pContext) return;
782 if(plValues)
784 if(LookupSource(pContext->SourceMap, source) != NULL)
786 switch(eParam)
788 case AL_SOURCE_RELATIVE:
789 case AL_CONE_INNER_ANGLE:
790 case AL_CONE_OUTER_ANGLE:
791 case AL_LOOPING:
792 case AL_BUFFER:
793 case AL_SOURCE_STATE:
794 case AL_SEC_OFFSET:
795 case AL_SAMPLE_OFFSET:
796 case AL_BYTE_OFFSET:
797 case AL_MAX_DISTANCE:
798 case AL_ROLLOFF_FACTOR:
799 case AL_REFERENCE_DISTANCE:
800 case AL_DIRECT_FILTER:
801 case AL_DIRECT_FILTER_GAINHF_AUTO:
802 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
803 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
804 case AL_DISTANCE_MODEL:
805 alSourcei(source, eParam, plValues[0]);
806 break;
808 case AL_POSITION:
809 case AL_VELOCITY:
810 case AL_DIRECTION:
811 case AL_AUXILIARY_SEND_FILTER:
812 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
813 break;
815 default:
816 alSetError(pContext, AL_INVALID_ENUM);
817 break;
820 else
821 alSetError(pContext, AL_INVALID_NAME);
823 else
824 alSetError(pContext, AL_INVALID_VALUE);
826 ProcessContext(pContext);
830 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
832 ALCcontext *pContext;
833 ALsource *Source;
834 ALdouble Offsets[2];
835 ALdouble updateLen;
837 pContext = GetContextSuspended();
838 if(!pContext) return;
840 if(pflValue)
842 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
844 switch(eParam)
846 case AL_PITCH:
847 *pflValue = Source->flPitch;
848 break;
850 case AL_GAIN:
851 *pflValue = Source->flGain;
852 break;
854 case AL_MIN_GAIN:
855 *pflValue = Source->flMinGain;
856 break;
858 case AL_MAX_GAIN:
859 *pflValue = Source->flMaxGain;
860 break;
862 case AL_MAX_DISTANCE:
863 *pflValue = Source->flMaxDistance;
864 break;
866 case AL_ROLLOFF_FACTOR:
867 *pflValue = Source->flRollOffFactor;
868 break;
870 case AL_CONE_OUTER_GAIN:
871 *pflValue = Source->flOuterGain;
872 break;
874 case AL_CONE_OUTER_GAINHF:
875 *pflValue = Source->OuterGainHF;
876 break;
878 case AL_SEC_OFFSET:
879 case AL_SAMPLE_OFFSET:
880 case AL_BYTE_OFFSET:
881 updateLen = (ALdouble)pContext->Device->UpdateSize /
882 pContext->Device->Frequency;
883 GetSourceOffset(Source, eParam, Offsets, updateLen);
884 *pflValue = Offsets[0];
885 break;
887 case AL_CONE_INNER_ANGLE:
888 *pflValue = Source->flInnerAngle;
889 break;
891 case AL_CONE_OUTER_ANGLE:
892 *pflValue = Source->flOuterAngle;
893 break;
895 case AL_REFERENCE_DISTANCE:
896 *pflValue = Source->flRefDistance;
897 break;
899 case AL_AIR_ABSORPTION_FACTOR:
900 *pflValue = Source->AirAbsorptionFactor;
901 break;
903 case AL_ROOM_ROLLOFF_FACTOR:
904 *pflValue = Source->RoomRolloffFactor;
905 break;
907 case AL_DOPPLER_FACTOR:
908 *pflValue = Source->DopplerFactor;
909 break;
911 default:
912 alSetError(pContext, AL_INVALID_ENUM);
913 break;
916 else
917 alSetError(pContext, AL_INVALID_NAME);
919 else
920 alSetError(pContext, AL_INVALID_VALUE);
922 ProcessContext(pContext);
926 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
928 ALCcontext *pContext;
929 ALsource *Source;
931 pContext = GetContextSuspended();
932 if(!pContext) return;
934 if(pflValue1 && pflValue2 && pflValue3)
936 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
938 switch(eParam)
940 case AL_POSITION:
941 *pflValue1 = Source->vPosition[0];
942 *pflValue2 = Source->vPosition[1];
943 *pflValue3 = Source->vPosition[2];
944 break;
946 case AL_VELOCITY:
947 *pflValue1 = Source->vVelocity[0];
948 *pflValue2 = Source->vVelocity[1];
949 *pflValue3 = Source->vVelocity[2];
950 break;
952 case AL_DIRECTION:
953 *pflValue1 = Source->vOrientation[0];
954 *pflValue2 = Source->vOrientation[1];
955 *pflValue3 = Source->vOrientation[2];
956 break;
958 default:
959 alSetError(pContext, AL_INVALID_ENUM);
960 break;
963 else
964 alSetError(pContext, AL_INVALID_NAME);
966 else
967 alSetError(pContext, AL_INVALID_VALUE);
969 ProcessContext(pContext);
973 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
975 ALCcontext *pContext;
976 ALsource *Source;
977 ALdouble Offsets[2];
978 ALdouble updateLen;
980 pContext = GetContextSuspended();
981 if(!pContext) return;
983 if(pflValues)
985 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
987 switch(eParam)
989 case AL_PITCH:
990 case AL_GAIN:
991 case AL_MIN_GAIN:
992 case AL_MAX_GAIN:
993 case AL_MAX_DISTANCE:
994 case AL_ROLLOFF_FACTOR:
995 case AL_DOPPLER_FACTOR:
996 case AL_CONE_OUTER_GAIN:
997 case AL_SEC_OFFSET:
998 case AL_SAMPLE_OFFSET:
999 case AL_BYTE_OFFSET:
1000 case AL_CONE_INNER_ANGLE:
1001 case AL_CONE_OUTER_ANGLE:
1002 case AL_REFERENCE_DISTANCE:
1003 case AL_CONE_OUTER_GAINHF:
1004 case AL_AIR_ABSORPTION_FACTOR:
1005 case AL_ROOM_ROLLOFF_FACTOR:
1006 alGetSourcef(source, eParam, pflValues);
1007 break;
1009 case AL_POSITION:
1010 case AL_VELOCITY:
1011 case AL_DIRECTION:
1012 alGetSource3f(source, eParam, pflValues+0, pflValues+1, pflValues+2);
1013 break;
1015 case AL_SAMPLE_RW_OFFSETS_SOFT:
1016 case AL_BYTE_RW_OFFSETS_SOFT:
1017 updateLen = (ALdouble)pContext->Device->UpdateSize /
1018 pContext->Device->Frequency;
1019 GetSourceOffset(Source, eParam, Offsets, updateLen);
1020 pflValues[0] = Offsets[0];
1021 pflValues[1] = Offsets[1];
1022 break;
1024 default:
1025 alSetError(pContext, AL_INVALID_ENUM);
1026 break;
1029 else
1030 alSetError(pContext, AL_INVALID_NAME);
1032 else
1033 alSetError(pContext, AL_INVALID_VALUE);
1035 ProcessContext(pContext);
1039 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1041 ALCcontext *pContext;
1042 ALsource *Source;
1043 ALdouble Offsets[2];
1044 ALdouble updateLen;
1046 pContext = GetContextSuspended();
1047 if(!pContext) return;
1049 if(plValue)
1051 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1053 switch(eParam)
1055 case AL_MAX_DISTANCE:
1056 *plValue = (ALint)Source->flMaxDistance;
1057 break;
1059 case AL_ROLLOFF_FACTOR:
1060 *plValue = (ALint)Source->flRollOffFactor;
1061 break;
1063 case AL_REFERENCE_DISTANCE:
1064 *plValue = (ALint)Source->flRefDistance;
1065 break;
1067 case AL_SOURCE_RELATIVE:
1068 *plValue = Source->bHeadRelative;
1069 break;
1071 case AL_CONE_INNER_ANGLE:
1072 *plValue = (ALint)Source->flInnerAngle;
1073 break;
1075 case AL_CONE_OUTER_ANGLE:
1076 *plValue = (ALint)Source->flOuterAngle;
1077 break;
1079 case AL_LOOPING:
1080 *plValue = Source->bLooping;
1081 break;
1083 case AL_BUFFER:
1084 *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
1085 break;
1087 case AL_SOURCE_STATE:
1088 *plValue = Source->state;
1089 break;
1091 case AL_BUFFERS_QUEUED:
1092 *plValue = Source->BuffersInQueue;
1093 break;
1095 case AL_BUFFERS_PROCESSED:
1096 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1098 /* Buffers on a looping source are in a perpetual state
1099 * of PENDING, so don't report any as PROCESSED */
1100 *plValue = 0;
1102 else
1103 *plValue = Source->BuffersPlayed;
1104 break;
1106 case AL_SOURCE_TYPE:
1107 *plValue = Source->lSourceType;
1108 break;
1110 case AL_SEC_OFFSET:
1111 case AL_SAMPLE_OFFSET:
1112 case AL_BYTE_OFFSET:
1113 updateLen = (ALdouble)pContext->Device->UpdateSize /
1114 pContext->Device->Frequency;
1115 GetSourceOffset(Source, eParam, Offsets, updateLen);
1116 *plValue = (ALint)Offsets[0];
1117 break;
1119 case AL_DIRECT_FILTER:
1120 *plValue = Source->DirectFilter.filter;
1121 break;
1123 case AL_DIRECT_FILTER_GAINHF_AUTO:
1124 *plValue = Source->DryGainHFAuto;
1125 break;
1127 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1128 *plValue = Source->WetGainAuto;
1129 break;
1131 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1132 *plValue = Source->WetGainHFAuto;
1133 break;
1135 case AL_DOPPLER_FACTOR:
1136 *plValue = (ALint)Source->DopplerFactor;
1137 break;
1139 case AL_DISTANCE_MODEL:
1140 *plValue = Source->DistanceModel;
1141 break;
1143 default:
1144 alSetError(pContext, AL_INVALID_ENUM);
1145 break;
1148 else
1149 alSetError(pContext, AL_INVALID_NAME);
1151 else
1152 alSetError(pContext, AL_INVALID_VALUE);
1154 ProcessContext(pContext);
1158 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1160 ALCcontext *pContext;
1161 ALsource *Source;
1163 pContext = GetContextSuspended();
1164 if(!pContext) return;
1166 if(plValue1 && plValue2 && plValue3)
1168 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1170 switch(eParam)
1172 case AL_POSITION:
1173 *plValue1 = (ALint)Source->vPosition[0];
1174 *plValue2 = (ALint)Source->vPosition[1];
1175 *plValue3 = (ALint)Source->vPosition[2];
1176 break;
1178 case AL_VELOCITY:
1179 *plValue1 = (ALint)Source->vVelocity[0];
1180 *plValue2 = (ALint)Source->vVelocity[1];
1181 *plValue3 = (ALint)Source->vVelocity[2];
1182 break;
1184 case AL_DIRECTION:
1185 *plValue1 = (ALint)Source->vOrientation[0];
1186 *plValue2 = (ALint)Source->vOrientation[1];
1187 *plValue3 = (ALint)Source->vOrientation[2];
1188 break;
1190 default:
1191 alSetError(pContext, AL_INVALID_ENUM);
1192 break;
1195 else
1196 alSetError(pContext, AL_INVALID_NAME);
1198 else
1199 alSetError(pContext, AL_INVALID_VALUE);
1201 ProcessContext(pContext);
1205 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1207 ALCcontext *pContext;
1208 ALsource *Source;
1209 ALdouble Offsets[2];
1210 ALdouble updateLen;
1212 pContext = GetContextSuspended();
1213 if(!pContext) return;
1215 if(plValues)
1217 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1219 switch(eParam)
1221 case AL_SOURCE_RELATIVE:
1222 case AL_CONE_INNER_ANGLE:
1223 case AL_CONE_OUTER_ANGLE:
1224 case AL_LOOPING:
1225 case AL_BUFFER:
1226 case AL_SOURCE_STATE:
1227 case AL_BUFFERS_QUEUED:
1228 case AL_BUFFERS_PROCESSED:
1229 case AL_SEC_OFFSET:
1230 case AL_SAMPLE_OFFSET:
1231 case AL_BYTE_OFFSET:
1232 case AL_MAX_DISTANCE:
1233 case AL_ROLLOFF_FACTOR:
1234 case AL_DOPPLER_FACTOR:
1235 case AL_REFERENCE_DISTANCE:
1236 case AL_SOURCE_TYPE:
1237 case AL_DIRECT_FILTER:
1238 case AL_DIRECT_FILTER_GAINHF_AUTO:
1239 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1240 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1241 case AL_DISTANCE_MODEL:
1242 alGetSourcei(source, eParam, plValues);
1243 break;
1245 case AL_POSITION:
1246 case AL_VELOCITY:
1247 case AL_DIRECTION:
1248 alGetSource3i(source, eParam, plValues+0, plValues+1, plValues+2);
1249 break;
1251 case AL_SAMPLE_RW_OFFSETS_SOFT:
1252 case AL_BYTE_RW_OFFSETS_SOFT:
1253 updateLen = (ALdouble)pContext->Device->UpdateSize /
1254 pContext->Device->Frequency;
1255 GetSourceOffset(Source, eParam, Offsets, updateLen);
1256 plValues[0] = (ALint)Offsets[0];
1257 plValues[1] = (ALint)Offsets[1];
1258 break;
1260 default:
1261 alSetError(pContext, AL_INVALID_ENUM);
1262 break;
1265 else
1266 alSetError(pContext, AL_INVALID_NAME);
1268 else
1269 alSetError(pContext, AL_INVALID_VALUE);
1271 ProcessContext(pContext);
1275 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1277 alSourcePlayv(1, &source);
1280 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1282 ALCcontext *Context;
1283 ALsource *Source;
1284 ALbufferlistitem *BufferList;
1285 ALsizei i, j;
1287 Context = GetContextSuspended();
1288 if(!Context) return;
1290 if(n < 0)
1292 alSetError(Context, AL_INVALID_VALUE);
1293 goto done;
1295 if(n > 0 && !sources)
1297 alSetError(Context, AL_INVALID_VALUE);
1298 goto done;
1301 // Check that all the Sources are valid
1302 for(i = 0;i < n;i++)
1304 if(!LookupSource(Context->SourceMap, sources[i]))
1306 alSetError(Context, AL_INVALID_NAME);
1307 goto done;
1311 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1313 void *temp = NULL;
1314 ALsizei newcount;
1316 newcount = Context->MaxActiveSources << 1;
1317 if(newcount > 0)
1318 temp = realloc(Context->ActiveSources,
1319 sizeof(*Context->ActiveSources) * newcount);
1320 if(!temp)
1322 alSetError(Context, AL_OUT_OF_MEMORY);
1323 goto done;
1326 Context->ActiveSources = temp;
1327 Context->MaxActiveSources = newcount;
1330 for(i = 0;i < n;i++)
1332 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1334 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1335 BufferList = Source->queue;
1336 while(BufferList)
1338 if(BufferList->buffer != NULL && BufferList->buffer->size)
1339 break;
1340 BufferList = BufferList->next;
1343 if(!BufferList)
1345 Source->BuffersPlayed = Source->BuffersInQueue;
1346 continue;
1349 if(Source->state != AL_PAUSED)
1351 Source->state = AL_PLAYING;
1352 Source->position = 0;
1353 Source->position_fraction = 0;
1354 Source->BuffersPlayed = 0;
1356 Source->Buffer = Source->queue->buffer;
1358 else
1359 Source->state = AL_PLAYING;
1361 // Check if an Offset has been set
1362 if(Source->lOffset)
1363 ApplyOffset(Source);
1365 // If device is disconnected, go right to stopped
1366 if(!Context->Device->Connected)
1368 Source->state = AL_STOPPED;
1369 Source->BuffersPlayed = Source->BuffersInQueue;
1370 Source->position = 0;
1371 Source->position_fraction = 0;
1373 else
1375 for(j = 0;j < Context->ActiveSourceCount;j++)
1377 if(Context->ActiveSources[j] == Source)
1378 break;
1380 if(j == Context->ActiveSourceCount)
1381 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1385 done:
1386 ProcessContext(Context);
1389 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1391 alSourcePausev(1, &source);
1394 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1396 ALCcontext *Context;
1397 ALsource *Source;
1398 ALsizei i;
1400 Context = GetContextSuspended();
1401 if(!Context) return;
1403 if(n < 0)
1405 alSetError(Context, AL_INVALID_VALUE);
1406 goto done;
1408 if(n > 0 && !sources)
1410 alSetError(Context, AL_INVALID_VALUE);
1411 goto done;
1414 // Check all the Sources are valid
1415 for(i = 0;i < n;i++)
1417 if(!LookupSource(Context->SourceMap, sources[i]))
1419 alSetError(Context, AL_INVALID_NAME);
1420 goto done;
1424 for(i = 0;i < n;i++)
1426 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1427 if(Source->state == AL_PLAYING)
1428 Source->state = AL_PAUSED;
1431 done:
1432 ProcessContext(Context);
1435 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1437 alSourceStopv(1, &source);
1440 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1442 ALCcontext *Context;
1443 ALsource *Source;
1444 ALsizei i;
1446 Context = GetContextSuspended();
1447 if(!Context) return;
1449 if(n < 0)
1451 alSetError(Context, AL_INVALID_VALUE);
1452 goto done;
1454 if(n > 0 && !sources)
1456 alSetError(Context, AL_INVALID_VALUE);
1457 goto done;
1460 // Check all the Sources are valid
1461 for(i = 0;i < n;i++)
1463 if(!LookupSource(Context->SourceMap, sources[i]))
1465 alSetError(Context, AL_INVALID_NAME);
1466 goto done;
1470 for(i = 0;i < n;i++)
1472 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1473 if(Source->state != AL_INITIAL)
1475 Source->state = AL_STOPPED;
1476 Source->BuffersPlayed = Source->BuffersInQueue;
1478 Source->lOffset = 0;
1481 done:
1482 ProcessContext(Context);
1485 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1487 alSourceRewindv(1, &source);
1490 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1492 ALCcontext *Context;
1493 ALsource *Source;
1494 ALsizei i;
1496 Context = GetContextSuspended();
1497 if(!Context) return;
1499 if(n < 0)
1501 alSetError(Context, AL_INVALID_VALUE);
1502 goto done;
1504 if(n > 0 && !sources)
1506 alSetError(Context, AL_INVALID_VALUE);
1507 goto done;
1510 // Check all the Sources are valid
1511 for(i = 0;i < n;i++)
1513 if(!LookupSource(Context->SourceMap, sources[i]))
1515 alSetError(Context, AL_INVALID_NAME);
1516 goto done;
1520 for(i = 0;i < n;i++)
1522 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1523 if(Source->state != AL_INITIAL)
1525 Source->state = AL_INITIAL;
1526 Source->position = 0;
1527 Source->position_fraction = 0;
1528 Source->BuffersPlayed = 0;
1529 if(Source->queue)
1530 Source->Buffer = Source->queue->buffer;
1532 Source->lOffset = 0;
1535 done:
1536 ProcessContext(Context);
1540 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1542 ALCcontext *Context;
1543 ALCdevice *device;
1544 ALsource *Source;
1545 ALbuffer *buffer;
1546 ALsizei i;
1547 ALbufferlistitem *BufferListStart;
1548 ALbufferlistitem *BufferList;
1549 ALint Frequency;
1550 ALint Format;
1552 if(n == 0)
1553 return;
1555 Context = GetContextSuspended();
1556 if(!Context) return;
1558 if(n < 0)
1560 alSetError(Context, AL_INVALID_VALUE);
1561 goto done;
1564 // Check that all buffers are valid or zero and that the source is valid
1566 // Check that this is a valid source
1567 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1569 alSetError(Context, AL_INVALID_NAME);
1570 goto done;
1573 // Check that this is not a STATIC Source
1574 if(Source->lSourceType == AL_STATIC)
1576 // Invalid Source Type (can't queue on a Static Source)
1577 alSetError(Context, AL_INVALID_OPERATION);
1578 goto done;
1581 device = Context->Device;
1583 Frequency = -1;
1584 Format = -1;
1586 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1587 BufferList = Source->queue;
1588 while(BufferList)
1590 if(BufferList->buffer)
1592 Frequency = BufferList->buffer->frequency;
1593 Format = BufferList->buffer->eOriginalFormat;
1594 break;
1596 BufferList = BufferList->next;
1599 for(i = 0;i < n;i++)
1601 if(!buffers[i])
1602 continue;
1604 if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
1606 alSetError(Context, AL_INVALID_NAME);
1607 goto done;
1610 if(Frequency == -1 && Format == -1)
1612 Frequency = buffer->frequency;
1613 Format = buffer->eOriginalFormat;
1614 if(aluChannelsFromFormat(buffer->format) == 1)
1615 Source->Update = CalcSourceParams;
1616 else
1617 Source->Update = CalcNonAttnSourceParams;
1618 Source->NeedsUpdate = AL_TRUE;
1620 else if(Frequency != buffer->frequency || Format != buffer->eOriginalFormat)
1622 alSetError(Context, AL_INVALID_OPERATION);
1623 goto done;
1627 // Change Source Type
1628 Source->lSourceType = AL_STREAMING;
1630 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1632 // All buffers are valid - so add them to the list
1633 BufferListStart = malloc(sizeof(ALbufferlistitem));
1634 BufferListStart->buffer = buffer;
1635 BufferListStart->next = NULL;
1637 // Increment reference counter for buffer
1638 if(buffer) buffer->refcount++;
1640 BufferList = BufferListStart;
1642 for(i = 1;i < n;i++)
1644 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1646 BufferList->next = malloc(sizeof(ALbufferlistitem));
1647 BufferList->next->buffer = buffer;
1648 BufferList->next->next = NULL;
1650 // Increment reference counter for buffer
1651 if(buffer) buffer->refcount++;
1653 BufferList = BufferList->next;
1656 if(Source->queue == NULL)
1658 Source->queue = BufferListStart;
1659 // Update Current Buffer
1660 Source->Buffer = BufferListStart->buffer;
1662 else
1664 // Find end of queue
1665 BufferList = Source->queue;
1666 while(BufferList->next != NULL)
1667 BufferList = BufferList->next;
1669 BufferList->next = BufferListStart;
1672 // Update number of buffers in queue
1673 Source->BuffersInQueue += n;
1675 done:
1676 ProcessContext(Context);
1680 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1681 // an array of buffer IDs that are to be filled with the names of the buffers removed
1682 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1684 ALCcontext *Context;
1685 ALsource *Source;
1686 ALsizei i;
1687 ALbufferlistitem *BufferList;
1689 if(n == 0)
1690 return;
1692 Context = GetContextSuspended();
1693 if(!Context) return;
1695 if(n < 0)
1697 alSetError(Context, AL_INVALID_VALUE);
1698 goto done;
1701 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1703 alSetError(Context, AL_INVALID_NAME);
1704 goto done;
1707 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1708 (ALuint)n > Source->BuffersPlayed)
1710 // Some buffers can't be unqueue because they have not been processed
1711 alSetError(Context, AL_INVALID_VALUE);
1712 goto done;
1715 for(i = 0;i < n;i++)
1717 BufferList = Source->queue;
1718 Source->queue = BufferList->next;
1720 if(BufferList->buffer)
1722 // Record name of buffer
1723 buffers[i] = BufferList->buffer->buffer;
1724 // Decrement buffer reference counter
1725 BufferList->buffer->refcount--;
1727 else
1728 buffers[i] = 0;
1730 // Release memory for buffer list item
1731 free(BufferList);
1732 Source->BuffersInQueue--;
1735 if(Source->state != AL_PLAYING)
1737 if(Source->queue)
1738 Source->Buffer = Source->queue->buffer;
1739 else
1740 Source->Buffer = NULL;
1742 Source->BuffersPlayed -= n;
1744 done:
1745 ProcessContext(Context);
1749 static ALvoid InitSourceParams(ALsource *Source)
1751 Source->flInnerAngle = 360.0f;
1752 Source->flOuterAngle = 360.0f;
1753 Source->flPitch = 1.0f;
1754 Source->vPosition[0] = 0.0f;
1755 Source->vPosition[1] = 0.0f;
1756 Source->vPosition[2] = 0.0f;
1757 Source->vOrientation[0] = 0.0f;
1758 Source->vOrientation[1] = 0.0f;
1759 Source->vOrientation[2] = 0.0f;
1760 Source->vVelocity[0] = 0.0f;
1761 Source->vVelocity[1] = 0.0f;
1762 Source->vVelocity[2] = 0.0f;
1763 Source->flRefDistance = 1.0f;
1764 Source->flMaxDistance = FLT_MAX;
1765 Source->flRollOffFactor = 1.0f;
1766 Source->bLooping = AL_FALSE;
1767 Source->flGain = 1.0f;
1768 Source->flMinGain = 0.0f;
1769 Source->flMaxGain = 1.0f;
1770 Source->flOuterGain = 0.0f;
1771 Source->OuterGainHF = 1.0f;
1773 Source->DryGainHFAuto = AL_TRUE;
1774 Source->WetGainAuto = AL_TRUE;
1775 Source->WetGainHFAuto = AL_TRUE;
1776 Source->AirAbsorptionFactor = 0.0f;
1777 Source->RoomRolloffFactor = 0.0f;
1778 Source->DopplerFactor = 1.0f;
1780 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1782 Source->Resampler = DefaultResampler;
1784 Source->state = AL_INITIAL;
1785 Source->lSourceType = AL_UNDETERMINED;
1787 Source->NeedsUpdate = AL_TRUE;
1789 Source->Buffer = NULL;
1794 GetSourceOffset
1796 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1797 The offset is relative to the start of the queue (not the start of the current buffer)
1799 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1801 ALbufferlistitem *BufferList;
1802 ALbuffer *Buffer = NULL;
1803 ALfloat BufferFreq;
1804 ALint Channels, Bytes;
1805 ALuint readPos, writePos;
1806 ALenum OriginalFormat;
1807 ALuint TotalBufferDataSize;
1808 ALuint i;
1810 // Find the first non-NULL Buffer in the Queue
1811 BufferList = Source->queue;
1812 while(BufferList)
1814 if(BufferList->buffer)
1816 Buffer = BufferList->buffer;
1817 break;
1819 BufferList = BufferList->next;
1822 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1824 offset[0] = 0.0;
1825 offset[1] = 0.0;
1826 return;
1829 // Get Current Buffer Size and frequency (in milliseconds)
1830 BufferFreq = (ALfloat)Buffer->frequency;
1831 OriginalFormat = Buffer->eOriginalFormat;
1832 Channels = aluChannelsFromFormat(Buffer->format);
1833 Bytes = aluBytesFromFormat(Buffer->format);
1835 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1836 readPos = Source->position * Channels * Bytes;
1837 // Add byte length of any processed buffers in the queue
1838 TotalBufferDataSize = 0;
1839 BufferList = Source->queue;
1840 for(i = 0;BufferList;i++)
1842 if(BufferList->buffer)
1844 if(i < Source->BuffersPlayed)
1845 readPos += BufferList->buffer->size;
1846 TotalBufferDataSize += BufferList->buffer->size;
1848 BufferList = BufferList->next;
1850 if(Source->state == AL_PLAYING)
1851 writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
1852 else
1853 writePos = readPos;
1855 if(Source->bLooping)
1857 readPos %= TotalBufferDataSize;
1858 writePos %= TotalBufferDataSize;
1860 else
1862 // Wrap positions back to 0
1863 if(readPos >= TotalBufferDataSize)
1864 readPos = 0;
1865 if(writePos >= TotalBufferDataSize)
1866 writePos = 0;
1869 switch(name)
1871 case AL_SEC_OFFSET:
1872 offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
1873 offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
1874 break;
1875 case AL_SAMPLE_OFFSET:
1876 case AL_SAMPLE_RW_OFFSETS_SOFT:
1877 offset[0] = (ALdouble)(readPos / (Channels * Bytes));
1878 offset[1] = (ALdouble)(writePos / (Channels * Bytes));
1879 break;
1880 case AL_BYTE_OFFSET:
1881 case AL_BYTE_RW_OFFSETS_SOFT:
1882 // Take into account the original format of the Buffer
1883 if((OriginalFormat == AL_FORMAT_MONO_IMA4) ||
1884 (OriginalFormat == AL_FORMAT_STEREO_IMA4))
1886 // Round down to nearest ADPCM block
1887 offset[0] = (ALdouble)((readPos / (65 * Bytes * Channels)) * 36 * Channels);
1888 if(Source->state == AL_PLAYING)
1890 // Round up to nearest ADPCM block
1891 offset[1] = (ALdouble)(((writePos + (65 * Bytes * Channels) - 1) / (65 * Bytes * Channels)) * 36 * Channels);
1893 else
1894 offset[1] = offset[0];
1896 else if(OriginalFormat == AL_FORMAT_MONO_MULAW ||
1897 OriginalFormat == AL_FORMAT_STEREO_MULAW ||
1898 OriginalFormat == AL_FORMAT_QUAD_MULAW ||
1899 OriginalFormat == AL_FORMAT_51CHN_MULAW ||
1900 OriginalFormat == AL_FORMAT_61CHN_MULAW ||
1901 OriginalFormat == AL_FORMAT_71CHN_MULAW)
1903 offset[0] = (ALdouble)(readPos / Bytes * 1);
1904 offset[1] = (ALdouble)(writePos / Bytes * 1);
1906 else if(OriginalFormat == AL_FORMAT_REAR_MULAW)
1908 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1909 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1911 else if(OriginalFormat == AL_FORMAT_REAR8)
1913 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1914 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1916 else if(OriginalFormat == AL_FORMAT_REAR16)
1918 offset[0] = (ALdouble)(readPos / 2 / Bytes * 2);
1919 offset[1] = (ALdouble)(writePos / 2 / Bytes * 2);
1921 else if(OriginalFormat == AL_FORMAT_REAR32)
1923 offset[0] = (ALdouble)(readPos / 2 / Bytes * 4);
1924 offset[1] = (ALdouble)(writePos / 2 / Bytes * 4);
1926 else
1928 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
1929 offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
1930 offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
1932 break;
1938 ApplyOffset
1940 Apply a playback offset to the Source. This function will update the queue (to correctly
1941 mark buffers as 'pending' or 'processed' depending upon the new offset.
1943 static ALboolean ApplyOffset(ALsource *Source)
1945 ALbufferlistitem *BufferList;
1946 ALbuffer *Buffer;
1947 ALint lBufferSize, lTotalBufferSize;
1948 ALint BuffersPlayed;
1949 ALint lByteOffset;
1951 // Get true byte offset
1952 lByteOffset = GetByteOffset(Source);
1954 // If the offset is invalid, don't apply it
1955 if(lByteOffset == -1)
1956 return AL_FALSE;
1958 // Sort out the queue (pending and processed states)
1959 BufferList = Source->queue;
1960 lTotalBufferSize = 0;
1961 BuffersPlayed = 0;
1963 while(BufferList)
1965 Buffer = BufferList->buffer;
1966 lBufferSize = Buffer ? Buffer->size : 0;
1968 if(lTotalBufferSize+lBufferSize <= lByteOffset)
1970 // Offset is past this buffer so increment BuffersPlayed
1971 BuffersPlayed++;
1973 else if(lTotalBufferSize <= lByteOffset)
1975 // Offset is within this buffer
1976 // Set Current Buffer
1977 Source->Buffer = BufferList->buffer;
1978 Source->BuffersPlayed = BuffersPlayed;
1980 // SW Mixer Positions are in Samples
1981 Source->position = (lByteOffset - lTotalBufferSize) /
1982 aluFrameSizeFromFormat(Buffer->format);
1983 return AL_TRUE;
1986 // Increment the TotalBufferSize
1987 lTotalBufferSize += lBufferSize;
1989 // Move on to next buffer in the Queue
1990 BufferList = BufferList->next;
1992 // Offset is out of range of the buffer queue
1993 return AL_FALSE;
1998 GetByteOffset
2000 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2001 offset supplied by the application). This takes into account the fact that the buffer format
2002 may have been modifed by AL (e.g 8bit samples are converted to float)
2004 static ALint GetByteOffset(ALsource *Source)
2006 ALbuffer *Buffer = NULL;
2007 ALbufferlistitem *BufferList;
2008 ALfloat BufferFreq;
2009 ALint Channels, Bytes;
2010 ALint ByteOffset = -1;
2012 // Find the first non-NULL Buffer in the Queue
2013 BufferList = Source->queue;
2014 while(BufferList)
2016 if(BufferList->buffer)
2018 Buffer = BufferList->buffer;
2019 break;
2021 BufferList = BufferList->next;
2024 if(!Buffer)
2026 Source->lOffset = 0;
2027 return -1;
2030 BufferFreq = ((ALfloat)Buffer->frequency);
2031 Channels = aluChannelsFromFormat(Buffer->format);
2032 Bytes = aluBytesFromFormat(Buffer->format);
2034 // Determine the ByteOffset (and ensure it is block aligned)
2035 switch(Source->lOffsetType)
2037 case AL_BYTE_OFFSET:
2038 // Take into consideration the original format
2039 ByteOffset = FramesFromBytes(Source->lOffset, Buffer->eOriginalFormat,
2040 Channels);
2041 ByteOffset *= Channels * Bytes;
2042 break;
2044 case AL_SAMPLE_OFFSET:
2045 ByteOffset = Source->lOffset * Channels * Bytes;
2046 break;
2048 case AL_SEC_OFFSET:
2049 // Note - lOffset is internally stored as Milliseconds
2050 ByteOffset = (ALint)(Source->lOffset / 1000.0f * BufferFreq);
2051 ByteOffset *= Channels * Bytes;
2052 break;
2054 // Clear Offset
2055 Source->lOffset = 0;
2057 return ByteOffset;
2060 static ALint FramesFromBytes(ALint offset, ALenum format, ALint channels)
2062 if(format==AL_FORMAT_MONO_IMA4 || format==AL_FORMAT_STEREO_IMA4)
2064 // Round down to nearest ADPCM block
2065 offset /= 36 * channels;
2066 // Multiply by compression rate (65 sample frames per block)
2067 offset *= 65;
2069 else if(format==AL_FORMAT_MONO_MULAW || format==AL_FORMAT_STEREO_MULAW ||
2070 format==AL_FORMAT_QUAD_MULAW || format==AL_FORMAT_51CHN_MULAW ||
2071 format==AL_FORMAT_61CHN_MULAW || format==AL_FORMAT_71CHN_MULAW)
2073 /* muLaw has 1 byte per sample */
2074 offset /= 1 * channels;
2076 else if(format == AL_FORMAT_REAR_MULAW)
2078 /* Rear is 2 channels */
2079 offset /= 1 * 2;
2081 else if(format == AL_FORMAT_REAR8)
2082 offset /= 1 * 2;
2083 else if(format == AL_FORMAT_REAR16)
2084 offset /= 2 * 2;
2085 else if(format == AL_FORMAT_REAR32)
2086 offset /= 4 * 2;
2087 else
2089 ALuint bytes = aluBytesFromFormat(format);
2090 offset /= bytes * channels;
2092 return offset;
2096 ALvoid ReleaseALSources(ALCcontext *Context)
2098 ALsizei pos;
2099 ALuint j;
2100 for(pos = 0;pos < Context->SourceMap.size;pos++)
2102 ALsource *temp = Context->SourceMap.array[pos].value;
2103 Context->SourceMap.array[pos].value = NULL;
2105 // For each buffer in the source's queue, decrement its reference counter and remove it
2106 while(temp->queue != NULL)
2108 ALbufferlistitem *BufferList = temp->queue;
2109 // Decrement buffer's reference counter
2110 if(BufferList->buffer != NULL)
2111 BufferList->buffer->refcount--;
2112 // Update queue to point to next element in list
2113 temp->queue = BufferList->next;
2114 // Release memory allocated for buffer list item
2115 free(BufferList);
2118 for(j = 0;j < MAX_SENDS;++j)
2120 if(temp->Send[j].Slot)
2121 temp->Send[j].Slot->refcount--;
2124 // Release source structure
2125 ALTHUNK_REMOVEENTRY(temp->source);
2126 memset(temp, 0, sizeof(ALsource));
2127 free(temp);