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
33 #include "alAuxEffectSlot.h"
35 static ALvoid
InitSourceParams(ALsource
*pSource
);
36 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
, ALuint updateSize
);
37 static ALvoid
ApplyOffset(ALsource
*pSource
, ALboolean bUpdateContext
);
38 static ALint
GetByteOffset(ALsource
*pSource
);
40 ALAPI ALvoid ALAPIENTRY
alGenSources(ALsizei n
,ALuint
*sources
)
46 Context
= GetContextSuspended();
51 Device
= Context
->Device
;
53 // Check that enough memory has been allocted in the 'sources' array for n Sources
54 if(!IsBadWritePtr((void*)sources
, n
* sizeof(ALuint
)))
56 // Check that the requested number of sources can be generated
57 if((Context
->SourceCount
+ n
) <= Device
->MaxNoOfSources
)
59 ALsource
**list
= &Context
->Source
;
61 list
= &(*list
)->next
;
63 // Add additional sources to the list (Source->next points to the location for the next Source structure)
66 *list
= calloc(1, sizeof(ALsource
));
69 alDeleteSources(i
, sources
);
70 alSetError(AL_OUT_OF_MEMORY
);
74 sources
[i
] = (ALuint
)ALTHUNK_ADDENTRY(*list
);
75 (*list
)->source
= sources
[i
];
77 InitSourceParams(*list
);
78 Context
->SourceCount
++;
81 list
= &(*list
)->next
;
86 // Not enough resources to create the Sources
87 alSetError(AL_INVALID_VALUE
);
93 alSetError(AL_INVALID_VALUE
);
97 ProcessContext(Context
);
101 ALAPI ALvoid ALAPIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
108 ALbufferlistitem
*ALBufferList
;
109 ALboolean bSourcesValid
= AL_TRUE
;
111 Context
= GetContextSuspended();
116 Device
= Context
->Device
;
118 // Check that all Sources are valid (and can therefore be deleted)
119 for (i
= 0; i
< n
; i
++)
121 if (!alIsSource(sources
[i
]))
123 alSetError(AL_INVALID_NAME
);
124 bSourcesValid
= AL_FALSE
;
131 // All Sources are valid, and can be deleted
132 for(i
= 0; i
< n
; i
++)
134 // Recheck that the Source is valid, because there could be duplicated Source names
135 if(alIsSource(sources
[i
]))
137 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
138 alSourceStop((ALuint
)ALSource
->source
);
140 // For each buffer in the source's queue, decrement its reference counter and remove it
141 while (ALSource
->queue
!= NULL
)
143 ALBufferList
= ALSource
->queue
;
144 // Decrement buffer's reference counter
145 if(ALBufferList
->buffer
!= NULL
)
146 ALBufferList
->buffer
->refcount
--;
147 // Update queue to point to next element in list
148 ALSource
->queue
= ALBufferList
->next
;
149 // Release memory allocated for buffer list item
153 for(j
= 0;j
< MAX_SENDS
;++j
)
155 if(ALSource
->Send
[j
].Slot
)
156 ALSource
->Send
[j
].Slot
->refcount
--;
157 ALSource
->Send
[j
].Slot
= NULL
;
160 // Decrement Source count
161 Context
->SourceCount
--;
163 // Remove Source from list of Sources
164 list
= &Context
->Source
;
165 while(*list
&& *list
!= ALSource
)
166 list
= &(*list
)->next
;
169 *list
= (*list
)->next
;
170 ALTHUNK_REMOVEENTRY(ALSource
->source
);
172 memset(ALSource
,0,sizeof(ALsource
));
179 alSetError(AL_INVALID_VALUE
);
181 ProcessContext(Context
);
185 ALAPI ALboolean ALAPIENTRY
alIsSource(ALuint source
)
187 ALboolean result
=AL_FALSE
;
191 Context
= GetContextSuspended();
192 if(!Context
) return AL_FALSE
;
194 // To determine if this is a valid Source name, look through the list of generated Sources
195 Source
= Context
->Source
;
198 if(Source
->source
== source
)
204 Source
= Source
->next
;
207 ProcessContext(Context
);
213 ALAPI ALvoid ALAPIENTRY
alSourcef(ALuint source
, ALenum eParam
, ALfloat flValue
)
215 ALCcontext
*pContext
;
218 pContext
= GetContextSuspended();
219 if(!pContext
) return;
221 if(alIsSource(source
))
223 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
230 pSource
->flPitch
= flValue
;
231 if(pSource
->flPitch
< 0.001f
)
232 pSource
->flPitch
= 0.001f
;
233 pSource
->NeedsUpdate
= AL_TRUE
;
236 alSetError(AL_INVALID_VALUE
);
239 case AL_CONE_INNER_ANGLE
:
240 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
242 pSource
->flInnerAngle
= flValue
;
243 pSource
->NeedsUpdate
= AL_TRUE
;
246 alSetError(AL_INVALID_VALUE
);
249 case AL_CONE_OUTER_ANGLE
:
250 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
252 pSource
->flOuterAngle
= flValue
;
253 pSource
->NeedsUpdate
= AL_TRUE
;
256 alSetError(AL_INVALID_VALUE
);
262 pSource
->flGain
= flValue
;
263 pSource
->NeedsUpdate
= AL_TRUE
;
266 alSetError(AL_INVALID_VALUE
);
269 case AL_MAX_DISTANCE
:
272 pSource
->flMaxDistance
= flValue
;
273 pSource
->NeedsUpdate
= AL_TRUE
;
276 alSetError(AL_INVALID_VALUE
);
279 case AL_ROLLOFF_FACTOR
:
282 pSource
->flRollOffFactor
= flValue
;
283 pSource
->NeedsUpdate
= AL_TRUE
;
286 alSetError(AL_INVALID_VALUE
);
289 case AL_REFERENCE_DISTANCE
:
292 pSource
->flRefDistance
= flValue
;
293 pSource
->NeedsUpdate
= AL_TRUE
;
296 alSetError(AL_INVALID_VALUE
);
300 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
302 pSource
->flMinGain
= flValue
;
303 pSource
->NeedsUpdate
= AL_TRUE
;
306 alSetError(AL_INVALID_VALUE
);
310 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
312 pSource
->flMaxGain
= flValue
;
313 pSource
->NeedsUpdate
= AL_TRUE
;
316 alSetError(AL_INVALID_VALUE
);
319 case AL_CONE_OUTER_GAIN
:
320 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
322 pSource
->flOuterGain
= flValue
;
323 pSource
->NeedsUpdate
= AL_TRUE
;
326 alSetError(AL_INVALID_VALUE
);
329 case AL_CONE_OUTER_GAINHF
:
330 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
332 pSource
->OuterGainHF
= flValue
;
333 pSource
->NeedsUpdate
= AL_TRUE
;
336 alSetError(AL_INVALID_VALUE
);
339 case AL_AIR_ABSORPTION_FACTOR
:
340 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
342 pSource
->AirAbsorptionFactor
= flValue
;
343 pSource
->NeedsUpdate
= AL_TRUE
;
346 alSetError(AL_INVALID_VALUE
);
349 case AL_ROOM_ROLLOFF_FACTOR
:
350 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
352 pSource
->RoomRolloffFactor
= flValue
;
353 pSource
->NeedsUpdate
= AL_TRUE
;
356 alSetError(AL_INVALID_VALUE
);
359 case AL_DOPPLER_FACTOR
:
360 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
362 pSource
->DopplerFactor
= flValue
;
363 pSource
->NeedsUpdate
= AL_TRUE
;
366 alSetError(AL_INVALID_VALUE
);
370 case AL_SAMPLE_OFFSET
:
374 pSource
->lOffsetType
= eParam
;
376 // Store Offset (convert Seconds into Milliseconds)
377 if(eParam
== AL_SEC_OFFSET
)
378 pSource
->lOffset
= (ALint
)(flValue
* 1000.0f
);
380 pSource
->lOffset
= (ALint
)flValue
;
382 if ((pSource
->state
== AL_PLAYING
) || (pSource
->state
== AL_PAUSED
))
383 ApplyOffset(pSource
, AL_TRUE
);
386 alSetError(AL_INVALID_VALUE
);
390 alSetError(AL_INVALID_ENUM
);
396 // Invalid Source Name
397 alSetError(AL_INVALID_NAME
);
400 ProcessContext(pContext
);
404 ALAPI ALvoid ALAPIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
406 ALCcontext
*pContext
;
409 pContext
= GetContextSuspended();
410 if(!pContext
) return;
412 if(alIsSource(source
))
414 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
418 pSource
->vPosition
[0] = flValue1
;
419 pSource
->vPosition
[1] = flValue2
;
420 pSource
->vPosition
[2] = flValue3
;
421 pSource
->NeedsUpdate
= AL_TRUE
;
425 pSource
->vVelocity
[0] = flValue1
;
426 pSource
->vVelocity
[1] = flValue2
;
427 pSource
->vVelocity
[2] = flValue3
;
428 pSource
->NeedsUpdate
= AL_TRUE
;
432 pSource
->vOrientation
[0] = flValue1
;
433 pSource
->vOrientation
[1] = flValue2
;
434 pSource
->vOrientation
[2] = flValue3
;
435 pSource
->NeedsUpdate
= AL_TRUE
;
439 alSetError(AL_INVALID_ENUM
);
444 alSetError(AL_INVALID_NAME
);
446 ProcessContext(pContext
);
450 ALAPI ALvoid ALAPIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
452 ALCcontext
*pContext
;
454 pContext
= GetContextSuspended();
455 if(!pContext
) return;
459 if(alIsSource(source
))
464 case AL_CONE_INNER_ANGLE
:
465 case AL_CONE_OUTER_ANGLE
:
467 case AL_MAX_DISTANCE
:
468 case AL_ROLLOFF_FACTOR
:
469 case AL_REFERENCE_DISTANCE
:
472 case AL_CONE_OUTER_GAIN
:
473 case AL_CONE_OUTER_GAINHF
:
475 case AL_SAMPLE_OFFSET
:
477 case AL_AIR_ABSORPTION_FACTOR
:
478 case AL_ROOM_ROLLOFF_FACTOR
:
479 alSourcef(source
, eParam
, pflValues
[0]);
485 alSource3f(source
, eParam
, pflValues
[0], pflValues
[1], pflValues
[2]);
489 alSetError(AL_INVALID_ENUM
);
494 alSetError(AL_INVALID_NAME
);
497 alSetError(AL_INVALID_VALUE
);
499 ProcessContext(pContext
);
503 ALAPI ALvoid ALAPIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
505 ALCcontext
*pContext
;
507 ALbufferlistitem
*pALBufferListItem
;
509 pContext
= GetContextSuspended();
510 if(!pContext
) return;
512 if(alIsSource(source
))
514 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
518 case AL_MAX_DISTANCE
:
519 case AL_ROLLOFF_FACTOR
:
520 case AL_REFERENCE_DISTANCE
:
521 alSourcef(source
, eParam
, (ALfloat
)lValue
);
524 case AL_SOURCE_RELATIVE
:
525 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
527 pSource
->bHeadRelative
= (ALboolean
)lValue
;
528 pSource
->NeedsUpdate
= AL_TRUE
;
531 alSetError(AL_INVALID_VALUE
);
534 case AL_CONE_INNER_ANGLE
:
535 if(lValue
>= 0 && lValue
<= 360)
537 pSource
->flInnerAngle
= (float)lValue
;
538 pSource
->NeedsUpdate
= AL_TRUE
;
541 alSetError(AL_INVALID_VALUE
);
544 case AL_CONE_OUTER_ANGLE
:
545 if(lValue
>= 0 && lValue
<= 360)
547 pSource
->flOuterAngle
= (float)lValue
;
548 pSource
->NeedsUpdate
= AL_TRUE
;
551 alSetError(AL_INVALID_VALUE
);
555 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
556 pSource
->bLooping
= (ALboolean
)lValue
;
558 alSetError(AL_INVALID_VALUE
);
562 if(pSource
->state
== AL_STOPPED
|| pSource
->state
== AL_INITIAL
)
564 if(alIsBuffer(lValue
))
566 ALbuffer
*buffer
= NULL
;
568 // Remove all elements in the queue
569 while(pSource
->queue
!= NULL
)
571 pALBufferListItem
= pSource
->queue
;
572 pSource
->queue
= pALBufferListItem
->next
;
573 // Decrement reference counter for buffer
574 if(pALBufferListItem
->buffer
)
575 pALBufferListItem
->buffer
->refcount
--;
576 // Release memory for buffer list item
577 free(pALBufferListItem
);
578 // Decrement the number of buffers in the queue
579 pSource
->BuffersInQueue
--;
582 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
585 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(lValue
);
587 // Source is now in STATIC mode
588 pSource
->lSourceType
= AL_STATIC
;
590 // Add the selected buffer to the queue
591 pALBufferListItem
= malloc(sizeof(ALbufferlistitem
));
592 pALBufferListItem
->buffer
= buffer
;
593 pALBufferListItem
->next
= NULL
;
595 pSource
->queue
= pALBufferListItem
;
596 pSource
->BuffersInQueue
= 1;
598 // Increment reference counter for buffer
603 // Source is now in UNDETERMINED mode
604 pSource
->lSourceType
= AL_UNDETERMINED
;
605 pSource
->BuffersPlayed
= 0;
608 // Update AL_BUFFER parameter
609 pSource
->Buffer
= buffer
;
610 pSource
->NeedsUpdate
= AL_TRUE
;
613 alSetError(AL_INVALID_VALUE
);
616 alSetError(AL_INVALID_OPERATION
);
619 case AL_SOURCE_STATE
:
621 alSetError(AL_INVALID_OPERATION
);
625 case AL_SAMPLE_OFFSET
:
629 pSource
->lOffsetType
= eParam
;
631 // Store Offset (convert Seconds into Milliseconds)
632 if(eParam
== AL_SEC_OFFSET
)
633 pSource
->lOffset
= lValue
* 1000;
635 pSource
->lOffset
= lValue
;
637 if(pSource
->state
== AL_PLAYING
|| pSource
->state
== AL_PAUSED
)
638 ApplyOffset(pSource
, AL_TRUE
);
641 alSetError(AL_INVALID_VALUE
);
644 case AL_DIRECT_FILTER
:
645 if(alIsFilter(lValue
))
647 ALfilter
*filter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue
);
650 pSource
->DirectFilter
.type
= AL_FILTER_NULL
;
651 pSource
->DirectFilter
.filter
= 0;
654 memcpy(&pSource
->DirectFilter
, filter
, sizeof(*filter
));
655 pSource
->NeedsUpdate
= AL_TRUE
;
658 alSetError(AL_INVALID_VALUE
);
661 case AL_DIRECT_FILTER_GAINHF_AUTO
:
662 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
664 pSource
->DryGainHFAuto
= lValue
;
665 pSource
->NeedsUpdate
= AL_TRUE
;
668 alSetError(AL_INVALID_VALUE
);
671 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
672 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
674 pSource
->WetGainAuto
= lValue
;
675 pSource
->NeedsUpdate
= AL_TRUE
;
678 alSetError(AL_INVALID_VALUE
);
681 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
682 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
684 pSource
->WetGainHFAuto
= lValue
;
685 pSource
->NeedsUpdate
= AL_TRUE
;
688 alSetError(AL_INVALID_VALUE
);
691 case AL_DISTANCE_MODEL
:
692 if(lValue
== AL_NONE
||
693 lValue
== AL_INVERSE_DISTANCE
||
694 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
695 lValue
== AL_LINEAR_DISTANCE
||
696 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
697 lValue
== AL_EXPONENT_DISTANCE
||
698 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
700 pSource
->DistanceModel
= lValue
;
701 if(pContext
->SourceDistanceModel
)
702 pSource
->NeedsUpdate
= AL_TRUE
;
705 alSetError(AL_INVALID_VALUE
);
709 alSetError(AL_INVALID_ENUM
);
714 alSetError(AL_INVALID_NAME
);
716 ProcessContext(pContext
);
720 ALAPI
void ALAPIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
722 ALCcontext
*pContext
;
724 pContext
= GetContextSuspended();
725 if(!pContext
) return;
727 if(alIsSource(source
))
729 ALsource
*pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
730 ALCdevice
*Device
= pContext
->Device
;
737 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
740 case AL_AUXILIARY_SEND_FILTER
:
741 if((ALuint
)lValue2
< Device
->NumAuxSends
&&
742 (lValue1
== 0 || alIsAuxiliaryEffectSlot(lValue1
)) &&
745 ALeffectslot
*ALEffectSlot
= (ALeffectslot
*)ALTHUNK_LOOKUPENTRY(lValue1
);
746 ALfilter
*ALFilter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue3
);
748 /* Release refcount on the previous slot, and add one for
750 if(pSource
->Send
[lValue2
].Slot
)
751 pSource
->Send
[lValue2
].Slot
->refcount
--;
752 pSource
->Send
[lValue2
].Slot
= ALEffectSlot
;
753 if(pSource
->Send
[lValue2
].Slot
)
754 pSource
->Send
[lValue2
].Slot
->refcount
++;
759 pSource
->Send
[lValue2
].WetFilter
.type
= 0;
760 pSource
->Send
[lValue2
].WetFilter
.filter
= 0;
763 memcpy(&pSource
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
764 pSource
->NeedsUpdate
= AL_TRUE
;
767 alSetError(AL_INVALID_VALUE
);
771 alSetError(AL_INVALID_ENUM
);
776 alSetError(AL_INVALID_NAME
);
778 ProcessContext(pContext
);
782 ALAPI
void ALAPIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
784 ALCcontext
*pContext
;
786 pContext
= GetContextSuspended();
787 if(!pContext
) return;
791 if(alIsSource(source
))
795 case AL_SOURCE_RELATIVE
:
796 case AL_CONE_INNER_ANGLE
:
797 case AL_CONE_OUTER_ANGLE
:
800 case AL_SOURCE_STATE
:
802 case AL_SAMPLE_OFFSET
:
804 case AL_MAX_DISTANCE
:
805 case AL_ROLLOFF_FACTOR
:
806 case AL_REFERENCE_DISTANCE
:
807 case AL_DIRECT_FILTER
:
808 case AL_DIRECT_FILTER_GAINHF_AUTO
:
809 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
810 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
811 case AL_DISTANCE_MODEL
:
812 alSourcei(source
, eParam
, plValues
[0]);
818 case AL_AUXILIARY_SEND_FILTER
:
819 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
823 alSetError(AL_INVALID_ENUM
);
828 alSetError(AL_INVALID_NAME
);
831 alSetError(AL_INVALID_VALUE
);
833 ProcessContext(pContext
);
837 ALAPI ALvoid ALAPIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
839 ALCcontext
*pContext
;
843 pContext
= GetContextSuspended();
844 if(!pContext
) return;
848 if(alIsSource(source
))
850 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
855 *pflValue
= pSource
->flPitch
;
859 *pflValue
= pSource
->flGain
;
863 *pflValue
= pSource
->flMinGain
;
867 *pflValue
= pSource
->flMaxGain
;
870 case AL_MAX_DISTANCE
:
871 *pflValue
= pSource
->flMaxDistance
;
874 case AL_ROLLOFF_FACTOR
:
875 *pflValue
= pSource
->flRollOffFactor
;
878 case AL_CONE_OUTER_GAIN
:
879 *pflValue
= pSource
->flOuterGain
;
882 case AL_CONE_OUTER_GAINHF
:
883 *pflValue
= pSource
->OuterGainHF
;
887 case AL_SAMPLE_OFFSET
:
889 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
890 *pflValue
= flOffset
[0];
892 alSetError(AL_INVALID_OPERATION
);
895 case AL_SEC_RW_OFFSETS_EXT
:
896 case AL_SAMPLE_RW_OFFSETS_EXT
:
897 case AL_BYTE_RW_OFFSETS_EXT
:
898 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
900 pflValue
[0] = flOffset
[0];
901 pflValue
[1] = flOffset
[1];
904 alSetError(AL_INVALID_OPERATION
);
907 case AL_CONE_INNER_ANGLE
:
908 *pflValue
= pSource
->flInnerAngle
;
911 case AL_CONE_OUTER_ANGLE
:
912 *pflValue
= pSource
->flOuterAngle
;
915 case AL_REFERENCE_DISTANCE
:
916 *pflValue
= pSource
->flRefDistance
;
919 case AL_AIR_ABSORPTION_FACTOR
:
920 *pflValue
= pSource
->AirAbsorptionFactor
;
923 case AL_ROOM_ROLLOFF_FACTOR
:
924 *pflValue
= pSource
->RoomRolloffFactor
;
927 case AL_DOPPLER_FACTOR
:
928 *pflValue
= pSource
->DopplerFactor
;
932 alSetError(AL_INVALID_ENUM
);
937 alSetError(AL_INVALID_NAME
);
940 alSetError(AL_INVALID_VALUE
);
942 ProcessContext(pContext
);
946 ALAPI ALvoid ALAPIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
948 ALCcontext
*pContext
;
951 pContext
= GetContextSuspended();
952 if(!pContext
) return;
954 if(pflValue1
&& pflValue2
&& pflValue3
)
956 if(alIsSource(source
))
958 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
963 *pflValue1
= pSource
->vPosition
[0];
964 *pflValue2
= pSource
->vPosition
[1];
965 *pflValue3
= pSource
->vPosition
[2];
969 *pflValue1
= pSource
->vVelocity
[0];
970 *pflValue2
= pSource
->vVelocity
[1];
971 *pflValue3
= pSource
->vVelocity
[2];
975 *pflValue1
= pSource
->vOrientation
[0];
976 *pflValue2
= pSource
->vOrientation
[1];
977 *pflValue3
= pSource
->vOrientation
[2];
981 alSetError(AL_INVALID_ENUM
);
986 alSetError(AL_INVALID_NAME
);
989 alSetError(AL_INVALID_VALUE
);
991 ProcessContext(pContext
);
995 ALAPI ALvoid ALAPIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
997 ALCcontext
*pContext
;
1000 pContext
= GetContextSuspended();
1001 if(!pContext
) return;
1005 if(alIsSource(source
))
1007 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1015 case AL_MAX_DISTANCE
:
1016 case AL_ROLLOFF_FACTOR
:
1017 case AL_DOPPLER_FACTOR
:
1018 case AL_CONE_OUTER_GAIN
:
1020 case AL_SAMPLE_OFFSET
:
1021 case AL_BYTE_OFFSET
:
1022 case AL_CONE_INNER_ANGLE
:
1023 case AL_CONE_OUTER_ANGLE
:
1024 case AL_REFERENCE_DISTANCE
:
1025 case AL_CONE_OUTER_GAINHF
:
1026 case AL_AIR_ABSORPTION_FACTOR
:
1027 case AL_ROOM_ROLLOFF_FACTOR
:
1028 alGetSourcef(source
, eParam
, pflValues
);
1032 pflValues
[0] = pSource
->vPosition
[0];
1033 pflValues
[1] = pSource
->vPosition
[1];
1034 pflValues
[2] = pSource
->vPosition
[2];
1038 pflValues
[0] = pSource
->vVelocity
[0];
1039 pflValues
[1] = pSource
->vVelocity
[1];
1040 pflValues
[2] = pSource
->vVelocity
[2];
1044 pflValues
[0] = pSource
->vOrientation
[0];
1045 pflValues
[1] = pSource
->vOrientation
[1];
1046 pflValues
[2] = pSource
->vOrientation
[2];
1050 alSetError(AL_INVALID_ENUM
);
1055 alSetError(AL_INVALID_NAME
);
1058 alSetError(AL_INVALID_VALUE
);
1060 ProcessContext(pContext
);
1064 ALAPI ALvoid ALAPIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1066 ALCcontext
*pContext
;
1068 ALfloat flOffset
[2];
1070 pContext
= GetContextSuspended();
1071 if(!pContext
) return;
1075 if(alIsSource(source
))
1077 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1081 case AL_MAX_DISTANCE
:
1082 *plValue
= (ALint
)pSource
->flMaxDistance
;
1085 case AL_ROLLOFF_FACTOR
:
1086 *plValue
= (ALint
)pSource
->flRollOffFactor
;
1089 case AL_REFERENCE_DISTANCE
:
1090 *plValue
= (ALint
)pSource
->flRefDistance
;
1093 case AL_SOURCE_RELATIVE
:
1094 *plValue
= pSource
->bHeadRelative
;
1097 case AL_CONE_INNER_ANGLE
:
1098 *plValue
= (ALint
)pSource
->flInnerAngle
;
1101 case AL_CONE_OUTER_ANGLE
:
1102 *plValue
= (ALint
)pSource
->flOuterAngle
;
1106 *plValue
= pSource
->bLooping
;
1110 *plValue
= (pSource
->Buffer
? pSource
->Buffer
->buffer
: 0);
1113 case AL_SOURCE_STATE
:
1114 *plValue
= pSource
->state
;
1117 case AL_BUFFERS_QUEUED
:
1118 *plValue
= pSource
->BuffersInQueue
;
1121 case AL_BUFFERS_PROCESSED
:
1122 if(pSource
->bLooping
)
1124 /* Buffers on a looping source are in a perpetual state
1125 * of PENDING, so don't report any as PROCESSED */
1129 *plValue
= pSource
->BuffersPlayed
;
1132 case AL_SOURCE_TYPE
:
1133 *plValue
= pSource
->lSourceType
;
1137 case AL_SAMPLE_OFFSET
:
1138 case AL_BYTE_OFFSET
:
1139 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
1140 *plValue
= (ALint
)flOffset
[0];
1142 alSetError(AL_INVALID_OPERATION
);
1145 case AL_SEC_RW_OFFSETS_EXT
:
1146 case AL_SAMPLE_RW_OFFSETS_EXT
:
1147 case AL_BYTE_RW_OFFSETS_EXT
:
1148 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
1150 plValue
[0] = (ALint
)flOffset
[0];
1151 plValue
[1] = (ALint
)flOffset
[1];
1154 alSetError(AL_INVALID_OPERATION
);
1157 case AL_DIRECT_FILTER
:
1158 *plValue
= pSource
->DirectFilter
.filter
;
1161 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1162 *plValue
= pSource
->DryGainHFAuto
;
1165 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1166 *plValue
= pSource
->WetGainAuto
;
1169 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1170 *plValue
= pSource
->WetGainHFAuto
;
1173 case AL_DOPPLER_FACTOR
:
1174 *plValue
= (ALint
)pSource
->DopplerFactor
;
1177 case AL_DISTANCE_MODEL
:
1178 *plValue
= pSource
->DistanceModel
;
1182 alSetError(AL_INVALID_ENUM
);
1187 alSetError(AL_INVALID_NAME
);
1190 alSetError(AL_INVALID_VALUE
);
1192 ProcessContext(pContext
);
1196 ALAPI
void ALAPIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1198 ALCcontext
*pContext
;
1201 pContext
= GetContextSuspended();
1202 if(!pContext
) return;
1204 if(plValue1
&& plValue2
&& plValue3
)
1206 if(alIsSource(source
))
1208 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1213 *plValue1
= (ALint
)pSource
->vPosition
[0];
1214 *plValue2
= (ALint
)pSource
->vPosition
[1];
1215 *plValue3
= (ALint
)pSource
->vPosition
[2];
1219 *plValue1
= (ALint
)pSource
->vVelocity
[0];
1220 *plValue2
= (ALint
)pSource
->vVelocity
[1];
1221 *plValue3
= (ALint
)pSource
->vVelocity
[2];
1225 *plValue1
= (ALint
)pSource
->vOrientation
[0];
1226 *plValue2
= (ALint
)pSource
->vOrientation
[1];
1227 *plValue3
= (ALint
)pSource
->vOrientation
[2];
1231 alSetError(AL_INVALID_ENUM
);
1236 alSetError(AL_INVALID_NAME
);
1239 alSetError(AL_INVALID_VALUE
);
1241 ProcessContext(pContext
);
1245 ALAPI
void ALAPIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1247 ALCcontext
*pContext
;
1250 pContext
= GetContextSuspended();
1251 if(!pContext
) return;
1255 if(alIsSource(source
))
1257 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1261 case AL_SOURCE_RELATIVE
:
1262 case AL_CONE_INNER_ANGLE
:
1263 case AL_CONE_OUTER_ANGLE
:
1266 case AL_SOURCE_STATE
:
1267 case AL_BUFFERS_QUEUED
:
1268 case AL_BUFFERS_PROCESSED
:
1270 case AL_SAMPLE_OFFSET
:
1271 case AL_BYTE_OFFSET
:
1272 case AL_MAX_DISTANCE
:
1273 case AL_ROLLOFF_FACTOR
:
1274 case AL_DOPPLER_FACTOR
:
1275 case AL_REFERENCE_DISTANCE
:
1276 case AL_SOURCE_TYPE
:
1277 case AL_DIRECT_FILTER
:
1278 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1279 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1280 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1281 case AL_DISTANCE_MODEL
:
1282 alGetSourcei(source
, eParam
, plValues
);
1286 plValues
[0] = (ALint
)pSource
->vPosition
[0];
1287 plValues
[1] = (ALint
)pSource
->vPosition
[1];
1288 plValues
[2] = (ALint
)pSource
->vPosition
[2];
1292 plValues
[0] = (ALint
)pSource
->vVelocity
[0];
1293 plValues
[1] = (ALint
)pSource
->vVelocity
[1];
1294 plValues
[2] = (ALint
)pSource
->vVelocity
[2];
1298 plValues
[0] = (ALint
)pSource
->vOrientation
[0];
1299 plValues
[1] = (ALint
)pSource
->vOrientation
[1];
1300 plValues
[2] = (ALint
)pSource
->vOrientation
[2];
1304 alSetError(AL_INVALID_ENUM
);
1309 alSetError(AL_INVALID_NAME
);
1312 alSetError(AL_INVALID_VALUE
);
1314 ProcessContext(pContext
);
1318 ALAPI ALvoid ALAPIENTRY
alSourcePlay(ALuint source
)
1320 alSourcePlayv(1, &source
);
1323 ALAPI ALvoid ALAPIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*pSourceList
)
1325 ALCcontext
*pContext
;
1327 ALbufferlistitem
*ALBufferList
;
1328 ALboolean bSourcesValid
= AL_TRUE
;
1332 pContext
= GetContextSuspended();
1333 if(!pContext
) return;
1337 // Check that all the Sources are valid
1338 for(i
= 0; i
< n
; i
++)
1340 if(!alIsSource(pSourceList
[i
]))
1342 alSetError(AL_INVALID_NAME
);
1343 bSourcesValid
= AL_FALSE
;
1350 for(i
= 0; i
< n
; i
++)
1352 // Assume Source won't need to play
1355 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(pSourceList
[i
]);
1357 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1358 ALBufferList
= pSource
->queue
;
1361 if(ALBufferList
->buffer
!= NULL
&& ALBufferList
->buffer
->size
)
1366 ALBufferList
= ALBufferList
->next
;
1371 for(j
= 0;j
< OUTPUTCHANNELS
;j
++)
1372 pSource
->DryGains
[j
] = 0.0f
;
1373 for(j
= 0;j
< MAX_SENDS
;j
++)
1374 pSource
->WetGains
[j
] = 0.0f
;
1376 if(pSource
->state
!= AL_PAUSED
)
1378 pSource
->state
= AL_PLAYING
;
1379 pSource
->position
= 0;
1380 pSource
->position_fraction
= 0;
1381 pSource
->BuffersPlayed
= 0;
1383 pSource
->Buffer
= pSource
->queue
->buffer
;
1386 pSource
->state
= AL_PLAYING
;
1388 // Check if an Offset has been set
1389 if(pSource
->lOffset
)
1390 ApplyOffset(pSource
, AL_FALSE
);
1392 if(pSource
->BuffersPlayed
== 0 && pSource
->position
== 0 &&
1393 pSource
->position_fraction
== 0)
1394 pSource
->FirstStart
= AL_TRUE
;
1396 pSource
->FirstStart
= AL_FALSE
;
1398 // If device is disconnected, go right to stopped
1399 if(!pContext
->Device
->Connected
)
1401 pSource
->state
= AL_STOPPED
;
1402 pSource
->BuffersPlayed
= pSource
->BuffersInQueue
;
1403 pSource
->position
= 0;
1404 pSource
->position_fraction
= 0;
1408 pSource
->BuffersPlayed
= pSource
->BuffersInQueue
;
1414 // sources is a NULL pointer
1415 alSetError(AL_INVALID_VALUE
);
1418 ProcessContext(pContext
);
1421 ALAPI ALvoid ALAPIENTRY
alSourcePause(ALuint source
)
1423 alSourcePausev(1, &source
);
1426 ALAPI ALvoid ALAPIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1428 ALCcontext
*Context
;
1431 ALboolean bSourcesValid
= AL_TRUE
;
1433 Context
= GetContextSuspended();
1434 if(!Context
) return;
1438 // Check all the Sources are valid
1441 if(!alIsSource(sources
[i
]))
1443 alSetError(AL_INVALID_NAME
);
1444 bSourcesValid
= AL_FALSE
;
1451 for(i
= 0;i
< n
;i
++)
1453 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1454 if(Source
->state
== AL_PLAYING
)
1455 Source
->state
= AL_PAUSED
;
1461 // sources is a NULL pointer
1462 alSetError(AL_INVALID_VALUE
);
1465 ProcessContext(Context
);
1468 ALAPI ALvoid ALAPIENTRY
alSourceStop(ALuint source
)
1470 alSourceStopv(1, &source
);
1473 ALAPI ALvoid ALAPIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1475 ALCcontext
*Context
;
1478 ALboolean bSourcesValid
= AL_TRUE
;
1480 Context
= GetContextSuspended();
1481 if(!Context
) return;
1485 // Check all the Sources are valid
1486 for(i
= 0;i
< n
;i
++)
1488 if(!alIsSource(sources
[i
]))
1490 alSetError(AL_INVALID_NAME
);
1491 bSourcesValid
= AL_FALSE
;
1498 for(i
= 0;i
< n
;i
++)
1500 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1501 if(Source
->state
!= AL_INITIAL
)
1503 Source
->state
= AL_STOPPED
;
1504 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1506 Source
->lOffset
= 0;
1512 // sources is a NULL pointer
1513 alSetError(AL_INVALID_VALUE
);
1516 ProcessContext(Context
);
1519 ALAPI ALvoid ALAPIENTRY
alSourceRewind(ALuint source
)
1521 alSourceRewindv(1, &source
);
1524 ALAPI ALvoid ALAPIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1526 ALCcontext
*Context
;
1529 ALboolean bSourcesValid
= AL_TRUE
;
1531 Context
= GetContextSuspended();
1532 if(!Context
) return;
1536 // Check all the Sources are valid
1537 for(i
= 0;i
< n
;i
++)
1539 if(!alIsSource(sources
[i
]))
1541 alSetError(AL_INVALID_NAME
);
1542 bSourcesValid
= AL_FALSE
;
1549 for(i
= 0;i
< n
;i
++)
1551 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1552 if(Source
->state
!= AL_INITIAL
)
1554 Source
->state
= AL_INITIAL
;
1555 Source
->position
= 0;
1556 Source
->position_fraction
= 0;
1557 Source
->BuffersPlayed
= 0;
1559 Source
->Buffer
= Source
->queue
->buffer
;
1561 Source
->lOffset
= 0;
1567 // sources is a NULL pointer
1568 alSetError(AL_INVALID_VALUE
);
1571 ProcessContext(Context
);
1575 ALAPI ALvoid ALAPIENTRY
alSourceQueueBuffers( ALuint source
, ALsizei n
, const ALuint
* buffers
)
1577 ALCcontext
*Context
;
1580 ALbufferlistitem
*ALBufferList
;
1581 ALbufferlistitem
*ALBufferListStart
;
1584 ALboolean bBuffersValid
= AL_TRUE
;
1585 ALboolean hadFormat
= AL_FALSE
;
1590 Context
= GetContextSuspended();
1591 if(!Context
) return;
1593 // Check that all buffers are valid or zero and that the source is valid
1595 // Check that this is a valid source
1596 if(alIsSource(source
))
1598 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1600 // Check that this is not a STATIC Source
1601 if(ALSource
->lSourceType
!= AL_STATIC
)
1606 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1607 ALBufferList
= ALSource
->queue
;
1610 if (ALBufferList
->buffer
)
1612 iFrequency
= ALBufferList
->buffer
->frequency
;
1613 iFormat
= ALBufferList
->buffer
->format
;
1614 hadFormat
= AL_TRUE
;
1617 ALBufferList
= ALBufferList
->next
;
1620 for(i
= 0; i
< n
; i
++)
1624 if(!alIsBuffer(buffers
[i
]))
1626 alSetError(AL_INVALID_NAME
);
1627 bBuffersValid
= AL_FALSE
;
1633 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1634 if(iFrequency
== -1 && iFormat
== -1)
1636 iFrequency
= buffer
->frequency
;
1637 iFormat
= buffer
->format
;
1639 else if(iFrequency
!= buffer
->frequency
||
1640 iFormat
!= buffer
->format
)
1642 alSetError(AL_INVALID_OPERATION
);
1643 bBuffersValid
= AL_FALSE
;
1650 ALbuffer
*buffer
= NULL
;
1652 // Change Source Type
1653 ALSource
->lSourceType
= AL_STREAMING
;
1655 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1657 // All buffers are valid - so add them to the list
1658 ALBufferListStart
= malloc(sizeof(ALbufferlistitem
));
1659 ALBufferListStart
->buffer
= buffer
;
1660 ALBufferListStart
->next
= NULL
;
1662 // Increment reference counter for buffer
1663 if(buffer
) buffer
->refcount
++;
1665 ALBufferList
= ALBufferListStart
;
1667 for(i
= 1; i
< n
; i
++)
1669 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1671 ALBufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1672 ALBufferList
->next
->buffer
= buffer
;
1673 ALBufferList
->next
->next
= NULL
;
1675 // Increment reference counter for buffer
1676 if(buffer
) buffer
->refcount
++;
1678 ALBufferList
= ALBufferList
->next
;
1681 if(ALSource
->queue
== NULL
)
1683 ALSource
->queue
= ALBufferListStart
;
1684 // Update Current Buffer
1685 ALSource
->Buffer
= ALBufferListStart
->buffer
;
1689 // Find end of queue
1690 ALBufferList
= ALSource
->queue
;
1691 while(ALBufferList
->next
!= NULL
)
1692 ALBufferList
= ALBufferList
->next
;
1694 ALBufferList
->next
= ALBufferListStart
;
1697 // Update number of buffers in queue
1698 ALSource
->BuffersInQueue
+= n
;
1699 // If no previous format, mark the source dirty now that it may
1702 ALSource
->NeedsUpdate
= AL_TRUE
;
1707 // Invalid Source Type (can't queue on a Static Source)
1708 alSetError(AL_INVALID_OPERATION
);
1713 // Invalid Source Name
1714 alSetError(AL_INVALID_NAME
);
1717 ProcessContext(Context
);
1721 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1722 // an array of buffer IDs that are to be filled with the names of the buffers removed
1723 ALAPI ALvoid ALAPIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1725 ALCcontext
*Context
;
1728 ALbufferlistitem
*ALBufferList
;
1729 ALboolean bBuffersProcessed
;
1734 bBuffersProcessed
= AL_TRUE
;
1736 Context
= GetContextSuspended();
1737 if(!Context
) return;
1739 if(alIsSource(source
))
1741 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1743 // If all 'n' buffers have been processed, remove them from the queue
1744 if(!ALSource
->bLooping
&& (ALuint
)n
<= ALSource
->BuffersPlayed
)
1746 for(i
= 0; i
< n
; i
++)
1748 ALBufferList
= ALSource
->queue
;
1750 ALSource
->queue
= ALBufferList
->next
;
1751 // Record name of buffer
1752 buffers
[i
] = ALBufferList
->buffer
->buffer
;
1753 // Decrement buffer reference counter
1754 if(ALBufferList
->buffer
)
1755 ALBufferList
->buffer
->refcount
--;
1757 // Release memory for buffer list item
1759 ALSource
->BuffersInQueue
--;
1762 if(ALSource
->state
!= AL_PLAYING
)
1765 ALSource
->Buffer
= ALSource
->queue
->buffer
;
1767 ALSource
->Buffer
= NULL
;
1770 ALSource
->BuffersPlayed
-= n
;
1774 // Some buffers can't be unqueue because they have not been processed
1775 alSetError(AL_INVALID_VALUE
);
1780 // Invalid Source Name
1781 alSetError(AL_INVALID_NAME
);
1784 ProcessContext(Context
);
1788 static ALvoid
InitSourceParams(ALsource
*pSource
)
1790 pSource
->flInnerAngle
= 360.0f
;
1791 pSource
->flOuterAngle
= 360.0f
;
1792 pSource
->flPitch
= 1.0f
;
1793 pSource
->vPosition
[0] = 0.0f
;
1794 pSource
->vPosition
[1] = 0.0f
;
1795 pSource
->vPosition
[2] = 0.0f
;
1796 pSource
->vOrientation
[0] = 0.0f
;
1797 pSource
->vOrientation
[1] = 0.0f
;
1798 pSource
->vOrientation
[2] = 0.0f
;
1799 pSource
->vVelocity
[0] = 0.0f
;
1800 pSource
->vVelocity
[1] = 0.0f
;
1801 pSource
->vVelocity
[2] = 0.0f
;
1802 pSource
->flRefDistance
= 1.0f
;
1803 pSource
->flMaxDistance
= FLT_MAX
;
1804 pSource
->flRollOffFactor
= 1.0f
;
1805 pSource
->bLooping
= AL_FALSE
;
1806 pSource
->flGain
= 1.0f
;
1807 pSource
->flMinGain
= 0.0f
;
1808 pSource
->flMaxGain
= 1.0f
;
1809 pSource
->flOuterGain
= 0.0f
;
1810 pSource
->OuterGainHF
= 1.0f
;
1812 pSource
->DryGainHFAuto
= AL_TRUE
;
1813 pSource
->WetGainAuto
= AL_TRUE
;
1814 pSource
->WetGainHFAuto
= AL_TRUE
;
1815 pSource
->AirAbsorptionFactor
= 0.0f
;
1816 pSource
->RoomRolloffFactor
= 0.0f
;
1817 pSource
->DopplerFactor
= 1.0f
;
1819 pSource
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1821 pSource
->state
= AL_INITIAL
;
1822 pSource
->lSourceType
= AL_UNDETERMINED
;
1824 pSource
->NeedsUpdate
= AL_TRUE
;
1826 pSource
->Buffer
= NULL
;
1833 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1834 The offset is relative to the start of the queue (not the start of the current buffer)
1836 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
, ALuint updateSize
)
1838 ALbufferlistitem
*pBufferList
;
1840 ALfloat flBufferFreq
;
1841 ALint lChannels
, lBytes
;
1842 ALint readPos
, writePos
;
1843 ALenum eOriginalFormat
;
1844 ALboolean bReturn
= AL_TRUE
;
1845 ALint lTotalBufferDataSize
;
1848 if((pSource
->state
== AL_PLAYING
|| pSource
->state
== AL_PAUSED
) && pSource
->Buffer
)
1850 pBuffer
= pSource
->Buffer
;
1851 // Get Current Buffer Size and frequency (in milliseconds)
1852 flBufferFreq
= (ALfloat
)pBuffer
->frequency
;
1853 eOriginalFormat
= pBuffer
->eOriginalFormat
;
1854 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
1855 lBytes
= aluBytesFromFormat(pBuffer
->format
);
1857 // Get Current BytesPlayed
1858 readPos
= pSource
->position
* lChannels
* lBytes
; // NOTE : This is the byte offset into the *current* buffer
1859 // Add byte length of any processed buffers in the queue
1860 pBufferList
= pSource
->queue
;
1861 for(i
= 0;i
< pSource
->BuffersPlayed
&& pBufferList
;i
++)
1863 readPos
+= pBufferList
->buffer
->size
;
1864 pBufferList
= pBufferList
->next
;
1867 if(pSource
->state
== AL_PLAYING
)
1868 writePos
= readPos
+ (updateSize
* lChannels
* lBytes
);
1872 lTotalBufferDataSize
= 0;
1873 pBufferList
= pSource
->queue
;
1876 if (pBufferList
->buffer
)
1877 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
1878 pBufferList
= pBufferList
->next
;
1881 if (pSource
->bLooping
)
1886 readPos
%= lTotalBufferDataSize
;
1890 writePos
%= lTotalBufferDataSize
;
1894 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1897 else if(readPos
> lTotalBufferDataSize
)
1898 readPos
= lTotalBufferDataSize
;
1901 else if(writePos
> lTotalBufferDataSize
)
1902 writePos
= lTotalBufferDataSize
;
1908 case AL_SEC_RW_OFFSETS_EXT
:
1909 pflOffset
[0] = (ALfloat
)readPos
/ (lChannels
* lBytes
* flBufferFreq
);
1910 pflOffset
[1] = (ALfloat
)writePos
/ (lChannels
* lBytes
* flBufferFreq
);
1912 case AL_SAMPLE_OFFSET
:
1913 case AL_SAMPLE_RW_OFFSETS_EXT
:
1914 pflOffset
[0] = (ALfloat
)(readPos
/ (lChannels
* lBytes
));
1915 pflOffset
[1] = (ALfloat
)(writePos
/ (lChannels
* lBytes
));
1917 case AL_BYTE_OFFSET
:
1918 case AL_BYTE_RW_OFFSETS_EXT
:
1919 // Take into account the original format of the Buffer
1920 if ((eOriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1921 (eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1923 // Round down to nearest ADPCM block
1924 pflOffset
[0] = (ALfloat
)((readPos
/ (65 * lBytes
* lChannels
)) * 36 * lChannels
);
1925 if(pSource
->state
== AL_PLAYING
)
1927 // Round up to nearest ADPCM block
1928 pflOffset
[1] = (ALfloat
)(((writePos
+ (65 * lBytes
* lChannels
) - 1) / (65 * lBytes
* lChannels
)) * 36 * lChannels
);
1931 pflOffset
[1] = pflOffset
[0];
1933 else if (eOriginalFormat
== AL_FORMAT_REAR8
)
1935 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 1);
1936 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 1);
1938 else if (eOriginalFormat
== AL_FORMAT_REAR16
)
1940 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 2);
1941 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 2);
1943 else if (eOriginalFormat
== AL_FORMAT_REAR32
)
1945 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 4);
1946 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 4);
1948 else if (aluBytesFromFormat(eOriginalFormat
) == 1)
1950 pflOffset
[0] = (ALfloat
)(readPos
/ lBytes
* 1);
1951 pflOffset
[1] = (ALfloat
)(writePos
/ lBytes
* 1);
1953 else if (aluBytesFromFormat(eOriginalFormat
) == 2)
1955 pflOffset
[0] = (ALfloat
)(readPos
/ lBytes
* 2);
1956 pflOffset
[1] = (ALfloat
)(writePos
/ lBytes
* 2);
1958 else if (aluBytesFromFormat(eOriginalFormat
) == 4)
1960 pflOffset
[0] = (ALfloat
)(readPos
/ lBytes
* 4);
1961 pflOffset
[1] = (ALfloat
)(writePos
/ lBytes
* 4);
1965 pflOffset
[0] = (ALfloat
)readPos
;
1966 pflOffset
[1] = (ALfloat
)writePos
;
1973 pflOffset
[0] = 0.0f
;
1974 pflOffset
[1] = 0.0f
;
1984 Apply a playback offset to the Source. This function will update the queue (to correctly
1985 mark buffers as 'pending' or 'processed' depending upon the new offset.
1987 static void ApplyOffset(ALsource
*pSource
, ALboolean bUpdateContext
)
1989 ALbufferlistitem
*pBufferList
;
1991 ALint lBufferSize
, lTotalBufferSize
;
1994 // Get true byte offset
1995 lByteOffset
= GetByteOffset(pSource
);
1997 // If this is a valid offset apply it
1998 if (lByteOffset
!= -1)
2000 // Sort out the queue (pending and processed states)
2001 pBufferList
= pSource
->queue
;
2002 lTotalBufferSize
= 0;
2003 pSource
->BuffersPlayed
= 0;
2006 pBuffer
= pBufferList
->buffer
;
2007 lBufferSize
= pBuffer
? pBuffer
->size
: 0;
2009 if ((lTotalBufferSize
+ lBufferSize
) <= lByteOffset
)
2011 // Offset is past this buffer so increment BuffersPlayed
2012 pSource
->BuffersPlayed
++;
2014 else if (lTotalBufferSize
<= lByteOffset
)
2016 // Offset is within this buffer
2017 // Set Current Buffer
2018 pSource
->Buffer
= pBufferList
->buffer
;
2020 // SW Mixer Positions are in Samples
2021 pSource
->position
= (lByteOffset
- lTotalBufferSize
) /
2022 aluBytesFromFormat(pBuffer
->format
) /
2023 aluChannelsFromFormat(pBuffer
->format
);
2026 // Increment the TotalBufferSize
2027 lTotalBufferSize
+= lBufferSize
;
2029 // Move on to next buffer in the Queue
2030 pBufferList
= pBufferList
->next
;
2036 alSetError(AL_INVALID_VALUE
);
2040 pSource
->lOffset
= 0;
2047 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2048 offset supplied by the application). This takes into account the fact that the buffer format
2049 may have been modifed by AL (e.g 8bit samples are converted to float)
2051 static ALint
GetByteOffset(ALsource
*pSource
)
2053 ALbuffer
*pBuffer
= NULL
;
2054 ALbufferlistitem
*pBufferList
;
2055 ALfloat flBufferFreq
;
2056 ALint lChannels
, lBytes
;
2057 ALint lByteOffset
= -1;
2058 ALint lTotalBufferDataSize
;
2060 // Find the first non-NULL Buffer in the Queue
2061 pBufferList
= pSource
->queue
;
2064 if (pBufferList
->buffer
)
2066 pBuffer
= pBufferList
->buffer
;
2069 pBufferList
= pBufferList
->next
;
2074 flBufferFreq
= ((ALfloat
)pBuffer
->frequency
);
2075 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
2076 lBytes
= aluBytesFromFormat(pBuffer
->format
);
2078 // Determine the ByteOffset (and ensure it is block aligned)
2079 switch (pSource
->lOffsetType
)
2081 case AL_BYTE_OFFSET
:
2082 // Take into consideration the original format
2083 if ((pBuffer
->eOriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
2084 (pBuffer
->eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
2086 // Round down to nearest ADPCM block
2087 lByteOffset
= pSource
->lOffset
/ (36 * lChannels
);
2088 // Multiply by compression rate
2089 lByteOffset
= lByteOffset
* 65 * lChannels
* lBytes
;
2090 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2092 else if (pBuffer
->eOriginalFormat
== AL_FORMAT_REAR8
)
2094 lByteOffset
= pSource
->lOffset
/ 1 * lBytes
* 2;
2095 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2097 else if (pBuffer
->eOriginalFormat
== AL_FORMAT_REAR16
)
2099 lByteOffset
= pSource
->lOffset
/ 2 * lBytes
* 2;
2100 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2102 else if (pBuffer
->eOriginalFormat
== AL_FORMAT_REAR32
)
2104 lByteOffset
= pSource
->lOffset
/ 4 * lBytes
* 2;
2105 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2107 else if (aluBytesFromFormat(pBuffer
->eOriginalFormat
) == 1)
2109 lByteOffset
= pSource
->lOffset
/ 1 * lBytes
;
2110 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2112 else if (aluBytesFromFormat(pBuffer
->eOriginalFormat
) == 2)
2114 lByteOffset
= pSource
->lOffset
/ 2 * lBytes
;
2115 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2117 else if (aluBytesFromFormat(pBuffer
->eOriginalFormat
) == 4)
2119 lByteOffset
= pSource
->lOffset
/ 4 * lBytes
;
2120 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2124 lByteOffset
= pSource
->lOffset
;
2125 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2129 case AL_SAMPLE_OFFSET
:
2130 lByteOffset
= pSource
->lOffset
* lChannels
* lBytes
;
2134 // Note - lOffset is internally stored as Milliseconds
2135 lByteOffset
= (ALint
)(pSource
->lOffset
* lChannels
* lBytes
* flBufferFreq
/ 1000.0f
);
2136 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2140 lTotalBufferDataSize
= 0;
2141 pBufferList
= pSource
->queue
;
2144 if (pBufferList
->buffer
)
2145 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
2146 pBufferList
= pBufferList
->next
;
2149 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2150 if (lByteOffset
>= lTotalBufferDataSize
)
2158 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2162 while(Context
->Source
)
2164 ALsource
*temp
= Context
->Source
;
2165 Context
->Source
= temp
->next
;
2167 // For each buffer in the source's queue, decrement its reference counter and remove it
2168 while(temp
->queue
!= NULL
)
2170 ALbufferlistitem
*ALBufferList
= temp
->queue
;
2171 // Decrement buffer's reference counter
2172 if(ALBufferList
->buffer
!= NULL
)
2173 ALBufferList
->buffer
->refcount
--;
2174 // Update queue to point to next element in list
2175 temp
->queue
= ALBufferList
->next
;
2176 // Release memory allocated for buffer list item
2180 for(j
= 0;j
< MAX_SENDS
;++j
)
2182 if(temp
->Send
[j
].Slot
)
2183 temp
->Send
[j
].Slot
->refcount
--;
2186 // Release source structure
2187 ALTHUNK_REMOVEENTRY(temp
->source
);
2188 memset(temp
, 0, sizeof(ALsource
));
2191 Context
->SourceCount
= 0;