Properly convert uint values when getting them as int64
[openal-soft.git] / OpenAL32 / alSource.c
blob5dbea3145f11955d39eaabde582f518c875824e9
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <math.h>
25 #include <float.h>
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alMain.h"
30 #include "alError.h"
31 #include "alSource.h"
32 #include "alBuffer.h"
33 #include "alThunk.h"
34 #include "alAuxEffectSlot.h"
37 enum Resampler DefaultResampler = LinearResampler;
38 const ALsizei ResamplerPadding[ResamplerMax] = {
39 0, /* Point */
40 1, /* Linear */
41 2, /* Cubic */
43 const ALsizei ResamplerPrePadding[ResamplerMax] = {
44 0, /* Point */
45 0, /* Linear */
46 1, /* Cubic */
50 static ALvoid InitSourceParams(ALsource *Source);
51 static ALint64 GetSourceOffset(const ALsource *Source);
52 static ALdouble GetSourceSecOffset(const ALsource *Source);
53 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
54 static ALint GetSampleOffset(ALsource *Source);
56 typedef enum SrcFloatProp {
57 sfPitch = AL_PITCH,
58 sfGain = AL_GAIN,
59 sfMinGain = AL_MIN_GAIN,
60 sfMaxGain = AL_MAX_GAIN,
61 sfMaxDistance = AL_MAX_DISTANCE,
62 sfRolloffFactor = AL_ROLLOFF_FACTOR,
63 sfDopplerFactor = AL_DOPPLER_FACTOR,
64 sfConeOuterGain = AL_CONE_OUTER_GAIN,
65 sfSecOffset = AL_SEC_OFFSET,
66 sfSampleOffset = AL_SAMPLE_OFFSET,
67 sfByteOffset = AL_BYTE_OFFSET,
68 sfConeInnerAngle = AL_CONE_INNER_ANGLE,
69 sfConeOuterAngle = AL_CONE_OUTER_ANGLE,
70 sfRefDistance = AL_REFERENCE_DISTANCE,
72 sfPosition = AL_POSITION,
73 sfVelocity = AL_VELOCITY,
74 sfDirection = AL_DIRECTION,
76 sfSourceRelative = AL_SOURCE_RELATIVE,
77 sfLooping = AL_LOOPING,
78 sfBuffer = AL_BUFFER,
79 sfSourceState = AL_SOURCE_STATE,
80 sfBuffersQueued = AL_BUFFERS_QUEUED,
81 sfBuffersProcessed = AL_BUFFERS_PROCESSED,
82 sfSourceType = AL_SOURCE_TYPE,
84 /* ALC_EXT_EFX */
85 sfConeOuterGainHF = AL_CONE_OUTER_GAINHF,
86 sfAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
87 sfRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
88 sfDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
89 sfAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
90 sfAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
92 /* AL_SOFT_direct_channels */
93 sfDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
95 /* AL_EXT_source_distance_model */
96 sfDistanceModel = AL_DISTANCE_MODEL,
98 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
99 sfSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
100 sfByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
102 /* AL_SOFT_source_latency */
103 sfSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
104 } SrcFloatProp;
106 typedef enum SrcIntProp {
107 siMaxDistance = AL_MAX_DISTANCE,
108 siRolloffFactor = AL_ROLLOFF_FACTOR,
109 siRefDistance = AL_REFERENCE_DISTANCE,
110 siSourceRelative = AL_SOURCE_RELATIVE,
111 siConeInnerAngle = AL_CONE_INNER_ANGLE,
112 siConeOuterAngle = AL_CONE_OUTER_ANGLE,
113 siLooping = AL_LOOPING,
114 siBuffer = AL_BUFFER,
115 siSourceState = AL_SOURCE_STATE,
116 siBuffersQueued = AL_BUFFERS_QUEUED,
117 siBuffersProcessed = AL_BUFFERS_PROCESSED,
118 siSourceType = AL_SOURCE_TYPE,
119 siSecOffset = AL_SEC_OFFSET,
120 siSampleOffset = AL_SAMPLE_OFFSET,
121 siByteOffset = AL_BYTE_OFFSET,
122 siDopplerFactor = AL_DOPPLER_FACTOR,
123 siPosition = AL_POSITION,
124 siVelocity = AL_VELOCITY,
125 siDirection = AL_DIRECTION,
127 /* ALC_EXT_EFX */
128 siDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
129 siAuxSendFilterGainAutio = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
130 siAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
131 siDirectFilter = AL_DIRECT_FILTER,
132 siAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
134 /* AL_SOFT_direct_channels */
135 siDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
137 /* AL_EXT_source_distance_model */
138 siDistanceModel = AL_DISTANCE_MODEL,
140 /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
141 siSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
142 siByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
144 /* AL_SOFT_source_latency */
145 siSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
146 } SrcIntProp;
148 static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values);
149 static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values);
150 static ALenum SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values);
152 static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values);
153 static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values);
154 static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values);
156 static ALint FloatValsByProp(ALenum prop)
158 if(prop != (ALenum)((SrcFloatProp)prop))
159 return 0;
160 switch((SrcFloatProp)prop)
162 case sfPitch:
163 case sfGain:
164 case sfMinGain:
165 case sfMaxGain:
166 case sfMaxDistance:
167 case sfRolloffFactor:
168 case sfDopplerFactor:
169 case sfConeOuterGain:
170 case sfSecOffset:
171 case sfSampleOffset:
172 case sfByteOffset:
173 case sfConeInnerAngle:
174 case sfConeOuterAngle:
175 case sfRefDistance:
176 case sfConeOuterGainHF:
177 case sfAirAbsorptionFactor:
178 case sfRoomRolloffFactor:
179 case sfDirectFilterGainHFAuto:
180 case sfAuxSendFilterGainAuto:
181 case sfAuxSendFilterGainHFAuto:
182 case sfDirectChannelsSOFT:
183 case sfDistanceModel:
184 case sfSourceRelative:
185 case sfLooping:
186 case sfBuffer:
187 case sfSourceState:
188 case sfBuffersQueued:
189 case sfBuffersProcessed:
190 case sfSourceType:
191 return 1;
193 case sfSampleRWOffsetsSOFT:
194 case sfByteRWOffsetsSOFT:
195 return 2;
197 case sfPosition:
198 case sfVelocity:
199 case sfDirection:
200 return 3;
202 case sfSecOffsetLatencySOFT:
203 break; /* Double only */
205 return 0;
207 static ALint DoubleValsByProp(ALenum prop)
209 if(prop != (ALenum)((SrcFloatProp)prop))
210 return 0;
211 switch((SrcFloatProp)prop)
213 case sfPitch:
214 case sfGain:
215 case sfMinGain:
216 case sfMaxGain:
217 case sfMaxDistance:
218 case sfRolloffFactor:
219 case sfDopplerFactor:
220 case sfConeOuterGain:
221 case sfSecOffset:
222 case sfSampleOffset:
223 case sfByteOffset:
224 case sfConeInnerAngle:
225 case sfConeOuterAngle:
226 case sfRefDistance:
227 case sfConeOuterGainHF:
228 case sfAirAbsorptionFactor:
229 case sfRoomRolloffFactor:
230 case sfDirectFilterGainHFAuto:
231 case sfAuxSendFilterGainAuto:
232 case sfAuxSendFilterGainHFAuto:
233 case sfDirectChannelsSOFT:
234 case sfDistanceModel:
235 case sfSourceRelative:
236 case sfLooping:
237 case sfBuffer:
238 case sfSourceState:
239 case sfBuffersQueued:
240 case sfBuffersProcessed:
241 case sfSourceType:
242 return 1;
244 case sfSampleRWOffsetsSOFT:
245 case sfByteRWOffsetsSOFT:
246 case sfSecOffsetLatencySOFT:
247 return 2;
249 case sfPosition:
250 case sfVelocity:
251 case sfDirection:
252 return 3;
254 return 0;
257 static ALint IntValsByProp(ALenum prop)
259 if(prop != (ALenum)((SrcIntProp)prop))
260 return 0;
261 switch((SrcIntProp)prop)
263 case siMaxDistance:
264 case siRolloffFactor:
265 case siRefDistance:
266 case siSourceRelative:
267 case siConeInnerAngle:
268 case siConeOuterAngle:
269 case siLooping:
270 case siBuffer:
271 case siSourceState:
272 case siBuffersQueued:
273 case siBuffersProcessed:
274 case siSourceType:
275 case siSecOffset:
276 case siSampleOffset:
277 case siByteOffset:
278 case siDopplerFactor:
279 case siDirectFilterGainHFAuto:
280 case siAuxSendFilterGainAutio:
281 case siAuxSendFilterGainHFAuto:
282 case siDirectFilter:
283 case siDirectChannelsSOFT:
284 case siDistanceModel:
285 return 1;
287 case siSampleRWOffsetsSOFT:
288 case siByteRWOffsetsSOFT:
289 return 2;
291 case siPosition:
292 case siVelocity:
293 case siDirection:
294 case siAuxSendFilter:
295 return 3;
297 case siSampleOffsetLatencySOFT:
298 break; /* i64 only */
300 return 0;
302 static ALint Int64ValsByProp(ALenum prop)
304 if(prop != (ALenum)((SrcIntProp)prop))
305 return 0;
306 switch((SrcIntProp)prop)
308 case siMaxDistance:
309 case siRolloffFactor:
310 case siRefDistance:
311 case siSourceRelative:
312 case siConeInnerAngle:
313 case siConeOuterAngle:
314 case siLooping:
315 case siBuffer:
316 case siSourceState:
317 case siBuffersQueued:
318 case siBuffersProcessed:
319 case siSourceType:
320 case siSecOffset:
321 case siSampleOffset:
322 case siByteOffset:
323 case siDopplerFactor:
324 case siDirectFilterGainHFAuto:
325 case siAuxSendFilterGainAutio:
326 case siAuxSendFilterGainHFAuto:
327 case siDirectFilter:
328 case siDirectChannelsSOFT:
329 case siDistanceModel:
330 return 1;
332 case siSampleRWOffsetsSOFT:
333 case siByteRWOffsetsSOFT:
334 case siSampleOffsetLatencySOFT:
335 return 2;
337 case siPosition:
338 case siVelocity:
339 case siDirection:
340 case siAuxSendFilter:
341 return 3;
343 return 0;
347 #define RETERR(x) do { \
348 alSetError(Context, (x)); \
349 return (x); \
350 } while(0)
352 #define CHECKVAL(x) do { \
353 if(!(x)) \
354 RETERR(AL_INVALID_VALUE); \
355 } while(0)
357 static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values)
359 ALint ival;
361 switch(prop)
363 case AL_PITCH:
364 CHECKVAL(*values >= 0.0f);
366 Source->Pitch = *values;
367 Source->NeedsUpdate = AL_TRUE;
368 return AL_NO_ERROR;
370 case AL_CONE_INNER_ANGLE:
371 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
373 Source->InnerAngle = *values;
374 Source->NeedsUpdate = AL_TRUE;
375 return AL_NO_ERROR;
377 case AL_CONE_OUTER_ANGLE:
378 CHECKVAL(*values >= 0.0f && *values <= 360.0f);
380 Source->OuterAngle = *values;
381 Source->NeedsUpdate = AL_TRUE;
382 return AL_NO_ERROR;
384 case AL_GAIN:
385 CHECKVAL(*values >= 0.0f);
387 Source->Gain = *values;
388 Source->NeedsUpdate = AL_TRUE;
389 return AL_NO_ERROR;
391 case AL_MAX_DISTANCE:
392 CHECKVAL(*values >= 0.0f);
394 Source->MaxDistance = *values;
395 Source->NeedsUpdate = AL_TRUE;
396 return AL_NO_ERROR;
398 case AL_ROLLOFF_FACTOR:
399 CHECKVAL(*values >= 0.0f);
401 Source->RollOffFactor = *values;
402 Source->NeedsUpdate = AL_TRUE;
403 return AL_NO_ERROR;
405 case AL_REFERENCE_DISTANCE:
406 CHECKVAL(*values >= 0.0f);
408 Source->RefDistance = *values;
409 Source->NeedsUpdate = AL_TRUE;
410 return AL_NO_ERROR;
412 case AL_MIN_GAIN:
413 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
415 Source->MinGain = *values;
416 Source->NeedsUpdate = AL_TRUE;
417 return AL_NO_ERROR;
419 case AL_MAX_GAIN:
420 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
422 Source->MaxGain = *values;
423 Source->NeedsUpdate = AL_TRUE;
424 return AL_NO_ERROR;
426 case AL_CONE_OUTER_GAIN:
427 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
429 Source->OuterGain = *values;
430 Source->NeedsUpdate = AL_TRUE;
431 return AL_NO_ERROR;
433 case AL_CONE_OUTER_GAINHF:
434 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
436 Source->OuterGainHF = *values;
437 Source->NeedsUpdate = AL_TRUE;
438 return AL_NO_ERROR;
440 case AL_AIR_ABSORPTION_FACTOR:
441 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
443 Source->AirAbsorptionFactor = *values;
444 Source->NeedsUpdate = AL_TRUE;
445 return AL_NO_ERROR;
447 case AL_ROOM_ROLLOFF_FACTOR:
448 CHECKVAL(*values >= 0.0f && *values <= 10.0f);
450 Source->RoomRolloffFactor = *values;
451 Source->NeedsUpdate = AL_TRUE;
452 return AL_NO_ERROR;
454 case AL_DOPPLER_FACTOR:
455 CHECKVAL(*values >= 0.0f && *values <= 1.0f);
457 Source->DopplerFactor = *values;
458 Source->NeedsUpdate = AL_TRUE;
459 return AL_NO_ERROR;
461 case AL_SEC_OFFSET:
462 case AL_SAMPLE_OFFSET:
463 case AL_BYTE_OFFSET:
464 CHECKVAL(*values >= 0.0f);
466 LockContext(Context);
467 Source->OffsetType = prop;
468 Source->Offset = *values;
470 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
471 !Context->DeferUpdates)
473 if(ApplyOffset(Source) == AL_FALSE)
475 UnlockContext(Context);
476 RETERR(AL_INVALID_VALUE);
479 UnlockContext(Context);
480 return AL_NO_ERROR;
483 case AL_SEC_OFFSET_LATENCY_SOFT:
484 /* Query only */
485 RETERR(AL_INVALID_OPERATION);
488 case AL_POSITION:
489 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
491 LockContext(Context);
492 Source->Position[0] = values[0];
493 Source->Position[1] = values[1];
494 Source->Position[2] = values[2];
495 UnlockContext(Context);
496 Source->NeedsUpdate = AL_TRUE;
497 return AL_NO_ERROR;
499 case AL_VELOCITY:
500 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
502 LockContext(Context);
503 Source->Velocity[0] = values[0];
504 Source->Velocity[1] = values[1];
505 Source->Velocity[2] = values[2];
506 UnlockContext(Context);
507 Source->NeedsUpdate = AL_TRUE;
508 return AL_NO_ERROR;
510 case AL_DIRECTION:
511 CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
513 LockContext(Context);
514 Source->Orientation[0] = values[0];
515 Source->Orientation[1] = values[1];
516 Source->Orientation[2] = values[2];
517 UnlockContext(Context);
518 Source->NeedsUpdate = AL_TRUE;
519 return AL_NO_ERROR;
522 case sfSampleRWOffsetsSOFT:
523 case sfByteRWOffsetsSOFT:
524 RETERR(AL_INVALID_OPERATION);
527 case sfSourceRelative:
528 case sfLooping:
529 case sfSourceState:
530 case sfSourceType:
531 case sfDistanceModel:
532 case sfDirectFilterGainHFAuto:
533 case sfAuxSendFilterGainAuto:
534 case sfAuxSendFilterGainHFAuto:
535 case sfDirectChannelsSOFT:
536 ival = (ALint)values[0];
537 return SetSourceiv(Source, Context, prop, &ival);
539 case sfBuffer:
540 case sfBuffersQueued:
541 case sfBuffersProcessed:
542 ival = (ALint)((ALuint)values[0]);
543 return SetSourceiv(Source, Context, prop, &ival);
546 ERR("Unexpected property: 0x%04x\n", prop);
547 RETERR(AL_INVALID_ENUM);
550 static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values)
552 ALCdevice *device = Context->Device;
553 ALbuffer *buffer = NULL;
554 ALfilter *filter = NULL;
555 ALeffectslot *slot = NULL;
556 ALbufferlistitem *oldlist;
557 ALfloat fvals[3];
559 switch(prop)
561 case AL_SOURCE_RELATIVE:
562 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
564 Source->HeadRelative = (ALboolean)*values;
565 Source->NeedsUpdate = AL_TRUE;
566 return AL_NO_ERROR;
568 case AL_LOOPING:
569 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
571 Source->Looping = (ALboolean)*values;
572 return AL_NO_ERROR;
574 case AL_BUFFER:
575 CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
577 LockContext(Context);
578 if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
580 UnlockContext(Context);
581 RETERR(AL_INVALID_OPERATION);
584 Source->BuffersInQueue = 0;
585 Source->BuffersPlayed = 0;
587 if(buffer != NULL)
589 ALbufferlistitem *BufferListItem;
591 /* Source is now Static */
592 Source->SourceType = AL_STATIC;
594 /* Add the selected buffer to a one-item queue */
595 BufferListItem = malloc(sizeof(ALbufferlistitem));
596 BufferListItem->buffer = buffer;
597 BufferListItem->next = NULL;
598 BufferListItem->prev = NULL;
599 IncrementRef(&buffer->ref);
601 oldlist = ExchangePtr((XchgPtr*)&Source->queue, BufferListItem);
602 Source->BuffersInQueue = 1;
604 ReadLock(&buffer->lock);
605 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
606 Source->SampleSize = BytesFromFmt(buffer->FmtType);
607 ReadUnlock(&buffer->lock);
608 if(buffer->FmtChannels == FmtMono)
609 Source->Update = CalcSourceParams;
610 else
611 Source->Update = CalcNonAttnSourceParams;
612 Source->NeedsUpdate = AL_TRUE;
614 else
616 /* Source is now Undetermined */
617 Source->SourceType = AL_UNDETERMINED;
618 oldlist = ExchangePtr((XchgPtr*)&Source->queue, NULL);
621 /* Delete all elements in the previous queue */
622 while(oldlist != NULL)
624 ALbufferlistitem *temp = oldlist;
625 oldlist = temp->next;
627 if(temp->buffer)
628 DecrementRef(&temp->buffer->ref);
629 free(temp);
631 UnlockContext(Context);
632 return AL_NO_ERROR;
634 case siSourceState:
635 case siSourceType:
636 case siBuffersQueued:
637 case siBuffersProcessed:
638 /* Query only */
639 RETERR(AL_INVALID_OPERATION);
641 case AL_SEC_OFFSET:
642 case AL_SAMPLE_OFFSET:
643 case AL_BYTE_OFFSET:
644 CHECKVAL(*values >= 0);
646 LockContext(Context);
647 Source->OffsetType = prop;
648 Source->Offset = *values;
650 if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
651 !Context->DeferUpdates)
653 if(ApplyOffset(Source) == AL_FALSE)
655 UnlockContext(Context);
656 RETERR(AL_INVALID_VALUE);
659 UnlockContext(Context);
660 return AL_NO_ERROR;
663 case siSampleRWOffsetsSOFT:
664 case siByteRWOffsetsSOFT:
665 /* Query only */
666 RETERR(AL_INVALID_OPERATION);
669 case AL_DIRECT_FILTER:
670 CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
672 LockContext(Context);
673 if(!filter)
675 Source->DirectGain = 1.0f;
676 Source->DirectGainHF = 1.0f;
678 else
680 Source->DirectGain = filter->Gain;
681 Source->DirectGainHF = filter->GainHF;
683 UnlockContext(Context);
684 Source->NeedsUpdate = AL_TRUE;
685 return AL_NO_ERROR;
687 case AL_DIRECT_FILTER_GAINHF_AUTO:
688 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
690 Source->DryGainHFAuto = *values;
691 Source->NeedsUpdate = AL_TRUE;
692 return AL_NO_ERROR;
694 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
695 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
697 Source->WetGainAuto = *values;
698 Source->NeedsUpdate = AL_TRUE;
699 return AL_NO_ERROR;
701 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
702 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
704 Source->WetGainHFAuto = *values;
705 Source->NeedsUpdate = AL_TRUE;
706 return AL_NO_ERROR;
708 case AL_DIRECT_CHANNELS_SOFT:
709 CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
711 Source->DirectChannels = *values;
712 Source->NeedsUpdate = AL_TRUE;
713 return AL_NO_ERROR;
715 case AL_DISTANCE_MODEL:
716 CHECKVAL(*values == AL_NONE ||
717 *values == AL_INVERSE_DISTANCE ||
718 *values == AL_INVERSE_DISTANCE_CLAMPED ||
719 *values == AL_LINEAR_DISTANCE ||
720 *values == AL_LINEAR_DISTANCE_CLAMPED ||
721 *values == AL_EXPONENT_DISTANCE ||
722 *values == AL_EXPONENT_DISTANCE_CLAMPED);
724 Source->DistanceModel = *values;
725 if(Context->SourceDistanceModel)
726 Source->NeedsUpdate = AL_TRUE;
727 return AL_NO_ERROR;
730 case AL_AUXILIARY_SEND_FILTER:
731 LockContext(Context);
732 if(!((ALuint)values[1] < device->NumAuxSends &&
733 (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
734 (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
736 UnlockContext(Context);
737 RETERR(AL_INVALID_VALUE);
740 /* Add refcount on the new slot, and release the previous slot */
741 if(slot) IncrementRef(&slot->ref);
742 slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
743 if(slot) DecrementRef(&slot->ref);
745 if(!filter)
747 /* Disable filter */
748 Source->Send[values[1]].Gain = 1.0f;
749 Source->Send[values[1]].GainHF = 1.0f;
751 else
753 Source->Send[values[1]].Gain = filter->Gain;
754 Source->Send[values[1]].GainHF = filter->GainHF;
756 Source->NeedsUpdate = AL_TRUE;
757 UnlockContext(Context);
758 return AL_NO_ERROR;
761 case AL_MAX_DISTANCE:
762 case AL_ROLLOFF_FACTOR:
763 case AL_CONE_INNER_ANGLE:
764 case AL_CONE_OUTER_ANGLE:
765 case AL_REFERENCE_DISTANCE:
766 case siDopplerFactor:
767 fvals[0] = (ALfloat)*values;
768 return SetSourcefv(Source, Context, (int)prop, fvals);
770 case AL_POSITION:
771 case AL_VELOCITY:
772 case AL_DIRECTION:
773 fvals[0] = (ALfloat)values[0];
774 fvals[1] = (ALfloat)values[1];
775 fvals[2] = (ALfloat)values[2];
776 return SetSourcefv(Source, Context, (int)prop, fvals);
778 case siSampleOffsetLatencySOFT:
779 /* i64 only */
780 break;
783 ERR("Unexpected property: 0x%04x\n", prop);
784 RETERR(AL_INVALID_ENUM);
787 static ALenum SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values)
789 ALfloat fvals[3];
790 ALint ivals[3];
792 switch(prop)
794 case siSampleRWOffsetsSOFT:
795 case siByteRWOffsetsSOFT:
796 case siSampleOffsetLatencySOFT:
797 /* Query only */
798 RETERR(AL_INVALID_OPERATION);
801 /* 1x int */
802 case AL_SOURCE_RELATIVE:
803 case AL_LOOPING:
804 case AL_SOURCE_STATE:
805 case AL_BYTE_OFFSET:
806 case AL_SAMPLE_OFFSET:
807 case siSourceType:
808 case siBuffersQueued:
809 case siBuffersProcessed:
810 case AL_DIRECT_FILTER_GAINHF_AUTO:
811 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
812 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
813 case AL_DIRECT_CHANNELS_SOFT:
814 case AL_DISTANCE_MODEL:
815 CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
817 ivals[0] = (ALint)*values;
818 return SetSourceiv(Source, Context, (int)prop, ivals);
820 /* 1x uint */
821 case AL_BUFFER:
822 case AL_DIRECT_FILTER:
823 CHECKVAL(*values <= UINT_MAX && *values >= 0);
825 ivals[0] = (ALuint)*values;
826 return SetSourceiv(Source, Context, (int)prop, ivals);
828 /* 3x uint */
829 case AL_AUXILIARY_SEND_FILTER:
830 CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
831 values[1] <= UINT_MAX && values[1] >= 0 &&
832 values[2] <= UINT_MAX && values[2] >= 0);
834 ivals[0] = (ALuint)values[0];
835 ivals[1] = (ALuint)values[1];
836 ivals[2] = (ALuint)values[2];
837 return SetSourceiv(Source, Context, (int)prop, ivals);
839 /* 1x float */
840 case AL_MAX_DISTANCE:
841 case AL_ROLLOFF_FACTOR:
842 case AL_CONE_INNER_ANGLE:
843 case AL_CONE_OUTER_ANGLE:
844 case AL_REFERENCE_DISTANCE:
845 case AL_SEC_OFFSET:
846 case siDopplerFactor:
847 fvals[0] = (ALfloat)*values;
848 return SetSourcefv(Source, Context, (int)prop, fvals);
850 /* 3x float */
851 case AL_POSITION:
852 case AL_VELOCITY:
853 case AL_DIRECTION:
854 fvals[0] = (ALfloat)values[0];
855 fvals[1] = (ALfloat)values[1];
856 fvals[2] = (ALfloat)values[2];
857 return SetSourcefv(Source, Context, (int)prop, fvals);
860 ERR("Unexpected property: 0x%04x\n", prop);
861 RETERR(AL_INVALID_ENUM);
864 #undef CHECKVAL
867 static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values)
869 ALdouble offsets[2];
870 ALdouble updateLen;
871 ALint ivals[3];
872 ALenum err;
874 switch(prop)
876 case AL_GAIN:
877 *values = Source->Gain;
878 return AL_NO_ERROR;
880 case AL_PITCH:
881 *values = Source->Pitch;
882 return AL_NO_ERROR;
884 case AL_MAX_DISTANCE:
885 *values = Source->MaxDistance;
886 return AL_NO_ERROR;
888 case AL_ROLLOFF_FACTOR:
889 *values = Source->RollOffFactor;
890 return AL_NO_ERROR;
892 case AL_REFERENCE_DISTANCE:
893 *values = Source->RefDistance;
894 return AL_NO_ERROR;
896 case AL_CONE_INNER_ANGLE:
897 *values = Source->InnerAngle;
898 return AL_NO_ERROR;
900 case AL_CONE_OUTER_ANGLE:
901 *values = Source->OuterAngle;
902 return AL_NO_ERROR;
904 case AL_MIN_GAIN:
905 *values = Source->MinGain;
906 return AL_NO_ERROR;
908 case AL_MAX_GAIN:
909 *values = Source->MaxGain;
910 return AL_NO_ERROR;
912 case AL_CONE_OUTER_GAIN:
913 *values = Source->OuterGain;
914 return AL_NO_ERROR;
916 case AL_SEC_OFFSET:
917 case AL_SAMPLE_OFFSET:
918 case AL_BYTE_OFFSET:
919 LockContext(Context);
920 updateLen = (ALdouble)Context->Device->UpdateSize /
921 Context->Device->Frequency;
922 GetSourceOffsets(Source, prop, offsets, updateLen);
923 UnlockContext(Context);
924 *values = offsets[0];
925 return AL_NO_ERROR;
927 case AL_CONE_OUTER_GAINHF:
928 *values = Source->OuterGainHF;
929 return AL_NO_ERROR;
931 case AL_AIR_ABSORPTION_FACTOR:
932 *values = Source->AirAbsorptionFactor;
933 return AL_NO_ERROR;
935 case AL_ROOM_ROLLOFF_FACTOR:
936 *values = Source->RoomRolloffFactor;
937 return AL_NO_ERROR;
939 case AL_DOPPLER_FACTOR:
940 *values = Source->DopplerFactor;
941 return AL_NO_ERROR;
943 case AL_SAMPLE_RW_OFFSETS_SOFT:
944 case AL_BYTE_RW_OFFSETS_SOFT:
945 LockContext(Context);
946 updateLen = (ALdouble)Context->Device->UpdateSize /
947 Context->Device->Frequency;
948 GetSourceOffsets(Source, prop, values, updateLen);
949 UnlockContext(Context);
950 return AL_NO_ERROR;
952 case AL_SEC_OFFSET_LATENCY_SOFT:
953 LockContext(Context);
954 values[0] = GetSourceSecOffset(Source);
955 values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) /
956 1000000000.0;
957 UnlockContext(Context);
958 return AL_NO_ERROR;
960 case AL_POSITION:
961 LockContext(Context);
962 values[0] = Source->Position[0];
963 values[1] = Source->Position[1];
964 values[2] = Source->Position[2];
965 UnlockContext(Context);
966 return AL_NO_ERROR;
968 case AL_VELOCITY:
969 LockContext(Context);
970 values[0] = Source->Velocity[0];
971 values[1] = Source->Velocity[1];
972 values[2] = Source->Velocity[2];
973 UnlockContext(Context);
974 return AL_NO_ERROR;
976 case AL_DIRECTION:
977 LockContext(Context);
978 values[0] = Source->Orientation[0];
979 values[1] = Source->Orientation[1];
980 values[2] = Source->Orientation[2];
981 UnlockContext(Context);
982 return AL_NO_ERROR;
984 case AL_SOURCE_RELATIVE:
985 case AL_LOOPING:
986 case AL_BUFFER:
987 case AL_SOURCE_STATE:
988 case AL_BUFFERS_QUEUED:
989 case AL_BUFFERS_PROCESSED:
990 case AL_SOURCE_TYPE:
991 case AL_DIRECT_FILTER_GAINHF_AUTO:
992 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
993 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
994 case AL_DIRECT_CHANNELS_SOFT:
995 case AL_DISTANCE_MODEL:
996 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) == AL_NO_ERROR)
997 *values = (ALdouble)ivals[0];
998 return err;
1001 ERR("Unexpected property: 0x%04x\n", prop);
1002 RETERR(AL_INVALID_ENUM);
1005 static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values)
1007 ALbufferlistitem *BufferList;
1008 ALdouble dvals[3];
1009 ALenum err;
1011 switch(prop)
1013 case AL_SOURCE_RELATIVE:
1014 *values = Source->HeadRelative;
1015 return AL_NO_ERROR;
1017 case AL_LOOPING:
1018 *values = Source->Looping;
1019 return AL_NO_ERROR;
1021 case AL_BUFFER:
1022 LockContext(Context);
1023 BufferList = Source->queue;
1024 if(Source->SourceType != AL_STATIC)
1026 ALuint i = Source->BuffersPlayed;
1027 while(i > 0)
1029 BufferList = BufferList->next;
1030 i--;
1033 *values = ((BufferList && BufferList->buffer) ?
1034 BufferList->buffer->id : 0);
1035 UnlockContext(Context);
1036 return AL_NO_ERROR;
1038 case AL_SOURCE_STATE:
1039 *values = Source->state;
1040 return AL_NO_ERROR;
1042 case AL_BUFFERS_QUEUED:
1043 *values = Source->BuffersInQueue;
1044 return AL_NO_ERROR;
1046 case AL_BUFFERS_PROCESSED:
1047 LockContext(Context);
1048 if(Source->Looping || Source->SourceType != AL_STREAMING)
1050 /* Buffers on a looping source are in a perpetual state of
1051 * PENDING, so don't report any as PROCESSED */
1052 *values = 0;
1054 else
1055 *values = Source->BuffersPlayed;
1056 UnlockContext(Context);
1057 return AL_NO_ERROR;
1059 case AL_SOURCE_TYPE:
1060 *values = Source->SourceType;
1061 return AL_NO_ERROR;
1063 case AL_DIRECT_FILTER_GAINHF_AUTO:
1064 *values = Source->DryGainHFAuto;
1065 return AL_NO_ERROR;
1067 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1068 *values = Source->WetGainAuto;
1069 return AL_NO_ERROR;
1071 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1072 *values = Source->WetGainHFAuto;
1073 return AL_NO_ERROR;
1075 case AL_DIRECT_CHANNELS_SOFT:
1076 *values = Source->DirectChannels;
1077 return AL_NO_ERROR;
1079 case AL_DISTANCE_MODEL:
1080 *values = Source->DistanceModel;
1081 return AL_NO_ERROR;
1083 case AL_MAX_DISTANCE:
1084 case AL_ROLLOFF_FACTOR:
1085 case AL_REFERENCE_DISTANCE:
1086 case AL_CONE_INNER_ANGLE:
1087 case AL_CONE_OUTER_ANGLE:
1088 case AL_SEC_OFFSET:
1089 case AL_SAMPLE_OFFSET:
1090 case AL_BYTE_OFFSET:
1091 case AL_DOPPLER_FACTOR:
1092 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
1093 *values = (ALint)dvals[0];
1094 return err;
1096 case AL_SAMPLE_RW_OFFSETS_SOFT:
1097 case AL_BYTE_RW_OFFSETS_SOFT:
1098 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
1100 values[0] = (ALint)dvals[0];
1101 values[1] = (ALint)dvals[1];
1103 return err;
1105 case AL_POSITION:
1106 case AL_VELOCITY:
1107 case AL_DIRECTION:
1108 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
1110 values[0] = (ALint)dvals[0];
1111 values[1] = (ALint)dvals[1];
1112 values[2] = (ALint)dvals[2];
1114 return err;
1116 case siSampleOffsetLatencySOFT:
1117 /* i64 only */
1118 break;
1120 case siDirectFilter:
1121 case siAuxSendFilter:
1122 /* ??? */
1123 break;
1126 ERR("Unexpected property: 0x%04x\n", prop);
1127 RETERR(AL_INVALID_ENUM);
1130 static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values)
1132 ALdouble dvals[3];
1133 ALint ivals[3];
1134 ALenum err;
1136 switch(prop)
1138 case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1139 LockContext(Context);
1140 values[0] = GetSourceOffset(Source);
1141 values[1] = ALCdevice_GetLatency(Context->Device);
1142 UnlockContext(Context);
1143 return AL_NO_ERROR;
1145 case AL_MAX_DISTANCE:
1146 case AL_ROLLOFF_FACTOR:
1147 case AL_REFERENCE_DISTANCE:
1148 case AL_CONE_INNER_ANGLE:
1149 case AL_CONE_OUTER_ANGLE:
1150 case AL_SEC_OFFSET:
1151 case AL_SAMPLE_OFFSET:
1152 case AL_BYTE_OFFSET:
1153 case AL_DOPPLER_FACTOR:
1154 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
1155 *values = (ALint64)dvals[0];
1156 return err;
1158 case AL_SAMPLE_RW_OFFSETS_SOFT:
1159 case AL_BYTE_RW_OFFSETS_SOFT:
1160 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
1162 values[0] = (ALint64)dvals[0];
1163 values[1] = (ALint64)dvals[1];
1165 return err;
1167 case AL_POSITION:
1168 case AL_VELOCITY:
1169 case AL_DIRECTION:
1170 if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR)
1172 values[0] = (ALint64)dvals[0];
1173 values[1] = (ALint64)dvals[1];
1174 values[2] = (ALint64)dvals[2];
1176 return err;
1178 case AL_SOURCE_RELATIVE:
1179 case AL_LOOPING:
1180 case AL_SOURCE_STATE:
1181 case AL_BUFFERS_QUEUED:
1182 case AL_BUFFERS_PROCESSED:
1183 case AL_SOURCE_TYPE:
1184 case AL_DIRECT_FILTER_GAINHF_AUTO:
1185 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1186 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1187 case AL_DIRECT_CHANNELS_SOFT:
1188 case AL_DISTANCE_MODEL:
1189 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) == AL_NO_ERROR)
1190 *values = ivals[0];
1191 return err;
1193 case siBuffer:
1194 case siDirectFilter:
1195 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) == AL_NO_ERROR)
1196 *values = ((ALuint*)ivals)[0];
1197 return err;
1199 case siAuxSendFilter:
1200 if((err=GetSourceiv(Source, Context, (int)prop, ivals)) == AL_NO_ERROR)
1202 values[0] = ((ALuint*)ivals)[0];
1203 values[1] = ((ALuint*)ivals)[1];
1204 values[2] = ((ALuint*)ivals)[2];
1206 return err;
1209 ERR("Unexpected property: 0x%04x\n", prop);
1210 RETERR(AL_INVALID_ENUM);
1213 #undef RETERR
1216 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1218 ALCcontext *Context;
1219 ALsizei cur = 0;
1221 Context = GetContextRef();
1222 if(!Context) return;
1224 al_try
1226 ALenum err;
1228 CHECK_VALUE(Context, n >= 0);
1229 for(cur = 0;cur < n;cur++)
1231 ALsource *source = al_calloc(16, sizeof(ALsource));
1232 if(!source)
1233 al_throwerr(Context, AL_OUT_OF_MEMORY);
1234 InitSourceParams(source);
1236 err = NewThunkEntry(&source->id);
1237 if(err == AL_NO_ERROR)
1238 err = InsertUIntMapEntry(&Context->SourceMap, source->id, source);
1239 if(err != AL_NO_ERROR)
1241 FreeThunkEntry(source->id);
1242 memset(source, 0, sizeof(ALsource));
1243 al_free(source);
1245 al_throwerr(Context, err);
1248 sources[cur] = source->id;
1251 al_catchany()
1253 if(cur > 0)
1254 alDeleteSources(cur, sources);
1256 al_endtry;
1258 ALCcontext_DecRef(Context);
1262 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1264 ALCcontext *Context;
1266 Context = GetContextRef();
1267 if(!Context) return;
1269 al_try
1271 ALbufferlistitem *BufferList;
1272 ALsource *Source;
1273 ALsizei i, j;
1275 CHECK_VALUE(Context, n >= 0);
1277 /* Check that all Sources are valid */
1278 for(i = 0;i < n;i++)
1280 if(LookupSource(Context, sources[i]) == NULL)
1281 al_throwerr(Context, AL_INVALID_NAME);
1284 for(i = 0;i < n;i++)
1286 ALsource **srclist, **srclistend;
1288 if((Source=RemoveSource(Context, sources[i])) == NULL)
1289 continue;
1290 FreeThunkEntry(Source->id);
1292 LockContext(Context);
1293 srclist = Context->ActiveSources;
1294 srclistend = srclist + Context->ActiveSourceCount;
1295 while(srclist != srclistend)
1297 if(*srclist == Source)
1299 Context->ActiveSourceCount--;
1300 *srclist = *(--srclistend);
1301 break;
1303 srclist++;
1305 UnlockContext(Context);
1307 while(Source->queue != NULL)
1309 BufferList = Source->queue;
1310 Source->queue = BufferList->next;
1312 if(BufferList->buffer != NULL)
1313 DecrementRef(&BufferList->buffer->ref);
1314 free(BufferList);
1317 for(j = 0;j < MAX_SENDS;++j)
1319 if(Source->Send[j].Slot)
1320 DecrementRef(&Source->Send[j].Slot->ref);
1321 Source->Send[j].Slot = NULL;
1324 memset(Source, 0, sizeof(*Source));
1325 al_free(Source);
1328 al_endtry;
1330 ALCcontext_DecRef(Context);
1334 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1336 ALCcontext *Context;
1337 ALboolean result;
1339 Context = GetContextRef();
1340 if(!Context) return AL_FALSE;
1342 result = (LookupSource(Context, source) ? AL_TRUE : AL_FALSE);
1344 ALCcontext_DecRef(Context);
1346 return result;
1350 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1352 ALCcontext *Context;
1353 ALsource *Source;
1355 Context = GetContextRef();
1356 if(!Context) return;
1358 if((Source=LookupSource(Context, source)) == NULL)
1359 alSetError(Context, AL_INVALID_NAME);
1360 else if(!(FloatValsByProp(param) == 1))
1361 alSetError(Context, AL_INVALID_ENUM);
1362 else
1363 SetSourcefv(Source, Context, param, &value);
1365 ALCcontext_DecRef(Context);
1368 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1370 ALCcontext *Context;
1371 ALsource *Source;
1373 Context = GetContextRef();
1374 if(!Context) return;
1376 if((Source=LookupSource(Context, source)) == NULL)
1377 alSetError(Context, AL_INVALID_NAME);
1378 else if(!(FloatValsByProp(param) == 3))
1379 alSetError(Context, AL_INVALID_ENUM);
1380 else
1382 ALfloat fvals[3] = { value1, value2, value3 };
1383 SetSourcefv(Source, Context, param, fvals);
1386 ALCcontext_DecRef(Context);
1389 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1391 ALCcontext *Context;
1392 ALsource *Source;
1394 Context = GetContextRef();
1395 if(!Context) return;
1397 if((Source=LookupSource(Context, source)) == NULL)
1398 alSetError(Context, AL_INVALID_NAME);
1399 else if(!values)
1400 alSetError(Context, AL_INVALID_VALUE);
1401 else if(!(FloatValsByProp(param) > 0))
1402 alSetError(Context, AL_INVALID_ENUM);
1403 else
1404 SetSourcefv(Source, Context, param, values);
1406 ALCcontext_DecRef(Context);
1410 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1412 ALCcontext *Context;
1413 ALsource *Source;
1415 Context = GetContextRef();
1416 if(!Context) return;
1418 if((Source=LookupSource(Context, source)) == NULL)
1419 alSetError(Context, AL_INVALID_NAME);
1420 else if(!(DoubleValsByProp(param) == 1))
1421 alSetError(Context, AL_INVALID_ENUM);
1422 else
1424 ALfloat fval = (ALfloat)value;
1425 SetSourcefv(Source, Context, param, &fval);
1428 ALCcontext_DecRef(Context);
1431 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1433 ALCcontext *Context;
1434 ALsource *Source;
1436 Context = GetContextRef();
1437 if(!Context) return;
1439 if((Source=LookupSource(Context, source)) == NULL)
1440 alSetError(Context, AL_INVALID_NAME);
1441 else if(!(DoubleValsByProp(param) == 3))
1442 alSetError(Context, AL_INVALID_ENUM);
1443 else
1445 ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1446 SetSourcefv(Source, Context, param, fvals);
1449 ALCcontext_DecRef(Context);
1452 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1454 ALCcontext *Context;
1455 ALsource *Source;
1456 ALint count;
1458 Context = GetContextRef();
1459 if(!Context) return;
1461 if((Source=LookupSource(Context, source)) == NULL)
1462 alSetError(Context, AL_INVALID_NAME);
1463 else if(!values)
1464 alSetError(Context, AL_INVALID_VALUE);
1465 else if(!((count=DoubleValsByProp(param)) > 0 && count <= 3))
1466 alSetError(Context, AL_INVALID_ENUM);
1467 else
1469 ALfloat fvals[3];
1470 ALint i;
1472 for(i = 0;i < count;i++)
1473 fvals[i] = (ALfloat)values[i];
1474 SetSourcefv(Source, Context, param, fvals);
1477 ALCcontext_DecRef(Context);
1481 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1483 ALCcontext *Context;
1484 ALsource *Source;
1486 Context = GetContextRef();
1487 if(!Context) return;
1489 if((Source=LookupSource(Context, source)) == NULL)
1490 alSetError(Context, AL_INVALID_NAME);
1491 else if(!(IntValsByProp(param) == 1))
1492 alSetError(Context, AL_INVALID_ENUM);
1493 else
1494 SetSourceiv(Source, Context, param, &value);
1496 ALCcontext_DecRef(Context);
1499 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1501 ALCcontext *Context;
1502 ALsource *Source;
1504 Context = GetContextRef();
1505 if(!Context) return;
1507 if((Source=LookupSource(Context, source)) == NULL)
1508 alSetError(Context, AL_INVALID_NAME);
1509 else if(!(IntValsByProp(param) == 3))
1510 alSetError(Context, AL_INVALID_ENUM);
1511 else
1513 ALint ivals[3] = { value1, value2, value3 };
1514 SetSourceiv(Source, Context, param, ivals);
1517 ALCcontext_DecRef(Context);
1520 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1522 ALCcontext *Context;
1523 ALsource *Source;
1525 Context = GetContextRef();
1526 if(!Context) return;
1528 if((Source=LookupSource(Context, source)) == NULL)
1529 alSetError(Context, AL_INVALID_NAME);
1530 else if(!values)
1531 alSetError(Context, AL_INVALID_VALUE);
1532 else if(!(IntValsByProp(param) > 0))
1533 alSetError(Context, AL_INVALID_ENUM);
1534 else
1535 SetSourceiv(Source, Context, param, values);
1537 ALCcontext_DecRef(Context);
1541 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1543 ALCcontext *Context;
1544 ALsource *Source;
1546 Context = GetContextRef();
1547 if(!Context) return;
1549 if((Source=LookupSource(Context, source)) == NULL)
1550 alSetError(Context, AL_INVALID_NAME);
1551 else if(!(Int64ValsByProp(param) == 1))
1552 alSetError(Context, AL_INVALID_ENUM);
1553 else
1554 SetSourcei64v(Source, Context, param, &value);
1556 ALCcontext_DecRef(Context);
1559 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1561 ALCcontext *Context;
1562 ALsource *Source;
1564 Context = GetContextRef();
1565 if(!Context) return;
1567 if((Source=LookupSource(Context, source)) == NULL)
1568 alSetError(Context, AL_INVALID_NAME);
1569 else if(!(Int64ValsByProp(param) == 3))
1570 alSetError(Context, AL_INVALID_ENUM);
1571 else
1573 ALint64SOFT i64vals[3] = { value1, value2, value3 };
1574 SetSourcei64v(Source, Context, param, i64vals);
1577 ALCcontext_DecRef(Context);
1580 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1582 ALCcontext *Context;
1583 ALsource *Source;
1585 Context = GetContextRef();
1586 if(!Context) return;
1588 if((Source=LookupSource(Context, source)) == NULL)
1589 alSetError(Context, AL_INVALID_NAME);
1590 else if(!values)
1591 alSetError(Context, AL_INVALID_VALUE);
1592 else if(!(Int64ValsByProp(param) > 0))
1593 alSetError(Context, AL_INVALID_ENUM);
1594 else
1595 SetSourcei64v(Source, Context, param, values);
1597 ALCcontext_DecRef(Context);
1601 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1603 ALCcontext *Context;
1604 ALsource *Source;
1606 Context = GetContextRef();
1607 if(!Context) return;
1609 if((Source=LookupSource(Context, source)) == NULL)
1610 alSetError(Context, AL_INVALID_NAME);
1611 else if(!value)
1612 alSetError(Context, AL_INVALID_VALUE);
1613 else if(!(FloatValsByProp(param) == 1))
1614 alSetError(Context, AL_INVALID_ENUM);
1615 else
1617 ALdouble dval;
1618 if(GetSourcedv(Source, Context, param, &dval) == AL_NO_ERROR)
1619 *value = (ALfloat)dval;
1622 ALCcontext_DecRef(Context);
1626 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1628 ALCcontext *Context;
1629 ALsource *Source;
1631 Context = GetContextRef();
1632 if(!Context) return;
1634 if((Source=LookupSource(Context, source)) == NULL)
1635 alSetError(Context, AL_INVALID_NAME);
1636 else if(!(value1 && value2 && value3))
1637 alSetError(Context, AL_INVALID_VALUE);
1638 else if(!(FloatValsByProp(param) == 3))
1639 alSetError(Context, AL_INVALID_ENUM);
1640 else
1642 ALdouble dvals[3];
1643 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1645 *value1 = (ALfloat)dvals[0];
1646 *value2 = (ALfloat)dvals[1];
1647 *value3 = (ALfloat)dvals[2];
1651 ALCcontext_DecRef(Context);
1655 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1657 ALCcontext *Context;
1658 ALsource *Source;
1659 ALint count;
1661 Context = GetContextRef();
1662 if(!Context) return;
1664 if((Source=LookupSource(Context, source)) == NULL)
1665 alSetError(Context, AL_INVALID_NAME);
1666 else if(!values)
1667 alSetError(Context, AL_INVALID_VALUE);
1668 else if(!((count=FloatValsByProp(param)) > 0 && count <= 3))
1669 alSetError(Context, AL_INVALID_ENUM);
1670 else
1672 ALdouble dvals[3];
1673 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1675 ALint i;
1676 for(i = 0;i < count;i++)
1677 values[i] = (ALfloat)dvals[i];
1681 ALCcontext_DecRef(Context);
1685 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1687 ALCcontext *Context;
1688 ALsource *Source;
1690 Context = GetContextRef();
1691 if(!Context) return;
1693 if((Source=LookupSource(Context, source)) == NULL)
1694 alSetError(Context, AL_INVALID_NAME);
1695 else if(!value)
1696 alSetError(Context, AL_INVALID_VALUE);
1697 else if(!(DoubleValsByProp(param) == 1))
1698 alSetError(Context, AL_INVALID_ENUM);
1699 else
1700 GetSourcedv(Source, Context, param, value);
1702 ALCcontext_DecRef(Context);
1705 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1707 ALCcontext *Context;
1708 ALsource *Source;
1710 Context = GetContextRef();
1711 if(!Context) return;
1713 if((Source=LookupSource(Context, source)) == NULL)
1714 alSetError(Context, AL_INVALID_NAME);
1715 else if(!(value1 && value2 && value3))
1716 alSetError(Context, AL_INVALID_VALUE);
1717 else if(!(DoubleValsByProp(param) == 3))
1718 alSetError(Context, AL_INVALID_ENUM);
1719 else
1721 ALdouble dvals[3];
1722 if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR)
1724 *value1 = dvals[0];
1725 *value2 = dvals[1];
1726 *value3 = dvals[2];
1730 ALCcontext_DecRef(Context);
1733 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1735 ALCcontext *Context;
1736 ALsource *Source;
1738 Context = GetContextRef();
1739 if(!Context) return;
1741 if((Source=LookupSource(Context, source)) == NULL)
1742 alSetError(Context, AL_INVALID_NAME);
1743 else if(!values)
1744 alSetError(Context, AL_INVALID_VALUE);
1745 else if(!(DoubleValsByProp(param) > 0))
1746 alSetError(Context, AL_INVALID_ENUM);
1747 else
1748 GetSourcedv(Source, Context, param, values);
1750 ALCcontext_DecRef(Context);
1754 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1756 ALCcontext *Context;
1757 ALsource *Source;
1759 Context = GetContextRef();
1760 if(!Context) return;
1762 if((Source=LookupSource(Context, source)) == NULL)
1763 alSetError(Context, AL_INVALID_NAME);
1764 else if(!value)
1765 alSetError(Context, AL_INVALID_VALUE);
1766 else if(!(IntValsByProp(param) == 1))
1767 alSetError(Context, AL_INVALID_ENUM);
1768 else
1769 GetSourceiv(Source, Context, param, value);
1771 ALCcontext_DecRef(Context);
1775 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
1777 ALCcontext *Context;
1778 ALsource *Source;
1780 Context = GetContextRef();
1781 if(!Context) return;
1783 if((Source=LookupSource(Context, source)) == NULL)
1784 alSetError(Context, AL_INVALID_NAME);
1785 else if(!(value1 && value2 && value3))
1786 alSetError(Context, AL_INVALID_VALUE);
1787 else if(!(IntValsByProp(param) == 3))
1788 alSetError(Context, AL_INVALID_ENUM);
1789 else
1791 ALint ivals[3];
1792 if(GetSourceiv(Source, Context, param, ivals) == AL_NO_ERROR)
1794 *value1 = ivals[0];
1795 *value2 = ivals[1];
1796 *value3 = ivals[2];
1800 ALCcontext_DecRef(Context);
1804 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
1806 ALCcontext *Context;
1807 ALsource *Source;
1809 Context = GetContextRef();
1810 if(!Context) return;
1812 if((Source=LookupSource(Context, source)) == NULL)
1813 alSetError(Context, AL_INVALID_NAME);
1814 else if(!values)
1815 alSetError(Context, AL_INVALID_VALUE);
1816 else if(!(IntValsByProp(param) > 0))
1817 alSetError(Context, AL_INVALID_ENUM);
1818 else
1819 GetSourceiv(Source, Context, param, values);
1821 ALCcontext_DecRef(Context);
1825 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
1827 ALCcontext *Context;
1828 ALsource *Source;
1830 Context = GetContextRef();
1831 if(!Context) return;
1833 if((Source=LookupSource(Context, source)) == NULL)
1834 alSetError(Context, AL_INVALID_NAME);
1835 else if(!value)
1836 alSetError(Context, AL_INVALID_VALUE);
1837 else if(!(Int64ValsByProp(param) == 1))
1838 alSetError(Context, AL_INVALID_ENUM);
1839 else
1840 GetSourcei64v(Source, Context, param, value);
1842 ALCcontext_DecRef(Context);
1845 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
1847 ALCcontext *Context;
1848 ALsource *Source;
1850 Context = GetContextRef();
1851 if(!Context) return;
1853 if((Source=LookupSource(Context, source)) == NULL)
1854 alSetError(Context, AL_INVALID_NAME);
1855 else if(!(value1 && value2 && value3))
1856 alSetError(Context, AL_INVALID_VALUE);
1857 else if(!(Int64ValsByProp(param) == 3))
1858 alSetError(Context, AL_INVALID_ENUM);
1859 else
1861 ALint64 i64vals[3];
1862 if(GetSourcei64v(Source, Context, param, i64vals) == AL_NO_ERROR)
1864 *value1 = i64vals[0];
1865 *value2 = i64vals[1];
1866 *value3 = i64vals[2];
1870 ALCcontext_DecRef(Context);
1873 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
1875 ALCcontext *Context;
1876 ALsource *Source;
1878 Context = GetContextRef();
1879 if(!Context) return;
1881 if((Source=LookupSource(Context, source)) == NULL)
1882 alSetError(Context, AL_INVALID_NAME);
1883 else if(!values)
1884 alSetError(Context, AL_INVALID_VALUE);
1885 else if(!(Int64ValsByProp(param) > 0))
1886 alSetError(Context, AL_INVALID_ENUM);
1887 else
1888 GetSourcei64v(Source, Context, param, values);
1890 ALCcontext_DecRef(Context);
1894 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
1896 alSourcePlayv(1, &source);
1898 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
1900 ALCcontext *Context;
1901 ALsource *Source;
1902 ALsizei i;
1904 Context = GetContextRef();
1905 if(!Context) return;
1907 al_try
1909 CHECK_VALUE(Context, n >= 0);
1910 for(i = 0;i < n;i++)
1912 if(!LookupSource(Context, sources[i]))
1913 al_throwerr(Context, AL_INVALID_NAME);
1916 LockContext(Context);
1917 while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
1919 void *temp = NULL;
1920 ALsizei newcount;
1922 newcount = Context->MaxActiveSources << 1;
1923 if(newcount > 0)
1924 temp = realloc(Context->ActiveSources,
1925 sizeof(*Context->ActiveSources) * newcount);
1926 if(!temp)
1928 UnlockContext(Context);
1929 al_throwerr(Context, AL_OUT_OF_MEMORY);
1932 Context->ActiveSources = temp;
1933 Context->MaxActiveSources = newcount;
1936 for(i = 0;i < n;i++)
1938 Source = LookupSource(Context, sources[i]);
1939 if(Context->DeferUpdates) Source->new_state = AL_PLAYING;
1940 else SetSourceState(Source, Context, AL_PLAYING);
1942 UnlockContext(Context);
1944 al_endtry;
1946 ALCcontext_DecRef(Context);
1949 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
1951 alSourcePausev(1, &source);
1953 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1955 ALCcontext *Context;
1956 ALsource *Source;
1957 ALsizei i;
1959 Context = GetContextRef();
1960 if(!Context) return;
1962 al_try
1964 CHECK_VALUE(Context, n >= 0);
1965 for(i = 0;i < n;i++)
1967 if(!LookupSource(Context, sources[i]))
1968 al_throwerr(Context, AL_INVALID_NAME);
1971 LockContext(Context);
1972 for(i = 0;i < n;i++)
1974 Source = LookupSource(Context, sources[i]);
1975 if(Context->DeferUpdates) Source->new_state = AL_PAUSED;
1976 else SetSourceState(Source, Context, AL_PAUSED);
1978 UnlockContext(Context);
1980 al_endtry;
1982 ALCcontext_DecRef(Context);
1985 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
1987 alSourceStopv(1, &source);
1989 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1991 ALCcontext *Context;
1992 ALsource *Source;
1993 ALsizei i;
1995 Context = GetContextRef();
1996 if(!Context) return;
1998 al_try
2000 CHECK_VALUE(Context, n >= 0);
2001 for(i = 0;i < n;i++)
2003 if(!LookupSource(Context, sources[i]))
2004 al_throwerr(Context, AL_INVALID_NAME);
2007 LockContext(Context);
2008 for(i = 0;i < n;i++)
2010 Source = LookupSource(Context, sources[i]);
2011 Source->new_state = AL_NONE;
2012 SetSourceState(Source, Context, AL_STOPPED);
2014 UnlockContext(Context);
2016 al_endtry;
2018 ALCcontext_DecRef(Context);
2021 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2023 alSourceRewindv(1, &source);
2025 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2027 ALCcontext *Context;
2028 ALsource *Source;
2029 ALsizei i;
2031 Context = GetContextRef();
2032 if(!Context) return;
2034 al_try
2036 CHECK_VALUE(Context, n >= 0);
2037 for(i = 0;i < n;i++)
2039 if(!LookupSource(Context, sources[i]))
2040 al_throwerr(Context, AL_INVALID_NAME);
2043 LockContext(Context);
2044 for(i = 0;i < n;i++)
2046 Source = LookupSource(Context, sources[i]);
2047 Source->new_state = AL_NONE;
2048 SetSourceState(Source, Context, AL_INITIAL);
2050 UnlockContext(Context);
2052 al_endtry;
2054 ALCcontext_DecRef(Context);
2058 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers)
2060 ALCcontext *Context;
2061 ALsource *Source;
2062 ALsizei i;
2063 ALbufferlistitem *BufferListStart = NULL;
2064 ALbufferlistitem *BufferList;
2065 ALbuffer *BufferFmt;
2067 if(nb == 0)
2068 return;
2070 Context = GetContextRef();
2071 if(!Context) return;
2073 al_try
2075 ALCdevice *device = Context->Device;
2077 CHECK_VALUE(Context, nb >= 0);
2079 if((Source=LookupSource(Context, source)) == NULL)
2080 al_throwerr(Context, AL_INVALID_NAME);
2082 LockContext(Context);
2083 if(Source->SourceType == AL_STATIC)
2085 UnlockContext(Context);
2086 /* Can't queue on a Static Source */
2087 al_throwerr(Context, AL_INVALID_OPERATION);
2090 BufferFmt = NULL;
2092 /* Check for a valid Buffer, for its frequency and format */
2093 BufferList = Source->queue;
2094 while(BufferList)
2096 if(BufferList->buffer)
2098 BufferFmt = BufferList->buffer;
2099 break;
2101 BufferList = BufferList->next;
2104 for(i = 0;i < nb;i++)
2106 ALbuffer *buffer = NULL;
2107 if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2109 UnlockContext(Context);
2110 al_throwerr(Context, AL_INVALID_NAME);
2113 if(!BufferListStart)
2115 BufferListStart = malloc(sizeof(ALbufferlistitem));
2116 BufferListStart->buffer = buffer;
2117 BufferListStart->next = NULL;
2118 BufferListStart->prev = NULL;
2119 BufferList = BufferListStart;
2121 else
2123 BufferList->next = malloc(sizeof(ALbufferlistitem));
2124 BufferList->next->buffer = buffer;
2125 BufferList->next->next = NULL;
2126 BufferList->next->prev = BufferList;
2127 BufferList = BufferList->next;
2129 if(!buffer) continue;
2130 IncrementRef(&buffer->ref);
2132 ReadLock(&buffer->lock);
2133 if(BufferFmt == NULL)
2135 BufferFmt = buffer;
2137 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2138 Source->SampleSize = BytesFromFmt(buffer->FmtType);
2139 if(buffer->FmtChannels == FmtMono)
2140 Source->Update = CalcSourceParams;
2141 else
2142 Source->Update = CalcNonAttnSourceParams;
2144 Source->NeedsUpdate = AL_TRUE;
2146 else if(BufferFmt->Frequency != buffer->Frequency ||
2147 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2148 BufferFmt->OriginalType != buffer->OriginalType)
2150 ReadUnlock(&buffer->lock);
2151 UnlockContext(Context);
2152 al_throwerr(Context, AL_INVALID_OPERATION);
2154 ReadUnlock(&buffer->lock);
2157 /* Source is now streaming */
2158 Source->SourceType = AL_STREAMING;
2160 if(Source->queue == NULL)
2161 Source->queue = BufferListStart;
2162 else
2164 /* Append to the end of the queue */
2165 BufferList = Source->queue;
2166 while(BufferList->next != NULL)
2167 BufferList = BufferList->next;
2169 BufferListStart->prev = BufferList;
2170 BufferList->next = BufferListStart;
2173 Source->BuffersInQueue += nb;
2175 UnlockContext(Context);
2177 al_catchany()
2179 while(BufferListStart)
2181 BufferList = BufferListStart;
2182 BufferListStart = BufferList->next;
2184 if(BufferList->buffer)
2185 DecrementRef(&BufferList->buffer->ref);
2186 free(BufferList);
2189 al_endtry;
2191 ALCcontext_DecRef(Context);
2194 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers)
2196 ALCcontext *Context;
2197 ALsource *Source;
2198 ALsizei i;
2199 ALbufferlistitem *BufferList;
2201 if(nb == 0)
2202 return;
2204 Context = GetContextRef();
2205 if(!Context) return;
2207 al_try
2209 CHECK_VALUE(Context, nb >= 0);
2211 if((Source=LookupSource(Context, source)) == NULL)
2212 al_throwerr(Context, AL_INVALID_NAME);
2214 LockContext(Context);
2215 if(Source->Looping || Source->SourceType != AL_STREAMING ||
2216 (ALuint)nb > Source->BuffersPlayed)
2218 UnlockContext(Context);
2219 /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2220 al_throwerr(Context, AL_INVALID_VALUE);
2223 for(i = 0;i < nb;i++)
2225 BufferList = Source->queue;
2226 Source->queue = BufferList->next;
2227 Source->BuffersInQueue--;
2228 Source->BuffersPlayed--;
2230 if(BufferList->buffer)
2232 buffers[i] = BufferList->buffer->id;
2233 DecrementRef(&BufferList->buffer->ref);
2235 else
2236 buffers[i] = 0;
2238 free(BufferList);
2240 if(Source->queue)
2241 Source->queue->prev = NULL;
2242 UnlockContext(Context);
2244 al_endtry;
2246 ALCcontext_DecRef(Context);
2250 static ALvoid InitSourceParams(ALsource *Source)
2252 ALuint i;
2254 Source->InnerAngle = 360.0f;
2255 Source->OuterAngle = 360.0f;
2256 Source->Pitch = 1.0f;
2257 Source->Position[0] = 0.0f;
2258 Source->Position[1] = 0.0f;
2259 Source->Position[2] = 0.0f;
2260 Source->Orientation[0] = 0.0f;
2261 Source->Orientation[1] = 0.0f;
2262 Source->Orientation[2] = 0.0f;
2263 Source->Velocity[0] = 0.0f;
2264 Source->Velocity[1] = 0.0f;
2265 Source->Velocity[2] = 0.0f;
2266 Source->RefDistance = 1.0f;
2267 Source->MaxDistance = FLT_MAX;
2268 Source->RollOffFactor = 1.0f;
2269 Source->Looping = AL_FALSE;
2270 Source->Gain = 1.0f;
2271 Source->MinGain = 0.0f;
2272 Source->MaxGain = 1.0f;
2273 Source->OuterGain = 0.0f;
2274 Source->OuterGainHF = 1.0f;
2276 Source->DryGainHFAuto = AL_TRUE;
2277 Source->WetGainAuto = AL_TRUE;
2278 Source->WetGainHFAuto = AL_TRUE;
2279 Source->AirAbsorptionFactor = 0.0f;
2280 Source->RoomRolloffFactor = 0.0f;
2281 Source->DopplerFactor = 1.0f;
2282 Source->DirectChannels = AL_FALSE;
2284 Source->DistanceModel = DefaultDistanceModel;
2286 Source->Resampler = DefaultResampler;
2288 Source->state = AL_INITIAL;
2289 Source->new_state = AL_NONE;
2290 Source->SourceType = AL_UNDETERMINED;
2291 Source->Offset = -1.0;
2293 Source->DirectGain = 1.0f;
2294 Source->DirectGainHF = 1.0f;
2295 for(i = 0;i < MAX_SENDS;i++)
2297 Source->Send[i].Gain = 1.0f;
2298 Source->Send[i].GainHF = 1.0f;
2301 Source->NeedsUpdate = AL_TRUE;
2303 Source->Hrtf.Moving = AL_FALSE;
2304 Source->Hrtf.Counter = 0;
2308 /* SetSourceState
2310 * Sets the source's new play state given its current state.
2312 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2314 if(state == AL_PLAYING)
2316 ALbufferlistitem *BufferList;
2317 ALsizei j, k;
2319 /* Check that there is a queue containing at least one valid, non zero
2320 * length Buffer. */
2321 BufferList = Source->queue;
2322 while(BufferList)
2324 if(BufferList->buffer != NULL && BufferList->buffer->SampleLen)
2325 break;
2326 BufferList = BufferList->next;
2329 if(Source->state != AL_PLAYING)
2331 for(j = 0;j < MaxChannels;j++)
2333 for(k = 0;k < SRC_HISTORY_LENGTH;k++)
2334 Source->Hrtf.History[j][k] = 0.0f;
2335 for(k = 0;k < HRIR_LENGTH;k++)
2337 Source->Hrtf.Values[j][k][0] = 0.0f;
2338 Source->Hrtf.Values[j][k][1] = 0.0f;
2343 if(Source->state != AL_PAUSED)
2345 Source->state = AL_PLAYING;
2346 Source->position = 0;
2347 Source->position_fraction = 0;
2348 Source->BuffersPlayed = 0;
2350 else
2351 Source->state = AL_PLAYING;
2353 // Check if an Offset has been set
2354 if(Source->Offset >= 0.0)
2355 ApplyOffset(Source);
2357 /* If there's nothing to play, or device is disconnected, go right to
2358 * stopped */
2359 if(!BufferList || !Context->Device->Connected)
2361 SetSourceState(Source, Context, AL_STOPPED);
2362 return;
2365 for(j = 0;j < Context->ActiveSourceCount;j++)
2367 if(Context->ActiveSources[j] == Source)
2368 break;
2370 if(j == Context->ActiveSourceCount)
2371 Context->ActiveSources[Context->ActiveSourceCount++] = Source;
2373 else if(state == AL_PAUSED)
2375 if(Source->state == AL_PLAYING)
2377 Source->state = AL_PAUSED;
2378 Source->Hrtf.Moving = AL_FALSE;
2379 Source->Hrtf.Counter = 0;
2382 else if(state == AL_STOPPED)
2384 if(Source->state != AL_INITIAL)
2386 Source->state = AL_STOPPED;
2387 Source->BuffersPlayed = Source->BuffersInQueue;
2388 Source->Hrtf.Moving = AL_FALSE;
2389 Source->Hrtf.Counter = 0;
2391 Source->Offset = -1.0;
2393 else if(state == AL_INITIAL)
2395 if(Source->state != AL_INITIAL)
2397 Source->state = AL_INITIAL;
2398 Source->position = 0;
2399 Source->position_fraction = 0;
2400 Source->BuffersPlayed = 0;
2401 Source->Hrtf.Moving = AL_FALSE;
2402 Source->Hrtf.Counter = 0;
2404 Source->Offset = -1.0;
2408 /* GetSourceOffset
2410 * Gets the current read offset for the given Source, in 32.32 fixed-point
2411 * samples. The offset is relative to the start of the queue (not the start of
2412 * the current buffer).
2414 static ALint64 GetSourceOffset(const ALsource *Source)
2416 const ALbufferlistitem *BufferList;
2417 ALuint64 readPos;
2418 ALuint i;
2420 if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2421 return 0;
2423 /* NOTE: This is the offset into the *current* buffer, so add the length of
2424 * any played buffers */
2425 readPos = (ALuint64)Source->position << 32;
2426 readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2427 BufferList = Source->queue;
2428 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2430 if(BufferList->buffer)
2431 readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2432 BufferList = BufferList->next;
2435 return (ALint64)minu64(readPos, MAKEU64(0x7fffffff,0xffffffff));
2438 /* GetSourceSecOffset
2440 * Gets the current read offset for the given Source, in seconds. The offset is
2441 * relative to the start of the queue (not the start of the current buffer).
2443 static ALdouble GetSourceSecOffset(const ALsource *Source)
2445 const ALbufferlistitem *BufferList;
2446 const ALbuffer *Buffer = NULL;
2447 ALuint64 readPos;
2448 ALuint i;
2450 BufferList = Source->queue;
2451 while(BufferList)
2453 if(BufferList->buffer)
2455 Buffer = BufferList->buffer;
2456 break;
2458 BufferList = BufferList->next;
2461 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2462 return 0.0;
2464 /* NOTE: This is the offset into the *current* buffer, so add the length of
2465 * any played buffers */
2466 readPos = (ALuint64)Source->position << FRACTIONBITS;
2467 readPos |= (ALuint64)Source->position_fraction;
2468 BufferList = Source->queue;
2469 for(i = 0;i < Source->BuffersPlayed && BufferList;i++)
2471 if(BufferList->buffer)
2472 readPos += (ALuint64)BufferList->buffer->SampleLen << FRACTIONBITS;
2473 BufferList = BufferList->next;
2476 return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2479 /* GetSourceOffsets
2481 * Gets the current read and write offsets for the given Source, in the
2482 * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2483 * the start of the queue (not the start of the current buffer).
2485 static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2487 const ALbufferlistitem *BufferList;
2488 const ALbuffer *Buffer = NULL;
2489 ALuint readPos, writePos;
2490 ALuint totalBufferLen;
2491 ALuint i;
2493 // Find the first valid Buffer in the Queue
2494 BufferList = Source->queue;
2495 while(BufferList)
2497 if(BufferList->buffer)
2499 Buffer = BufferList->buffer;
2500 break;
2502 BufferList = BufferList->next;
2505 if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
2507 offset[0] = 0.0;
2508 offset[1] = 0.0;
2509 return;
2512 if(updateLen > 0.0 && updateLen < 0.015)
2513 updateLen = 0.015;
2515 /* NOTE: This is the offset into the *current* buffer, so add the length of
2516 * any played buffers */
2517 readPos = Source->position;
2518 totalBufferLen = 0;
2519 BufferList = Source->queue;
2520 for(i = 0;BufferList;i++)
2522 if(BufferList->buffer)
2524 if(i < Source->BuffersPlayed)
2525 readPos += BufferList->buffer->SampleLen;
2526 totalBufferLen += BufferList->buffer->SampleLen;
2528 BufferList = BufferList->next;
2530 if(Source->state == AL_PLAYING)
2531 writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
2532 else
2533 writePos = readPos;
2535 if(Source->Looping)
2537 readPos %= totalBufferLen;
2538 writePos %= totalBufferLen;
2540 else
2542 /* Wrap positions back to 0 */
2543 if(readPos >= totalBufferLen)
2544 readPos = 0;
2545 if(writePos >= totalBufferLen)
2546 writePos = 0;
2549 switch(name)
2551 case AL_SEC_OFFSET:
2552 offset[0] = (ALdouble)readPos / Buffer->Frequency;
2553 offset[1] = (ALdouble)writePos / Buffer->Frequency;
2554 break;
2556 case AL_SAMPLE_OFFSET:
2557 case AL_SAMPLE_RW_OFFSETS_SOFT:
2558 offset[0] = (ALdouble)readPos;
2559 offset[1] = (ALdouble)writePos;
2560 break;
2562 case AL_BYTE_OFFSET:
2563 case AL_BYTE_RW_OFFSETS_SOFT:
2564 if(Buffer->OriginalType == UserFmtIMA4)
2566 ALuint BlockSize = 36 * ChannelsFromFmt(Buffer->FmtChannels);
2567 ALuint FrameBlockSize = 65;
2569 /* Round down to nearest ADPCM block */
2570 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2571 if(Source->state != AL_PLAYING)
2572 offset[1] = offset[0];
2573 else
2575 /* Round up to nearest ADPCM block */
2576 offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2577 FrameBlockSize * BlockSize);
2580 else
2582 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2583 offset[0] = (ALdouble)(readPos * FrameSize);
2584 offset[1] = (ALdouble)(writePos * FrameSize);
2586 break;
2591 /* ApplyOffset
2593 * Apply the stored playback offset to the Source. This function will update
2594 * the number of buffers "played" given the stored offset.
2596 ALboolean ApplyOffset(ALsource *Source)
2598 const ALbufferlistitem *BufferList;
2599 const ALbuffer *Buffer;
2600 ALint bufferLen, totalBufferLen;
2601 ALint buffersPlayed;
2602 ALint offset;
2604 /* Get sample frame offset */
2605 offset = GetSampleOffset(Source);
2606 if(offset == -1)
2607 return AL_FALSE;
2609 buffersPlayed = 0;
2610 totalBufferLen = 0;
2612 BufferList = Source->queue;
2613 while(BufferList)
2615 Buffer = BufferList->buffer;
2616 bufferLen = Buffer ? Buffer->SampleLen : 0;
2618 if(bufferLen <= offset-totalBufferLen)
2620 /* Offset is past this buffer so increment to the next buffer */
2621 buffersPlayed++;
2623 else if(totalBufferLen <= offset)
2625 /* Offset is in this buffer */
2626 Source->BuffersPlayed = buffersPlayed;
2628 Source->position = offset - totalBufferLen;
2629 Source->position_fraction = 0;
2630 return AL_TRUE;
2633 totalBufferLen += bufferLen;
2635 BufferList = BufferList->next;
2638 /* Offset is out of range of the queue */
2639 return AL_FALSE;
2643 /* GetSampleOffset
2645 * Returns the sample offset into the Source's queue (from the Sample, Byte or
2646 * Second offset supplied by the application). This takes into account the fact
2647 * that the buffer format may have been modifed since.
2649 static ALint GetSampleOffset(ALsource *Source)
2651 const ALbuffer *Buffer = NULL;
2652 const ALbufferlistitem *BufferList;
2653 ALint Offset = -1;
2655 /* Find the first valid Buffer in the Queue */
2656 BufferList = Source->queue;
2657 while(BufferList)
2659 if(BufferList->buffer)
2661 Buffer = BufferList->buffer;
2662 break;
2664 BufferList = BufferList->next;
2667 if(!Buffer)
2669 Source->Offset = -1.0;
2670 return -1;
2673 switch(Source->OffsetType)
2675 case AL_BYTE_OFFSET:
2676 /* Determine the ByteOffset (and ensure it is block aligned) */
2677 Offset = (ALint)Source->Offset;
2678 if(Buffer->OriginalType == UserFmtIMA4)
2680 Offset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
2681 Offset *= 65;
2683 else
2684 Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2685 break;
2687 case AL_SAMPLE_OFFSET:
2688 Offset = (ALint)Source->Offset;
2689 break;
2691 case AL_SEC_OFFSET:
2692 Offset = (ALint)(Source->Offset * Buffer->Frequency);
2693 break;
2695 Source->Offset = -1.0;
2697 return Offset;
2701 /* ReleaseALSources
2703 * Destroys all sources in the source map.
2705 ALvoid ReleaseALSources(ALCcontext *Context)
2707 ALsizei pos;
2708 ALuint j;
2709 for(pos = 0;pos < Context->SourceMap.size;pos++)
2711 ALsource *temp = Context->SourceMap.array[pos].value;
2712 Context->SourceMap.array[pos].value = NULL;
2714 while(temp->queue != NULL)
2716 ALbufferlistitem *BufferList = temp->queue;
2717 temp->queue = BufferList->next;
2719 if(BufferList->buffer != NULL)
2720 DecrementRef(&BufferList->buffer->ref);
2721 free(BufferList);
2724 for(j = 0;j < MAX_SENDS;++j)
2726 if(temp->Send[j].Slot)
2727 DecrementRef(&temp->Send[j].Slot->ref);
2728 temp->Send[j].Slot = NULL;
2731 FreeThunkEntry(temp->id);
2732 memset(temp, 0, sizeof(*temp));
2733 al_free(temp);