view OpenAL32/alSource.c @ 0:f9476ff7637e

initial forking of open-al to create multiple listeners
author Robert McIntyre <rlm@mit.edu>
date Tue, 25 Oct 2011 13:02:31 -0700
parents
children
line wrap: on
line source
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.
8 *
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.
13 *
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
19 */
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"
36 enum Resampler DefaultResampler;
37 const ALsizei ResamplerPadding[RESAMPLER_MAX] = {
38 0, /* Point */
39 1, /* Linear */
40 2, /* Cubic */
41 };
42 const ALsizei ResamplerPrePadding[RESAMPLER_MAX] = {
43 0, /* Point */
44 0, /* Linear */
45 1, /* Cubic */
46 };
49 static ALvoid InitSourceParams(ALsource *Source);
50 static ALvoid GetSourceOffset(ALsource *Source, ALenum eName, ALdouble *Offsets, ALdouble updateLen);
51 static ALint GetByteOffset(ALsource *Source);
53 #define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k)))
54 #define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
55 #define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
56 #define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
58 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources)
59 {
60 ALCcontext *Context;
61 ALCdevice *Device;
63 Context = GetLockedContext();
64 if(!Context) return;
66 Device = Context->Device;
67 if(n < 0 || IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
68 alSetError(Context, AL_INVALID_VALUE);
69 else if((ALuint)n > Device->MaxNoOfSources - Context->SourceMap.size)
70 alSetError(Context, AL_INVALID_VALUE);
71 else
72 {
73 ALenum err;
74 ALsizei i;
76 // Add additional sources to the list
77 i = 0;
78 while(i < n)
79 {
80 ALsource *source = calloc(1, sizeof(ALsource));
81 if(!source)
82 {
83 alSetError(Context, AL_OUT_OF_MEMORY);
84 alDeleteSources(i, sources);
85 break;
86 }
88 err = NewThunkEntry(&source->source);
89 if(err == AL_NO_ERROR)
90 err = InsertUIntMapEntry(&Context->SourceMap, source->source, source);
91 if(err != AL_NO_ERROR)
92 {
93 FreeThunkEntry(source->source);
94 memset(source, 0, sizeof(ALsource));
95 free(source);
97 alSetError(Context, err);
98 alDeleteSources(i, sources);
99 break;
100 }
102 sources[i++] = source->source;
103 InitSourceParams(source);
104 }
105 }
107 UnlockContext(Context);
108 }
111 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
112 {
113 ALCcontext *Context;
114 ALsource *Source;
115 ALsizei i, j;
116 ALbufferlistitem *BufferList;
117 ALboolean SourcesValid = AL_FALSE;
119 Context = GetLockedContext();
120 if(!Context) return;
122 if(n < 0)
123 alSetError(Context, AL_INVALID_VALUE);
124 else
125 {
126 SourcesValid = AL_TRUE;
127 // Check that all Sources are valid (and can therefore be deleted)
128 for(i = 0;i < n;i++)
129 {
130 if(LookupSource(Context->SourceMap, sources[i]) == NULL)
131 {
132 alSetError(Context, AL_INVALID_NAME);
133 SourcesValid = AL_FALSE;
134 break;
135 }
136 }
137 }
139 if(SourcesValid)
140 {
141 // All Sources are valid, and can be deleted
142 for(i = 0;i < n;i++)
143 {
144 // Recheck that the Source is valid, because there could be duplicated Source names
145 if((Source=LookupSource(Context->SourceMap, sources[i])) == NULL)
146 continue;
148 for(j = 0;j < Context->ActiveSourceCount;j++)
149 {
150 if(Context->ActiveSources[j] == Source)
151 {
152 ALsizei end = --(Context->ActiveSourceCount);
153 Context->ActiveSources[j] = Context->ActiveSources[end];
154 break;
155 }
156 }
158 // For each buffer in the source's queue...
159 while(Source->queue != NULL)
160 {
161 BufferList = Source->queue;
162 Source->queue = BufferList->next;
164 if(BufferList->buffer != NULL)
165 BufferList->buffer->refcount--;
166 free(BufferList);
167 }
169 for(j = 0;j < MAX_SENDS;++j)
170 {
171 if(Source->Send[j].Slot)
172 Source->Send[j].Slot->refcount--;
173 Source->Send[j].Slot = NULL;
174 }
176 // Remove Source from list of Sources
177 RemoveUIntMapKey(&Context->SourceMap, Source->source);
178 FreeThunkEntry(Source->source);
180 memset(Source,0,sizeof(ALsource));
181 free(Source);
182 }
183 }
185 UnlockContext(Context);
186 }
189 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
190 {
191 ALCcontext *Context;
192 ALboolean result;
194 Context = GetLockedContext();
195 if(!Context) return AL_FALSE;
197 result = (LookupSource(Context->SourceMap, source) ? AL_TRUE : AL_FALSE);
199 UnlockContext(Context);
201 return result;
202 }
205 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
206 {
207 ALCcontext *pContext;
208 ALsource *Source;
210 pContext = GetLockedContext();
211 if(!pContext) return;
213 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
214 {
215 switch(eParam)
216 {
217 case AL_PITCH:
218 if(flValue >= 0.0f)
219 {
220 Source->flPitch = flValue;
221 Source->NeedsUpdate = AL_TRUE;
222 }
223 else
224 alSetError(pContext, AL_INVALID_VALUE);
225 break;
227 case AL_CONE_INNER_ANGLE:
228 if(flValue >= 0.0f && flValue <= 360.0f)
229 {
230 Source->flInnerAngle = flValue;
231 Source->NeedsUpdate = AL_TRUE;
232 }
233 else
234 alSetError(pContext, AL_INVALID_VALUE);
235 break;
237 case AL_CONE_OUTER_ANGLE:
238 if(flValue >= 0.0f && flValue <= 360.0f)
239 {
240 Source->flOuterAngle = flValue;
241 Source->NeedsUpdate = AL_TRUE;
242 }
243 else
244 alSetError(pContext, AL_INVALID_VALUE);
245 break;
247 case AL_GAIN:
248 if(flValue >= 0.0f)
249 {
250 Source->flGain = flValue;
251 Source->NeedsUpdate = AL_TRUE;
252 }
253 else
254 alSetError(pContext, AL_INVALID_VALUE);
255 break;
257 case AL_MAX_DISTANCE:
258 if(flValue >= 0.0f)
259 {
260 Source->flMaxDistance = flValue;
261 Source->NeedsUpdate = AL_TRUE;
262 }
263 else
264 alSetError(pContext, AL_INVALID_VALUE);
265 break;
267 case AL_ROLLOFF_FACTOR:
268 if(flValue >= 0.0f)
269 {
270 Source->flRollOffFactor = flValue;
271 Source->NeedsUpdate = AL_TRUE;
272 }
273 else
274 alSetError(pContext, AL_INVALID_VALUE);
275 break;
277 case AL_REFERENCE_DISTANCE:
278 if(flValue >= 0.0f)
279 {
280 Source->flRefDistance = flValue;
281 Source->NeedsUpdate = AL_TRUE;
282 }
283 else
284 alSetError(pContext, AL_INVALID_VALUE);
285 break;
287 case AL_MIN_GAIN:
288 if(flValue >= 0.0f && flValue <= 1.0f)
289 {
290 Source->flMinGain = flValue;
291 Source->NeedsUpdate = AL_TRUE;
292 }
293 else
294 alSetError(pContext, AL_INVALID_VALUE);
295 break;
297 case AL_MAX_GAIN:
298 if(flValue >= 0.0f && flValue <= 1.0f)
299 {
300 Source->flMaxGain = flValue;
301 Source->NeedsUpdate = AL_TRUE;
302 }
303 else
304 alSetError(pContext, AL_INVALID_VALUE);
305 break;
307 case AL_CONE_OUTER_GAIN:
308 if(flValue >= 0.0f && flValue <= 1.0f)
309 {
310 Source->flOuterGain = flValue;
311 Source->NeedsUpdate = AL_TRUE;
312 }
313 else
314 alSetError(pContext, AL_INVALID_VALUE);
315 break;
317 case AL_CONE_OUTER_GAINHF:
318 if(flValue >= 0.0f && flValue <= 1.0f)
319 {
320 Source->OuterGainHF = flValue;
321 Source->NeedsUpdate = AL_TRUE;
322 }
323 else
324 alSetError(pContext, AL_INVALID_VALUE);
325 break;
327 case AL_AIR_ABSORPTION_FACTOR:
328 if(flValue >= 0.0f && flValue <= 10.0f)
329 {
330 Source->AirAbsorptionFactor = flValue;
331 Source->NeedsUpdate = AL_TRUE;
332 }
333 else
334 alSetError(pContext, AL_INVALID_VALUE);
335 break;
337 case AL_ROOM_ROLLOFF_FACTOR:
338 if(flValue >= 0.0f && flValue <= 10.0f)
339 {
340 Source->RoomRolloffFactor = flValue;
341 Source->NeedsUpdate = AL_TRUE;
342 }
343 else
344 alSetError(pContext, AL_INVALID_VALUE);
345 break;
347 case AL_DOPPLER_FACTOR:
348 if(flValue >= 0.0f && flValue <= 1.0f)
349 {
350 Source->DopplerFactor = flValue;
351 Source->NeedsUpdate = AL_TRUE;
352 }
353 else
354 alSetError(pContext, AL_INVALID_VALUE);
355 break;
357 case AL_SEC_OFFSET:
358 case AL_SAMPLE_OFFSET:
359 case AL_BYTE_OFFSET:
360 if(flValue >= 0.0f)
361 {
362 Source->lOffsetType = eParam;
364 // Store Offset (convert Seconds into Milliseconds)
365 if(eParam == AL_SEC_OFFSET)
366 Source->lOffset = (ALint)(flValue * 1000.0f);
367 else
368 Source->lOffset = (ALint)flValue;
370 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
371 !pContext->DeferUpdates)
372 {
373 if(ApplyOffset(Source) == AL_FALSE)
374 alSetError(pContext, AL_INVALID_VALUE);
375 }
376 }
377 else
378 alSetError(pContext, AL_INVALID_VALUE);
379 break;
381 default:
382 alSetError(pContext, AL_INVALID_ENUM);
383 break;
384 }
385 }
386 else
387 {
388 // Invalid Source Name
389 alSetError(pContext, AL_INVALID_NAME);
390 }
392 UnlockContext(pContext);
393 }
396 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
397 {
398 ALCcontext *pContext;
399 ALsource *Source;
401 pContext = GetLockedContext();
402 if(!pContext) return;
404 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
405 {
406 switch(eParam)
407 {
408 case AL_POSITION:
409 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
410 {
411 Source->vPosition[0] = flValue1;
412 Source->vPosition[1] = flValue2;
413 Source->vPosition[2] = flValue3;
414 Source->NeedsUpdate = AL_TRUE;
415 }
416 else
417 alSetError(pContext, AL_INVALID_VALUE);
418 break;
420 case AL_VELOCITY:
421 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
422 {
423 Source->vVelocity[0] = flValue1;
424 Source->vVelocity[1] = flValue2;
425 Source->vVelocity[2] = flValue3;
426 Source->NeedsUpdate = AL_TRUE;
427 }
428 else
429 alSetError(pContext, AL_INVALID_VALUE);
430 break;
432 case AL_DIRECTION:
433 if(isfinite(flValue1) && isfinite(flValue2) && isfinite(flValue3))
434 {
435 Source->vOrientation[0] = flValue1;
436 Source->vOrientation[1] = flValue2;
437 Source->vOrientation[2] = flValue3;
438 Source->NeedsUpdate = AL_TRUE;
439 }
440 else
441 alSetError(pContext, AL_INVALID_VALUE);
442 break;
444 default:
445 alSetError(pContext, AL_INVALID_ENUM);
446 break;
447 }
448 }
449 else
450 alSetError(pContext, AL_INVALID_NAME);
452 UnlockContext(pContext);
453 }
456 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
457 {
458 ALCcontext *pContext;
460 if(pflValues)
461 {
462 switch(eParam)
463 {
464 case AL_PITCH:
465 case AL_CONE_INNER_ANGLE:
466 case AL_CONE_OUTER_ANGLE:
467 case AL_GAIN:
468 case AL_MAX_DISTANCE:
469 case AL_ROLLOFF_FACTOR:
470 case AL_REFERENCE_DISTANCE:
471 case AL_MIN_GAIN:
472 case AL_MAX_GAIN:
473 case AL_CONE_OUTER_GAIN:
474 case AL_CONE_OUTER_GAINHF:
475 case AL_SEC_OFFSET:
476 case AL_SAMPLE_OFFSET:
477 case AL_BYTE_OFFSET:
478 case AL_AIR_ABSORPTION_FACTOR:
479 case AL_ROOM_ROLLOFF_FACTOR:
480 alSourcef(source, eParam, pflValues[0]);
481 return;
483 case AL_POSITION:
484 case AL_VELOCITY:
485 case AL_DIRECTION:
486 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
487 return;
488 }
489 }
491 pContext = GetLockedContext();
492 if(!pContext) return;
494 if(pflValues)
495 {
496 if(LookupSource(pContext->SourceMap, source) != NULL)
497 {
498 switch(eParam)
499 {
500 default:
501 alSetError(pContext, AL_INVALID_ENUM);
502 break;
503 }
504 }
505 else
506 alSetError(pContext, AL_INVALID_NAME);
507 }
508 else
509 alSetError(pContext, AL_INVALID_VALUE);
511 UnlockContext(pContext);
512 }
515 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
516 {
517 ALCcontext *pContext;
518 ALsource *Source;
519 ALbufferlistitem *BufferListItem;
521 switch(eParam)
522 {
523 case AL_MAX_DISTANCE:
524 case AL_ROLLOFF_FACTOR:
525 case AL_CONE_INNER_ANGLE:
526 case AL_CONE_OUTER_ANGLE:
527 case AL_REFERENCE_DISTANCE:
528 alSourcef(source, eParam, (ALfloat)lValue);
529 return;
530 }
532 pContext = GetLockedContext();
533 if(!pContext) return;
535 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
536 {
537 ALCdevice *device = pContext->Device;
539 switch(eParam)
540 {
541 case AL_SOURCE_RELATIVE:
542 if(lValue == AL_FALSE || lValue == AL_TRUE)
543 {
544 Source->bHeadRelative = (ALboolean)lValue;
545 Source->NeedsUpdate = AL_TRUE;
546 }
547 else
548 alSetError(pContext, AL_INVALID_VALUE);
549 break;
551 case AL_LOOPING:
552 if(lValue == AL_FALSE || lValue == AL_TRUE)
553 Source->bLooping = (ALboolean)lValue;
554 else
555 alSetError(pContext, AL_INVALID_VALUE);
556 break;
558 case AL_BUFFER:
559 if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
560 {
561 ALbuffer *buffer = NULL;
563 if(lValue == 0 ||
564 (buffer=LookupBuffer(device->BufferMap, lValue)) != NULL)
565 {
566 // Remove all elements in the queue
567 while(Source->queue != NULL)
568 {
569 BufferListItem = Source->queue;
570 Source->queue = BufferListItem->next;
572 if(BufferListItem->buffer)
573 BufferListItem->buffer->refcount--;
574 free(BufferListItem);
575 }
576 Source->BuffersInQueue = 0;
578 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
579 if(buffer != NULL)
580 {
581 // Source is now in STATIC mode
582 Source->lSourceType = AL_STATIC;
584 // Add the selected buffer to the queue
585 BufferListItem = malloc(sizeof(ALbufferlistitem));
586 BufferListItem->buffer = buffer;
587 BufferListItem->next = NULL;
588 BufferListItem->prev = NULL;
590 Source->queue = BufferListItem;
591 Source->BuffersInQueue = 1;
593 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
594 Source->SampleSize = BytesFromFmt(buffer->FmtType);
595 if(buffer->FmtChannels == FmtMono)
596 Source->Update = CalcSourceParams;
597 else
598 Source->Update = CalcNonAttnSourceParams;
600 // Increment reference counter for buffer
601 buffer->refcount++;
602 }
603 else
604 {
605 // Source is now in UNDETERMINED mode
606 Source->lSourceType = AL_UNDETERMINED;
607 }
608 Source->BuffersPlayed = 0;
610 // Update AL_BUFFER parameter
611 Source->Buffer = buffer;
612 Source->NeedsUpdate = AL_TRUE;
613 }
614 else
615 alSetError(pContext, AL_INVALID_VALUE);
616 }
617 else
618 alSetError(pContext, AL_INVALID_OPERATION);
619 break;
621 case AL_SOURCE_STATE:
622 // Query only
623 alSetError(pContext, AL_INVALID_OPERATION);
624 break;
626 case AL_SEC_OFFSET:
627 case AL_SAMPLE_OFFSET:
628 case AL_BYTE_OFFSET:
629 if(lValue >= 0)
630 {
631 Source->lOffsetType = eParam;
633 // Store Offset (convert Seconds into Milliseconds)
634 if(eParam == AL_SEC_OFFSET)
635 Source->lOffset = lValue * 1000;
636 else
637 Source->lOffset = lValue;
639 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
640 !pContext->DeferUpdates)
641 {
642 if(ApplyOffset(Source) == AL_FALSE)
643 alSetError(pContext, AL_INVALID_VALUE);
644 }
645 }
646 else
647 alSetError(pContext, AL_INVALID_VALUE);
648 break;
650 case AL_DIRECT_FILTER: {
651 ALfilter *filter = NULL;
653 if(lValue == 0 ||
654 (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL)
655 {
656 if(!filter)
657 {
658 Source->DirectFilter.type = AL_FILTER_NULL;
659 Source->DirectFilter.filter = 0;
660 }
661 else
662 memcpy(&Source->DirectFilter, filter, sizeof(*filter));
663 Source->NeedsUpdate = AL_TRUE;
664 }
665 else
666 alSetError(pContext, AL_INVALID_VALUE);
667 } break;
669 case AL_DIRECT_FILTER_GAINHF_AUTO:
670 if(lValue == AL_TRUE || lValue == AL_FALSE)
671 {
672 Source->DryGainHFAuto = lValue;
673 Source->NeedsUpdate = AL_TRUE;
674 }
675 else
676 alSetError(pContext, AL_INVALID_VALUE);
677 break;
679 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
680 if(lValue == AL_TRUE || lValue == AL_FALSE)
681 {
682 Source->WetGainAuto = lValue;
683 Source->NeedsUpdate = AL_TRUE;
684 }
685 else
686 alSetError(pContext, AL_INVALID_VALUE);
687 break;
689 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
690 if(lValue == AL_TRUE || lValue == AL_FALSE)
691 {
692 Source->WetGainHFAuto = lValue;
693 Source->NeedsUpdate = AL_TRUE;
694 }
695 else
696 alSetError(pContext, AL_INVALID_VALUE);
697 break;
699 case AL_VIRTUAL_CHANNELS_SOFT:
700 if(lValue == AL_TRUE || lValue == AL_FALSE)
701 {
702 Source->VirtualChannels = lValue;
703 Source->NeedsUpdate = AL_TRUE;
704 }
705 else
706 alSetError(pContext, AL_INVALID_VALUE);
707 break;
709 case AL_DISTANCE_MODEL:
710 if(lValue == AL_NONE ||
711 lValue == AL_INVERSE_DISTANCE ||
712 lValue == AL_INVERSE_DISTANCE_CLAMPED ||
713 lValue == AL_LINEAR_DISTANCE ||
714 lValue == AL_LINEAR_DISTANCE_CLAMPED ||
715 lValue == AL_EXPONENT_DISTANCE ||
716 lValue == AL_EXPONENT_DISTANCE_CLAMPED)
717 {
718 Source->DistanceModel = lValue;
719 if(pContext->SourceDistanceModel)
720 Source->NeedsUpdate = AL_TRUE;
721 }
722 else
723 alSetError(pContext, AL_INVALID_VALUE);
724 break;
726 default:
727 alSetError(pContext, AL_INVALID_ENUM);
728 break;
729 }
730 }
731 else
732 alSetError(pContext, AL_INVALID_NAME);
734 UnlockContext(pContext);
735 }
738 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
739 {
740 ALCcontext *pContext;
741 ALsource *Source;
743 switch(eParam)
744 {
745 case AL_POSITION:
746 case AL_VELOCITY:
747 case AL_DIRECTION:
748 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
749 return;
750 }
752 pContext = GetLockedContext();
753 if(!pContext) return;
755 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
756 {
757 ALCdevice *device = pContext->Device;
759 switch(eParam)
760 {
761 case AL_AUXILIARY_SEND_FILTER: {
762 ALeffectslot *ALEffectSlot = NULL;
763 ALfilter *ALFilter = NULL;
765 if((ALuint)lValue2 < device->NumAuxSends &&
766 (lValue1 == 0 ||
767 (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
768 (lValue3 == 0 ||
769 (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL))
770 {
771 /* Release refcount on the previous slot, and add one for
772 * the new slot */
773 if(Source->Send[lValue2].Slot)
774 Source->Send[lValue2].Slot->refcount--;
775 Source->Send[lValue2].Slot = ALEffectSlot;
776 if(Source->Send[lValue2].Slot)
777 Source->Send[lValue2].Slot->refcount++;
779 if(!ALFilter)
780 {
781 /* Disable filter */
782 Source->Send[lValue2].WetFilter.type = 0;
783 Source->Send[lValue2].WetFilter.filter = 0;
784 }
785 else
786 memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
787 Source->NeedsUpdate = AL_TRUE;
788 }
789 else
790 alSetError(pContext, AL_INVALID_VALUE);
791 } break;
793 default:
794 alSetError(pContext, AL_INVALID_ENUM);
795 break;
796 }
797 }
798 else
799 alSetError(pContext, AL_INVALID_NAME);
801 UnlockContext(pContext);
802 }
805 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
806 {
807 ALCcontext *pContext;
809 if(plValues)
810 {
811 switch(eParam)
812 {
813 case AL_SOURCE_RELATIVE:
814 case AL_CONE_INNER_ANGLE:
815 case AL_CONE_OUTER_ANGLE:
816 case AL_LOOPING:
817 case AL_BUFFER:
818 case AL_SOURCE_STATE:
819 case AL_SEC_OFFSET:
820 case AL_SAMPLE_OFFSET:
821 case AL_BYTE_OFFSET:
822 case AL_MAX_DISTANCE:
823 case AL_ROLLOFF_FACTOR:
824 case AL_REFERENCE_DISTANCE:
825 case AL_DIRECT_FILTER:
826 case AL_DIRECT_FILTER_GAINHF_AUTO:
827 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
828 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
829 case AL_DISTANCE_MODEL:
830 case AL_VIRTUAL_CHANNELS_SOFT:
831 alSourcei(source, eParam, plValues[0]);
832 return;
834 case AL_POSITION:
835 case AL_VELOCITY:
836 case AL_DIRECTION:
837 case AL_AUXILIARY_SEND_FILTER:
838 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
839 return;
840 }
841 }
843 pContext = GetLockedContext();
844 if(!pContext) return;
846 if(plValues)
847 {
848 if(LookupSource(pContext->SourceMap, source) != NULL)
849 {
850 switch(eParam)
851 {
852 default:
853 alSetError(pContext, AL_INVALID_ENUM);
854 break;
855 }
856 }
857 else
858 alSetError(pContext, AL_INVALID_NAME);
859 }
860 else
861 alSetError(pContext, AL_INVALID_VALUE);
863 UnlockContext(pContext);
864 }
867 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
868 {
869 ALCcontext *pContext;
870 ALsource *Source;
871 ALdouble Offsets[2];
872 ALdouble updateLen;
874 pContext = GetLockedContext();
875 if(!pContext) return;
877 if(pflValue)
878 {
879 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
880 {
881 switch(eParam)
882 {
883 case AL_PITCH:
884 *pflValue = Source->flPitch;
885 break;
887 case AL_GAIN:
888 *pflValue = Source->flGain;
889 break;
891 case AL_MIN_GAIN:
892 *pflValue = Source->flMinGain;
893 break;
895 case AL_MAX_GAIN:
896 *pflValue = Source->flMaxGain;
897 break;
899 case AL_MAX_DISTANCE:
900 *pflValue = Source->flMaxDistance;
901 break;
903 case AL_ROLLOFF_FACTOR:
904 *pflValue = Source->flRollOffFactor;
905 break;
907 case AL_CONE_OUTER_GAIN:
908 *pflValue = Source->flOuterGain;
909 break;
911 case AL_CONE_OUTER_GAINHF:
912 *pflValue = Source->OuterGainHF;
913 break;
915 case AL_SEC_OFFSET:
916 case AL_SAMPLE_OFFSET:
917 case AL_BYTE_OFFSET:
918 updateLen = (ALdouble)pContext->Device->UpdateSize /
919 pContext->Device->Frequency;
920 GetSourceOffset(Source, eParam, Offsets, updateLen);
921 *pflValue = Offsets[0];
922 break;
924 case AL_CONE_INNER_ANGLE:
925 *pflValue = Source->flInnerAngle;
926 break;
928 case AL_CONE_OUTER_ANGLE:
929 *pflValue = Source->flOuterAngle;
930 break;
932 case AL_REFERENCE_DISTANCE:
933 *pflValue = Source->flRefDistance;
934 break;
936 case AL_AIR_ABSORPTION_FACTOR:
937 *pflValue = Source->AirAbsorptionFactor;
938 break;
940 case AL_ROOM_ROLLOFF_FACTOR:
941 *pflValue = Source->RoomRolloffFactor;
942 break;
944 case AL_DOPPLER_FACTOR:
945 *pflValue = Source->DopplerFactor;
946 break;
948 default:
949 alSetError(pContext, AL_INVALID_ENUM);
950 break;
951 }
952 }
953 else
954 alSetError(pContext, AL_INVALID_NAME);
955 }
956 else
957 alSetError(pContext, AL_INVALID_VALUE);
959 UnlockContext(pContext);
960 }
963 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
964 {
965 ALCcontext *pContext;
966 ALsource *Source;
968 pContext = GetLockedContext();
969 if(!pContext) return;
971 if(pflValue1 && pflValue2 && pflValue3)
972 {
973 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
974 {
975 switch(eParam)
976 {
977 case AL_POSITION:
978 *pflValue1 = Source->vPosition[0];
979 *pflValue2 = Source->vPosition[1];
980 *pflValue3 = Source->vPosition[2];
981 break;
983 case AL_VELOCITY:
984 *pflValue1 = Source->vVelocity[0];
985 *pflValue2 = Source->vVelocity[1];
986 *pflValue3 = Source->vVelocity[2];
987 break;
989 case AL_DIRECTION:
990 *pflValue1 = Source->vOrientation[0];
991 *pflValue2 = Source->vOrientation[1];
992 *pflValue3 = Source->vOrientation[2];
993 break;
995 default:
996 alSetError(pContext, AL_INVALID_ENUM);
997 break;
998 }
999 }
1000 else
1001 alSetError(pContext, AL_INVALID_NAME);
1003 else
1004 alSetError(pContext, AL_INVALID_VALUE);
1006 UnlockContext(pContext);
1010 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1012 ALCcontext *pContext;
1013 ALsource *Source;
1014 ALdouble Offsets[2];
1015 ALdouble updateLen;
1017 switch(eParam)
1019 case AL_PITCH:
1020 case AL_GAIN:
1021 case AL_MIN_GAIN:
1022 case AL_MAX_GAIN:
1023 case AL_MAX_DISTANCE:
1024 case AL_ROLLOFF_FACTOR:
1025 case AL_DOPPLER_FACTOR:
1026 case AL_CONE_OUTER_GAIN:
1027 case AL_SEC_OFFSET:
1028 case AL_SAMPLE_OFFSET:
1029 case AL_BYTE_OFFSET:
1030 case AL_CONE_INNER_ANGLE:
1031 case AL_CONE_OUTER_ANGLE:
1032 case AL_REFERENCE_DISTANCE:
1033 case AL_CONE_OUTER_GAINHF:
1034 case AL_AIR_ABSORPTION_FACTOR:
1035 case AL_ROOM_ROLLOFF_FACTOR:
1036 alGetSourcef(source, eParam, pflValues);
1037 return;
1039 case AL_POSITION:
1040 case AL_VELOCITY:
1041 case AL_DIRECTION:
1042 alGetSource3f(source, eParam, pflValues+0, pflValues+1, pflValues+2);
1043 return;
1046 pContext = GetLockedContext();
1047 if(!pContext) return;
1049 if(pflValues)
1051 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1053 switch(eParam)
1055 case AL_SAMPLE_RW_OFFSETS_SOFT:
1056 case AL_BYTE_RW_OFFSETS_SOFT:
1057 updateLen = (ALdouble)pContext->Device->UpdateSize /
1058 pContext->Device->Frequency;
1059 GetSourceOffset(Source, eParam, Offsets, updateLen);
1060 pflValues[0] = Offsets[0];
1061 pflValues[1] = Offsets[1];
1062 break;
1064 default:
1065 alSetError(pContext, AL_INVALID_ENUM);
1066 break;
1069 else
1070 alSetError(pContext, AL_INVALID_NAME);
1072 else
1073 alSetError(pContext, AL_INVALID_VALUE);
1075 UnlockContext(pContext);
1079 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1081 ALCcontext *pContext;
1082 ALsource *Source;
1083 ALdouble Offsets[2];
1084 ALdouble updateLen;
1086 pContext = GetLockedContext();
1087 if(!pContext) return;
1089 if(plValue)
1091 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1093 switch(eParam)
1095 case AL_MAX_DISTANCE:
1096 *plValue = (ALint)Source->flMaxDistance;
1097 break;
1099 case AL_ROLLOFF_FACTOR:
1100 *plValue = (ALint)Source->flRollOffFactor;
1101 break;
1103 case AL_REFERENCE_DISTANCE:
1104 *plValue = (ALint)Source->flRefDistance;
1105 break;
1107 case AL_SOURCE_RELATIVE:
1108 *plValue = Source->bHeadRelative;
1109 break;
1111 case AL_CONE_INNER_ANGLE:
1112 *plValue = (ALint)Source->flInnerAngle;
1113 break;
1115 case AL_CONE_OUTER_ANGLE:
1116 *plValue = (ALint)Source->flOuterAngle;
1117 break;
1119 case AL_LOOPING:
1120 *plValue = Source->bLooping;
1121 break;
1123 case AL_BUFFER:
1124 *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
1125 break;
1127 case AL_SOURCE_STATE:
1128 *plValue = Source->state;
1129 break;
1131 case AL_BUFFERS_QUEUED:
1132 *plValue = Source->BuffersInQueue;
1133 break;
1135 case AL_BUFFERS_PROCESSED:
1136 if(Source->bLooping || Source->lSourceType != AL_STREAMING)
1138 /* Buffers on a looping source are in a perpetual state
1139 * of PENDING, so don't report any as PROCESSED */
1140 *plValue = 0;
1142 else
1143 *plValue = Source->BuffersPlayed;
1144 break;
1146 case AL_SOURCE_TYPE:
1147 *plValue = Source->lSourceType;
1148 break;
1150 case AL_SEC_OFFSET:
1151 case AL_SAMPLE_OFFSET:
1152 case AL_BYTE_OFFSET:
1153 updateLen = (ALdouble)pContext->Device->UpdateSize /
1154 pContext->Device->Frequency;
1155 GetSourceOffset(Source, eParam, Offsets, updateLen);
1156 *plValue = (ALint)Offsets[0];
1157 break;
1159 case AL_DIRECT_FILTER:
1160 *plValue = Source->DirectFilter.filter;
1161 break;
1163 case AL_DIRECT_FILTER_GAINHF_AUTO:
1164 *plValue = Source->DryGainHFAuto;
1165 break;
1167 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1168 *plValue = Source->WetGainAuto;
1169 break;
1171 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1172 *plValue = Source->WetGainHFAuto;
1173 break;
1175 case AL_DOPPLER_FACTOR:
1176 *plValue = (ALint)Source->DopplerFactor;
1177 break;
1179 case AL_VIRTUAL_CHANNELS_SOFT:
1180 *plValue = Source->VirtualChannels;
1181 break;
1183 case AL_DISTANCE_MODEL:
1184 *plValue = Source->DistanceModel;
1185 break;
1187 default:
1188 alSetError(pContext, AL_INVALID_ENUM);
1189 break;
1192 else
1193 alSetError(pContext, AL_INVALID_NAME);
1195 else
1196 alSetError(pContext, AL_INVALID_VALUE);
1198 UnlockContext(pContext);
1202 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1204 ALCcontext *pContext;
1205 ALsource *Source;
1207 pContext = GetLockedContext();
1208 if(!pContext) return;
1210 if(plValue1 && plValue2 && plValue3)
1212 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1214 switch(eParam)
1216 case AL_POSITION:
1217 *plValue1 = (ALint)Source->vPosition[0];
1218 *plValue2 = (ALint)Source->vPosition[1];
1219 *plValue3 = (ALint)Source->vPosition[2];
1220 break;
1222 case AL_VELOCITY:
1223 *plValue1 = (ALint)Source->vVelocity[0];
1224 *plValue2 = (ALint)Source->vVelocity[1];
1225 *plValue3 = (ALint)Source->vVelocity[2];
1226 break;
1228 case AL_DIRECTION:
1229 *plValue1 = (ALint)Source->vOrientation[0];
1230 *plValue2 = (ALint)Source->vOrientation[1];
1231 *plValue3 = (ALint)Source->vOrientation[2];
1232 break;
1234 default:
1235 alSetError(pContext, AL_INVALID_ENUM);
1236 break;
1239 else
1240 alSetError(pContext, AL_INVALID_NAME);
1242 else
1243 alSetError(pContext, AL_INVALID_VALUE);
1245 UnlockContext(pContext);
1249 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1251 ALCcontext *pContext;
1252 ALsource *Source;
1253 ALdouble Offsets[2];
1254 ALdouble updateLen;
1256 switch(eParam)
1258 case AL_SOURCE_RELATIVE:
1259 case AL_CONE_INNER_ANGLE:
1260 case AL_CONE_OUTER_ANGLE:
1261 case AL_LOOPING:
1262 case AL_BUFFER:
1263 case AL_SOURCE_STATE:
1264 case AL_BUFFERS_QUEUED:
1265 case AL_BUFFERS_PROCESSED:
1266 case AL_SEC_OFFSET:
1267 case AL_SAMPLE_OFFSET:
1268 case AL_BYTE_OFFSET:
1269 case AL_MAX_DISTANCE:
1270 case AL_ROLLOFF_FACTOR:
1271 case AL_DOPPLER_FACTOR:
1272 case AL_REFERENCE_DISTANCE:
1273 case AL_SOURCE_TYPE:
1274 case AL_DIRECT_FILTER:
1275 case AL_DIRECT_FILTER_GAINHF_AUTO:
1276 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1277 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1278 case AL_DISTANCE_MODEL:
1279 case AL_VIRTUAL_CHANNELS_SOFT:
1280 alGetSourcei(source, eParam, plValues);
1281 return;
1283 case AL_POSITION:
1284 case AL_VELOCITY:
1285 case AL_DIRECTION:
1286 alGetSource3i(source, eParam, plValues+0, plValues+1, plValues+2);
1287 return;
1290 pContext = GetLockedContext();
1291 if(!pContext) return;
1293 if(plValues)
1295 if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
1297 switch(eParam)
1299 case AL_SAMPLE_RW_OFFSETS_SOFT:
1300 case AL_BYTE_RW_OFFSETS_SOFT:
1301 updateLen = (ALdouble)pContext->Device->UpdateSize /
1302 pContext->Device->Frequency;
1303 GetSourceOffset(Source, eParam, Offsets, updateLen);
1304 plValues[0] = (ALint)Offsets[0];
1305 plValues[1] = (ALint)Offsets[1];
1306 break;
1308 default:
1309 alSetError(pContext, AL_INVALID_ENUM);
1310 break;
1313 else
1314 alSetError(pContext, AL_INVALID_NAME);
1316 else
1317 alSetError(pContext, AL_INVALID_VALUE);
1319 UnlockContext(pContext);
1323 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1325 alSourcePlayv(1, &source);
1328 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1330 ALCcontext *Context;
1331 ALsource *Source;
1332 ALsizei i;
1334 Context = GetLockedContext();
1335 if(!Context) return;
1337 if(n < 0)
1339 alSetError(Context, AL_INVALID_VALUE);
1340 goto done;
1342 if(n > 0 && !sources)
1344 alSetError(Context, AL_INVALID_VALUE);
1345 goto done;
1348 // Check that all the Sources are valid
1349 for(i = 0;i < n;i++)
1351 if(!LookupSource(Context->SourceMap, sources[i]))
1353 alSetError(Context, AL_INVALID_NAME);
1354 goto done;
1358 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1360 void *temp = NULL;
1361 ALsizei newcount;
1363 newcount = Context->MaxActiveSources << 1;
1364 if(newcount > 0)
1365 temp = realloc(Context->ActiveSources,
1366 sizeof(*Context->ActiveSources) * newcount);
1367 if(!temp)
1369 alSetError(Context, AL_OUT_OF_MEMORY);
1370 goto done;
1373 Context->ActiveSources = temp;
1374 Context->MaxActiveSources = newcount;
1377 for(i = 0;i < n;i++)
1379 Source = LookupSource(Context->SourceMap, sources[i]);
1380 if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
1381 else SetSourceState(Source, Context, AL_PLAYING);
1384 done:
1385 UnlockContext(Context);
1388 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1390 alSourcePausev(1, &source);
1393 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1395 ALCcontext *Context;
1396 ALsource *Source;
1397 ALsizei i;
1399 Context = GetLockedContext();
1400 if(!Context) return;
1402 if(n < 0)
1404 alSetError(Context, AL_INVALID_VALUE);
1405 goto done;
1407 if(n > 0 && !sources)
1409 alSetError(Context, AL_INVALID_VALUE);
1410 goto done;
1413 // Check all the Sources are valid
1414 for(i = 0;i < n;i++)
1416 if(!LookupSource(Context->SourceMap, sources[i]))
1418 alSetError(Context, AL_INVALID_NAME);
1419 goto done;
1423 for(i = 0;i < n;i++)
1425 Source = LookupSource(Context->SourceMap, sources[i]);
1426 if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
1427 else SetSourceState(Source, Context, AL_PAUSED);
1430 done:
1431 UnlockContext(Context);
1434 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1436 alSourceStopv(1, &source);
1439 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1441 ALCcontext *Context;
1442 ALsource *Source;
1443 ALsizei i;
1445 Context = GetLockedContext();
1446 if(!Context) return;
1448 if(n < 0)
1450 alSetError(Context, AL_INVALID_VALUE);
1451 goto done;
1453 if(n > 0 && !sources)
1455 alSetError(Context, AL_INVALID_VALUE);
1456 goto done;
1459 // Check all the Sources are valid
1460 for(i = 0;i < n;i++)
1462 if(!LookupSource(Context->SourceMap, sources[i]))
1464 alSetError(Context, AL_INVALID_NAME);
1465 goto done;
1469 for(i = 0;i < n;i++)
1471 Source = LookupSource(Context->SourceMap, sources[i]);
1472 if(Context->DeferUpdates) Source->new_state = AL_STOPPED;
1473 else SetSourceState(Source, Context, AL_STOPPED);
1476 done:
1477 UnlockContext(Context);
1480 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
1482 alSourceRewindv(1, &source);
1485 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1487 ALCcontext *Context;
1488 ALsource *Source;
1489 ALsizei i;
1491 Context = GetLockedContext();
1492 if(!Context) return;
1494 if(n < 0)
1496 alSetError(Context, AL_INVALID_VALUE);
1497 goto done;
1499 if(n > 0 && !sources)
1501 alSetError(Context, AL_INVALID_VALUE);
1502 goto done;
1505 // Check all the Sources are valid
1506 for(i = 0;i < n;i++)
1508 if(!LookupSource(Context->SourceMap, sources[i]))
1510 alSetError(Context, AL_INVALID_NAME);
1511 goto done;
1515 for(i = 0;i < n;i++)
1517 Source = LookupSource(Context->SourceMap, sources[i]);
1518 if(Context->DeferUpdates) Source->new_state = AL_INITIAL;
1519 else SetSourceState(Source, Context, AL_INITIAL);
1522 done:
1523 UnlockContext(Context);
1527 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
1529 ALCcontext *Context;
1530 ALCdevice *device;
1531 ALsource *Source;
1532 ALbuffer *buffer;
1533 ALsizei i;
1534 ALbufferlistitem *BufferListStart;
1535 ALbufferlistitem *BufferList;
1536 ALbuffer *BufferFmt;
1538 if(n == 0)
1539 return;
1541 Context = GetLockedContext();
1542 if(!Context) return;
1544 if(n < 0)
1546 alSetError(Context, AL_INVALID_VALUE);
1547 goto done;
1550 // Check that all buffers are valid or zero and that the source is valid
1552 // Check that this is a valid source
1553 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1555 alSetError(Context, AL_INVALID_NAME);
1556 goto done;
1559 // Check that this is not a STATIC Source
1560 if(Source->lSourceType == AL_STATIC)
1562 // Invalid Source Type (can't queue on a Static Source)
1563 alSetError(Context, AL_INVALID_OPERATION);
1564 goto done;
1567 device = Context->Device;
1569 BufferFmt = NULL;
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 BufferFmt = BufferList->buffer;
1578 break;
1580 BufferList = BufferList->next;
1583 for(i = 0;i < n;i++)
1585 if(!buffers[i])
1586 continue;
1588 if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
1590 alSetError(Context, AL_INVALID_NAME);
1591 goto done;
1594 if(BufferFmt == NULL)
1596 BufferFmt = buffer;
1598 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
1599 Source->SampleSize = BytesFromFmt(buffer->FmtType);
1600 if(buffer->FmtChannels == FmtMono)
1601 Source->Update = CalcSourceParams;
1602 else
1603 Source->Update = CalcNonAttnSourceParams;
1605 Source->NeedsUpdate = AL_TRUE;
1607 else if(BufferFmt->Frequency != buffer->Frequency ||
1608 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
1609 BufferFmt->OriginalType != buffer->OriginalType)
1611 alSetError(Context, AL_INVALID_OPERATION);
1612 goto done;
1616 // Change Source Type
1617 Source->lSourceType = AL_STREAMING;
1619 buffer = LookupBuffer(device->BufferMap, buffers[0]);
1621 // All buffers are valid - so add them to the list
1622 BufferListStart = malloc(sizeof(ALbufferlistitem));
1623 BufferListStart->buffer = buffer;
1624 BufferListStart->next = NULL;
1625 BufferListStart->prev = NULL;
1627 // Increment reference counter for buffer
1628 if(buffer) buffer->refcount++;
1630 BufferList = BufferListStart;
1632 for(i = 1;i < n;i++)
1634 buffer = LookupBuffer(device->BufferMap, buffers[i]);
1636 BufferList->next = malloc(sizeof(ALbufferlistitem));
1637 BufferList->next->buffer = buffer;
1638 BufferList->next->next = NULL;
1639 BufferList->next->prev = BufferList;
1641 // Increment reference counter for buffer
1642 if(buffer) buffer->refcount++;
1644 BufferList = BufferList->next;
1647 if(Source->queue == NULL)
1649 Source->queue = BufferListStart;
1650 // Update Current Buffer
1651 Source->Buffer = BufferListStart->buffer;
1653 else
1655 // Find end of queue
1656 BufferList = Source->queue;
1657 while(BufferList->next != NULL)
1658 BufferList = BufferList->next;
1660 BufferList->next = BufferListStart;
1661 BufferList->next->prev = BufferList;
1664 // Update number of buffers in queue
1665 Source->BuffersInQueue += n;
1667 done:
1668 UnlockContext(Context);
1672 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1673 // an array of buffer IDs that are to be filled with the names of the buffers removed
1674 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1676 ALCcontext *Context;
1677 ALsource *Source;
1678 ALsizei i;
1679 ALbufferlistitem *BufferList;
1681 if(n == 0)
1682 return;
1684 Context = GetLockedContext();
1685 if(!Context) return;
1687 if(n < 0)
1689 alSetError(Context, AL_INVALID_VALUE);
1690 goto done;
1693 if((Source=LookupSource(Context->SourceMap, source)) == NULL)
1695 alSetError(Context, AL_INVALID_NAME);
1696 goto done;
1699 if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
1700 (ALuint)n > Source->BuffersPlayed)
1702 // Some buffers can't be unqueue because they have not been processed
1703 alSetError(Context, AL_INVALID_VALUE);
1704 goto done;
1707 for(i = 0;i < n;i++)
1709 BufferList = Source->queue;
1710 Source->queue = BufferList->next;
1712 if(BufferList->buffer)
1714 // Record name of buffer
1715 buffers[i] = BufferList->buffer->buffer;
1716 // Decrement buffer reference counter
1717 BufferList->buffer->refcount--;
1719 else
1720 buffers[i] = 0;
1722 // Release memory for buffer list item
1723 free(BufferList);
1724 Source->BuffersInQueue--;
1726 if(Source->queue)
1727 Source->queue->prev = NULL;
1729 if(Source->state != AL_PLAYING)
1731 if(Source->queue)
1732 Source->Buffer = Source->queue->buffer;
1733 else
1734 Source->Buffer = NULL;
1736 Source->BuffersPlayed -= n;
1738 done:
1739 UnlockContext(Context);
1743 static ALvoid InitSourceParams(ALsource *Source)
1745 Source->flInnerAngle = 360.0f;
1746 Source->flOuterAngle = 360.0f;
1747 Source->flPitch = 1.0f;
1748 Source->vPosition[0] = 0.0f;
1749 Source->vPosition[1] = 0.0f;
1750 Source->vPosition[2] = 0.0f;
1751 Source->vOrientation[0] = 0.0f;
1752 Source->vOrientation[1] = 0.0f;
1753 Source->vOrientation[2] = 0.0f;
1754 Source->vVelocity[0] = 0.0f;
1755 Source->vVelocity[1] = 0.0f;
1756 Source->vVelocity[2] = 0.0f;
1757 Source->flRefDistance = 1.0f;
1758 Source->flMaxDistance = FLT_MAX;
1759 Source->flRollOffFactor = 1.0f;
1760 Source->bLooping = AL_FALSE;
1761 Source->flGain = 1.0f;
1762 Source->flMinGain = 0.0f;
1763 Source->flMaxGain = 1.0f;
1764 Source->flOuterGain = 0.0f;
1765 Source->OuterGainHF = 1.0f;
1767 Source->DryGainHFAuto = AL_TRUE;
1768 Source->WetGainAuto = AL_TRUE;
1769 Source->WetGainHFAuto = AL_TRUE;
1770 Source->AirAbsorptionFactor = 0.0f;
1771 Source->RoomRolloffFactor = 0.0f;
1772 Source->DopplerFactor = 1.0f;
1773 Source->VirtualChannels = AL_TRUE;
1775 Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
1777 Source->Resampler = DefaultResampler;
1779 Source->state = AL_INITIAL;
1780 Source->new_state = AL_NONE;
1781 Source->lSourceType = AL_UNDETERMINED;
1782 Source->lOffset = -1;
1784 Source->NeedsUpdate = AL_TRUE;
1786 Source->Buffer = NULL;
1788 Source->HrtfMoving = AL_FALSE;
1789 Source->HrtfCounter = 0;
1793 /*
1794 * SetSourceState
1796 * Sets the source's new play state given its current state
1797 */
1798 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
1800 if(state == AL_PLAYING)
1802 ALbufferlistitem *BufferList;
1803 ALsizei j, k;
1805 /* Check that there is a queue containing at least one non-null, non zero length AL Buffer */
1806 BufferList = Source->queue;
1807 while(BufferList)
1809 if(BufferList->buffer != NULL && BufferList->buffer->size)
1810 break;
1811 BufferList = BufferList->next;
1814 /* If there's nothing to play, or device is disconnected, go right to
1815 * stopped */
1816 if(!BufferList || !Context->Device->Connected)
1818 SetSourceState(Source, Context, AL_STOPPED);
1819 return;
1822 if(Source->state != AL_PLAYING)
1824 for(j = 0;j < MAXCHANNELS;j++)
1826 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
1827 Source->HrtfHistory[j][k] = 0.0f;
1828 for(k = 0;k < HRIR_LENGTH;k++)
1830 Source->HrtfValues[j][k][0] = 0.0f;
1831 Source->HrtfValues[j][k][1] = 0.0f;
1836 if(Source->state != AL_PAUSED)
1838 Source->state = AL_PLAYING;
1839 Source->position = 0;
1840 Source->position_fraction = 0;
1841 Source->BuffersPlayed = 0;
1843 Source->Buffer = Source->queue->buffer;
1845 else
1846 Source->state = AL_PLAYING;
1848 // Check if an Offset has been set
1849 if(Source->lOffset != -1)
1850 ApplyOffset(Source);
1852 for(j = 0;j < Context->ActiveSourceCount;j++)
1854 if(Context->ActiveSources[j] == Source)
1855 break;
1857 if(j == Context->ActiveSourceCount)
1858 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
1860 else if(state == AL_PAUSED)
1862 if(Source->state == AL_PLAYING)
1864 Source->state = AL_PAUSED;
1865 Source->HrtfMoving = AL_FALSE;
1866 Source->HrtfCounter = 0;
1869 else if(state == AL_STOPPED)
1871 if(Source->state != AL_INITIAL)
1873 Source->state = AL_STOPPED;
1874 Source->BuffersPlayed = Source->BuffersInQueue;
1875 Source->HrtfMoving = AL_FALSE;
1876 Source->HrtfCounter = 0;
1878 Source->lOffset = -1;
1880 else if(state == AL_INITIAL)
1882 if(Source->state != AL_INITIAL)
1884 Source->state = AL_INITIAL;
1885 Source->position = 0;
1886 Source->position_fraction = 0;
1887 Source->BuffersPlayed = 0;
1888 if(Source->queue)
1889 Source->Buffer = Source->queue->buffer;
1890 Source->HrtfMoving = AL_FALSE;
1891 Source->HrtfCounter = 0;
1893 Source->lOffset = -1;
1897 /*
1898 GetSourceOffset
1900 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1901 The offset is relative to the start of the queue (not the start of the current buffer)
1902 */
1903 static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
1905 const ALbufferlistitem *BufferList;
1906 const ALbuffer *Buffer = NULL;
1907 enum UserFmtType OriginalType;
1908 ALsizei BufferFreq;
1909 ALint Channels, Bytes;
1910 ALuint readPos, writePos;
1911 ALuint TotalBufferDataSize;
1912 ALuint i;
1914 // Find the first non-NULL Buffer in the Queue
1915 BufferList = Source->queue;
1916 while(BufferList)
1918 if(BufferList->buffer)
1920 Buffer = BufferList->buffer;
1921 break;
1923 BufferList = BufferList->next;
1926 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
1928 offset[0] = 0.0;
1929 offset[1] = 0.0;
1930 return;
1933 // Get Current Buffer Size and frequency (in milliseconds)
1934 BufferFreq = Buffer->Frequency;
1935 OriginalType = Buffer->OriginalType;
1936 Channels = ChannelsFromFmt(Buffer->FmtChannels);
1937 Bytes = BytesFromFmt(Buffer->FmtType);
1939 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1940 readPos = Source->position * Channels * Bytes;
1941 // Add byte length of any processed buffers in the queue
1942 TotalBufferDataSize = 0;
1943 BufferList = Source->queue;
1944 for(i = 0;BufferList;i++)
1946 if(BufferList->buffer)
1948 if(i < Source->BuffersPlayed)
1949 readPos += BufferList->buffer->size;
1950 TotalBufferDataSize += BufferList->buffer->size;
1952 BufferList = BufferList->next;
1954 if(Source->state == AL_PLAYING)
1955 writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
1956 else
1957 writePos = readPos;
1959 if(Source->bLooping)
1961 readPos %= TotalBufferDataSize;
1962 writePos %= TotalBufferDataSize;
1964 else
1966 // Wrap positions back to 0
1967 if(readPos >= TotalBufferDataSize)
1968 readPos = 0;
1969 if(writePos >= TotalBufferDataSize)
1970 writePos = 0;
1973 switch(name)
1975 case AL_SEC_OFFSET:
1976 offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
1977 offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
1978 break;
1979 case AL_SAMPLE_OFFSET:
1980 case AL_SAMPLE_RW_OFFSETS_SOFT:
1981 offset[0] = (ALdouble)(readPos / (Channels * Bytes));
1982 offset[1] = (ALdouble)(writePos / (Channels * Bytes));
1983 break;
1984 case AL_BYTE_OFFSET:
1985 case AL_BYTE_RW_OFFSETS_SOFT:
1986 // Take into account the original format of the Buffer
1987 if(OriginalType == UserFmtIMA4)
1989 ALuint FrameBlockSize = 65 * Bytes * Channels;
1990 ALuint BlockSize = 36 * Channels;
1992 // Round down to nearest ADPCM block
1993 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
1994 if(Source->state != AL_PLAYING)
1995 offset[1] = offset[0];
1996 else
1998 // Round up to nearest ADPCM block
1999 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2000 FrameBlockSize * BlockSize);
2003 else
2005 ALuint OrigBytes = BytesFromUserFmt(OriginalType);
2006 offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
2007 offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
2009 break;
2014 /*
2015 ApplyOffset
2017 Apply a playback offset to the Source. This function will update the queue (to correctly
2018 mark buffers as 'pending' or 'processed' depending upon the new offset.
2019 */
2020 ALboolean ApplyOffset(ALsource *Source)
2022 const ALbufferlistitem *BufferList;
2023 const ALbuffer *Buffer;
2024 ALint lBufferSize, lTotalBufferSize;
2025 ALint BuffersPlayed;
2026 ALint lByteOffset;
2028 // Get true byte offset
2029 lByteOffset = GetByteOffset(Source);
2031 // If the offset is invalid, don't apply it
2032 if(lByteOffset == -1)
2033 return AL_FALSE;
2035 // Sort out the queue (pending and processed states)
2036 BufferList = Source->queue;
2037 lTotalBufferSize = 0;
2038 BuffersPlayed = 0;
2040 while(BufferList)
2042 Buffer = BufferList->buffer;
2043 lBufferSize = Buffer ? Buffer->size : 0;
2045 if(lBufferSize <= lByteOffset-lTotalBufferSize)
2047 // Offset is past this buffer so increment BuffersPlayed
2048 BuffersPlayed++;
2050 else if(lTotalBufferSize <= lByteOffset)
2052 // Offset is within this buffer
2053 // Set Current Buffer
2054 Source->Buffer = BufferList->buffer;
2055 Source->BuffersPlayed = BuffersPlayed;
2057 // SW Mixer Positions are in Samples
2058 Source->position = (lByteOffset - lTotalBufferSize) /
2059 FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
2060 return AL_TRUE;
2063 // Increment the TotalBufferSize
2064 lTotalBufferSize += lBufferSize;
2066 // Move on to next buffer in the Queue
2067 BufferList = BufferList->next;
2069 // Offset is out of range of the buffer queue
2070 return AL_FALSE;
2074 /*
2075 GetByteOffset
2077 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2078 offset supplied by the application). This takes into account the fact that the buffer format
2079 may have been modifed by AL (e.g 8bit samples are converted to float)
2080 */
2081 static ALint GetByteOffset(ALsource *Source)
2083 const ALbuffer *Buffer = NULL;
2084 const ALbufferlistitem *BufferList;
2085 ALint ByteOffset = -1;
2087 // Find the first non-NULL Buffer in the Queue
2088 BufferList = Source->queue;
2089 while(BufferList)
2091 if(BufferList->buffer)
2093 Buffer = BufferList->buffer;
2094 break;
2096 BufferList = BufferList->next;
2099 if(!Buffer)
2101 Source->lOffset = -1;
2102 return -1;
2105 // Determine the ByteOffset (and ensure it is block aligned)
2106 switch(Source->lOffsetType)
2108 case AL_BYTE_OFFSET:
2109 // Take into consideration the original format
2110 ByteOffset = Source->lOffset;
2111 if(Buffer->OriginalType == UserFmtIMA4)
2113 // Round down to nearest ADPCM block
2114 ByteOffset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
2115 // Multiply by compression rate (65 sample frames per block)
2116 ByteOffset *= 65;
2118 else
2119 ByteOffset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2120 ByteOffset *= FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
2121 break;
2123 case AL_SAMPLE_OFFSET:
2124 ByteOffset = Source->lOffset * FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
2125 break;
2127 case AL_SEC_OFFSET:
2128 // Note - lOffset is internally stored as Milliseconds
2129 ByteOffset = (ALint)(Source->lOffset / 1000.0 * Buffer->Frequency);
2130 ByteOffset *= FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
2131 break;
2133 // Clear Offset
2134 Source->lOffset = -1;
2136 return ByteOffset;
2140 ALvoid ReleaseALSources(ALCcontext *Context)
2142 ALsizei pos;
2143 ALuint j;
2144 for(pos = 0;pos < Context->SourceMap.size;pos++)
2146 ALsource *temp = Context->SourceMap.array[pos].value;
2147 Context->SourceMap.array[pos].value = NULL;
2149 // For each buffer in the source's queue, decrement its reference counter and remove it
2150 while(temp->queue != NULL)
2152 ALbufferlistitem *BufferList = temp->queue;
2153 temp->queue = BufferList->next;
2155 if(BufferList->buffer != NULL)
2156 BufferList->buffer->refcount--;
2157 free(BufferList);
2160 for(j = 0;j < MAX_SENDS;++j)
2162 if(temp->Send[j].Slot)
2163 temp->Send[j].Slot->refcount--;
2164 temp->Send[j].Slot = NULL;
2167 // Release source structure
2168 FreeThunkEntry(temp->source);
2169 memset(temp, 0, sizeof(ALsource));
2170 free(temp);