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
;
612 alSetError(AL_INVALID_VALUE
);
615 alSetError(AL_INVALID_OPERATION
);
618 case AL_SOURCE_STATE
:
620 alSetError(AL_INVALID_OPERATION
);
624 case AL_SAMPLE_OFFSET
:
628 pSource
->lOffsetType
= eParam
;
630 // Store Offset (convert Seconds into Milliseconds)
631 if(eParam
== AL_SEC_OFFSET
)
632 pSource
->lOffset
= lValue
* 1000;
634 pSource
->lOffset
= lValue
;
636 if(pSource
->state
== AL_PLAYING
|| pSource
->state
== AL_PAUSED
)
637 ApplyOffset(pSource
, AL_TRUE
);
640 alSetError(AL_INVALID_VALUE
);
643 case AL_DIRECT_FILTER
:
644 if(alIsFilter(lValue
))
646 ALfilter
*filter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue
);
649 pSource
->DirectFilter
.type
= AL_FILTER_NULL
;
650 pSource
->DirectFilter
.filter
= 0;
653 memcpy(&pSource
->DirectFilter
, filter
, sizeof(*filter
));
654 pSource
->NeedsUpdate
= AL_TRUE
;
657 alSetError(AL_INVALID_VALUE
);
660 case AL_DIRECT_FILTER_GAINHF_AUTO
:
661 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
663 pSource
->DryGainHFAuto
= lValue
;
664 pSource
->NeedsUpdate
= AL_TRUE
;
667 alSetError(AL_INVALID_VALUE
);
670 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
671 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
673 pSource
->WetGainAuto
= lValue
;
674 pSource
->NeedsUpdate
= AL_TRUE
;
677 alSetError(AL_INVALID_VALUE
);
680 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
681 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
683 pSource
->WetGainHFAuto
= lValue
;
684 pSource
->NeedsUpdate
= AL_TRUE
;
687 alSetError(AL_INVALID_VALUE
);
690 case AL_DISTANCE_MODEL
:
691 if(lValue
== AL_NONE
||
692 lValue
== AL_INVERSE_DISTANCE
||
693 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
694 lValue
== AL_LINEAR_DISTANCE
||
695 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
696 lValue
== AL_EXPONENT_DISTANCE
||
697 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
699 pSource
->DistanceModel
= lValue
;
700 if(pContext
->SourceDistanceModel
)
701 pSource
->NeedsUpdate
= AL_TRUE
;
704 alSetError(AL_INVALID_VALUE
);
708 alSetError(AL_INVALID_ENUM
);
713 alSetError(AL_INVALID_NAME
);
715 ProcessContext(pContext
);
719 ALAPI
void ALAPIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
721 ALCcontext
*pContext
;
723 pContext
= GetContextSuspended();
724 if(!pContext
) return;
726 if(alIsSource(source
))
728 ALsource
*pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
729 ALCdevice
*Device
= pContext
->Device
;
736 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
739 case AL_AUXILIARY_SEND_FILTER
:
740 if((ALuint
)lValue2
< Device
->NumAuxSends
&&
741 (lValue1
== 0 || alIsAuxiliaryEffectSlot(lValue1
)) &&
744 ALeffectslot
*ALEffectSlot
= (ALeffectslot
*)ALTHUNK_LOOKUPENTRY(lValue1
);
745 ALfilter
*ALFilter
= (ALfilter
*)ALTHUNK_LOOKUPENTRY(lValue3
);
747 /* Release refcount on the previous slot, and add one for
749 if(pSource
->Send
[lValue2
].Slot
)
750 pSource
->Send
[lValue2
].Slot
->refcount
--;
751 pSource
->Send
[lValue2
].Slot
= ALEffectSlot
;
752 if(pSource
->Send
[lValue2
].Slot
)
753 pSource
->Send
[lValue2
].Slot
->refcount
++;
758 pSource
->Send
[lValue2
].WetFilter
.type
= 0;
759 pSource
->Send
[lValue2
].WetFilter
.filter
= 0;
762 memcpy(&pSource
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
763 pSource
->NeedsUpdate
= AL_TRUE
;
766 alSetError(AL_INVALID_VALUE
);
770 alSetError(AL_INVALID_ENUM
);
775 alSetError(AL_INVALID_NAME
);
777 ProcessContext(pContext
);
781 ALAPI
void ALAPIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
783 ALCcontext
*pContext
;
785 pContext
= GetContextSuspended();
786 if(!pContext
) return;
790 if(alIsSource(source
))
794 case AL_SOURCE_RELATIVE
:
795 case AL_CONE_INNER_ANGLE
:
796 case AL_CONE_OUTER_ANGLE
:
799 case AL_SOURCE_STATE
:
801 case AL_SAMPLE_OFFSET
:
803 case AL_MAX_DISTANCE
:
804 case AL_ROLLOFF_FACTOR
:
805 case AL_REFERENCE_DISTANCE
:
806 case AL_DIRECT_FILTER
:
807 case AL_DIRECT_FILTER_GAINHF_AUTO
:
808 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
809 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
810 case AL_DISTANCE_MODEL
:
811 alSourcei(source
, eParam
, plValues
[0]);
817 case AL_AUXILIARY_SEND_FILTER
:
818 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
822 alSetError(AL_INVALID_ENUM
);
827 alSetError(AL_INVALID_NAME
);
830 alSetError(AL_INVALID_VALUE
);
832 ProcessContext(pContext
);
836 ALAPI ALvoid ALAPIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
838 ALCcontext
*pContext
;
842 pContext
= GetContextSuspended();
843 if(!pContext
) return;
847 if(alIsSource(source
))
849 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
854 *pflValue
= pSource
->flPitch
;
858 *pflValue
= pSource
->flGain
;
862 *pflValue
= pSource
->flMinGain
;
866 *pflValue
= pSource
->flMaxGain
;
869 case AL_MAX_DISTANCE
:
870 *pflValue
= pSource
->flMaxDistance
;
873 case AL_ROLLOFF_FACTOR
:
874 *pflValue
= pSource
->flRollOffFactor
;
877 case AL_CONE_OUTER_GAIN
:
878 *pflValue
= pSource
->flOuterGain
;
881 case AL_CONE_OUTER_GAINHF
:
882 *pflValue
= pSource
->OuterGainHF
;
886 case AL_SAMPLE_OFFSET
:
888 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
889 *pflValue
= flOffset
[0];
891 alSetError(AL_INVALID_OPERATION
);
894 case AL_SEC_RW_OFFSETS_EXT
:
895 case AL_SAMPLE_RW_OFFSETS_EXT
:
896 case AL_BYTE_RW_OFFSETS_EXT
:
897 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
899 pflValue
[0] = flOffset
[0];
900 pflValue
[1] = flOffset
[1];
903 alSetError(AL_INVALID_OPERATION
);
906 case AL_CONE_INNER_ANGLE
:
907 *pflValue
= pSource
->flInnerAngle
;
910 case AL_CONE_OUTER_ANGLE
:
911 *pflValue
= pSource
->flOuterAngle
;
914 case AL_REFERENCE_DISTANCE
:
915 *pflValue
= pSource
->flRefDistance
;
918 case AL_AIR_ABSORPTION_FACTOR
:
919 *pflValue
= pSource
->AirAbsorptionFactor
;
922 case AL_ROOM_ROLLOFF_FACTOR
:
923 *pflValue
= pSource
->RoomRolloffFactor
;
926 case AL_DOPPLER_FACTOR
:
927 *pflValue
= pSource
->DopplerFactor
;
931 alSetError(AL_INVALID_ENUM
);
936 alSetError(AL_INVALID_NAME
);
939 alSetError(AL_INVALID_VALUE
);
941 ProcessContext(pContext
);
945 ALAPI ALvoid ALAPIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
947 ALCcontext
*pContext
;
950 pContext
= GetContextSuspended();
951 if(!pContext
) return;
953 if(pflValue1
&& pflValue2
&& pflValue3
)
955 if(alIsSource(source
))
957 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
962 *pflValue1
= pSource
->vPosition
[0];
963 *pflValue2
= pSource
->vPosition
[1];
964 *pflValue3
= pSource
->vPosition
[2];
968 *pflValue1
= pSource
->vVelocity
[0];
969 *pflValue2
= pSource
->vVelocity
[1];
970 *pflValue3
= pSource
->vVelocity
[2];
974 *pflValue1
= pSource
->vOrientation
[0];
975 *pflValue2
= pSource
->vOrientation
[1];
976 *pflValue3
= pSource
->vOrientation
[2];
980 alSetError(AL_INVALID_ENUM
);
985 alSetError(AL_INVALID_NAME
);
988 alSetError(AL_INVALID_VALUE
);
990 ProcessContext(pContext
);
994 ALAPI ALvoid ALAPIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
996 ALCcontext
*pContext
;
999 pContext
= GetContextSuspended();
1000 if(!pContext
) return;
1004 if(alIsSource(source
))
1006 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1014 case AL_MAX_DISTANCE
:
1015 case AL_ROLLOFF_FACTOR
:
1016 case AL_DOPPLER_FACTOR
:
1017 case AL_CONE_OUTER_GAIN
:
1019 case AL_SAMPLE_OFFSET
:
1020 case AL_BYTE_OFFSET
:
1021 case AL_CONE_INNER_ANGLE
:
1022 case AL_CONE_OUTER_ANGLE
:
1023 case AL_REFERENCE_DISTANCE
:
1024 case AL_CONE_OUTER_GAINHF
:
1025 case AL_AIR_ABSORPTION_FACTOR
:
1026 case AL_ROOM_ROLLOFF_FACTOR
:
1027 alGetSourcef(source
, eParam
, pflValues
);
1031 pflValues
[0] = pSource
->vPosition
[0];
1032 pflValues
[1] = pSource
->vPosition
[1];
1033 pflValues
[2] = pSource
->vPosition
[2];
1037 pflValues
[0] = pSource
->vVelocity
[0];
1038 pflValues
[1] = pSource
->vVelocity
[1];
1039 pflValues
[2] = pSource
->vVelocity
[2];
1043 pflValues
[0] = pSource
->vOrientation
[0];
1044 pflValues
[1] = pSource
->vOrientation
[1];
1045 pflValues
[2] = pSource
->vOrientation
[2];
1049 alSetError(AL_INVALID_ENUM
);
1054 alSetError(AL_INVALID_NAME
);
1057 alSetError(AL_INVALID_VALUE
);
1059 ProcessContext(pContext
);
1063 ALAPI ALvoid ALAPIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1065 ALCcontext
*pContext
;
1067 ALfloat flOffset
[2];
1069 pContext
= GetContextSuspended();
1070 if(!pContext
) return;
1074 if(alIsSource(source
))
1076 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1080 case AL_MAX_DISTANCE
:
1081 *plValue
= (ALint
)pSource
->flMaxDistance
;
1084 case AL_ROLLOFF_FACTOR
:
1085 *plValue
= (ALint
)pSource
->flRollOffFactor
;
1088 case AL_REFERENCE_DISTANCE
:
1089 *plValue
= (ALint
)pSource
->flRefDistance
;
1092 case AL_SOURCE_RELATIVE
:
1093 *plValue
= pSource
->bHeadRelative
;
1096 case AL_CONE_INNER_ANGLE
:
1097 *plValue
= (ALint
)pSource
->flInnerAngle
;
1100 case AL_CONE_OUTER_ANGLE
:
1101 *plValue
= (ALint
)pSource
->flOuterAngle
;
1105 *plValue
= pSource
->bLooping
;
1109 *plValue
= (pSource
->Buffer
? pSource
->Buffer
->buffer
: 0);
1112 case AL_SOURCE_STATE
:
1113 *plValue
= pSource
->state
;
1116 case AL_BUFFERS_QUEUED
:
1117 *plValue
= pSource
->BuffersInQueue
;
1120 case AL_BUFFERS_PROCESSED
:
1121 if(pSource
->bLooping
)
1123 /* Buffers on a looping source are in a perpetual state
1124 * of PENDING, so don't report any as PROCESSED */
1128 *plValue
= pSource
->BuffersPlayed
;
1131 case AL_SOURCE_TYPE
:
1132 *plValue
= pSource
->lSourceType
;
1136 case AL_SAMPLE_OFFSET
:
1137 case AL_BYTE_OFFSET
:
1138 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
1139 *plValue
= (ALint
)flOffset
[0];
1141 alSetError(AL_INVALID_OPERATION
);
1144 case AL_SEC_RW_OFFSETS_EXT
:
1145 case AL_SAMPLE_RW_OFFSETS_EXT
:
1146 case AL_BYTE_RW_OFFSETS_EXT
:
1147 if(GetSourceOffset(pSource
, eParam
, flOffset
, pContext
->Device
->UpdateSize
))
1149 plValue
[0] = (ALint
)flOffset
[0];
1150 plValue
[1] = (ALint
)flOffset
[1];
1153 alSetError(AL_INVALID_OPERATION
);
1156 case AL_DIRECT_FILTER
:
1157 *plValue
= pSource
->DirectFilter
.filter
;
1160 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1161 *plValue
= pSource
->DryGainHFAuto
;
1164 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1165 *plValue
= pSource
->WetGainAuto
;
1168 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1169 *plValue
= pSource
->WetGainHFAuto
;
1172 case AL_DOPPLER_FACTOR
:
1173 *plValue
= (ALint
)pSource
->DopplerFactor
;
1176 case AL_DISTANCE_MODEL
:
1177 *plValue
= pSource
->DistanceModel
;
1181 alSetError(AL_INVALID_ENUM
);
1186 alSetError(AL_INVALID_NAME
);
1189 alSetError(AL_INVALID_VALUE
);
1191 ProcessContext(pContext
);
1195 ALAPI
void ALAPIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1197 ALCcontext
*pContext
;
1200 pContext
= GetContextSuspended();
1201 if(!pContext
) return;
1203 if(plValue1
&& plValue2
&& plValue3
)
1205 if(alIsSource(source
))
1207 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1212 *plValue1
= (ALint
)pSource
->vPosition
[0];
1213 *plValue2
= (ALint
)pSource
->vPosition
[1];
1214 *plValue3
= (ALint
)pSource
->vPosition
[2];
1218 *plValue1
= (ALint
)pSource
->vVelocity
[0];
1219 *plValue2
= (ALint
)pSource
->vVelocity
[1];
1220 *plValue3
= (ALint
)pSource
->vVelocity
[2];
1224 *plValue1
= (ALint
)pSource
->vOrientation
[0];
1225 *plValue2
= (ALint
)pSource
->vOrientation
[1];
1226 *plValue3
= (ALint
)pSource
->vOrientation
[2];
1230 alSetError(AL_INVALID_ENUM
);
1235 alSetError(AL_INVALID_NAME
);
1238 alSetError(AL_INVALID_VALUE
);
1240 ProcessContext(pContext
);
1244 ALAPI
void ALAPIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1246 ALCcontext
*pContext
;
1249 pContext
= GetContextSuspended();
1250 if(!pContext
) return;
1254 if(alIsSource(source
))
1256 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1260 case AL_SOURCE_RELATIVE
:
1261 case AL_CONE_INNER_ANGLE
:
1262 case AL_CONE_OUTER_ANGLE
:
1265 case AL_SOURCE_STATE
:
1266 case AL_BUFFERS_QUEUED
:
1267 case AL_BUFFERS_PROCESSED
:
1269 case AL_SAMPLE_OFFSET
:
1270 case AL_BYTE_OFFSET
:
1271 case AL_MAX_DISTANCE
:
1272 case AL_ROLLOFF_FACTOR
:
1273 case AL_DOPPLER_FACTOR
:
1274 case AL_REFERENCE_DISTANCE
:
1275 case AL_SOURCE_TYPE
:
1276 case AL_DIRECT_FILTER
:
1277 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1278 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1279 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1280 case AL_DISTANCE_MODEL
:
1281 alGetSourcei(source
, eParam
, plValues
);
1285 plValues
[0] = (ALint
)pSource
->vPosition
[0];
1286 plValues
[1] = (ALint
)pSource
->vPosition
[1];
1287 plValues
[2] = (ALint
)pSource
->vPosition
[2];
1291 plValues
[0] = (ALint
)pSource
->vVelocity
[0];
1292 plValues
[1] = (ALint
)pSource
->vVelocity
[1];
1293 plValues
[2] = (ALint
)pSource
->vVelocity
[2];
1297 plValues
[0] = (ALint
)pSource
->vOrientation
[0];
1298 plValues
[1] = (ALint
)pSource
->vOrientation
[1];
1299 plValues
[2] = (ALint
)pSource
->vOrientation
[2];
1303 alSetError(AL_INVALID_ENUM
);
1308 alSetError(AL_INVALID_NAME
);
1311 alSetError(AL_INVALID_VALUE
);
1313 ProcessContext(pContext
);
1317 ALAPI ALvoid ALAPIENTRY
alSourcePlay(ALuint source
)
1319 alSourcePlayv(1, &source
);
1322 ALAPI ALvoid ALAPIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*pSourceList
)
1324 ALCcontext
*pContext
;
1326 ALbufferlistitem
*ALBufferList
;
1327 ALboolean bSourcesValid
= AL_TRUE
;
1331 pContext
= GetContextSuspended();
1332 if(!pContext
) return;
1336 // Check that all the Sources are valid
1337 for(i
= 0; i
< n
; i
++)
1339 if(!alIsSource(pSourceList
[i
]))
1341 alSetError(AL_INVALID_NAME
);
1342 bSourcesValid
= AL_FALSE
;
1349 for(i
= 0; i
< n
; i
++)
1351 // Assume Source won't need to play
1354 pSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(pSourceList
[i
]);
1356 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1357 ALBufferList
= pSource
->queue
;
1360 if(ALBufferList
->buffer
!= NULL
&& ALBufferList
->buffer
->size
)
1365 ALBufferList
= ALBufferList
->next
;
1370 for(j
= 0;j
< OUTPUTCHANNELS
;j
++)
1371 pSource
->DryGains
[j
] = 0.0f
;
1372 for(j
= 0;j
< MAX_SENDS
;j
++)
1373 pSource
->WetGains
[j
] = 0.0f
;
1375 if(pSource
->state
!= AL_PAUSED
)
1377 pSource
->state
= AL_PLAYING
;
1378 pSource
->position
= 0;
1379 pSource
->position_fraction
= 0;
1380 pSource
->BuffersPlayed
= 0;
1382 pSource
->Buffer
= pSource
->queue
->buffer
;
1385 pSource
->state
= AL_PLAYING
;
1387 // Check if an Offset has been set
1388 if(pSource
->lOffset
)
1389 ApplyOffset(pSource
, AL_FALSE
);
1391 if(pSource
->BuffersPlayed
== 0 && pSource
->position
== 0 &&
1392 pSource
->position_fraction
== 0)
1393 pSource
->FirstStart
= AL_TRUE
;
1395 pSource
->FirstStart
= AL_FALSE
;
1397 // If device is disconnected, go right to stopped
1398 if(!pContext
->Device
->Connected
)
1400 pSource
->state
= AL_STOPPED
;
1401 pSource
->BuffersPlayed
= pSource
->BuffersInQueue
;
1402 pSource
->position
= 0;
1403 pSource
->position_fraction
= 0;
1407 pSource
->BuffersPlayed
= pSource
->BuffersInQueue
;
1413 // sources is a NULL pointer
1414 alSetError(AL_INVALID_VALUE
);
1417 ProcessContext(pContext
);
1420 ALAPI ALvoid ALAPIENTRY
alSourcePause(ALuint source
)
1422 alSourcePausev(1, &source
);
1425 ALAPI ALvoid ALAPIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1427 ALCcontext
*Context
;
1430 ALboolean bSourcesValid
= AL_TRUE
;
1432 Context
= GetContextSuspended();
1433 if(!Context
) return;
1437 // Check all the Sources are valid
1440 if(!alIsSource(sources
[i
]))
1442 alSetError(AL_INVALID_NAME
);
1443 bSourcesValid
= AL_FALSE
;
1450 for(i
= 0;i
< n
;i
++)
1452 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1453 if(Source
->state
== AL_PLAYING
)
1454 Source
->state
= AL_PAUSED
;
1460 // sources is a NULL pointer
1461 alSetError(AL_INVALID_VALUE
);
1464 ProcessContext(Context
);
1467 ALAPI ALvoid ALAPIENTRY
alSourceStop(ALuint source
)
1469 alSourceStopv(1, &source
);
1472 ALAPI ALvoid ALAPIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1474 ALCcontext
*Context
;
1477 ALboolean bSourcesValid
= AL_TRUE
;
1479 Context
= GetContextSuspended();
1480 if(!Context
) return;
1484 // Check all the Sources are valid
1485 for(i
= 0;i
< n
;i
++)
1487 if(!alIsSource(sources
[i
]))
1489 alSetError(AL_INVALID_NAME
);
1490 bSourcesValid
= AL_FALSE
;
1497 for(i
= 0;i
< n
;i
++)
1499 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1500 if(Source
->state
!= AL_INITIAL
)
1502 Source
->state
= AL_STOPPED
;
1503 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1505 Source
->lOffset
= 0;
1511 // sources is a NULL pointer
1512 alSetError(AL_INVALID_VALUE
);
1515 ProcessContext(Context
);
1518 ALAPI ALvoid ALAPIENTRY
alSourceRewind(ALuint source
)
1520 alSourceRewindv(1, &source
);
1523 ALAPI ALvoid ALAPIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1525 ALCcontext
*Context
;
1528 ALboolean bSourcesValid
= AL_TRUE
;
1530 Context
= GetContextSuspended();
1531 if(!Context
) return;
1535 // Check all the Sources are valid
1536 for(i
= 0;i
< n
;i
++)
1538 if(!alIsSource(sources
[i
]))
1540 alSetError(AL_INVALID_NAME
);
1541 bSourcesValid
= AL_FALSE
;
1548 for(i
= 0;i
< n
;i
++)
1550 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1551 if(Source
->state
!= AL_INITIAL
)
1553 Source
->state
= AL_INITIAL
;
1554 Source
->position
= 0;
1555 Source
->position_fraction
= 0;
1556 Source
->BuffersPlayed
= 0;
1558 Source
->Buffer
= Source
->queue
->buffer
;
1560 Source
->lOffset
= 0;
1566 // sources is a NULL pointer
1567 alSetError(AL_INVALID_VALUE
);
1570 ProcessContext(Context
);
1574 ALAPI ALvoid ALAPIENTRY
alSourceQueueBuffers( ALuint source
, ALsizei n
, const ALuint
* buffers
)
1576 ALCcontext
*Context
;
1579 ALbufferlistitem
*ALBufferList
;
1580 ALbufferlistitem
*ALBufferListStart
;
1583 ALboolean bBuffersValid
= AL_TRUE
;
1588 Context
= GetContextSuspended();
1589 if(!Context
) return;
1591 // Check that all buffers are valid or zero and that the source is valid
1593 // Check that this is a valid source
1594 if(alIsSource(source
))
1596 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1598 // Check that this is not a STATIC Source
1599 if(ALSource
->lSourceType
!= AL_STATIC
)
1604 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1605 ALBufferList
= ALSource
->queue
;
1608 if (ALBufferList
->buffer
)
1610 iFrequency
= ALBufferList
->buffer
->frequency
;
1611 iFormat
= ALBufferList
->buffer
->format
;
1614 ALBufferList
= ALBufferList
->next
;
1617 for(i
= 0; i
< n
; i
++)
1621 if(!alIsBuffer(buffers
[i
]))
1623 alSetError(AL_INVALID_NAME
);
1624 bBuffersValid
= AL_FALSE
;
1630 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1631 if(iFrequency
== -1 && iFormat
== -1)
1633 iFrequency
= buffer
->frequency
;
1634 iFormat
= buffer
->format
;
1636 else if(iFrequency
!= buffer
->frequency
||
1637 iFormat
!= buffer
->format
)
1639 alSetError(AL_INVALID_OPERATION
);
1640 bBuffersValid
= AL_FALSE
;
1647 ALbuffer
*buffer
= NULL
;
1649 // Change Source Type
1650 ALSource
->lSourceType
= AL_STREAMING
;
1652 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1654 // All buffers are valid - so add them to the list
1655 ALBufferListStart
= malloc(sizeof(ALbufferlistitem
));
1656 ALBufferListStart
->buffer
= buffer
;
1657 ALBufferListStart
->next
= NULL
;
1659 // Increment reference counter for buffer
1660 if(buffer
) buffer
->refcount
++;
1662 ALBufferList
= ALBufferListStart
;
1664 for(i
= 1; i
< n
; i
++)
1666 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1668 ALBufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1669 ALBufferList
->next
->buffer
= buffer
;
1670 ALBufferList
->next
->next
= NULL
;
1672 // Increment reference counter for buffer
1673 if(buffer
) buffer
->refcount
++;
1675 ALBufferList
= ALBufferList
->next
;
1678 if(ALSource
->queue
== NULL
)
1680 ALSource
->queue
= ALBufferListStart
;
1681 // Update Current Buffer
1682 ALSource
->Buffer
= ALBufferListStart
->buffer
;
1686 // Find end of queue
1687 ALBufferList
= ALSource
->queue
;
1688 while(ALBufferList
->next
!= NULL
)
1689 ALBufferList
= ALBufferList
->next
;
1691 ALBufferList
->next
= ALBufferListStart
;
1694 // Update number of buffers in queue
1695 ALSource
->BuffersInQueue
+= n
;
1700 // Invalid Source Type (can't queue on a Static Source)
1701 alSetError(AL_INVALID_OPERATION
);
1706 // Invalid Source Name
1707 alSetError(AL_INVALID_NAME
);
1710 ProcessContext(Context
);
1714 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1715 // an array of buffer IDs that are to be filled with the names of the buffers removed
1716 ALAPI ALvoid ALAPIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1718 ALCcontext
*Context
;
1721 ALbufferlistitem
*ALBufferList
;
1722 ALboolean bBuffersProcessed
;
1727 bBuffersProcessed
= AL_TRUE
;
1729 Context
= GetContextSuspended();
1730 if(!Context
) return;
1732 if(alIsSource(source
))
1734 ALSource
= (ALsource
*)ALTHUNK_LOOKUPENTRY(source
);
1736 // If all 'n' buffers have been processed, remove them from the queue
1737 if(!ALSource
->bLooping
&& (ALuint
)n
<= ALSource
->BuffersPlayed
)
1739 for(i
= 0; i
< n
; i
++)
1741 ALBufferList
= ALSource
->queue
;
1743 ALSource
->queue
= ALBufferList
->next
;
1744 // Record name of buffer
1745 buffers
[i
] = ALBufferList
->buffer
->buffer
;
1746 // Decrement buffer reference counter
1747 if(ALBufferList
->buffer
)
1748 ALBufferList
->buffer
->refcount
--;
1750 // Release memory for buffer list item
1752 ALSource
->BuffersInQueue
--;
1755 if(ALSource
->state
!= AL_PLAYING
)
1758 ALSource
->Buffer
= ALSource
->queue
->buffer
;
1760 ALSource
->Buffer
= NULL
;
1763 ALSource
->BuffersPlayed
-= n
;
1767 // Some buffers can't be unqueue because they have not been processed
1768 alSetError(AL_INVALID_VALUE
);
1773 // Invalid Source Name
1774 alSetError(AL_INVALID_NAME
);
1777 ProcessContext(Context
);
1781 static ALvoid
InitSourceParams(ALsource
*pSource
)
1783 pSource
->flInnerAngle
= 360.0f
;
1784 pSource
->flOuterAngle
= 360.0f
;
1785 pSource
->flPitch
= 1.0f
;
1786 pSource
->vPosition
[0] = 0.0f
;
1787 pSource
->vPosition
[1] = 0.0f
;
1788 pSource
->vPosition
[2] = 0.0f
;
1789 pSource
->vOrientation
[0] = 0.0f
;
1790 pSource
->vOrientation
[1] = 0.0f
;
1791 pSource
->vOrientation
[2] = 0.0f
;
1792 pSource
->vVelocity
[0] = 0.0f
;
1793 pSource
->vVelocity
[1] = 0.0f
;
1794 pSource
->vVelocity
[2] = 0.0f
;
1795 pSource
->flRefDistance
= 1.0f
;
1796 pSource
->flMaxDistance
= FLT_MAX
;
1797 pSource
->flRollOffFactor
= 1.0f
;
1798 pSource
->bLooping
= AL_FALSE
;
1799 pSource
->flGain
= 1.0f
;
1800 pSource
->flMinGain
= 0.0f
;
1801 pSource
->flMaxGain
= 1.0f
;
1802 pSource
->flOuterGain
= 0.0f
;
1803 pSource
->OuterGainHF
= 1.0f
;
1805 pSource
->DryGainHFAuto
= AL_TRUE
;
1806 pSource
->WetGainAuto
= AL_TRUE
;
1807 pSource
->WetGainHFAuto
= AL_TRUE
;
1808 pSource
->AirAbsorptionFactor
= 0.0f
;
1809 pSource
->RoomRolloffFactor
= 0.0f
;
1810 pSource
->DopplerFactor
= 1.0f
;
1812 pSource
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1814 pSource
->state
= AL_INITIAL
;
1815 pSource
->lSourceType
= AL_UNDETERMINED
;
1817 pSource
->NeedsUpdate
= AL_TRUE
;
1819 pSource
->Buffer
= NULL
;
1826 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1827 The offset is relative to the start of the queue (not the start of the current buffer)
1829 static ALboolean
GetSourceOffset(ALsource
*pSource
, ALenum eName
, ALfloat
*pflOffset
, ALuint updateSize
)
1831 ALbufferlistitem
*pBufferList
;
1833 ALfloat flBufferFreq
;
1834 ALint lChannels
, lBytes
;
1835 ALint readPos
, writePos
;
1836 ALenum eOriginalFormat
;
1837 ALboolean bReturn
= AL_TRUE
;
1838 ALint lTotalBufferDataSize
;
1841 if((pSource
->state
== AL_PLAYING
|| pSource
->state
== AL_PAUSED
) && pSource
->Buffer
)
1843 pBuffer
= pSource
->Buffer
;
1844 // Get Current Buffer Size and frequency (in milliseconds)
1845 flBufferFreq
= (ALfloat
)pBuffer
->frequency
;
1846 eOriginalFormat
= pBuffer
->eOriginalFormat
;
1847 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
1848 lBytes
= aluBytesFromFormat(pBuffer
->format
);
1850 // Get Current BytesPlayed
1851 readPos
= pSource
->position
* lChannels
* lBytes
; // NOTE : This is the byte offset into the *current* buffer
1852 // Add byte length of any processed buffers in the queue
1853 pBufferList
= pSource
->queue
;
1854 for(i
= 0;i
< pSource
->BuffersPlayed
&& pBufferList
;i
++)
1856 readPos
+= pBufferList
->buffer
->size
;
1857 pBufferList
= pBufferList
->next
;
1860 if(pSource
->state
== AL_PLAYING
)
1861 writePos
= readPos
+ (updateSize
* lChannels
* lBytes
);
1865 lTotalBufferDataSize
= 0;
1866 pBufferList
= pSource
->queue
;
1869 if (pBufferList
->buffer
)
1870 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
1871 pBufferList
= pBufferList
->next
;
1874 if (pSource
->bLooping
)
1879 readPos
%= lTotalBufferDataSize
;
1883 writePos
%= lTotalBufferDataSize
;
1887 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1890 else if(readPos
> lTotalBufferDataSize
)
1891 readPos
= lTotalBufferDataSize
;
1894 else if(writePos
> lTotalBufferDataSize
)
1895 writePos
= lTotalBufferDataSize
;
1901 case AL_SEC_RW_OFFSETS_EXT
:
1902 pflOffset
[0] = (ALfloat
)readPos
/ (lChannels
* lBytes
* flBufferFreq
);
1903 pflOffset
[1] = (ALfloat
)writePos
/ (lChannels
* lBytes
* flBufferFreq
);
1905 case AL_SAMPLE_OFFSET
:
1906 case AL_SAMPLE_RW_OFFSETS_EXT
:
1907 pflOffset
[0] = (ALfloat
)(readPos
/ (lChannels
* lBytes
));
1908 pflOffset
[1] = (ALfloat
)(writePos
/ (lChannels
* lBytes
));
1910 case AL_BYTE_OFFSET
:
1911 case AL_BYTE_RW_OFFSETS_EXT
:
1912 // Take into account the original format of the Buffer
1913 if ((eOriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1914 (eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1916 // Round down to nearest ADPCM block
1917 pflOffset
[0] = (ALfloat
)((readPos
/ (65 * lBytes
* lChannels
)) * 36 * lChannels
);
1918 if(pSource
->state
== AL_PLAYING
)
1920 // Round up to nearest ADPCM block
1921 pflOffset
[1] = (ALfloat
)(((writePos
+ (65 * lBytes
* lChannels
) - 1) / (65 * lBytes
* lChannels
)) * 36 * lChannels
);
1924 pflOffset
[1] = pflOffset
[0];
1926 else if (eOriginalFormat
== AL_FORMAT_REAR8
)
1928 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 1);
1929 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 1);
1931 else if (eOriginalFormat
== AL_FORMAT_REAR16
)
1933 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 2);
1934 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 2);
1936 else if (eOriginalFormat
== AL_FORMAT_REAR32
)
1938 pflOffset
[0] = (ALfloat
)(readPos
/ 2 / lBytes
* 4);
1939 pflOffset
[1] = (ALfloat
)(writePos
/ 2 / lBytes
* 4);
1941 else if (aluBytesFromFormat(eOriginalFormat
) == 1)
1943 pflOffset
[0] = (ALfloat
)(readPos
/ lBytes
* 1);
1944 pflOffset
[1] = (ALfloat
)(writePos
/ lBytes
* 1);
1946 else if (aluBytesFromFormat(eOriginalFormat
) == 2)
1948 pflOffset
[0] = (ALfloat
)(readPos
/ lBytes
* 2);
1949 pflOffset
[1] = (ALfloat
)(writePos
/ lBytes
* 2);
1951 else if (aluBytesFromFormat(eOriginalFormat
) == 4)
1953 pflOffset
[0] = (ALfloat
)(readPos
/ lBytes
* 4);
1954 pflOffset
[1] = (ALfloat
)(writePos
/ lBytes
* 4);
1958 pflOffset
[0] = (ALfloat
)readPos
;
1959 pflOffset
[1] = (ALfloat
)writePos
;
1966 pflOffset
[0] = 0.0f
;
1967 pflOffset
[1] = 0.0f
;
1977 Apply a playback offset to the Source. This function will update the queue (to correctly
1978 mark buffers as 'pending' or 'processed' depending upon the new offset.
1980 static void ApplyOffset(ALsource
*pSource
, ALboolean bUpdateContext
)
1982 ALbufferlistitem
*pBufferList
;
1984 ALint lBufferSize
, lTotalBufferSize
;
1987 // Get true byte offset
1988 lByteOffset
= GetByteOffset(pSource
);
1990 // If this is a valid offset apply it
1991 if (lByteOffset
!= -1)
1993 // Sort out the queue (pending and processed states)
1994 pBufferList
= pSource
->queue
;
1995 lTotalBufferSize
= 0;
1996 pSource
->BuffersPlayed
= 0;
1999 pBuffer
= pBufferList
->buffer
;
2000 lBufferSize
= pBuffer
? pBuffer
->size
: 0;
2002 if ((lTotalBufferSize
+ lBufferSize
) <= lByteOffset
)
2004 // Offset is past this buffer so increment BuffersPlayed
2005 pSource
->BuffersPlayed
++;
2007 else if (lTotalBufferSize
<= lByteOffset
)
2009 // Offset is within this buffer
2010 // Set Current Buffer
2011 pSource
->Buffer
= pBufferList
->buffer
;
2013 // SW Mixer Positions are in Samples
2014 pSource
->position
= (lByteOffset
- lTotalBufferSize
) /
2015 aluBytesFromFormat(pBuffer
->format
) /
2016 aluChannelsFromFormat(pBuffer
->format
);
2019 // Increment the TotalBufferSize
2020 lTotalBufferSize
+= lBufferSize
;
2022 // Move on to next buffer in the Queue
2023 pBufferList
= pBufferList
->next
;
2029 alSetError(AL_INVALID_VALUE
);
2033 pSource
->lOffset
= 0;
2040 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2041 offset supplied by the application). This takes into account the fact that the buffer format
2042 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2044 static ALint
GetByteOffset(ALsource
*pSource
)
2046 ALbuffer
*pBuffer
= NULL
;
2047 ALbufferlistitem
*pBufferList
;
2048 ALfloat flBufferFreq
;
2049 ALint lChannels
, lBytes
;
2050 ALint lByteOffset
= -1;
2051 ALint lTotalBufferDataSize
;
2053 // Find the first non-NULL Buffer in the Queue
2054 pBufferList
= pSource
->queue
;
2057 if (pBufferList
->buffer
)
2059 pBuffer
= pBufferList
->buffer
;
2062 pBufferList
= pBufferList
->next
;
2067 flBufferFreq
= ((ALfloat
)pBuffer
->frequency
);
2068 lChannels
= aluChannelsFromFormat(pBuffer
->format
);
2069 lBytes
= aluBytesFromFormat(pBuffer
->format
);
2071 // Determine the ByteOffset (and ensure it is block aligned)
2072 switch (pSource
->lOffsetType
)
2074 case AL_BYTE_OFFSET
:
2075 // Take into consideration the original format
2076 if ((pBuffer
->eOriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
2077 (pBuffer
->eOriginalFormat
== AL_FORMAT_STEREO_IMA4
))
2079 // Round down to nearest ADPCM block
2080 lByteOffset
= (pSource
->lOffset
/ (36 * lChannels
)) * 36 * lChannels
;
2081 // Multiply by compression rate
2082 lByteOffset
= (ALint
)(3.6111f
* (ALfloat
)lByteOffset
);
2083 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2085 else if (pBuffer
->eOriginalFormat
== AL_FORMAT_REAR8
)
2087 lByteOffset
= pSource
->lOffset
/ 1 * lBytes
* 2;
2088 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2090 else if (pBuffer
->eOriginalFormat
== AL_FORMAT_REAR16
)
2092 lByteOffset
= pSource
->lOffset
/ 2 * lBytes
* 2;
2093 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2095 else if (pBuffer
->eOriginalFormat
== AL_FORMAT_REAR32
)
2097 lByteOffset
= pSource
->lOffset
/ 4 * lBytes
* 2;
2098 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2100 else if (aluBytesFromFormat(pBuffer
->eOriginalFormat
) == 1)
2102 lByteOffset
= pSource
->lOffset
/ 1 * lBytes
;
2103 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2105 else if (aluBytesFromFormat(pBuffer
->eOriginalFormat
) == 2)
2107 lByteOffset
= pSource
->lOffset
/ 2 * lBytes
;
2108 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2110 else if (aluBytesFromFormat(pBuffer
->eOriginalFormat
) == 4)
2112 lByteOffset
= pSource
->lOffset
/ 4 * lBytes
;
2113 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2117 lByteOffset
= pSource
->lOffset
;
2118 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2122 case AL_SAMPLE_OFFSET
:
2123 lByteOffset
= pSource
->lOffset
* lChannels
* lBytes
;
2127 // Note - lOffset is internally stored as Milliseconds
2128 lByteOffset
= (ALint
)(pSource
->lOffset
* lChannels
* lBytes
* flBufferFreq
/ 1000.0f
);
2129 lByteOffset
-= (lByteOffset
% (lChannels
* lBytes
));
2133 lTotalBufferDataSize
= 0;
2134 pBufferList
= pSource
->queue
;
2137 if (pBufferList
->buffer
)
2138 lTotalBufferDataSize
+= pBufferList
->buffer
->size
;
2139 pBufferList
= pBufferList
->next
;
2142 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2143 if (lByteOffset
>= lTotalBufferDataSize
)
2151 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2155 while(Context
->Source
)
2157 ALsource
*temp
= Context
->Source
;
2158 Context
->Source
= temp
->next
;
2160 // For each buffer in the source's queue, decrement its reference counter and remove it
2161 while(temp
->queue
!= NULL
)
2163 ALbufferlistitem
*ALBufferList
= temp
->queue
;
2164 // Decrement buffer's reference counter
2165 if(ALBufferList
->buffer
!= NULL
)
2166 ALBufferList
->buffer
->refcount
--;
2167 // Update queue to point to next element in list
2168 temp
->queue
= ALBufferList
->next
;
2169 // Release memory allocated for buffer list item
2173 for(j
= 0;j
< MAX_SENDS
;++j
)
2175 if(temp
->Send
[j
].Slot
)
2176 temp
->Send
[j
].Slot
->refcount
--;
2179 // Release source structure
2180 ALTHUNK_REMOVEENTRY(temp
->source
);
2181 memset(temp
, 0, sizeof(ALsource
));
2184 Context
->SourceCount
= 0;