Use click removal when starting a source
[openal-soft.git] / OpenAL32 / alSource.c
blob5435e5d08a2f594bfd6295c00ec233c1a36fd0c3
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)
57 Device = Context->Device;
59 // Check that enough memory has been allocted in the 'sources' array for n Sources
60 if(!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
62 // Check that the requested number of sources can be generated
63 if((Context->SourceMap.size + n) <= (ALsizei)Device->MaxNoOfSources)
65 ALenum err;
67 // Add additional sources to the list
68 while(i < n)
70 ALsource *source = calloc(1, sizeof(ALsource));
71 if(!source)
73 alSetError(Context, AL_OUT_OF_MEMORY);
74 alDeleteSources(i, sources);
75 break;
78 source->source = (ALuint)ALTHUNK_ADDENTRY(source);
79 err = InsertUIntMapEntry(&Context->SourceMap, source->source,
80 source);
81 if(err != AL_NO_ERROR)
83 ALTHUNK_REMOVEENTRY(source->source);
84 memset(source, 0, sizeof(ALsource));
85 free(source);
87 alSetError(Context, err);
88 alDeleteSources(i, sources);
89 break;
92 sources[i++] = source->source;
93 InitSourceParams(source);
96 else
98 // Not enough resources to create the Sources
99 alSetError(Context, AL_INVALID_VALUE);
102 else
104 // Bad pointer
105 alSetError(Context, AL_INVALID_VALUE);
109 ProcessContext(Context);
113 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
115 ALCcontext *Context;
116 ALCdevice *Device;
117 ALsource *Source;
118 ALsizei i, j;
119 ALbufferlistitem *BufferList;
120 ALboolean bSourcesValid = AL_TRUE;
122 Context = GetContextSuspended();
123 if(!Context) return;
125 if(n >= 0)
127 Device = Context->Device;
129 // Check that all Sources are valid (and can therefore be deleted)
130 for (i = 0; i < n; i++)
132 if(LookupSource(Context->SourceMap, sources[i]) == NULL)
134 alSetError(Context, AL_INVALID_NAME);
135 bSourcesValid = AL_FALSE;
136 break;
140 if(bSourcesValid)
142 // All Sources are valid, and can be deleted
143 for(i = 0; i < n; i++)
145 // Recheck that the Source is valid, because there could be duplicated Source names
146 if((Source=LookupSource(Context->SourceMap, sources[i])) != NULL)
148 for(j = 0;j < Context->ActiveSourceCount;j++)
150 if(Context->ActiveSources[j] == Source)
152 ALsizei end = --(Context->ActiveSourceCount);
153 Context->ActiveSources[j] = Context->ActiveSources[end];
154 break;
158 // For each buffer in the source's queue, decrement its reference counter and remove it
159 while(Source->queue != NULL)
161 BufferList = Source->queue;
162 // Decrement buffer's reference counter
163 if(BufferList->buffer != NULL)
164 BufferList->buffer->refcount--;
165 // Update queue to point to next element in list
166 Source->queue = BufferList->next;
167 // Release memory allocated for buffer list item
168 free(BufferList);
171 for(j = 0;j < MAX_SENDS;++j)
173 if(Source->Send[j].Slot)
174 Source->Send[j].Slot->refcount--;
175 Source->Send[j].Slot = NULL;
178 // Remove Source from list of Sources
179 RemoveUIntMapKey(&Context->SourceMap, Source->source);
180 ALTHUNK_REMOVEENTRY(Source->source);
182 memset(Source,0,sizeof(ALsource));
183 free(Source);
188 else
189 alSetError(Context, AL_INVALID_VALUE);
191 ProcessContext(Context);
195 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
197 ALCcontext *Context;
198 ALboolean result;
200 Context = GetContextSuspended();
201 if(!Context) return AL_FALSE;
203 result = (LookupSource(Context->SourceMap, source) ? AL_TRUE : AL_FALSE);
205 ProcessContext(Context);
207 return result;
211 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
213 ALCcontext *pContext;
214 ALsource *Source;
216 pContext = GetContextSuspended();
217 if(!pContext) return;
219 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
221 switch(eParam)
223 case AL_PITCH:
224 if(flValue >= 0.0f)
226 Source->flPitch = flValue;
227 if(Source->flPitch < 0.001f)
228 Source->flPitch = 0.001f;
229 Source->NeedsUpdate = AL_TRUE;
231 else
232 alSetError(pContext, AL_INVALID_VALUE);
233 break;
235 case AL_CONE_INNER_ANGLE:
236 if(flValue >= 0.0f && flValue <= 360.0f)
238 Source->flInnerAngle = flValue;
239 Source->NeedsUpdate = AL_TRUE;
241 else
242 alSetError(pContext, AL_INVALID_VALUE);
243 break;
245 case AL_CONE_OUTER_ANGLE:
246 if(flValue >= 0.0f && flValue <= 360.0f)
248 Source->flOuterAngle = flValue;
249 Source->NeedsUpdate = AL_TRUE;
251 else
252 alSetError(pContext, AL_INVALID_VALUE);
253 break;
255 case AL_GAIN:
256 if(flValue >= 0.0f)
258 Source->flGain = flValue;
259 Source->NeedsUpdate = AL_TRUE;
261 else
262 alSetError(pContext, AL_INVALID_VALUE);
263 break;
265 case AL_MAX_DISTANCE:
266 if(flValue >= 0.0f)
268 Source->flMaxDistance = flValue;
269 Source->NeedsUpdate = AL_TRUE;
271 else
272 alSetError(pContext, AL_INVALID_VALUE);
273 break;
275 case AL_ROLLOFF_FACTOR:
276 if(flValue >= 0.0f)
278 Source->flRollOffFactor = flValue;
279 Source->NeedsUpdate = AL_TRUE;
281 else
282 alSetError(pContext, AL_INVALID_VALUE);
283 break;
285 case AL_REFERENCE_DISTANCE:
286 if(flValue >= 0.0f)
288 Source->flRefDistance = flValue;
289 Source->NeedsUpdate = AL_TRUE;
291 else
292 alSetError(pContext, AL_INVALID_VALUE);
293 break;
295 case AL_MIN_GAIN:
296 if(flValue >= 0.0f && flValue <= 1.0f)
298 Source->flMinGain = flValue;
299 Source->NeedsUpdate = AL_TRUE;
301 else
302 alSetError(pContext, AL_INVALID_VALUE);
303 break;
305 case AL_MAX_GAIN:
306 if(flValue >= 0.0f && flValue <= 1.0f)
308 Source->flMaxGain = flValue;
309 Source->NeedsUpdate = AL_TRUE;
311 else
312 alSetError(pContext, AL_INVALID_VALUE);
313 break;
315 case AL_CONE_OUTER_GAIN:
316 if(flValue >= 0.0f && flValue <= 1.0f)
318 Source->flOuterGain = flValue;
319 Source->NeedsUpdate = AL_TRUE;
321 else
322 alSetError(pContext, AL_INVALID_VALUE);
323 break;
325 case AL_CONE_OUTER_GAINHF:
326 if(flValue >= 0.0f && flValue <= 1.0f)
328 Source->OuterGainHF = flValue;
329 Source->NeedsUpdate = AL_TRUE;
331 else
332 alSetError(pContext, AL_INVALID_VALUE);
333 break;
335 case AL_AIR_ABSORPTION_FACTOR:
336 if(flValue >= 0.0f && flValue <= 10.0f)
338 Source->AirAbsorptionFactor = flValue;
339 Source->NeedsUpdate = AL_TRUE;
341 else
342 alSetError(pContext, AL_INVALID_VALUE);
343 break;
345 case AL_ROOM_ROLLOFF_FACTOR:
346 if(flValue >= 0.0f && flValue <= 10.0f)
348 Source->RoomRolloffFactor = flValue;
349 Source->NeedsUpdate = AL_TRUE;
351 else
352 alSetError(pContext, AL_INVALID_VALUE);
353 break;
355 case AL_DOPPLER_FACTOR:
356 if(flValue >= 0.0f && flValue <= 1.0f)
358 Source->DopplerFactor = flValue;
359 Source->NeedsUpdate = AL_TRUE;
361 else
362 alSetError(pContext, AL_INVALID_VALUE);
363 break;
365 case AL_SEC_OFFSET:
366 case AL_SAMPLE_OFFSET:
367 case AL_BYTE_OFFSET:
368 if(flValue >= 0.0f)
370 Source->lOffsetType = eParam;
372 // Store Offset (convert Seconds into Milliseconds)
373 if(eParam == AL_SEC_OFFSET)
374 Source->lOffset = (ALint)(flValue * 1000.0f);
375 else
376 Source->lOffset = (ALint)flValue;
378 if ((Source->state == AL_PLAYING) || (Source->state == AL_PAUSED))
380 if(ApplyOffset(Source) == AL_FALSE)
381 alSetError(pContext, AL_INVALID_VALUE);
384 else
385 alSetError(pContext, AL_INVALID_VALUE);
386 break;
388 default:
389 alSetError(pContext, AL_INVALID_ENUM);
390 break;
393 else
395 // Invalid Source Name
396 alSetError(pContext, AL_INVALID_NAME);
399 ProcessContext(pContext);
403 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
405 ALCcontext *pContext;
406 ALsource *Source;
408 pContext = GetContextSuspended();
409 if(!pContext) return;
411 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
413 switch(eParam)
415 case AL_POSITION:
416 Source->vPosition[0] = flValue1;
417 Source->vPosition[1] = flValue2;
418 Source->vPosition[2] = flValue3;
419 Source->NeedsUpdate = AL_TRUE;
420 break;
422 case AL_VELOCITY:
423 Source->vVelocity[0] = flValue1;
424 Source->vVelocity[1] = flValue2;
425 Source->vVelocity[2] = flValue3;
426 Source->NeedsUpdate = AL_TRUE;
427 break;
429 case AL_DIRECTION:
430 Source->vOrientation[0] = flValue1;
431 Source->vOrientation[1] = flValue2;
432 Source->vOrientation[2] = flValue3;
433 Source->NeedsUpdate = AL_TRUE;
434 break;
436 default:
437 alSetError(pContext, AL_INVALID_ENUM);
438 break;
441 else
442 alSetError(pContext, AL_INVALID_NAME);
444 ProcessContext(pContext);
448 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
450 ALCcontext *pContext;
452 pContext = GetContextSuspended();
453 if(!pContext) return;
455 if(pflValues)
457 if(LookupSource(pContext->SourceMap, source) != NULL)
459 switch(eParam)
461 case AL_PITCH:
462 case AL_CONE_INNER_ANGLE:
463 case AL_CONE_OUTER_ANGLE:
464 case AL_GAIN:
465 case AL_MAX_DISTANCE:
466 case AL_ROLLOFF_FACTOR:
467 case AL_REFERENCE_DISTANCE:
468 case AL_MIN_GAIN:
469 case AL_MAX_GAIN:
470 case AL_CONE_OUTER_GAIN:
471 case AL_CONE_OUTER_GAINHF:
472 case AL_SEC_OFFSET:
473 case AL_SAMPLE_OFFSET:
474 case AL_BYTE_OFFSET:
475 case AL_AIR_ABSORPTION_FACTOR:
476 case AL_ROOM_ROLLOFF_FACTOR:
477 alSourcef(source, eParam, pflValues[0]);
478 break;
480 case AL_POSITION:
481 case AL_VELOCITY:
482 case AL_DIRECTION:
483 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
484 break;
486 default:
487 alSetError(pContext, AL_INVALID_ENUM);
488 break;
491 else
492 alSetError(pContext, AL_INVALID_NAME);
494 else
495 alSetError(pContext, AL_INVALID_VALUE);
497 ProcessContext(pContext);
501 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
503 ALCcontext *pContext;
504 ALsource *Source;
505 ALbufferlistitem *BufferListItem;
507 pContext = GetContextSuspended();
508 if(!pContext) return;
510 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
512 ALCdevice *device = pContext->Device;
514 switch(eParam)
516 case AL_MAX_DISTANCE:
517 case AL_ROLLOFF_FACTOR:
518 case AL_CONE_INNER_ANGLE:
519 case AL_CONE_OUTER_ANGLE:
520 case AL_REFERENCE_DISTANCE:
521 alSourcef(source, eParam, (ALfloat)lValue);
522 break;
524 case AL_SOURCE_RELATIVE:
525 if(lValue == AL_FALSE || lValue == AL_TRUE)
527 Source->bHeadRelative = (ALboolean)lValue;
528 Source->NeedsUpdate = AL_TRUE;
530 else
531 alSetError(pContext, AL_INVALID_VALUE);
532 break;
534 case AL_LOOPING:
535 if(lValue == AL_FALSE || lValue == AL_TRUE)
536 Source->bLooping = (ALboolean)lValue;
537 else
538 alSetError(pContext, AL_INVALID_VALUE);
539 break;
541 case AL_BUFFER:
542 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
544 ALbuffer *buffer = NULL;
546 if(lValue == 0 ||
547 (buffer=LookupBuffer(device->BufferMap, lValue)) != NULL)
549 // Remove all elements in the queue
550 while(Source->queue != NULL)
552 BufferListItem = Source->queue;
553 Source->queue = BufferListItem->next;
554 // Decrement reference counter for buffer
555 if(BufferListItem->buffer)
556 BufferListItem->buffer->refcount--;
557 // Release memory for buffer list item
558 free(BufferListItem);
559 // Decrement the number of buffers in the queue
560 Source->BuffersInQueue--;
563 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
564 if(lValue != 0)
566 // Source is now in STATIC mode
567 Source->lSourceType = AL_STATIC;
569 // Add the selected buffer to the queue
570 BufferListItem = malloc(sizeof(ALbufferlistitem));
571 BufferListItem->buffer = buffer;
572 BufferListItem->next = NULL;
574 Source->queue = BufferListItem;
575 Source->BuffersInQueue = 1;
577 if(aluChannelsFromFormat(buffer->format) == 1)
578 Source->Update = CalcSourceParams;
579 else
580 Source->Update = CalcNonAttnSourceParams;
582 // Increment reference counter for buffer
583 buffer->refcount++;
585 else
587 // Source is now in UNDETERMINED mode
588 Source->lSourceType = AL_UNDETERMINED;
590 Source->BuffersPlayed = 0;
592 // Update AL_BUFFER parameter
593 Source->Buffer = buffer;
594 Source->NeedsUpdate = AL_TRUE;
596 else
597 alSetError(pContext, AL_INVALID_VALUE);
599 else
600 alSetError(pContext, AL_INVALID_OPERATION);
601 break;
603 case AL_SOURCE_STATE:
604 // Query only
605 alSetError(pContext, AL_INVALID_OPERATION);
606 break;
608 case AL_SEC_OFFSET:
609 case AL_SAMPLE_OFFSET:
610 case AL_BYTE_OFFSET:
611 if(lValue >= 0)
613 Source->lOffsetType = eParam;
615 // Store Offset (convert Seconds into Milliseconds)
616 if(eParam == AL_SEC_OFFSET)
617 Source->lOffset = lValue * 1000;
618 else
619 Source->lOffset = lValue;
621 if(Source->state == AL_PLAYING || Source->state == AL_PAUSED)
623 if(ApplyOffset(Source) == AL_FALSE)
624 alSetError(pContext, AL_INVALID_VALUE);
627 else
628 alSetError(pContext, AL_INVALID_VALUE);
629 break;
631 case AL_DIRECT_FILTER: {
632 ALfilter *filter = NULL;
634 if(lValue == 0 ||
635 (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL)
637 if(!filter)
639 Source->DirectFilter.type = AL_FILTER_NULL;
640 Source->DirectFilter.filter = 0;
642 else
643 memcpy(&Source->DirectFilter, filter, sizeof(*filter));
644 Source->NeedsUpdate = AL_TRUE;
646 else
647 alSetError(pContext, AL_INVALID_VALUE);
648 } break;
650 case AL_DIRECT_FILTER_GAINHF_AUTO:
651 if(lValue == AL_TRUE || lValue == AL_FALSE)
653 Source->DryGainHFAuto = lValue;
654 Source->NeedsUpdate = AL_TRUE;
656 else
657 alSetError(pContext, AL_INVALID_VALUE);
658 break;
660 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
661 if(lValue == AL_TRUE || lValue == AL_FALSE)
663 Source->WetGainAuto = lValue;
664 Source->NeedsUpdate = AL_TRUE;
666 else
667 alSetError(pContext, AL_INVALID_VALUE);
668 break;
670 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
671 if(lValue == AL_TRUE || lValue == AL_FALSE)
673 Source->WetGainHFAuto = lValue;
674 Source->NeedsUpdate = AL_TRUE;
676 else
677 alSetError(pContext, AL_INVALID_VALUE);
678 break;
680 case AL_DISTANCE_MODEL:
681 if(lValue == AL_NONE ||
682 lValue == AL_INVERSE_DISTANCE ||
683 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
684 lValue == AL_LINEAR_DISTANCE ||
685 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
686 lValue == AL_EXPONENT_DISTANCE ||
687 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
689 Source->DistanceModel = lValue;
690 if(pContext->SourceDistanceModel)
691 Source->NeedsUpdate = AL_TRUE;
693 else
694 alSetError(pContext, AL_INVALID_VALUE);
695 break;
697 default:
698 alSetError(pContext, AL_INVALID_ENUM);
699 break;
702 else
703 alSetError(pContext, AL_INVALID_NAME);
705 ProcessContext(pContext);
709 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
711 ALCcontext *pContext;
712 ALsource *Source;
714 pContext = GetContextSuspended();
715 if(!pContext) return;
717 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
719 ALCdevice *device = pContext->Device;
721 switch (eParam)
723 case AL_POSITION:
724 case AL_VELOCITY:
725 case AL_DIRECTION:
726 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
727 break;
729 case AL_AUXILIARY_SEND_FILTER: {
730 ALeffectslot *ALEffectSlot = NULL;
731 ALfilter *ALFilter = NULL;
733 if((ALuint)lValue2 < device->NumAuxSends &&
734 (lValue1 == 0 ||
735 (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
736 (lValue3 == 0 ||
737 (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL))
739 /* Release refcount on the previous slot, and add one for
740 * the new slot */
741 if(Source->Send[lValue2].Slot)
742 Source->Send[lValue2].Slot->refcount--;
743 Source->Send[lValue2].Slot = ALEffectSlot;
744 if(Source->Send[lValue2].Slot)
745 Source->Send[lValue2].Slot->refcount++;
747 if(!ALFilter)
749 /* Disable filter */
750 Source->Send[lValue2].WetFilter.type = 0;
751 Source->Send[lValue2].WetFilter.filter = 0;
753 else
754 memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
755 Source->NeedsUpdate = AL_TRUE;
757 else
758 alSetError(pContext, AL_INVALID_VALUE);
759 } break;
761 default:
762 alSetError(pContext, AL_INVALID_ENUM);
763 break;
766 else
767 alSetError(pContext, AL_INVALID_NAME);
769 ProcessContext(pContext);
773 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
775 ALCcontext *pContext;
777 pContext = GetContextSuspended();
778 if(!pContext) return;
780 if(plValues)
782 if(LookupSource(pContext->SourceMap, source) != NULL)
784 switch(eParam)
786 case AL_SOURCE_RELATIVE:
787 case AL_CONE_INNER_ANGLE:
788 case AL_CONE_OUTER_ANGLE:
789 case AL_LOOPING:
790 case AL_BUFFER:
791 case AL_SOURCE_STATE:
792 case AL_SEC_OFFSET:
793 case AL_SAMPLE_OFFSET:
794 case AL_BYTE_OFFSET:
795 case AL_MAX_DISTANCE:
796 case AL_ROLLOFF_FACTOR:
797 case AL_REFERENCE_DISTANCE:
798 case AL_DIRECT_FILTER:
799 case AL_DIRECT_FILTER_GAINHF_AUTO:
800 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
801 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
802 case AL_DISTANCE_MODEL:
803 alSourcei(source, eParam, plValues[0]);
804 break;
806 case AL_POSITION:
807 case AL_VELOCITY:
808 case AL_DIRECTION:
809 case AL_AUXILIARY_SEND_FILTER:
810 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
811 break;
813 default:
814 alSetError(pContext, AL_INVALID_ENUM);
815 break;
818 else
819 alSetError(pContext, AL_INVALID_NAME);
821 else
822 alSetError(pContext, AL_INVALID_VALUE);
824 ProcessContext(pContext);
828 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
830 ALCcontext *pContext;
831 ALsource *Source;
832 ALdouble Offsets[2];
833 ALdouble updateLen;
835 pContext = GetContextSuspended();
836 if(!pContext) return;
838 if(pflValue)
840 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
842 switch(eParam)
844 case AL_PITCH:
845 *pflValue = Source->flPitch;
846 break;
848 case AL_GAIN:
849 *pflValue = Source->flGain;
850 break;
852 case AL_MIN_GAIN:
853 *pflValue = Source->flMinGain;
854 break;
856 case AL_MAX_GAIN:
857 *pflValue = Source->flMaxGain;
858 break;
860 case AL_MAX_DISTANCE:
861 *pflValue = Source->flMaxDistance;
862 break;
864 case AL_ROLLOFF_FACTOR:
865 *pflValue = Source->flRollOffFactor;
866 break;
868 case AL_CONE_OUTER_GAIN:
869 *pflValue = Source->flOuterGain;
870 break;
872 case AL_CONE_OUTER_GAINHF:
873 *pflValue = Source->OuterGainHF;
874 break;
876 case AL_SEC_OFFSET:
877 case AL_SAMPLE_OFFSET:
878 case AL_BYTE_OFFSET:
879 updateLen = (ALdouble)pContext->Device->UpdateSize /
880 pContext->Device->Frequency;
881 GetSourceOffset(Source, eParam, Offsets, updateLen);
882 *pflValue = Offsets[0];
883 break;
885 case AL_CONE_INNER_ANGLE:
886 *pflValue = Source->flInnerAngle;
887 break;
889 case AL_CONE_OUTER_ANGLE:
890 *pflValue = Source->flOuterAngle;
891 break;
893 case AL_REFERENCE_DISTANCE:
894 *pflValue = Source->flRefDistance;
895 break;
897 case AL_AIR_ABSORPTION_FACTOR:
898 *pflValue = Source->AirAbsorptionFactor;
899 break;
901 case AL_ROOM_ROLLOFF_FACTOR:
902 *pflValue = Source->RoomRolloffFactor;
903 break;
905 case AL_DOPPLER_FACTOR:
906 *pflValue = Source->DopplerFactor;
907 break;
909 default:
910 alSetError(pContext, AL_INVALID_ENUM);
911 break;
914 else
915 alSetError(pContext, AL_INVALID_NAME);
917 else
918 alSetError(pContext, AL_INVALID_VALUE);
920 ProcessContext(pContext);
924 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
926 ALCcontext *pContext;
927 ALsource *Source;
929 pContext = GetContextSuspended();
930 if(!pContext) return;
932 if(pflValue1 && pflValue2 && pflValue3)
934 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
936 switch(eParam)
938 case AL_POSITION:
939 *pflValue1 = Source->vPosition[0];
940 *pflValue2 = Source->vPosition[1];
941 *pflValue3 = Source->vPosition[2];
942 break;
944 case AL_VELOCITY:
945 *pflValue1 = Source->vVelocity[0];
946 *pflValue2 = Source->vVelocity[1];
947 *pflValue3 = Source->vVelocity[2];
948 break;
950 case AL_DIRECTION:
951 *pflValue1 = Source->vOrientation[0];
952 *pflValue2 = Source->vOrientation[1];
953 *pflValue3 = Source->vOrientation[2];
954 break;
956 default:
957 alSetError(pContext, AL_INVALID_ENUM);
958 break;
961 else
962 alSetError(pContext, AL_INVALID_NAME);
964 else
965 alSetError(pContext, AL_INVALID_VALUE);
967 ProcessContext(pContext);
971 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
973 ALCcontext *pContext;
974 ALsource *Source;
975 ALdouble Offsets[2];
976 ALdouble updateLen;
978 pContext = GetContextSuspended();
979 if(!pContext) return;
981 if(pflValues)
983 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
985 switch(eParam)
987 case AL_PITCH:
988 case AL_GAIN:
989 case AL_MIN_GAIN:
990 case AL_MAX_GAIN:
991 case AL_MAX_DISTANCE:
992 case AL_ROLLOFF_FACTOR:
993 case AL_DOPPLER_FACTOR:
994 case AL_CONE_OUTER_GAIN:
995 case AL_SEC_OFFSET:
996 case AL_SAMPLE_OFFSET:
997 case AL_BYTE_OFFSET:
998 case AL_CONE_INNER_ANGLE:
999 case AL_CONE_OUTER_ANGLE:
1000 case AL_REFERENCE_DISTANCE:
1001 case AL_CONE_OUTER_GAINHF:
1002 case AL_AIR_ABSORPTION_FACTOR:
1003 case AL_ROOM_ROLLOFF_FACTOR:
1004 alGetSourcef(source, eParam, pflValues);
1005 break;
1007 case AL_POSITION:
1008 case AL_VELOCITY:
1009 case AL_DIRECTION:
1010 alGetSource3f(source, eParam, pflValues+0, pflValues+1, pflValues+2);
1011 break;
1013 case AL_SAMPLE_RW_OFFSETS_EXT:
1014 case AL_BYTE_RW_OFFSETS_EXT:
1015 updateLen = (ALdouble)pContext->Device->UpdateSize /
1016 pContext->Device->Frequency;
1017 GetSourceOffset(Source, eParam, Offsets, updateLen);
1018 pflValues[0] = Offsets[0];
1019 pflValues[1] = Offsets[1];
1020 break;
1022 default:
1023 alSetError(pContext, AL_INVALID_ENUM);
1024 break;
1027 else
1028 alSetError(pContext, AL_INVALID_NAME);
1030 else
1031 alSetError(pContext, AL_INVALID_VALUE);
1033 ProcessContext(pContext);
1037 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1039 ALCcontext *pContext;
1040 ALsource *Source;
1041 ALdouble Offsets[2];
1042 ALdouble updateLen;
1044 pContext = GetContextSuspended();
1045 if(!pContext) return;
1047 if(plValue)
1049 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1051 switch(eParam)
1053 case AL_MAX_DISTANCE:
1054 *plValue = (ALint)Source->flMaxDistance;
1055 break;
1057 case AL_ROLLOFF_FACTOR:
1058 *plValue = (ALint)Source->flRollOffFactor;
1059 break;
1061 case AL_REFERENCE_DISTANCE:
1062 *plValue = (ALint)Source->flRefDistance;
1063 break;
1065 case AL_SOURCE_RELATIVE:
1066 *plValue = Source->bHeadRelative;
1067 break;
1069 case AL_CONE_INNER_ANGLE:
1070 *plValue = (ALint)Source->flInnerAngle;
1071 break;
1073 case AL_CONE_OUTER_ANGLE:
1074 *plValue = (ALint)Source->flOuterAngle;
1075 break;
1077 case AL_LOOPING:
1078 *plValue = Source->bLooping;
1079 break;
1081 case AL_BUFFER:
1082 *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
1083 break;
1085 case AL_SOURCE_STATE:
1086 *plValue = Source->state;
1087 break;
1089 case AL_BUFFERS_QUEUED:
1090 *plValue = Source->BuffersInQueue;
1091 break;
1093 case AL_BUFFERS_PROCESSED:
1094 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1096 /* Buffers on a looping source are in a perpetual state
1097 * of PENDING, so don't report any as PROCESSED */
1098 *plValue = 0;
1100 else
1101 *plValue = Source->BuffersPlayed;
1102 break;
1104 case AL_SOURCE_TYPE:
1105 *plValue = Source->lSourceType;
1106 break;
1108 case AL_SEC_OFFSET:
1109 case AL_SAMPLE_OFFSET:
1110 case AL_BYTE_OFFSET:
1111 updateLen = (ALdouble)pContext->Device->UpdateSize /
1112 pContext->Device->Frequency;
1113 GetSourceOffset(Source, eParam, Offsets, updateLen);
1114 *plValue = (ALint)Offsets[0];
1115 break;
1117 case AL_DIRECT_FILTER:
1118 *plValue = Source->DirectFilter.filter;
1119 break;
1121 case AL_DIRECT_FILTER_GAINHF_AUTO:
1122 *plValue = Source->DryGainHFAuto;
1123 break;
1125 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1126 *plValue = Source->WetGainAuto;
1127 break;
1129 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1130 *plValue = Source->WetGainHFAuto;
1131 break;
1133 case AL_DOPPLER_FACTOR:
1134 *plValue = (ALint)Source->DopplerFactor;
1135 break;
1137 case AL_DISTANCE_MODEL:
1138 *plValue = Source->DistanceModel;
1139 break;
1141 default:
1142 alSetError(pContext, AL_INVALID_ENUM);
1143 break;
1146 else
1147 alSetError(pContext, AL_INVALID_NAME);
1149 else
1150 alSetError(pContext, AL_INVALID_VALUE);
1152 ProcessContext(pContext);
1156 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1158 ALCcontext *pContext;
1159 ALsource *Source;
1161 pContext = GetContextSuspended();
1162 if(!pContext) return;
1164 if(plValue1 && plValue2 && plValue3)
1166 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1168 switch(eParam)
1170 case AL_POSITION:
1171 *plValue1 = (ALint)Source->vPosition[0];
1172 *plValue2 = (ALint)Source->vPosition[1];
1173 *plValue3 = (ALint)Source->vPosition[2];
1174 break;
1176 case AL_VELOCITY:
1177 *plValue1 = (ALint)Source->vVelocity[0];
1178 *plValue2 = (ALint)Source->vVelocity[1];
1179 *plValue3 = (ALint)Source->vVelocity[2];
1180 break;
1182 case AL_DIRECTION:
1183 *plValue1 = (ALint)Source->vOrientation[0];
1184 *plValue2 = (ALint)Source->vOrientation[1];
1185 *plValue3 = (ALint)Source->vOrientation[2];
1186 break;
1188 default:
1189 alSetError(pContext, AL_INVALID_ENUM);
1190 break;
1193 else
1194 alSetError(pContext, AL_INVALID_NAME);
1196 else
1197 alSetError(pContext, AL_INVALID_VALUE);
1199 ProcessContext(pContext);
1203 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1205 ALCcontext *pContext;
1206 ALsource *Source;
1207 ALdouble Offsets[2];
1208 ALdouble updateLen;
1210 pContext = GetContextSuspended();
1211 if(!pContext) return;
1213 if(plValues)
1215 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1217 switch(eParam)
1219 case AL_SOURCE_RELATIVE:
1220 case AL_CONE_INNER_ANGLE:
1221 case AL_CONE_OUTER_ANGLE:
1222 case AL_LOOPING:
1223 case AL_BUFFER:
1224 case AL_SOURCE_STATE:
1225 case AL_BUFFERS_QUEUED:
1226 case AL_BUFFERS_PROCESSED:
1227 case AL_SEC_OFFSET:
1228 case AL_SAMPLE_OFFSET:
1229 case AL_BYTE_OFFSET:
1230 case AL_MAX_DISTANCE:
1231 case AL_ROLLOFF_FACTOR:
1232 case AL_DOPPLER_FACTOR:
1233 case AL_REFERENCE_DISTANCE:
1234 case AL_SOURCE_TYPE:
1235 case AL_DIRECT_FILTER:
1236 case AL_DIRECT_FILTER_GAINHF_AUTO:
1237 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1238 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1239 case AL_DISTANCE_MODEL:
1240 alGetSourcei(source, eParam, plValues);
1241 break;
1243 case AL_POSITION:
1244 case AL_VELOCITY:
1245 case AL_DIRECTION:
1246 alGetSource3i(source, eParam, plValues+0, plValues+1, plValues+2);
1247 break;
1249 case AL_SAMPLE_RW_OFFSETS_EXT:
1250 case AL_BYTE_RW_OFFSETS_EXT:
1251 updateLen = (ALdouble)pContext->Device->UpdateSize /
1252 pContext->Device->Frequency;
1253 GetSourceOffset(Source, eParam, Offsets, updateLen);
1254 plValues[0] = (ALint)Offsets[0];
1255 plValues[1] = (ALint)Offsets[1];
1256 break;
1258 default:
1259 alSetError(pContext, AL_INVALID_ENUM);
1260 break;
1263 else
1264 alSetError(pContext, AL_INVALID_NAME);
1266 else
1267 alSetError(pContext, AL_INVALID_VALUE);
1269 ProcessContext(pContext);
1273 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1275 alSourcePlayv(1, &source);
1278 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1280 ALCcontext *Context;
1281 ALsource *Source;
1282 ALbufferlistitem *BufferList;
1283 ALsizei i, j;
1285 Context = GetContextSuspended();
1286 if(!Context) return;
1288 if(!sources)
1290 alSetError(Context, AL_INVALID_VALUE);
1291 goto done;
1294 // Check that all the Sources are valid
1295 for(i = 0;i < n;i++)
1297 if(!LookupSource(Context->SourceMap, sources[i]))
1299 alSetError(Context, AL_INVALID_NAME);
1300 goto done;
1304 if(Context->ActiveSourceCount+n < n)
1306 alSetError(Context, AL_OUT_OF_MEMORY);
1307 goto done;
1310 while(Context->MaxActiveSources < Context->ActiveSourceCount+n)
1312 void *temp = NULL;
1313 ALsizei newcount;
1315 newcount = Context->MaxActiveSources << 1;
1316 if(newcount > 0)
1317 temp = realloc(Context->ActiveSources,
1318 sizeof(*Context->ActiveSources) * newcount);
1319 if(!temp)
1321 alSetError(Context, AL_OUT_OF_MEMORY);
1322 goto done;
1325 Context->ActiveSources = temp;
1326 Context->MaxActiveSources = newcount;
1329 for(i = 0;i < n;i++)
1331 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1333 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1334 BufferList = Source->queue;
1335 while(BufferList)
1337 if(BufferList->buffer != NULL && BufferList->buffer->size)
1338 break;
1339 BufferList = BufferList->next;
1342 if(!BufferList)
1344 Source->BuffersPlayed = Source->BuffersInQueue;
1345 continue;
1348 for(j = 0;j < OUTPUTCHANNELS;j++)
1349 Source->DryGains[j] = 0.0f;
1350 for(j = 0;j < MAX_SENDS;j++)
1351 Source->WetGains[j] = 0.0f;
1353 if(Source->state != AL_PAUSED)
1355 Source->state = AL_PLAYING;
1356 Source->position = 0;
1357 Source->position_fraction = 0;
1358 Source->BuffersPlayed = 0;
1360 Source->Buffer = Source->queue->buffer;
1362 else
1363 Source->state = AL_PLAYING;
1365 // Check if an Offset has been set
1366 if(Source->lOffset)
1367 ApplyOffset(Source);
1369 Source->FirstStart = AL_TRUE;
1371 // If device is disconnected, go right to stopped
1372 if(!Context->Device->Connected)
1374 Source->state = AL_STOPPED;
1375 Source->BuffersPlayed = Source->BuffersInQueue;
1376 Source->position = 0;
1377 Source->position_fraction = 0;
1379 else
1381 for(j = 0;j < Context->ActiveSourceCount;j++)
1383 if(Context->ActiveSources[j] == Source)
1384 break;
1386 if(j == Context->ActiveSourceCount)
1387 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1391 done:
1392 ProcessContext(Context);
1395 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1397 alSourcePausev(1, &source);
1400 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1402 ALCcontext *Context;
1403 ALsource *Source;
1404 ALsizei i;
1406 Context = GetContextSuspended();
1407 if(!Context) return;
1409 if(!sources)
1411 alSetError(Context, AL_INVALID_VALUE);
1412 goto done;
1415 // Check all the Sources are valid
1416 for(i = 0;i < n;i++)
1418 if(!LookupSource(Context->SourceMap, sources[i]))
1420 alSetError(Context, AL_INVALID_NAME);
1421 goto done;
1425 for(i = 0;i < n;i++)
1427 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1428 if(Source->state == AL_PLAYING)
1429 Source->state = AL_PAUSED;
1432 done:
1433 ProcessContext(Context);
1436 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1438 alSourceStopv(1, &source);
1441 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1443 ALCcontext *Context;
1444 ALsource *Source;
1445 ALsizei i;
1447 Context = GetContextSuspended();
1448 if(!Context) return;
1450 if(!sources)
1452 alSetError(Context, AL_INVALID_VALUE);
1453 goto done;
1456 // Check all the Sources are valid
1457 for(i = 0;i < n;i++)
1459 if(!LookupSource(Context->SourceMap, sources[i]))
1461 alSetError(Context, AL_INVALID_NAME);
1462 goto done;
1466 for(i = 0;i < n;i++)
1468 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1469 if(Source->state != AL_INITIAL)
1471 Source->state = AL_STOPPED;
1472 Source->BuffersPlayed = Source->BuffersInQueue;
1474 Source->lOffset = 0;
1477 done:
1478 ProcessContext(Context);
1481 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1483 alSourceRewindv(1, &source);
1486 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1488 ALCcontext *Context;
1489 ALsource *Source;
1490 ALsizei i;
1492 Context = GetContextSuspended();
1493 if(!Context) return;
1495 if(!sources)
1497 alSetError(Context, AL_INVALID_VALUE);
1498 goto done;
1501 // Check all the Sources are valid
1502 for(i = 0;i < n;i++)
1504 if(!LookupSource(Context->SourceMap, sources[i]))
1506 alSetError(Context, AL_INVALID_NAME);
1507 goto done;
1511 for(i = 0;i < n;i++)
1513 Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
1514 if(Source->state != AL_INITIAL)
1516 Source->state = AL_INITIAL;
1517 Source->position = 0;
1518 Source->position_fraction = 0;
1519 Source->BuffersPlayed = 0;
1520 if(Source->queue)
1521 Source->Buffer = Source->queue->buffer;
1523 Source->lOffset = 0;
1526 done:
1527 ProcessContext(Context);
1531 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1533 ALCcontext *Context;
1534 ALCdevice *device;
1535 ALsource *Source;
1536 ALbuffer *buffer;
1537 ALsizei i;
1538 ALbufferlistitem *BufferListStart;
1539 ALbufferlistitem *BufferList;
1540 ALint Frequency;
1541 ALint Format;
1543 if(n == 0)
1544 return;
1546 Context = GetContextSuspended();
1547 if(!Context) return;
1549 // Check that all buffers are valid or zero and that the source is valid
1551 // Check that this is a valid source
1552 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1554 alSetError(Context, AL_INVALID_NAME);
1555 goto done;
1558 // Check that this is not a STATIC Source
1559 if(Source->lSourceType == AL_STATIC)
1561 // Invalid Source Type (can't queue on a Static Source)
1562 alSetError(Context, AL_INVALID_OPERATION);
1563 goto done;
1566 device = Context->Device;
1568 Frequency = -1;
1569 Format = -1;
1571 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1572 BufferList = Source->queue;
1573 while(BufferList)
1575 if(BufferList->buffer)
1577 Frequency = BufferList->buffer->frequency;
1578 Format = BufferList->buffer->eOriginalFormat;
1579 break;
1581 BufferList = BufferList->next;
1584 for(i = 0;i < n;i++)
1586 if(!buffers[i])
1587 continue;
1589 if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
1591 alSetError(Context, AL_INVALID_NAME);
1592 goto done;
1595 if(Frequency == -1 && Format == -1)
1597 Frequency = buffer->frequency;
1598 Format = buffer->eOriginalFormat;
1599 if(aluChannelsFromFormat(buffer->format) == 1)
1600 Source->Update = CalcSourceParams;
1601 else
1602 Source->Update = CalcNonAttnSourceParams;
1603 Source->NeedsUpdate = AL_TRUE;
1605 else if(Frequency != buffer->frequency || Format != buffer->eOriginalFormat)
1607 alSetError(Context, AL_INVALID_OPERATION);
1608 goto done;
1612 // Change Source Type
1613 Source->lSourceType = AL_STREAMING;
1615 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
1617 // All buffers are valid - so add them to the list
1618 BufferListStart = malloc(sizeof(ALbufferlistitem));
1619 BufferListStart->buffer = buffer;
1620 BufferListStart->next = NULL;
1622 // Increment reference counter for buffer
1623 if(buffer) buffer->refcount++;
1625 BufferList = BufferListStart;
1627 for(i = 1;i < n;i++)
1629 buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
1631 BufferList->next = malloc(sizeof(ALbufferlistitem));
1632 BufferList->next->buffer = buffer;
1633 BufferList->next->next = NULL;
1635 // Increment reference counter for buffer
1636 if(buffer) buffer->refcount++;
1638 BufferList = BufferList->next;
1641 if(Source->queue == NULL)
1643 Source->queue = BufferListStart;
1644 // Update Current Buffer
1645 Source->Buffer = BufferListStart->buffer;
1647 else
1649 // Find end of queue
1650 BufferList = Source->queue;
1651 while(BufferList->next != NULL)
1652 BufferList = BufferList->next;
1654 BufferList->next = BufferListStart;
1657 // Update number of buffers in queue
1658 Source->BuffersInQueue += n;
1660 done:
1661 ProcessContext(Context);
1665 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1666 // an array of buffer IDs that are to be filled with the names of the buffers removed
1667 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1669 ALCcontext *Context;
1670 ALsource *Source;
1671 ALsizei i;
1672 ALbufferlistitem *BufferList;
1674 if(n == 0)
1675 return;
1677 Context = GetContextSuspended();
1678 if(!Context) return;
1680 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1682 alSetError(Context, AL_INVALID_NAME);
1683 goto done;
1686 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1687 (ALuint)n > Source->BuffersPlayed)
1689 // Some buffers can't be unqueue because they have not been processed
1690 alSetError(Context, AL_INVALID_VALUE);
1691 goto done;
1694 for(i = 0;i < n;i++)
1696 BufferList = Source->queue;
1697 Source->queue = BufferList->next;
1699 if(BufferList->buffer)
1701 // Record name of buffer
1702 buffers[i] = BufferList->buffer->buffer;
1703 // Decrement buffer reference counter
1704 BufferList->buffer->refcount--;
1706 else
1707 buffers[i] = 0;
1709 // Release memory for buffer list item
1710 free(BufferList);
1711 Source->BuffersInQueue--;
1714 if(Source->state != AL_PLAYING)
1716 if(Source->queue)
1717 Source->Buffer = Source->queue->buffer;
1718 else
1719 Source->Buffer = NULL;
1721 Source->BuffersPlayed -= n;
1723 done:
1724 ProcessContext(Context);
1728 static ALvoid InitSourceParams(ALsource *Source)
1730 Source->flInnerAngle = 360.0f;
1731 Source->flOuterAngle = 360.0f;
1732 Source->flPitch = 1.0f;
1733 Source->vPosition[0] = 0.0f;
1734 Source->vPosition[1] = 0.0f;
1735 Source->vPosition[2] = 0.0f;
1736 Source->vOrientation[0] = 0.0f;
1737 Source->vOrientation[1] = 0.0f;
1738 Source->vOrientation[2] = 0.0f;
1739 Source->vVelocity[0] = 0.0f;
1740 Source->vVelocity[1] = 0.0f;
1741 Source->vVelocity[2] = 0.0f;
1742 Source->flRefDistance = 1.0f;
1743 Source->flMaxDistance = FLT_MAX;
1744 Source->flRollOffFactor = 1.0f;
1745 Source->bLooping = AL_FALSE;
1746 Source->flGain = 1.0f;
1747 Source->flMinGain = 0.0f;
1748 Source->flMaxGain = 1.0f;
1749 Source->flOuterGain = 0.0f;
1750 Source->OuterGainHF = 1.0f;
1752 Source->DryGainHFAuto = AL_TRUE;
1753 Source->WetGainAuto = AL_TRUE;
1754 Source->WetGainHFAuto = AL_TRUE;
1755 Source->AirAbsorptionFactor = 0.0f;
1756 Source->RoomRolloffFactor = 0.0f;
1757 Source->DopplerFactor = 1.0f;
1759 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1761 Source->Resampler = DefaultResampler;
1763 Source->state = AL_INITIAL;
1764 Source->lSourceType = AL_UNDETERMINED;
1766 Source->NeedsUpdate = AL_TRUE;
1768 Source->Buffer = NULL;
1773 GetSourceOffset
1775 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1776 The offset is relative to the start of the queue (not the start of the current buffer)
1778 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1780 ALbufferlistitem *BufferList;
1781 ALbuffer *Buffer = NULL;
1782 ALfloat BufferFreq;
1783 ALint Channels, Bytes;
1784 ALuint readPos, writePos;
1785 ALenum OriginalFormat;
1786 ALuint TotalBufferDataSize;
1787 ALuint i;
1789 // Find the first non-NULL Buffer in the Queue
1790 BufferList = Source->queue;
1791 while(BufferList)
1793 if(BufferList->buffer)
1795 Buffer = BufferList->buffer;
1796 break;
1798 BufferList = BufferList->next;
1801 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1803 offset[0] = 0.0;
1804 offset[1] = 0.0;
1805 return;
1808 // Get Current Buffer Size and frequency (in milliseconds)
1809 BufferFreq = (ALfloat)Buffer->frequency;
1810 OriginalFormat = Buffer->eOriginalFormat;
1811 Channels = aluChannelsFromFormat(Buffer->format);
1812 Bytes = aluBytesFromFormat(Buffer->format);
1814 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1815 readPos = Source->position * Channels * Bytes;
1816 // Add byte length of any processed buffers in the queue
1817 TotalBufferDataSize = 0;
1818 BufferList = Source->queue;
1819 for(i = 0;BufferList;i++)
1821 if(BufferList->buffer)
1823 if(i < Source->BuffersPlayed)
1824 readPos += BufferList->buffer->size;
1825 TotalBufferDataSize += BufferList->buffer->size;
1827 BufferList = BufferList->next;
1829 if(Source->state == AL_PLAYING)
1830 writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
1831 else
1832 writePos = readPos;
1834 if(Source->bLooping)
1836 readPos %= TotalBufferDataSize;
1837 writePos %= TotalBufferDataSize;
1839 else
1841 // Clamp positions to TotalBufferDataSize
1842 if(readPos > TotalBufferDataSize)
1843 readPos = TotalBufferDataSize;
1844 if(writePos > TotalBufferDataSize)
1845 writePos = TotalBufferDataSize;
1848 switch(name)
1850 case AL_SEC_OFFSET:
1851 offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
1852 offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
1853 break;
1854 case AL_SAMPLE_OFFSET:
1855 case AL_SAMPLE_RW_OFFSETS_EXT:
1856 offset[0] = (ALdouble)(readPos / (Channels * Bytes));
1857 offset[1] = (ALdouble)(writePos / (Channels * Bytes));
1858 break;
1859 case AL_BYTE_OFFSET:
1860 case AL_BYTE_RW_OFFSETS_EXT:
1861 // Take into account the original format of the Buffer
1862 if((OriginalFormat == AL_FORMAT_MONO_IMA4) ||
1863 (OriginalFormat == AL_FORMAT_STEREO_IMA4))
1865 // Round down to nearest ADPCM block
1866 offset[0] = (ALdouble)((readPos / (65 * Bytes * Channels)) * 36 * Channels);
1867 if(Source->state == AL_PLAYING)
1869 // Round up to nearest ADPCM block
1870 offset[1] = (ALdouble)(((writePos + (65 * Bytes * Channels) - 1) / (65 * Bytes * Channels)) * 36 * Channels);
1872 else
1873 offset[1] = offset[0];
1875 else if(OriginalFormat == AL_FORMAT_MONO_MULAW ||
1876 OriginalFormat == AL_FORMAT_STEREO_MULAW ||
1877 OriginalFormat == AL_FORMAT_QUAD_MULAW ||
1878 OriginalFormat == AL_FORMAT_51CHN_MULAW ||
1879 OriginalFormat == AL_FORMAT_61CHN_MULAW ||
1880 OriginalFormat == AL_FORMAT_71CHN_MULAW)
1882 offset[0] = (ALdouble)(readPos / Bytes * 1);
1883 offset[1] = (ALdouble)(writePos / Bytes * 1);
1885 else if(OriginalFormat == AL_FORMAT_REAR_MULAW)
1887 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1888 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1890 else if(OriginalFormat == AL_FORMAT_REAR8)
1892 offset[0] = (ALdouble)(readPos / 2 / Bytes * 1);
1893 offset[1] = (ALdouble)(writePos / 2 / Bytes * 1);
1895 else if(OriginalFormat == AL_FORMAT_REAR16)
1897 offset[0] = (ALdouble)(readPos / 2 / Bytes * 2);
1898 offset[1] = (ALdouble)(writePos / 2 / Bytes * 2);
1900 else if(OriginalFormat == AL_FORMAT_REAR32)
1902 offset[0] = (ALdouble)(readPos / 2 / Bytes * 4);
1903 offset[1] = (ALdouble)(writePos / 2 / Bytes * 4);
1905 else
1907 ALuint OrigBytes = aluBytesFromFormat(OriginalFormat);
1908 offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
1909 offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
1911 break;
1917 ApplyOffset
1919 Apply a playback offset to the Source. This function will update the queue (to correctly
1920 mark buffers as 'pending' or 'processed' depending upon the new offset.
1922 static ALboolean ApplyOffset(ALsource *Source)
1924 ALbufferlistitem *BufferList;
1925 ALbuffer *Buffer;
1926 ALint lBufferSize, lTotalBufferSize;
1927 ALint BuffersPlayed;
1928 ALint lByteOffset;
1930 // Get true byte offset
1931 lByteOffset = GetByteOffset(Source);
1933 // If the offset is invalid, don't apply it
1934 if(lByteOffset == -1)
1935 return AL_FALSE;
1937 // Sort out the queue (pending and processed states)
1938 BufferList = Source->queue;
1939 lTotalBufferSize = 0;
1940 BuffersPlayed = 0;
1942 while(BufferList)
1944 Buffer = BufferList->buffer;
1945 lBufferSize = Buffer ? Buffer->size : 0;
1947 if(lTotalBufferSize+lBufferSize <= lByteOffset)
1949 // Offset is past this buffer so increment BuffersPlayed
1950 BuffersPlayed++;
1952 else if(lTotalBufferSize <= lByteOffset)
1954 // Offset is within this buffer
1955 // Set Current Buffer
1956 Source->Buffer = BufferList->buffer;
1957 Source->BuffersPlayed = BuffersPlayed;
1959 // SW Mixer Positions are in Samples
1960 Source->position = (lByteOffset - lTotalBufferSize) /
1961 aluFrameSizeFromFormat(Buffer->format);
1962 return AL_TRUE;
1965 // Increment the TotalBufferSize
1966 lTotalBufferSize += lBufferSize;
1968 // Move on to next buffer in the Queue
1969 BufferList = BufferList->next;
1971 // Offset is out of range of the buffer queue
1972 return AL_FALSE;
1977 GetByteOffset
1979 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1980 offset supplied by the application). This takes into account the fact that the buffer format
1981 may have been modifed by AL (e.g 8bit samples are converted to float)
1983 static ALint GetByteOffset(ALsource *Source)
1985 ALbuffer *Buffer = NULL;
1986 ALbufferlistitem *BufferList;
1987 ALfloat BufferFreq;
1988 ALint Channels, Bytes;
1989 ALint ByteOffset = -1;
1991 // Find the first non-NULL Buffer in the Queue
1992 BufferList = Source->queue;
1993 while(BufferList)
1995 if(BufferList->buffer)
1997 Buffer = BufferList->buffer;
1998 break;
2000 BufferList = BufferList->next;
2003 if(!Buffer)
2005 Source->lOffset = 0;
2006 return -1;
2009 BufferFreq = ((ALfloat)Buffer->frequency);
2010 Channels = aluChannelsFromFormat(Buffer->format);
2011 Bytes = aluBytesFromFormat(Buffer->format);
2013 // Determine the ByteOffset (and ensure it is block aligned)
2014 switch(Source->lOffsetType)
2016 case AL_BYTE_OFFSET:
2017 // Take into consideration the original format
2018 ByteOffset = FramesFromBytes(Source->lOffset, Buffer->eOriginalFormat,
2019 Channels);
2020 ByteOffset *= Channels * Bytes;
2021 break;
2023 case AL_SAMPLE_OFFSET:
2024 ByteOffset = Source->lOffset * Channels * Bytes;
2025 break;
2027 case AL_SEC_OFFSET:
2028 // Note - lOffset is internally stored as Milliseconds
2029 ByteOffset = (ALint)(Source->lOffset / 1000.0f * BufferFreq);
2030 ByteOffset *= Channels * Bytes;
2031 break;
2033 // Clear Offset
2034 Source->lOffset = 0;
2036 return ByteOffset;
2039 static ALint FramesFromBytes(ALint offset, ALenum format, ALint channels)
2041 if(format==AL_FORMAT_MONO_IMA4 || format==AL_FORMAT_STEREO_IMA4)
2043 // Round down to nearest ADPCM block
2044 offset /= 36 * channels;
2045 // Multiply by compression rate (65 sample frames per block)
2046 offset *= 65;
2048 else if(format==AL_FORMAT_MONO_MULAW || format==AL_FORMAT_STEREO_MULAW ||
2049 format==AL_FORMAT_QUAD_MULAW || format==AL_FORMAT_51CHN_MULAW ||
2050 format==AL_FORMAT_61CHN_MULAW || format==AL_FORMAT_71CHN_MULAW)
2052 /* muLaw has 1 byte per sample */
2053 offset /= 1 * channels;
2055 else if(format == AL_FORMAT_REAR_MULAW)
2057 /* Rear is 2 channels */
2058 offset /= 1 * 2;
2060 else if(format == AL_FORMAT_REAR8)
2061 offset /= 1 * 2;
2062 else if(format == AL_FORMAT_REAR16)
2063 offset /= 2 * 2;
2064 else if(format == AL_FORMAT_REAR32)
2065 offset /= 4 * 2;
2066 else
2068 ALuint bytes = aluBytesFromFormat(format);
2069 offset /= bytes * channels;
2071 return offset;
2075 ALvoid ReleaseALSources(ALCcontext *Context)
2077 ALsizei pos;
2078 ALuint j;
2079 for(pos = 0;pos < Context->SourceMap.size;pos++)
2081 ALsource *temp = Context->SourceMap.array[pos].value;
2082 Context->SourceMap.array[pos].value = NULL;
2084 // For each buffer in the source's queue, decrement its reference counter and remove it
2085 while(temp->queue != NULL)
2087 ALbufferlistitem *BufferList = temp->queue;
2088 // Decrement buffer's reference counter
2089 if(BufferList->buffer != NULL)
2090 BufferList->buffer->refcount--;
2091 // Update queue to point to next element in list
2092 temp->queue = BufferList->next;
2093 // Release memory allocated for buffer list item
2094 free(BufferList);
2097 for(j = 0;j < MAX_SENDS;++j)
2099 if(temp->Send[j].Slot)
2100 temp->Send[j].Slot->refcount--;
2103 // Release source structure
2104 ALTHUNK_REMOVEENTRY(temp->source);
2105 memset(temp, 0, sizeof(ALsource));
2106 free(temp);