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
*Source
);
36 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum eName
, ALfloat
*pflOffset
, ALfloat updateLen
);
37 static ALboolean
ApplyOffset(ALsource
*Source
);
38 static ALint
GetByteOffset(ALsource
*Source
);
40 DECL_VERIFIER(Source
, ALsource
, source
)
41 DECL_VERIFIER(Buffer
, ALbuffer
, buffer
)
42 DECL_VERIFIER(Filter
, ALfilter
, filter
)
43 DECL_VERIFIER(EffectSlot
, ALeffectslot
, effectslot
)
45 AL_API ALvoid AL_APIENTRY
alGenSources(ALsizei n
,ALuint
*sources
)
51 Context
= GetContextSuspended();
56 Device
= Context
->Device
;
58 // Check that enough memory has been allocted in the 'sources' array for n Sources
59 if(!IsBadWritePtr((void*)sources
, n
* sizeof(ALuint
)))
61 // Check that the requested number of sources can be generated
62 if((Context
->SourceCount
+ n
) <= Device
->MaxNoOfSources
)
65 ALsource
**list
= &Context
->SourceList
;
67 list
= &(*list
)->next
;
69 // Add additional sources to the list (Source->next points to the location for the next Source structure)
73 *list
= calloc(1, sizeof(ALsource
));
78 ALsource
*temp
= end
->next
;
79 end
->next
= temp
->next
;
81 ALTHUNK_REMOVEENTRY(temp
->source
);
82 Context
->SourceCount
--;
85 alSetError(Context
, AL_OUT_OF_MEMORY
);
89 sources
[i
] = (ALuint
)ALTHUNK_ADDENTRY(*list
);
90 (*list
)->source
= sources
[i
];
92 InitSourceParams(*list
);
93 Context
->SourceCount
++;
96 list
= &(*list
)->next
;
101 // Not enough resources to create the Sources
102 alSetError(Context
, AL_INVALID_VALUE
);
108 alSetError(Context
, AL_INVALID_VALUE
);
112 ProcessContext(Context
);
116 AL_API ALvoid AL_APIENTRY
alDeleteSources(ALsizei n
, const ALuint
*sources
)
123 ALbufferlistitem
*BufferList
;
124 ALboolean bSourcesValid
= AL_TRUE
;
126 Context
= GetContextSuspended();
131 Device
= Context
->Device
;
133 // Check that all Sources are valid (and can therefore be deleted)
134 for (i
= 0; i
< n
; i
++)
136 if(VerifySource(Context
->SourceList
, sources
[i
]) == NULL
)
138 alSetError(Context
, AL_INVALID_NAME
);
139 bSourcesValid
= AL_FALSE
;
146 // All Sources are valid, and can be deleted
147 for(i
= 0; i
< n
; i
++)
149 // Recheck that the Source is valid, because there could be duplicated Source names
150 if((Source
=VerifySource(Context
->SourceList
, sources
[i
])) != NULL
)
152 // For each buffer in the source's queue, decrement its reference counter and remove it
153 while (Source
->queue
!= NULL
)
155 BufferList
= Source
->queue
;
156 // Decrement buffer's reference counter
157 if(BufferList
->buffer
!= NULL
)
158 BufferList
->buffer
->refcount
--;
159 // Update queue to point to next element in list
160 Source
->queue
= BufferList
->next
;
161 // Release memory allocated for buffer list item
165 for(j
= 0;j
< MAX_SENDS
;++j
)
167 if(Source
->Send
[j
].Slot
)
168 Source
->Send
[j
].Slot
->refcount
--;
169 Source
->Send
[j
].Slot
= NULL
;
172 // Decrement Source count
173 Context
->SourceCount
--;
175 // Remove Source from list of Sources
176 list
= &Context
->SourceList
;
177 while(*list
&& *list
!= Source
)
178 list
= &(*list
)->next
;
181 *list
= (*list
)->next
;
182 ALTHUNK_REMOVEENTRY(Source
->source
);
184 memset(Source
,0,sizeof(ALsource
));
191 alSetError(Context
, AL_INVALID_VALUE
);
193 ProcessContext(Context
);
197 AL_API ALboolean AL_APIENTRY
alIsSource(ALuint source
)
202 Context
= GetContextSuspended();
203 if(!Context
) return AL_FALSE
;
205 result
= (VerifySource(Context
->SourceList
, source
) ? AL_TRUE
: AL_FALSE
);
207 ProcessContext(Context
);
213 AL_API ALvoid AL_APIENTRY
alSourcef(ALuint source
, ALenum eParam
, ALfloat flValue
)
215 ALCcontext
*pContext
;
218 pContext
= GetContextSuspended();
219 if(!pContext
) return;
221 if((Source
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
228 Source
->flPitch
= flValue
;
229 if(Source
->flPitch
< 0.001f
)
230 Source
->flPitch
= 0.001f
;
231 Source
->NeedsUpdate
= AL_TRUE
;
234 alSetError(pContext
, AL_INVALID_VALUE
);
237 case AL_CONE_INNER_ANGLE
:
238 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
240 Source
->flInnerAngle
= flValue
;
241 Source
->NeedsUpdate
= AL_TRUE
;
244 alSetError(pContext
, AL_INVALID_VALUE
);
247 case AL_CONE_OUTER_ANGLE
:
248 if(flValue
>= 0.0f
&& flValue
<= 360.0f
)
250 Source
->flOuterAngle
= flValue
;
251 Source
->NeedsUpdate
= AL_TRUE
;
254 alSetError(pContext
, AL_INVALID_VALUE
);
260 Source
->flGain
= flValue
;
261 Source
->NeedsUpdate
= AL_TRUE
;
264 alSetError(pContext
, AL_INVALID_VALUE
);
267 case AL_MAX_DISTANCE
:
270 Source
->flMaxDistance
= flValue
;
271 Source
->NeedsUpdate
= AL_TRUE
;
274 alSetError(pContext
, AL_INVALID_VALUE
);
277 case AL_ROLLOFF_FACTOR
:
280 Source
->flRollOffFactor
= flValue
;
281 Source
->NeedsUpdate
= AL_TRUE
;
284 alSetError(pContext
, AL_INVALID_VALUE
);
287 case AL_REFERENCE_DISTANCE
:
290 Source
->flRefDistance
= flValue
;
291 Source
->NeedsUpdate
= AL_TRUE
;
294 alSetError(pContext
, AL_INVALID_VALUE
);
298 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
300 Source
->flMinGain
= flValue
;
301 Source
->NeedsUpdate
= AL_TRUE
;
304 alSetError(pContext
, AL_INVALID_VALUE
);
308 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
310 Source
->flMaxGain
= flValue
;
311 Source
->NeedsUpdate
= AL_TRUE
;
314 alSetError(pContext
, AL_INVALID_VALUE
);
317 case AL_CONE_OUTER_GAIN
:
318 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
320 Source
->flOuterGain
= flValue
;
321 Source
->NeedsUpdate
= AL_TRUE
;
324 alSetError(pContext
, AL_INVALID_VALUE
);
327 case AL_CONE_OUTER_GAINHF
:
328 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
330 Source
->OuterGainHF
= flValue
;
331 Source
->NeedsUpdate
= AL_TRUE
;
334 alSetError(pContext
, AL_INVALID_VALUE
);
337 case AL_AIR_ABSORPTION_FACTOR
:
338 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
340 Source
->AirAbsorptionFactor
= flValue
;
341 Source
->NeedsUpdate
= AL_TRUE
;
344 alSetError(pContext
, AL_INVALID_VALUE
);
347 case AL_ROOM_ROLLOFF_FACTOR
:
348 if(flValue
>= 0.0f
&& flValue
<= 10.0f
)
350 Source
->RoomRolloffFactor
= flValue
;
351 Source
->NeedsUpdate
= AL_TRUE
;
354 alSetError(pContext
, AL_INVALID_VALUE
);
357 case AL_DOPPLER_FACTOR
:
358 if(flValue
>= 0.0f
&& flValue
<= 1.0f
)
360 Source
->DopplerFactor
= flValue
;
361 Source
->NeedsUpdate
= AL_TRUE
;
364 alSetError(pContext
, AL_INVALID_VALUE
);
368 case AL_SAMPLE_OFFSET
:
372 Source
->lOffsetType
= eParam
;
374 // Store Offset (convert Seconds into Milliseconds)
375 if(eParam
== AL_SEC_OFFSET
)
376 Source
->lOffset
= (ALint
)(flValue
* 1000.0f
);
378 Source
->lOffset
= (ALint
)flValue
;
380 if ((Source
->state
== AL_PLAYING
) || (Source
->state
== AL_PAUSED
))
382 if(ApplyOffset(Source
) == AL_FALSE
)
383 alSetError(pContext
, AL_INVALID_VALUE
);
387 alSetError(pContext
, AL_INVALID_VALUE
);
391 alSetError(pContext
, AL_INVALID_ENUM
);
397 // Invalid Source Name
398 alSetError(pContext
, AL_INVALID_NAME
);
401 ProcessContext(pContext
);
405 AL_API ALvoid AL_APIENTRY
alSource3f(ALuint source
, ALenum eParam
, ALfloat flValue1
,ALfloat flValue2
,ALfloat flValue3
)
407 ALCcontext
*pContext
;
410 pContext
= GetContextSuspended();
411 if(!pContext
) return;
413 if((Source
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
418 Source
->vPosition
[0] = flValue1
;
419 Source
->vPosition
[1] = flValue2
;
420 Source
->vPosition
[2] = flValue3
;
421 Source
->NeedsUpdate
= AL_TRUE
;
425 Source
->vVelocity
[0] = flValue1
;
426 Source
->vVelocity
[1] = flValue2
;
427 Source
->vVelocity
[2] = flValue3
;
428 Source
->NeedsUpdate
= AL_TRUE
;
432 Source
->vOrientation
[0] = flValue1
;
433 Source
->vOrientation
[1] = flValue2
;
434 Source
->vOrientation
[2] = flValue3
;
435 Source
->NeedsUpdate
= AL_TRUE
;
439 alSetError(pContext
, AL_INVALID_ENUM
);
444 alSetError(pContext
, AL_INVALID_NAME
);
446 ProcessContext(pContext
);
450 AL_API ALvoid AL_APIENTRY
alSourcefv(ALuint source
, ALenum eParam
, const ALfloat
*pflValues
)
452 ALCcontext
*pContext
;
454 pContext
= GetContextSuspended();
455 if(!pContext
) return;
459 if(VerifySource(pContext
->SourceList
, source
) != NULL
)
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(pContext
, AL_INVALID_ENUM
);
494 alSetError(pContext
, AL_INVALID_NAME
);
497 alSetError(pContext
, AL_INVALID_VALUE
);
499 ProcessContext(pContext
);
503 AL_API ALvoid AL_APIENTRY
alSourcei(ALuint source
,ALenum eParam
,ALint lValue
)
505 ALCcontext
*pContext
;
507 ALbufferlistitem
*BufferListItem
;
509 pContext
= GetContextSuspended();
510 if(!pContext
) return;
512 if((Source
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
514 ALCdevice
*device
= pContext
->Device
;
518 case AL_MAX_DISTANCE
:
519 case AL_ROLLOFF_FACTOR
:
520 case AL_CONE_INNER_ANGLE
:
521 case AL_CONE_OUTER_ANGLE
:
522 case AL_REFERENCE_DISTANCE
:
523 alSourcef(source
, eParam
, (ALfloat
)lValue
);
526 case AL_SOURCE_RELATIVE
:
527 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
529 Source
->bHeadRelative
= (ALboolean
)lValue
;
530 Source
->NeedsUpdate
= AL_TRUE
;
533 alSetError(pContext
, AL_INVALID_VALUE
);
537 if(lValue
== AL_FALSE
|| lValue
== AL_TRUE
)
538 Source
->bLooping
= (ALboolean
)lValue
;
540 alSetError(pContext
, AL_INVALID_VALUE
);
544 if(Source
->state
== AL_STOPPED
|| Source
->state
== AL_INITIAL
)
546 ALbuffer
*buffer
= NULL
;
549 (buffer
=VerifyBuffer(device
->BufferList
, lValue
)) != NULL
)
551 // Remove all elements in the queue
552 while(Source
->queue
!= NULL
)
554 BufferListItem
= Source
->queue
;
555 Source
->queue
= BufferListItem
->next
;
556 // Decrement reference counter for buffer
557 if(BufferListItem
->buffer
)
558 BufferListItem
->buffer
->refcount
--;
559 // Release memory for buffer list item
560 free(BufferListItem
);
561 // Decrement the number of buffers in the queue
562 Source
->BuffersInQueue
--;
565 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
568 // Source is now in STATIC mode
569 Source
->lSourceType
= AL_STATIC
;
571 // Add the selected buffer to the queue
572 BufferListItem
= malloc(sizeof(ALbufferlistitem
));
573 BufferListItem
->buffer
= buffer
;
574 BufferListItem
->next
= NULL
;
576 Source
->queue
= BufferListItem
;
577 Source
->BuffersInQueue
= 1;
579 // Increment reference counter for buffer
584 // Source is now in UNDETERMINED mode
585 Source
->lSourceType
= AL_UNDETERMINED
;
586 Source
->BuffersPlayed
= 0;
589 // Update AL_BUFFER parameter
590 Source
->Buffer
= buffer
;
591 Source
->NeedsUpdate
= AL_TRUE
;
594 alSetError(pContext
, AL_INVALID_VALUE
);
597 alSetError(pContext
, AL_INVALID_OPERATION
);
600 case AL_SOURCE_STATE
:
602 alSetError(pContext
, AL_INVALID_OPERATION
);
606 case AL_SAMPLE_OFFSET
:
610 Source
->lOffsetType
= eParam
;
612 // Store Offset (convert Seconds into Milliseconds)
613 if(eParam
== AL_SEC_OFFSET
)
614 Source
->lOffset
= lValue
* 1000;
616 Source
->lOffset
= lValue
;
618 if(Source
->state
== AL_PLAYING
|| Source
->state
== AL_PAUSED
)
620 if(ApplyOffset(Source
) == AL_FALSE
)
621 alSetError(pContext
, AL_INVALID_VALUE
);
625 alSetError(pContext
, AL_INVALID_VALUE
);
628 case AL_DIRECT_FILTER
: {
629 ALfilter
*filter
= NULL
;
632 (filter
=VerifyFilter(pContext
->Device
->FilterList
, lValue
)) != NULL
)
636 Source
->DirectFilter
.type
= AL_FILTER_NULL
;
637 Source
->DirectFilter
.filter
= 0;
640 memcpy(&Source
->DirectFilter
, filter
, sizeof(*filter
));
641 Source
->NeedsUpdate
= AL_TRUE
;
644 alSetError(pContext
, AL_INVALID_VALUE
);
647 case AL_DIRECT_FILTER_GAINHF_AUTO
:
648 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
650 Source
->DryGainHFAuto
= lValue
;
651 Source
->NeedsUpdate
= AL_TRUE
;
654 alSetError(pContext
, AL_INVALID_VALUE
);
657 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
658 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
660 Source
->WetGainAuto
= lValue
;
661 Source
->NeedsUpdate
= AL_TRUE
;
664 alSetError(pContext
, AL_INVALID_VALUE
);
667 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
668 if(lValue
== AL_TRUE
|| lValue
== AL_FALSE
)
670 Source
->WetGainHFAuto
= lValue
;
671 Source
->NeedsUpdate
= AL_TRUE
;
674 alSetError(pContext
, AL_INVALID_VALUE
);
677 case AL_DISTANCE_MODEL
:
678 if(lValue
== AL_NONE
||
679 lValue
== AL_INVERSE_DISTANCE
||
680 lValue
== AL_INVERSE_DISTANCE_CLAMPED
||
681 lValue
== AL_LINEAR_DISTANCE
||
682 lValue
== AL_LINEAR_DISTANCE_CLAMPED
||
683 lValue
== AL_EXPONENT_DISTANCE
||
684 lValue
== AL_EXPONENT_DISTANCE_CLAMPED
)
686 Source
->DistanceModel
= lValue
;
687 if(pContext
->SourceDistanceModel
)
688 Source
->NeedsUpdate
= AL_TRUE
;
691 alSetError(pContext
, AL_INVALID_VALUE
);
695 alSetError(pContext
, AL_INVALID_ENUM
);
700 alSetError(pContext
, AL_INVALID_NAME
);
702 ProcessContext(pContext
);
706 AL_API
void AL_APIENTRY
alSource3i(ALuint source
, ALenum eParam
, ALint lValue1
, ALint lValue2
, ALint lValue3
)
708 ALCcontext
*pContext
;
711 pContext
= GetContextSuspended();
712 if(!pContext
) return;
714 if((Source
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
716 ALCdevice
*device
= pContext
->Device
;
723 alSource3f(source
, eParam
, (ALfloat
)lValue1
, (ALfloat
)lValue2
, (ALfloat
)lValue3
);
726 case AL_AUXILIARY_SEND_FILTER
: {
727 ALeffectslot
*ALEffectSlot
= NULL
;
728 ALfilter
*ALFilter
= NULL
;
730 if((ALuint
)lValue2
< device
->NumAuxSends
&&
732 (ALEffectSlot
=VerifyEffectSlot(pContext
->EffectSlotList
, lValue1
)) != NULL
) &&
734 (ALFilter
=VerifyFilter(device
->FilterList
, lValue3
)) != NULL
))
736 /* Release refcount on the previous slot, and add one for
738 if(Source
->Send
[lValue2
].Slot
)
739 Source
->Send
[lValue2
].Slot
->refcount
--;
740 Source
->Send
[lValue2
].Slot
= ALEffectSlot
;
741 if(Source
->Send
[lValue2
].Slot
)
742 Source
->Send
[lValue2
].Slot
->refcount
++;
747 Source
->Send
[lValue2
].WetFilter
.type
= 0;
748 Source
->Send
[lValue2
].WetFilter
.filter
= 0;
751 memcpy(&Source
->Send
[lValue2
].WetFilter
, ALFilter
, sizeof(*ALFilter
));
752 Source
->NeedsUpdate
= AL_TRUE
;
755 alSetError(pContext
, AL_INVALID_VALUE
);
759 alSetError(pContext
, AL_INVALID_ENUM
);
764 alSetError(pContext
, AL_INVALID_NAME
);
766 ProcessContext(pContext
);
770 AL_API
void AL_APIENTRY
alSourceiv(ALuint source
, ALenum eParam
, const ALint
* plValues
)
772 ALCcontext
*pContext
;
774 pContext
= GetContextSuspended();
775 if(!pContext
) return;
779 if(VerifySource(pContext
->SourceList
, source
) != NULL
)
783 case AL_SOURCE_RELATIVE
:
784 case AL_CONE_INNER_ANGLE
:
785 case AL_CONE_OUTER_ANGLE
:
788 case AL_SOURCE_STATE
:
790 case AL_SAMPLE_OFFSET
:
792 case AL_MAX_DISTANCE
:
793 case AL_ROLLOFF_FACTOR
:
794 case AL_REFERENCE_DISTANCE
:
795 case AL_DIRECT_FILTER
:
796 case AL_DIRECT_FILTER_GAINHF_AUTO
:
797 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
798 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
799 case AL_DISTANCE_MODEL
:
800 alSourcei(source
, eParam
, plValues
[0]);
806 case AL_AUXILIARY_SEND_FILTER
:
807 alSource3i(source
, eParam
, plValues
[0], plValues
[1], plValues
[2]);
811 alSetError(pContext
, AL_INVALID_ENUM
);
816 alSetError(pContext
, AL_INVALID_NAME
);
819 alSetError(pContext
, AL_INVALID_VALUE
);
821 ProcessContext(pContext
);
825 AL_API ALvoid AL_APIENTRY
alGetSourcef(ALuint source
, ALenum eParam
, ALfloat
*pflValue
)
827 ALCcontext
*pContext
;
832 pContext
= GetContextSuspended();
833 if(!pContext
) return;
837 if((Source
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
842 *pflValue
= Source
->flPitch
;
846 *pflValue
= Source
->flGain
;
850 *pflValue
= Source
->flMinGain
;
854 *pflValue
= Source
->flMaxGain
;
857 case AL_MAX_DISTANCE
:
858 *pflValue
= Source
->flMaxDistance
;
861 case AL_ROLLOFF_FACTOR
:
862 *pflValue
= Source
->flRollOffFactor
;
865 case AL_CONE_OUTER_GAIN
:
866 *pflValue
= Source
->flOuterGain
;
869 case AL_CONE_OUTER_GAINHF
:
870 *pflValue
= Source
->OuterGainHF
;
874 case AL_SAMPLE_OFFSET
:
876 updateLen
= (ALfloat
)pContext
->Device
->UpdateSize
/
877 pContext
->Device
->Frequency
;
878 GetSourceOffset(Source
, eParam
, flOffset
, updateLen
);
879 *pflValue
= flOffset
[0];
882 case AL_CONE_INNER_ANGLE
:
883 *pflValue
= Source
->flInnerAngle
;
886 case AL_CONE_OUTER_ANGLE
:
887 *pflValue
= Source
->flOuterAngle
;
890 case AL_REFERENCE_DISTANCE
:
891 *pflValue
= Source
->flRefDistance
;
894 case AL_AIR_ABSORPTION_FACTOR
:
895 *pflValue
= Source
->AirAbsorptionFactor
;
898 case AL_ROOM_ROLLOFF_FACTOR
:
899 *pflValue
= Source
->RoomRolloffFactor
;
902 case AL_DOPPLER_FACTOR
:
903 *pflValue
= Source
->DopplerFactor
;
907 alSetError(pContext
, AL_INVALID_ENUM
);
912 alSetError(pContext
, AL_INVALID_NAME
);
915 alSetError(pContext
, AL_INVALID_VALUE
);
917 ProcessContext(pContext
);
921 AL_API ALvoid AL_APIENTRY
alGetSource3f(ALuint source
, ALenum eParam
, ALfloat
* pflValue1
, ALfloat
* pflValue2
, ALfloat
* pflValue3
)
923 ALCcontext
*pContext
;
926 pContext
= GetContextSuspended();
927 if(!pContext
) return;
929 if(pflValue1
&& pflValue2
&& pflValue3
)
931 if((Source
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
936 *pflValue1
= Source
->vPosition
[0];
937 *pflValue2
= Source
->vPosition
[1];
938 *pflValue3
= Source
->vPosition
[2];
942 *pflValue1
= Source
->vVelocity
[0];
943 *pflValue2
= Source
->vVelocity
[1];
944 *pflValue3
= Source
->vVelocity
[2];
948 *pflValue1
= Source
->vOrientation
[0];
949 *pflValue2
= Source
->vOrientation
[1];
950 *pflValue3
= Source
->vOrientation
[2];
954 alSetError(pContext
, AL_INVALID_ENUM
);
959 alSetError(pContext
, AL_INVALID_NAME
);
962 alSetError(pContext
, AL_INVALID_VALUE
);
964 ProcessContext(pContext
);
968 AL_API ALvoid AL_APIENTRY
alGetSourcefv(ALuint source
, ALenum eParam
, ALfloat
*pflValues
)
970 ALCcontext
*pContext
;
975 pContext
= GetContextSuspended();
976 if(!pContext
) return;
980 if((Source
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
988 case AL_MAX_DISTANCE
:
989 case AL_ROLLOFF_FACTOR
:
990 case AL_DOPPLER_FACTOR
:
991 case AL_CONE_OUTER_GAIN
:
993 case AL_SAMPLE_OFFSET
:
995 case AL_CONE_INNER_ANGLE
:
996 case AL_CONE_OUTER_ANGLE
:
997 case AL_REFERENCE_DISTANCE
:
998 case AL_CONE_OUTER_GAINHF
:
999 case AL_AIR_ABSORPTION_FACTOR
:
1000 case AL_ROOM_ROLLOFF_FACTOR
:
1001 alGetSourcef(source
, eParam
, pflValues
);
1004 case AL_SAMPLE_RW_OFFSETS_EXT
:
1005 case AL_BYTE_RW_OFFSETS_EXT
:
1006 updateLen
= (ALfloat
)pContext
->Device
->UpdateSize
/
1007 pContext
->Device
->Frequency
;
1008 GetSourceOffset(Source
, eParam
, flOffset
, updateLen
);
1009 pflValues
[0] = flOffset
[0];
1010 pflValues
[1] = flOffset
[1];
1014 pflValues
[0] = Source
->vPosition
[0];
1015 pflValues
[1] = Source
->vPosition
[1];
1016 pflValues
[2] = Source
->vPosition
[2];
1020 pflValues
[0] = Source
->vVelocity
[0];
1021 pflValues
[1] = Source
->vVelocity
[1];
1022 pflValues
[2] = Source
->vVelocity
[2];
1026 pflValues
[0] = Source
->vOrientation
[0];
1027 pflValues
[1] = Source
->vOrientation
[1];
1028 pflValues
[2] = Source
->vOrientation
[2];
1032 alSetError(pContext
, AL_INVALID_ENUM
);
1037 alSetError(pContext
, AL_INVALID_NAME
);
1040 alSetError(pContext
, AL_INVALID_VALUE
);
1042 ProcessContext(pContext
);
1046 AL_API ALvoid AL_APIENTRY
alGetSourcei(ALuint source
, ALenum eParam
, ALint
*plValue
)
1048 ALCcontext
*pContext
;
1050 ALfloat flOffset
[2];
1053 pContext
= GetContextSuspended();
1054 if(!pContext
) return;
1058 if((Source
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
1062 case AL_MAX_DISTANCE
:
1063 *plValue
= (ALint
)Source
->flMaxDistance
;
1066 case AL_ROLLOFF_FACTOR
:
1067 *plValue
= (ALint
)Source
->flRollOffFactor
;
1070 case AL_REFERENCE_DISTANCE
:
1071 *plValue
= (ALint
)Source
->flRefDistance
;
1074 case AL_SOURCE_RELATIVE
:
1075 *plValue
= Source
->bHeadRelative
;
1078 case AL_CONE_INNER_ANGLE
:
1079 *plValue
= (ALint
)Source
->flInnerAngle
;
1082 case AL_CONE_OUTER_ANGLE
:
1083 *plValue
= (ALint
)Source
->flOuterAngle
;
1087 *plValue
= Source
->bLooping
;
1091 *plValue
= (Source
->Buffer
? Source
->Buffer
->buffer
: 0);
1094 case AL_SOURCE_STATE
:
1095 *plValue
= Source
->state
;
1098 case AL_BUFFERS_QUEUED
:
1099 *plValue
= Source
->BuffersInQueue
;
1102 case AL_BUFFERS_PROCESSED
:
1103 if(Source
->bLooping
)
1105 /* Buffers on a looping source are in a perpetual state
1106 * of PENDING, so don't report any as PROCESSED */
1110 *plValue
= Source
->BuffersPlayed
;
1113 case AL_SOURCE_TYPE
:
1114 *plValue
= Source
->lSourceType
;
1118 case AL_SAMPLE_OFFSET
:
1119 case AL_BYTE_OFFSET
:
1120 updateLen
= (ALfloat
)pContext
->Device
->UpdateSize
/
1121 pContext
->Device
->Frequency
;
1122 GetSourceOffset(Source
, eParam
, flOffset
, updateLen
);
1123 *plValue
= (ALint
)flOffset
[0];
1126 case AL_DIRECT_FILTER
:
1127 *plValue
= Source
->DirectFilter
.filter
;
1130 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1131 *plValue
= Source
->DryGainHFAuto
;
1134 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1135 *plValue
= Source
->WetGainAuto
;
1138 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1139 *plValue
= Source
->WetGainHFAuto
;
1142 case AL_DOPPLER_FACTOR
:
1143 *plValue
= (ALint
)Source
->DopplerFactor
;
1146 case AL_DISTANCE_MODEL
:
1147 *plValue
= Source
->DistanceModel
;
1151 alSetError(pContext
, AL_INVALID_ENUM
);
1156 alSetError(pContext
, AL_INVALID_NAME
);
1159 alSetError(pContext
, AL_INVALID_VALUE
);
1161 ProcessContext(pContext
);
1165 AL_API
void AL_APIENTRY
alGetSource3i(ALuint source
, ALenum eParam
, ALint
* plValue1
, ALint
* plValue2
, ALint
* plValue3
)
1167 ALCcontext
*pContext
;
1170 pContext
= GetContextSuspended();
1171 if(!pContext
) return;
1173 if(plValue1
&& plValue2
&& plValue3
)
1175 if((Source
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
1180 *plValue1
= (ALint
)Source
->vPosition
[0];
1181 *plValue2
= (ALint
)Source
->vPosition
[1];
1182 *plValue3
= (ALint
)Source
->vPosition
[2];
1186 *plValue1
= (ALint
)Source
->vVelocity
[0];
1187 *plValue2
= (ALint
)Source
->vVelocity
[1];
1188 *plValue3
= (ALint
)Source
->vVelocity
[2];
1192 *plValue1
= (ALint
)Source
->vOrientation
[0];
1193 *plValue2
= (ALint
)Source
->vOrientation
[1];
1194 *plValue3
= (ALint
)Source
->vOrientation
[2];
1198 alSetError(pContext
, AL_INVALID_ENUM
);
1203 alSetError(pContext
, AL_INVALID_NAME
);
1206 alSetError(pContext
, AL_INVALID_VALUE
);
1208 ProcessContext(pContext
);
1212 AL_API
void AL_APIENTRY
alGetSourceiv(ALuint source
, ALenum eParam
, ALint
* plValues
)
1214 ALCcontext
*pContext
;
1216 ALfloat flOffset
[2];
1219 pContext
= GetContextSuspended();
1220 if(!pContext
) return;
1224 if((Source
=VerifySource(pContext
->SourceList
, source
)) != NULL
)
1228 case AL_SOURCE_RELATIVE
:
1229 case AL_CONE_INNER_ANGLE
:
1230 case AL_CONE_OUTER_ANGLE
:
1233 case AL_SOURCE_STATE
:
1234 case AL_BUFFERS_QUEUED
:
1235 case AL_BUFFERS_PROCESSED
:
1237 case AL_SAMPLE_OFFSET
:
1238 case AL_BYTE_OFFSET
:
1239 case AL_MAX_DISTANCE
:
1240 case AL_ROLLOFF_FACTOR
:
1241 case AL_DOPPLER_FACTOR
:
1242 case AL_REFERENCE_DISTANCE
:
1243 case AL_SOURCE_TYPE
:
1244 case AL_DIRECT_FILTER
:
1245 case AL_DIRECT_FILTER_GAINHF_AUTO
:
1246 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO
:
1247 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO
:
1248 case AL_DISTANCE_MODEL
:
1249 alGetSourcei(source
, eParam
, plValues
);
1252 case AL_SAMPLE_RW_OFFSETS_EXT
:
1253 case AL_BYTE_RW_OFFSETS_EXT
:
1254 updateLen
= (ALfloat
)pContext
->Device
->UpdateSize
/
1255 pContext
->Device
->Frequency
;
1256 GetSourceOffset(Source
, eParam
, flOffset
, updateLen
);
1257 plValues
[0] = (ALint
)flOffset
[0];
1258 plValues
[1] = (ALint
)flOffset
[1];
1262 plValues
[0] = (ALint
)Source
->vPosition
[0];
1263 plValues
[1] = (ALint
)Source
->vPosition
[1];
1264 plValues
[2] = (ALint
)Source
->vPosition
[2];
1268 plValues
[0] = (ALint
)Source
->vVelocity
[0];
1269 plValues
[1] = (ALint
)Source
->vVelocity
[1];
1270 plValues
[2] = (ALint
)Source
->vVelocity
[2];
1274 plValues
[0] = (ALint
)Source
->vOrientation
[0];
1275 plValues
[1] = (ALint
)Source
->vOrientation
[1];
1276 plValues
[2] = (ALint
)Source
->vOrientation
[2];
1280 alSetError(pContext
, AL_INVALID_ENUM
);
1285 alSetError(pContext
, AL_INVALID_NAME
);
1288 alSetError(pContext
, AL_INVALID_VALUE
);
1290 ProcessContext(pContext
);
1294 AL_API ALvoid AL_APIENTRY
alSourcePlay(ALuint source
)
1296 alSourcePlayv(1, &source
);
1299 AL_API ALvoid AL_APIENTRY
alSourcePlayv(ALsizei n
, const ALuint
*sources
)
1301 ALCcontext
*Context
;
1303 ALbufferlistitem
*BufferList
;
1306 Context
= GetContextSuspended();
1307 if(!Context
) return;
1311 alSetError(Context
, AL_INVALID_VALUE
);
1315 // Check that all the Sources are valid
1316 for(i
= 0;i
< n
;i
++)
1318 if(!VerifySource(Context
->SourceList
, sources
[i
]))
1320 alSetError(Context
, AL_INVALID_NAME
);
1325 for(i
= 0;i
< n
;i
++)
1327 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1329 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1330 BufferList
= Source
->queue
;
1333 if(BufferList
->buffer
!= NULL
&& BufferList
->buffer
->size
)
1335 BufferList
= BufferList
->next
;
1340 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1344 for(j
= 0;j
< OUTPUTCHANNELS
;j
++)
1345 Source
->DryGains
[j
] = 0.0f
;
1346 for(j
= 0;j
< MAX_SENDS
;j
++)
1347 Source
->WetGains
[j
] = 0.0f
;
1349 if(Source
->state
!= AL_PAUSED
)
1351 Source
->state
= AL_PLAYING
;
1352 Source
->position
= 0;
1353 Source
->position_fraction
= 0;
1354 Source
->BuffersPlayed
= 0;
1356 Source
->Buffer
= Source
->queue
->buffer
;
1359 Source
->state
= AL_PLAYING
;
1361 // Check if an Offset has been set
1363 ApplyOffset(Source
);
1365 if(Source
->BuffersPlayed
== 0 && Source
->position
== 0 &&
1366 Source
->position_fraction
== 0)
1367 Source
->FirstStart
= AL_TRUE
;
1369 Source
->FirstStart
= AL_FALSE
;
1371 // If device is disconnected, go right to stopped
1372 if(!Context
->Device
->Connected
)
1374 Source
->state
= AL_STOPPED
;
1375 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1376 Source
->position
= 0;
1377 Source
->position_fraction
= 0;
1382 ProcessContext(Context
);
1385 AL_API ALvoid AL_APIENTRY
alSourcePause(ALuint source
)
1387 alSourcePausev(1, &source
);
1390 AL_API ALvoid AL_APIENTRY
alSourcePausev(ALsizei n
, const ALuint
*sources
)
1392 ALCcontext
*Context
;
1396 Context
= GetContextSuspended();
1397 if(!Context
) return;
1401 alSetError(Context
, AL_INVALID_VALUE
);
1405 // Check all the Sources are valid
1406 for(i
= 0;i
< n
;i
++)
1408 if(!VerifySource(Context
->SourceList
, sources
[i
]))
1410 alSetError(Context
, AL_INVALID_NAME
);
1415 for(i
= 0;i
< n
;i
++)
1417 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1418 if(Source
->state
== AL_PLAYING
)
1419 Source
->state
= AL_PAUSED
;
1423 ProcessContext(Context
);
1426 AL_API ALvoid AL_APIENTRY
alSourceStop(ALuint source
)
1428 alSourceStopv(1, &source
);
1431 AL_API ALvoid AL_APIENTRY
alSourceStopv(ALsizei n
, const ALuint
*sources
)
1433 ALCcontext
*Context
;
1437 Context
= GetContextSuspended();
1438 if(!Context
) return;
1442 alSetError(Context
, AL_INVALID_VALUE
);
1446 // Check all the Sources are valid
1447 for(i
= 0;i
< n
;i
++)
1449 if(!VerifySource(Context
->SourceList
, sources
[i
]))
1451 alSetError(Context
, AL_INVALID_NAME
);
1456 for(i
= 0;i
< n
;i
++)
1458 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1459 if(Source
->state
!= AL_INITIAL
)
1461 Source
->state
= AL_STOPPED
;
1462 Source
->BuffersPlayed
= Source
->BuffersInQueue
;
1464 Source
->lOffset
= 0;
1468 ProcessContext(Context
);
1471 AL_API ALvoid AL_APIENTRY
alSourceRewind(ALuint source
)
1473 alSourceRewindv(1, &source
);
1476 AL_API ALvoid AL_APIENTRY
alSourceRewindv(ALsizei n
, const ALuint
*sources
)
1478 ALCcontext
*Context
;
1482 Context
= GetContextSuspended();
1483 if(!Context
) return;
1487 alSetError(Context
, AL_INVALID_VALUE
);
1491 // Check all the Sources are valid
1492 for(i
= 0;i
< n
;i
++)
1494 if(!VerifySource(Context
->SourceList
, sources
[i
]))
1496 alSetError(Context
, AL_INVALID_NAME
);
1501 for(i
= 0;i
< n
;i
++)
1503 Source
= (ALsource
*)ALTHUNK_LOOKUPENTRY(sources
[i
]);
1504 if(Source
->state
!= AL_INITIAL
)
1506 Source
->state
= AL_INITIAL
;
1507 Source
->position
= 0;
1508 Source
->position_fraction
= 0;
1509 Source
->BuffersPlayed
= 0;
1511 Source
->Buffer
= Source
->queue
->buffer
;
1513 Source
->lOffset
= 0;
1517 ProcessContext(Context
);
1521 AL_API ALvoid AL_APIENTRY
alSourceQueueBuffers(ALuint source
, ALsizei n
, const ALuint
*buffers
)
1523 ALCcontext
*Context
;
1528 ALbufferlistitem
*BufferListStart
;
1529 ALbufferlistitem
*BufferList
;
1530 ALboolean HadFormat
;
1537 Context
= GetContextSuspended();
1538 if(!Context
) return;
1540 // Check that all buffers are valid or zero and that the source is valid
1542 // Check that this is a valid source
1543 if((Source
=VerifySource(Context
->SourceList
, source
)) == NULL
)
1545 alSetError(Context
, AL_INVALID_NAME
);
1549 // Check that this is not a STATIC Source
1550 if(Source
->lSourceType
== AL_STATIC
)
1552 // Invalid Source Type (can't queue on a Static Source)
1553 alSetError(Context
, AL_INVALID_OPERATION
);
1557 device
= Context
->Device
;
1561 HadFormat
= AL_FALSE
;
1563 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1564 BufferList
= Source
->queue
;
1567 if(BufferList
->buffer
)
1569 Frequency
= BufferList
->buffer
->frequency
;
1570 Format
= BufferList
->buffer
->format
;
1571 HadFormat
= AL_TRUE
;
1574 BufferList
= BufferList
->next
;
1577 for(i
= 0;i
< n
;i
++)
1582 if((buffer
=VerifyBuffer(device
->BufferList
, buffers
[i
])) == NULL
)
1584 alSetError(Context
, AL_INVALID_NAME
);
1588 if(Frequency
== -1 && Format
== -1)
1590 Frequency
= buffer
->frequency
;
1591 Format
= buffer
->format
;
1593 else if(Frequency
!= buffer
->frequency
|| Format
!= buffer
->format
)
1595 alSetError(Context
, AL_INVALID_OPERATION
);
1600 // Change Source Type
1601 Source
->lSourceType
= AL_STREAMING
;
1603 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[0]);
1605 // All buffers are valid - so add them to the list
1606 BufferListStart
= malloc(sizeof(ALbufferlistitem
));
1607 BufferListStart
->buffer
= buffer
;
1608 BufferListStart
->next
= NULL
;
1610 // Increment reference counter for buffer
1611 if(buffer
) buffer
->refcount
++;
1613 BufferList
= BufferListStart
;
1615 for(i
= 1;i
< n
;i
++)
1617 buffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(buffers
[i
]);
1619 BufferList
->next
= malloc(sizeof(ALbufferlistitem
));
1620 BufferList
->next
->buffer
= buffer
;
1621 BufferList
->next
->next
= NULL
;
1623 // Increment reference counter for buffer
1624 if(buffer
) buffer
->refcount
++;
1626 BufferList
= BufferList
->next
;
1629 if(Source
->queue
== NULL
)
1631 Source
->queue
= BufferListStart
;
1632 // Update Current Buffer
1633 Source
->Buffer
= BufferListStart
->buffer
;
1637 // Find end of queue
1638 BufferList
= Source
->queue
;
1639 while(BufferList
->next
!= NULL
)
1640 BufferList
= BufferList
->next
;
1642 BufferList
->next
= BufferListStart
;
1645 // Update number of buffers in queue
1646 Source
->BuffersInQueue
+= n
;
1647 // If no previous format, mark the source dirty now that it may have one
1649 Source
->NeedsUpdate
= AL_TRUE
;
1652 ProcessContext(Context
);
1656 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1657 // an array of buffer IDs that are to be filled with the names of the buffers removed
1658 AL_API ALvoid AL_APIENTRY
alSourceUnqueueBuffers( ALuint source
, ALsizei n
, ALuint
* buffers
)
1660 ALCcontext
*Context
;
1663 ALbufferlistitem
*BufferList
;
1668 Context
= GetContextSuspended();
1669 if(!Context
) return;
1671 if((Source
=VerifySource(Context
->SourceList
, source
)) == NULL
)
1673 alSetError(Context
, AL_INVALID_NAME
);
1677 if(Source
->bLooping
|| (ALuint
)n
> Source
->BuffersPlayed
)
1679 // Some buffers can't be unqueue because they have not been processed
1680 alSetError(Context
, AL_INVALID_VALUE
);
1684 for(i
= 0;i
< n
;i
++)
1686 BufferList
= Source
->queue
;
1687 Source
->queue
= BufferList
->next
;
1689 if(BufferList
->buffer
)
1691 // Record name of buffer
1692 buffers
[i
] = BufferList
->buffer
->buffer
;
1693 // Decrement buffer reference counter
1694 BufferList
->buffer
->refcount
--;
1699 // Release memory for buffer list item
1701 Source
->BuffersInQueue
--;
1704 if(Source
->state
!= AL_PLAYING
)
1707 Source
->Buffer
= Source
->queue
->buffer
;
1709 Source
->Buffer
= NULL
;
1711 Source
->BuffersPlayed
-= n
;
1714 ProcessContext(Context
);
1718 static ALvoid
InitSourceParams(ALsource
*Source
)
1720 Source
->flInnerAngle
= 360.0f
;
1721 Source
->flOuterAngle
= 360.0f
;
1722 Source
->flPitch
= 1.0f
;
1723 Source
->vPosition
[0] = 0.0f
;
1724 Source
->vPosition
[1] = 0.0f
;
1725 Source
->vPosition
[2] = 0.0f
;
1726 Source
->vOrientation
[0] = 0.0f
;
1727 Source
->vOrientation
[1] = 0.0f
;
1728 Source
->vOrientation
[2] = 0.0f
;
1729 Source
->vVelocity
[0] = 0.0f
;
1730 Source
->vVelocity
[1] = 0.0f
;
1731 Source
->vVelocity
[2] = 0.0f
;
1732 Source
->flRefDistance
= 1.0f
;
1733 Source
->flMaxDistance
= FLT_MAX
;
1734 Source
->flRollOffFactor
= 1.0f
;
1735 Source
->bLooping
= AL_FALSE
;
1736 Source
->flGain
= 1.0f
;
1737 Source
->flMinGain
= 0.0f
;
1738 Source
->flMaxGain
= 1.0f
;
1739 Source
->flOuterGain
= 0.0f
;
1740 Source
->OuterGainHF
= 1.0f
;
1742 Source
->DryGainHFAuto
= AL_TRUE
;
1743 Source
->WetGainAuto
= AL_TRUE
;
1744 Source
->WetGainHFAuto
= AL_TRUE
;
1745 Source
->AirAbsorptionFactor
= 0.0f
;
1746 Source
->RoomRolloffFactor
= 0.0f
;
1747 Source
->DopplerFactor
= 1.0f
;
1749 Source
->DistanceModel
= AL_INVERSE_DISTANCE_CLAMPED
;
1751 Source
->Resampler
= DefaultResampler
;
1753 Source
->state
= AL_INITIAL
;
1754 Source
->lSourceType
= AL_UNDETERMINED
;
1756 Source
->NeedsUpdate
= AL_TRUE
;
1758 Source
->Buffer
= NULL
;
1765 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1766 The offset is relative to the start of the queue (not the start of the current buffer)
1768 static ALvoid
GetSourceOffset(ALsource
*Source
, ALenum name
, ALfloat
*offset
, ALfloat updateLen
)
1770 ALbufferlistitem
*BufferList
;
1773 ALint Channels
, Bytes
;
1774 ALint readPos
, writePos
;
1775 ALenum OriginalFormat
;
1776 ALint TotalBufferDataSize
;
1779 if((Source
->state
!= AL_PLAYING
&& Source
->state
!= AL_PAUSED
) ||
1787 Buffer
= Source
->Buffer
;
1789 // Get Current Buffer Size and frequency (in milliseconds)
1790 BufferFreq
= (ALfloat
)Buffer
->frequency
;
1791 OriginalFormat
= Buffer
->eOriginalFormat
;
1792 Channels
= aluChannelsFromFormat(Buffer
->format
);
1793 Bytes
= aluBytesFromFormat(Buffer
->format
);
1795 // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
1796 readPos
= Source
->position
* Channels
* Bytes
;
1797 // Add byte length of any processed buffers in the queue
1798 BufferList
= Source
->queue
;
1799 for(i
= 0;i
< Source
->BuffersPlayed
&& BufferList
;i
++)
1801 readPos
+= BufferList
->buffer
->size
;
1802 BufferList
= BufferList
->next
;
1805 if(Source
->state
== AL_PLAYING
)
1806 writePos
= readPos
+ ((ALuint
)(updateLen
*BufferFreq
) * Channels
* Bytes
);
1810 TotalBufferDataSize
= 0;
1811 BufferList
= Source
->queue
;
1814 if(BufferList
->buffer
)
1815 TotalBufferDataSize
+= BufferList
->buffer
->size
;
1816 BufferList
= BufferList
->next
;
1819 if(Source
->bLooping
)
1821 readPos
%= TotalBufferDataSize
;
1822 writePos
%= TotalBufferDataSize
;
1826 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
1829 else if(readPos
> TotalBufferDataSize
)
1830 readPos
= TotalBufferDataSize
;
1833 else if(writePos
> TotalBufferDataSize
)
1834 writePos
= TotalBufferDataSize
;
1840 offset
[0] = (ALfloat
)readPos
/ (Channels
* Bytes
* BufferFreq
);
1841 offset
[1] = (ALfloat
)writePos
/ (Channels
* Bytes
* BufferFreq
);
1843 case AL_SAMPLE_OFFSET
:
1844 case AL_SAMPLE_RW_OFFSETS_EXT
:
1845 offset
[0] = (ALfloat
)(readPos
/ (Channels
* Bytes
));
1846 offset
[1] = (ALfloat
)(writePos
/ (Channels
* Bytes
));
1848 case AL_BYTE_OFFSET
:
1849 case AL_BYTE_RW_OFFSETS_EXT
:
1850 // Take into account the original format of the Buffer
1851 if((OriginalFormat
== AL_FORMAT_MONO_IMA4
) ||
1852 (OriginalFormat
== AL_FORMAT_STEREO_IMA4
))
1854 // Round down to nearest ADPCM block
1855 offset
[0] = (ALfloat
)((readPos
/ (65 * Bytes
* Channels
)) * 36 * Channels
);
1856 if(Source
->state
== AL_PLAYING
)
1858 // Round up to nearest ADPCM block
1859 offset
[1] = (ALfloat
)(((writePos
+ (65 * Bytes
* Channels
) - 1) / (65 * Bytes
* Channels
)) * 36 * Channels
);
1862 offset
[1] = offset
[0];
1864 else if(OriginalFormat
== AL_FORMAT_MONO_MULAW
||
1865 OriginalFormat
== AL_FORMAT_STEREO_MULAW
||
1866 OriginalFormat
== AL_FORMAT_QUAD_MULAW
||
1867 OriginalFormat
== AL_FORMAT_51CHN_MULAW
||
1868 OriginalFormat
== AL_FORMAT_61CHN_MULAW
||
1869 OriginalFormat
== AL_FORMAT_71CHN_MULAW
)
1871 offset
[0] = (ALfloat
)(readPos
/ Bytes
* 1);
1872 offset
[1] = (ALfloat
)(writePos
/ Bytes
* 1);
1874 else if(OriginalFormat
== AL_FORMAT_REAR_MULAW
)
1876 offset
[0] = (ALfloat
)(readPos
/ 2 / Bytes
* 1);
1877 offset
[1] = (ALfloat
)(writePos
/ 2 / Bytes
* 1);
1879 else if(OriginalFormat
== AL_FORMAT_REAR8
)
1881 offset
[0] = (ALfloat
)(readPos
/ 2 / Bytes
* 1);
1882 offset
[1] = (ALfloat
)(writePos
/ 2 / Bytes
* 1);
1884 else if(OriginalFormat
== AL_FORMAT_REAR16
)
1886 offset
[0] = (ALfloat
)(readPos
/ 2 / Bytes
* 2);
1887 offset
[1] = (ALfloat
)(writePos
/ 2 / Bytes
* 2);
1889 else if(OriginalFormat
== AL_FORMAT_REAR32
)
1891 offset
[0] = (ALfloat
)(readPos
/ 2 / Bytes
* 4);
1892 offset
[1] = (ALfloat
)(writePos
/ 2 / Bytes
* 4);
1896 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
1897 offset
[0] = (ALfloat
)(readPos
/ Bytes
* OrigBytes
);
1898 offset
[1] = (ALfloat
)(writePos
/ Bytes
* OrigBytes
);
1908 Apply a playback offset to the Source. This function will update the queue (to correctly
1909 mark buffers as 'pending' or 'processed' depending upon the new offset.
1911 static ALboolean
ApplyOffset(ALsource
*Source
)
1913 ALbufferlistitem
*BufferList
;
1915 ALint lBufferSize
, lTotalBufferSize
;
1918 // Get true byte offset
1919 lByteOffset
= GetByteOffset(Source
);
1921 // If the offset is invalid, don't apply it
1922 if(lByteOffset
== -1)
1925 // Sort out the queue (pending and processed states)
1926 BufferList
= Source
->queue
;
1927 lTotalBufferSize
= 0;
1928 Source
->BuffersPlayed
= 0;
1932 Buffer
= BufferList
->buffer
;
1933 lBufferSize
= Buffer
? Buffer
->size
: 0;
1935 if(lTotalBufferSize
+lBufferSize
<= lByteOffset
)
1937 // Offset is past this buffer so increment BuffersPlayed
1938 Source
->BuffersPlayed
++;
1940 else if(lTotalBufferSize
<= lByteOffset
)
1942 // Offset is within this buffer
1943 // Set Current Buffer
1944 Source
->Buffer
= BufferList
->buffer
;
1946 // SW Mixer Positions are in Samples
1947 Source
->position
= (lByteOffset
- lTotalBufferSize
) /
1948 aluBytesFromFormat(Buffer
->format
) /
1949 aluChannelsFromFormat(Buffer
->format
);
1953 // Increment the TotalBufferSize
1954 lTotalBufferSize
+= lBufferSize
;
1956 // Move on to next buffer in the Queue
1957 BufferList
= BufferList
->next
;
1967 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
1968 offset supplied by the application). This takes into account the fact that the buffer format
1969 may have been modifed by AL (e.g 8bit samples are converted to float)
1971 static ALint
GetByteOffset(ALsource
*Source
)
1973 ALbuffer
*Buffer
= NULL
;
1974 ALbufferlistitem
*BufferList
;
1976 ALint Channels
, Bytes
;
1977 ALint ByteOffset
= -1;
1978 ALint TotalBufferDataSize
;
1979 ALenum OriginalFormat
;
1981 // Find the first non-NULL Buffer in the Queue
1982 BufferList
= Source
->queue
;
1985 if(BufferList
->buffer
)
1987 Buffer
= BufferList
->buffer
;
1990 BufferList
= BufferList
->next
;
1995 Source
->lOffset
= 0;
1999 BufferFreq
= ((ALfloat
)Buffer
->frequency
);
2000 Channels
= aluChannelsFromFormat(Buffer
->format
);
2001 Bytes
= aluBytesFromFormat(Buffer
->format
);
2002 OriginalFormat
= Buffer
->eOriginalFormat
;
2004 // Determine the ByteOffset (and ensure it is block aligned)
2005 switch(Source
->lOffsetType
)
2007 case AL_BYTE_OFFSET
:
2008 // Take into consideration the original format
2009 if(OriginalFormat
== AL_FORMAT_MONO_IMA4
||
2010 OriginalFormat
== AL_FORMAT_STEREO_IMA4
)
2012 // Round down to nearest ADPCM block
2013 ByteOffset
= Source
->lOffset
/ (36 * Channels
);
2014 // Multiply by compression rate (65 samples per 36 byte block)
2015 ByteOffset
= ByteOffset
* 65 * Channels
* Bytes
;
2017 else if(OriginalFormat
== AL_FORMAT_MONO_MULAW
||
2018 OriginalFormat
== AL_FORMAT_STEREO_MULAW
||
2019 OriginalFormat
== AL_FORMAT_QUAD_MULAW
||
2020 OriginalFormat
== AL_FORMAT_51CHN_MULAW
||
2021 OriginalFormat
== AL_FORMAT_61CHN_MULAW
||
2022 OriginalFormat
== AL_FORMAT_71CHN_MULAW
)
2024 /* muLaw has 1 byte per sample */
2025 ByteOffset
= Source
->lOffset
/ 1 * Bytes
;
2027 else if(OriginalFormat
== AL_FORMAT_REAR_MULAW
)
2029 /* Rear is converted from 2 -> 4 channel */
2030 ByteOffset
= Source
->lOffset
/ 1 * Bytes
* 2;
2032 else if(OriginalFormat
== AL_FORMAT_REAR8
)
2033 ByteOffset
= Source
->lOffset
/ 1 * Bytes
* 2;
2034 else if(OriginalFormat
== AL_FORMAT_REAR16
)
2035 ByteOffset
= Source
->lOffset
/ 2 * Bytes
* 2;
2036 else if(OriginalFormat
== AL_FORMAT_REAR32
)
2037 ByteOffset
= Source
->lOffset
/ 4 * Bytes
* 2;
2040 ALuint OrigBytes
= aluBytesFromFormat(OriginalFormat
);
2041 ByteOffset
= Source
->lOffset
/ OrigBytes
* Bytes
;
2043 ByteOffset
-= (ByteOffset
% (Channels
* Bytes
));
2046 case AL_SAMPLE_OFFSET
:
2047 ByteOffset
= Source
->lOffset
* Channels
* Bytes
;
2051 // Note - lOffset is internally stored as Milliseconds
2052 ByteOffset
= (ALint
)(Source
->lOffset
/ 1000.0f
* BufferFreq
);
2053 ByteOffset
*= Channels
* Bytes
;
2057 Source
->lOffset
= 0;
2059 TotalBufferDataSize
= 0;
2060 BufferList
= Source
->queue
;
2063 if(BufferList
->buffer
)
2064 TotalBufferDataSize
+= BufferList
->buffer
->size
;
2065 BufferList
= BufferList
->next
;
2068 // Finally, if the ByteOffset is beyond the length of all the buffers in
2069 // the queue, return -1
2070 if(ByteOffset
>= TotalBufferDataSize
)
2076 ALvoid
ReleaseALSources(ALCcontext
*Context
)
2080 while(Context
->SourceList
)
2082 ALsource
*temp
= Context
->SourceList
;
2083 Context
->SourceList
= temp
->next
;
2085 // For each buffer in the source's queue, decrement its reference counter and remove it
2086 while(temp
->queue
!= NULL
)
2088 ALbufferlistitem
*BufferList
= temp
->queue
;
2089 // Decrement buffer's reference counter
2090 if(BufferList
->buffer
!= NULL
)
2091 BufferList
->buffer
->refcount
--;
2092 // Update queue to point to next element in list
2093 temp
->queue
= BufferList
->next
;
2094 // Release memory allocated for buffer list item
2098 for(j
= 0;j
< MAX_SENDS
;++j
)
2100 if(temp
->Send
[j
].Slot
)
2101 temp
->Send
[j
].Slot
->refcount
--;
2104 // Release source structure
2105 ALTHUNK_REMOVEENTRY(temp
->source
);
2106 memset(temp
, 0, sizeof(ALsource
));
2109 Context
->SourceCount
= 0;