7382b87a1e30fb9d6bb4ae4c97866226facc1599
[platform/upstream/openal-soft.git] / OpenAL32 / alSource.c
1 /**
2  * OpenAL cross platform audio library
3  * Copyright (C) 1999-2007 by authors.
4  * This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Library General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  *  License along with this library; if not, write to the
16  *  Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  * Or go to http://www.gnu.org/copyleft/lgpl.html
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <math.h>
26 #include <float.h>
27
28 #include "AL/al.h"
29 #include "AL/alc.h"
30 #include "alMain.h"
31 #include "alError.h"
32 #include "alSource.h"
33 #include "alBuffer.h"
34 #include "alThunk.h"
35 #include "alAuxEffectSlot.h"
36
37 #include "backends/base.h"
38
39 #include "threads.h"
40
41
42 extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
43 extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
44
45 static ALvoid InitSourceParams(ALsource *Source);
46 static ALint64 GetSourceSampleOffset(ALsource *Source);
47 static ALdouble GetSourceSecOffset(ALsource *Source);
48 static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
49 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac);
50
51 typedef enum SourceProp {
52     srcPitch = AL_PITCH,
53     srcGain = AL_GAIN,
54     srcMinGain = AL_MIN_GAIN,
55     srcMaxGain = AL_MAX_GAIN,
56     srcMaxDistance = AL_MAX_DISTANCE,
57     srcRolloffFactor = AL_ROLLOFF_FACTOR,
58     srcDopplerFactor = AL_DOPPLER_FACTOR,
59     srcConeOuterGain = AL_CONE_OUTER_GAIN,
60     srcSecOffset = AL_SEC_OFFSET,
61     srcSampleOffset = AL_SAMPLE_OFFSET,
62     srcByteOffset = AL_BYTE_OFFSET,
63     srcConeInnerAngle = AL_CONE_INNER_ANGLE,
64     srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
65     srcRefDistance = AL_REFERENCE_DISTANCE,
66
67     srcPosition = AL_POSITION,
68     srcVelocity = AL_VELOCITY,
69     srcDirection = AL_DIRECTION,
70
71     srcSourceRelative = AL_SOURCE_RELATIVE,
72     srcLooping = AL_LOOPING,
73     srcBuffer = AL_BUFFER,
74     srcSourceState = AL_SOURCE_STATE,
75     srcBuffersQueued = AL_BUFFERS_QUEUED,
76     srcBuffersProcessed = AL_BUFFERS_PROCESSED,
77     srcSourceType = AL_SOURCE_TYPE,
78
79     /* ALC_EXT_EFX */
80     srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
81     srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
82     srcRoomRolloffFactor =  AL_ROOM_ROLLOFF_FACTOR,
83     srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
84     srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
85     srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
86     srcDirectFilter = AL_DIRECT_FILTER,
87     srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
88
89     /* AL_SOFT_direct_channels */
90     srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
91
92     /* AL_EXT_source_distance_model */
93     srcDistanceModel = AL_DISTANCE_MODEL,
94
95     srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
96     srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
97     srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
98
99     /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
100     srcSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
101     srcByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
102
103     /* AL_SOFT_source_latency */
104     srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
105     srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
106
107     /* AL_EXT_BFORMAT */
108     srcOrientation = AL_ORIENTATION,
109 } SourceProp;
110
111 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
112 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
113 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
114
115 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
116 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
117 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
118
119 static ALint FloatValsByProp(ALenum prop)
120 {
121     if(prop != (ALenum)((SourceProp)prop))
122         return 0;
123     switch((SourceProp)prop)
124     {
125         case AL_PITCH:
126         case AL_GAIN:
127         case AL_MIN_GAIN:
128         case AL_MAX_GAIN:
129         case AL_MAX_DISTANCE:
130         case AL_ROLLOFF_FACTOR:
131         case AL_DOPPLER_FACTOR:
132         case AL_CONE_OUTER_GAIN:
133         case AL_SEC_OFFSET:
134         case AL_SAMPLE_OFFSET:
135         case AL_BYTE_OFFSET:
136         case AL_CONE_INNER_ANGLE:
137         case AL_CONE_OUTER_ANGLE:
138         case AL_REFERENCE_DISTANCE:
139         case AL_CONE_OUTER_GAINHF:
140         case AL_AIR_ABSORPTION_FACTOR:
141         case AL_ROOM_ROLLOFF_FACTOR:
142         case AL_DIRECT_FILTER_GAINHF_AUTO:
143         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
144         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
145         case AL_DIRECT_CHANNELS_SOFT:
146         case AL_DISTANCE_MODEL:
147         case AL_SOURCE_RELATIVE:
148         case AL_LOOPING:
149         case AL_SOURCE_STATE:
150         case AL_BUFFERS_QUEUED:
151         case AL_BUFFERS_PROCESSED:
152         case AL_SOURCE_TYPE:
153         case AL_BYTE_LENGTH_SOFT:
154         case AL_SAMPLE_LENGTH_SOFT:
155         case AL_SEC_LENGTH_SOFT:
156             return 1;
157
158         case AL_SAMPLE_RW_OFFSETS_SOFT:
159         case AL_BYTE_RW_OFFSETS_SOFT:
160             return 2;
161
162         case AL_POSITION:
163         case AL_VELOCITY:
164         case AL_DIRECTION:
165             return 3;
166
167         case AL_ORIENTATION:
168             return 6;
169
170         case AL_SEC_OFFSET_LATENCY_SOFT:
171             break; /* Double only */
172
173         case AL_BUFFER:
174         case AL_DIRECT_FILTER:
175         case AL_AUXILIARY_SEND_FILTER:
176             break; /* i/i64 only */
177         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
178             break; /* i64 only */
179     }
180     return 0;
181 }
182 static ALint DoubleValsByProp(ALenum prop)
183 {
184     if(prop != (ALenum)((SourceProp)prop))
185         return 0;
186     switch((SourceProp)prop)
187     {
188         case AL_PITCH:
189         case AL_GAIN:
190         case AL_MIN_GAIN:
191         case AL_MAX_GAIN:
192         case AL_MAX_DISTANCE:
193         case AL_ROLLOFF_FACTOR:
194         case AL_DOPPLER_FACTOR:
195         case AL_CONE_OUTER_GAIN:
196         case AL_SEC_OFFSET:
197         case AL_SAMPLE_OFFSET:
198         case AL_BYTE_OFFSET:
199         case AL_CONE_INNER_ANGLE:
200         case AL_CONE_OUTER_ANGLE:
201         case AL_REFERENCE_DISTANCE:
202         case AL_CONE_OUTER_GAINHF:
203         case AL_AIR_ABSORPTION_FACTOR:
204         case AL_ROOM_ROLLOFF_FACTOR:
205         case AL_DIRECT_FILTER_GAINHF_AUTO:
206         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
207         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
208         case AL_DIRECT_CHANNELS_SOFT:
209         case AL_DISTANCE_MODEL:
210         case AL_SOURCE_RELATIVE:
211         case AL_LOOPING:
212         case AL_SOURCE_STATE:
213         case AL_BUFFERS_QUEUED:
214         case AL_BUFFERS_PROCESSED:
215         case AL_SOURCE_TYPE:
216         case AL_BYTE_LENGTH_SOFT:
217         case AL_SAMPLE_LENGTH_SOFT:
218         case AL_SEC_LENGTH_SOFT:
219             return 1;
220
221         case AL_SAMPLE_RW_OFFSETS_SOFT:
222         case AL_BYTE_RW_OFFSETS_SOFT:
223         case AL_SEC_OFFSET_LATENCY_SOFT:
224             return 2;
225
226         case AL_POSITION:
227         case AL_VELOCITY:
228         case AL_DIRECTION:
229             return 3;
230
231         case AL_ORIENTATION:
232             return 6;
233
234         case AL_BUFFER:
235         case AL_DIRECT_FILTER:
236         case AL_AUXILIARY_SEND_FILTER:
237             break; /* i/i64 only */
238         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
239             break; /* i64 only */
240     }
241     return 0;
242 }
243
244 static ALint IntValsByProp(ALenum prop)
245 {
246     if(prop != (ALenum)((SourceProp)prop))
247         return 0;
248     switch((SourceProp)prop)
249     {
250         case AL_PITCH:
251         case AL_GAIN:
252         case AL_MIN_GAIN:
253         case AL_MAX_GAIN:
254         case AL_MAX_DISTANCE:
255         case AL_ROLLOFF_FACTOR:
256         case AL_DOPPLER_FACTOR:
257         case AL_CONE_OUTER_GAIN:
258         case AL_SEC_OFFSET:
259         case AL_SAMPLE_OFFSET:
260         case AL_BYTE_OFFSET:
261         case AL_CONE_INNER_ANGLE:
262         case AL_CONE_OUTER_ANGLE:
263         case AL_REFERENCE_DISTANCE:
264         case AL_CONE_OUTER_GAINHF:
265         case AL_AIR_ABSORPTION_FACTOR:
266         case AL_ROOM_ROLLOFF_FACTOR:
267         case AL_DIRECT_FILTER_GAINHF_AUTO:
268         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
269         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
270         case AL_DIRECT_CHANNELS_SOFT:
271         case AL_DISTANCE_MODEL:
272         case AL_SOURCE_RELATIVE:
273         case AL_LOOPING:
274         case AL_BUFFER:
275         case AL_SOURCE_STATE:
276         case AL_BUFFERS_QUEUED:
277         case AL_BUFFERS_PROCESSED:
278         case AL_SOURCE_TYPE:
279         case AL_DIRECT_FILTER:
280         case AL_BYTE_LENGTH_SOFT:
281         case AL_SAMPLE_LENGTH_SOFT:
282         case AL_SEC_LENGTH_SOFT:
283             return 1;
284
285         case AL_SAMPLE_RW_OFFSETS_SOFT:
286         case AL_BYTE_RW_OFFSETS_SOFT:
287             return 2;
288
289         case AL_POSITION:
290         case AL_VELOCITY:
291         case AL_DIRECTION:
292         case AL_AUXILIARY_SEND_FILTER:
293             return 3;
294
295         case AL_ORIENTATION:
296             return 6;
297
298         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
299             break; /* i64 only */
300         case AL_SEC_OFFSET_LATENCY_SOFT:
301             break; /* Double only */
302     }
303     return 0;
304 }
305 static ALint Int64ValsByProp(ALenum prop)
306 {
307     if(prop != (ALenum)((SourceProp)prop))
308         return 0;
309     switch((SourceProp)prop)
310     {
311         case AL_PITCH:
312         case AL_GAIN:
313         case AL_MIN_GAIN:
314         case AL_MAX_GAIN:
315         case AL_MAX_DISTANCE:
316         case AL_ROLLOFF_FACTOR:
317         case AL_DOPPLER_FACTOR:
318         case AL_CONE_OUTER_GAIN:
319         case AL_SEC_OFFSET:
320         case AL_SAMPLE_OFFSET:
321         case AL_BYTE_OFFSET:
322         case AL_CONE_INNER_ANGLE:
323         case AL_CONE_OUTER_ANGLE:
324         case AL_REFERENCE_DISTANCE:
325         case AL_CONE_OUTER_GAINHF:
326         case AL_AIR_ABSORPTION_FACTOR:
327         case AL_ROOM_ROLLOFF_FACTOR:
328         case AL_DIRECT_FILTER_GAINHF_AUTO:
329         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
330         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
331         case AL_DIRECT_CHANNELS_SOFT:
332         case AL_DISTANCE_MODEL:
333         case AL_SOURCE_RELATIVE:
334         case AL_LOOPING:
335         case AL_BUFFER:
336         case AL_SOURCE_STATE:
337         case AL_BUFFERS_QUEUED:
338         case AL_BUFFERS_PROCESSED:
339         case AL_SOURCE_TYPE:
340         case AL_DIRECT_FILTER:
341         case AL_BYTE_LENGTH_SOFT:
342         case AL_SAMPLE_LENGTH_SOFT:
343         case AL_SEC_LENGTH_SOFT:
344             return 1;
345
346         case AL_SAMPLE_RW_OFFSETS_SOFT:
347         case AL_BYTE_RW_OFFSETS_SOFT:
348         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
349             return 2;
350
351         case AL_POSITION:
352         case AL_VELOCITY:
353         case AL_DIRECTION:
354         case AL_AUXILIARY_SEND_FILTER:
355             return 3;
356
357         case AL_ORIENTATION:
358             return 6;
359
360         case AL_SEC_OFFSET_LATENCY_SOFT:
361             break; /* Double only */
362     }
363     return 0;
364 }
365
366
367 #define CHECKVAL(x) do {                                                      \
368     if(!(x))                                                                  \
369         SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);      \
370 } while(0)
371
372 static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
373 {
374     ALint ival;
375
376     switch(prop)
377     {
378         case AL_BYTE_RW_OFFSETS_SOFT:
379         case AL_SAMPLE_RW_OFFSETS_SOFT:
380         case AL_BYTE_LENGTH_SOFT:
381         case AL_SAMPLE_LENGTH_SOFT:
382         case AL_SEC_LENGTH_SOFT:
383         case AL_SEC_OFFSET_LATENCY_SOFT:
384             /* Query only */
385             SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
386
387         case AL_PITCH:
388             CHECKVAL(*values >= 0.0f);
389
390             Source->Pitch = *values;
391             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
392             return AL_TRUE;
393
394         case AL_CONE_INNER_ANGLE:
395             CHECKVAL(*values >= 0.0f && *values <= 360.0f);
396
397             Source->InnerAngle = *values;
398             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
399             return AL_TRUE;
400
401         case AL_CONE_OUTER_ANGLE:
402             CHECKVAL(*values >= 0.0f && *values <= 360.0f);
403
404             Source->OuterAngle = *values;
405             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
406             return AL_TRUE;
407
408         case AL_GAIN:
409             CHECKVAL(*values >= 0.0f);
410
411             Source->Gain = *values;
412             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
413             return AL_TRUE;
414
415         case AL_MAX_DISTANCE:
416             CHECKVAL(*values >= 0.0f);
417
418             Source->MaxDistance = *values;
419             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
420             return AL_TRUE;
421
422         case AL_ROLLOFF_FACTOR:
423             CHECKVAL(*values >= 0.0f);
424
425             Source->RollOffFactor = *values;
426             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
427             return AL_TRUE;
428
429         case AL_REFERENCE_DISTANCE:
430             CHECKVAL(*values >= 0.0f);
431
432             Source->RefDistance = *values;
433             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
434             return AL_TRUE;
435
436         case AL_MIN_GAIN:
437             CHECKVAL(*values >= 0.0f && *values <= 1.0f);
438
439             Source->MinGain = *values;
440             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
441             return AL_TRUE;
442
443         case AL_MAX_GAIN:
444             CHECKVAL(*values >= 0.0f && *values <= 1.0f);
445
446             Source->MaxGain = *values;
447             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
448             return AL_TRUE;
449
450         case AL_CONE_OUTER_GAIN:
451             CHECKVAL(*values >= 0.0f && *values <= 1.0f);
452
453             Source->OuterGain = *values;
454             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
455             return AL_TRUE;
456
457         case AL_CONE_OUTER_GAINHF:
458             CHECKVAL(*values >= 0.0f && *values <= 1.0f);
459
460             Source->OuterGainHF = *values;
461             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
462             return AL_TRUE;
463
464         case AL_AIR_ABSORPTION_FACTOR:
465             CHECKVAL(*values >= 0.0f && *values <= 10.0f);
466
467             Source->AirAbsorptionFactor = *values;
468             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
469             return AL_TRUE;
470
471         case AL_ROOM_ROLLOFF_FACTOR:
472             CHECKVAL(*values >= 0.0f && *values <= 10.0f);
473
474             Source->RoomRolloffFactor = *values;
475             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
476             return AL_TRUE;
477
478         case AL_DOPPLER_FACTOR:
479             CHECKVAL(*values >= 0.0f && *values <= 1.0f);
480
481             Source->DopplerFactor = *values;
482             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
483             return AL_TRUE;
484
485         case AL_SEC_OFFSET:
486         case AL_SAMPLE_OFFSET:
487         case AL_BYTE_OFFSET:
488             CHECKVAL(*values >= 0.0f);
489
490             LockContext(Context);
491             Source->OffsetType = prop;
492             Source->Offset = *values;
493
494             if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
495                !Context->DeferUpdates)
496             {
497                 WriteLock(&Source->queue_lock);
498                 if(ApplyOffset(Source) == AL_FALSE)
499                 {
500                     WriteUnlock(&Source->queue_lock);
501                     UnlockContext(Context);
502                     SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
503                 }
504                 WriteUnlock(&Source->queue_lock);
505             }
506             UnlockContext(Context);
507             return AL_TRUE;
508
509
510         case AL_POSITION:
511             CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
512
513             LockContext(Context);
514             aluVectorSet(&Source->Position, values[0], values[1], values[2], 1.0f);
515             UnlockContext(Context);
516             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
517             return AL_TRUE;
518
519         case AL_VELOCITY:
520             CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
521
522             LockContext(Context);
523             aluVectorSet(&Source->Velocity, values[0], values[1], values[2], 0.0f);
524             UnlockContext(Context);
525             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
526             return AL_TRUE;
527
528         case AL_DIRECTION:
529             CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
530
531             LockContext(Context);
532             aluVectorSet(&Source->Direction, values[0], values[1], values[2], 0.0f);
533             UnlockContext(Context);
534             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
535             return AL_TRUE;
536
537         case AL_ORIENTATION:
538             CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
539                      isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
540
541             LockContext(Context);
542             Source->Orientation[0][0] = values[0];
543             Source->Orientation[0][1] = values[1];
544             Source->Orientation[0][2] = values[2];
545             Source->Orientation[1][0] = values[3];
546             Source->Orientation[1][1] = values[4];
547             Source->Orientation[1][2] = values[5];
548             UnlockContext(Context);
549             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
550             return AL_TRUE;
551
552
553         case AL_SOURCE_RELATIVE:
554         case AL_LOOPING:
555         case AL_SOURCE_STATE:
556         case AL_SOURCE_TYPE:
557         case AL_DISTANCE_MODEL:
558         case AL_DIRECT_FILTER_GAINHF_AUTO:
559         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
560         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
561         case AL_DIRECT_CHANNELS_SOFT:
562             ival = (ALint)values[0];
563             return SetSourceiv(Source, Context, prop, &ival);
564
565         case AL_BUFFERS_QUEUED:
566         case AL_BUFFERS_PROCESSED:
567             ival = (ALint)((ALuint)values[0]);
568             return SetSourceiv(Source, Context, prop, &ival);
569
570         case AL_BUFFER:
571         case AL_DIRECT_FILTER:
572         case AL_AUXILIARY_SEND_FILTER:
573         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
574             break;
575     }
576
577     ERR("Unexpected property: 0x%04x\n", prop);
578     SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
579 }
580
581 static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
582 {
583     ALCdevice *device = Context->Device;
584     ALbuffer  *buffer = NULL;
585     ALfilter  *filter = NULL;
586     ALeffectslot *slot = NULL;
587     ALbufferlistitem *oldlist;
588     ALbufferlistitem *newlist;
589     ALfloat fvals[6];
590
591     switch(prop)
592     {
593         case AL_SOURCE_STATE:
594         case AL_SOURCE_TYPE:
595         case AL_BUFFERS_QUEUED:
596         case AL_BUFFERS_PROCESSED:
597         case AL_SAMPLE_RW_OFFSETS_SOFT:
598         case AL_BYTE_RW_OFFSETS_SOFT:
599         case AL_BYTE_LENGTH_SOFT:
600         case AL_SAMPLE_LENGTH_SOFT:
601         case AL_SEC_LENGTH_SOFT:
602             /* Query only */
603             SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
604
605         case AL_SOURCE_RELATIVE:
606             CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
607
608             Source->HeadRelative = (ALboolean)*values;
609             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
610             return AL_TRUE;
611
612         case AL_LOOPING:
613             CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
614
615             Source->Looping = (ALboolean)*values;
616             return AL_TRUE;
617
618         case AL_BUFFER:
619             CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
620
621             WriteLock(&Source->queue_lock);
622             if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
623             {
624                 WriteUnlock(&Source->queue_lock);
625                 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
626             }
627
628             if(buffer != NULL)
629             {
630                 /* Add the selected buffer to a one-item queue */
631                 newlist = malloc(sizeof(ALbufferlistitem));
632                 newlist->buffer = buffer;
633                 newlist->next = NULL;
634                 newlist->prev = NULL;
635                 IncrementRef(&buffer->ref);
636
637                 /* Source is now Static */
638                 Source->SourceType = AL_STATIC;
639
640                 ReadLock(&buffer->lock);
641                 Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
642                 Source->SampleSize  = BytesFromFmt(buffer->FmtType);
643                 ReadUnlock(&buffer->lock);
644             }
645             else
646             {
647                 /* Source is now Undetermined */
648                 Source->SourceType = AL_UNDETERMINED;
649                 newlist = NULL;
650             }
651             oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist);
652             ATOMIC_STORE(&Source->current_buffer, newlist);
653             WriteUnlock(&Source->queue_lock);
654
655             /* Delete all elements in the previous queue */
656             while(oldlist != NULL)
657             {
658                 ALbufferlistitem *temp = oldlist;
659                 oldlist = temp->next;
660
661                 if(temp->buffer)
662                     DecrementRef(&temp->buffer->ref);
663                 free(temp);
664             }
665             return AL_TRUE;
666
667         case AL_SEC_OFFSET:
668         case AL_SAMPLE_OFFSET:
669         case AL_BYTE_OFFSET:
670             CHECKVAL(*values >= 0);
671
672             LockContext(Context);
673             Source->OffsetType = prop;
674             Source->Offset = *values;
675
676             if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
677                 !Context->DeferUpdates)
678             {
679                 WriteLock(&Source->queue_lock);
680                 if(ApplyOffset(Source) == AL_FALSE)
681                 {
682                     WriteUnlock(&Source->queue_lock);
683                     UnlockContext(Context);
684                     SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
685                 }
686                 WriteUnlock(&Source->queue_lock);
687             }
688             UnlockContext(Context);
689             return AL_TRUE;
690
691         case AL_DIRECT_FILTER:
692             CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
693
694             LockContext(Context);
695             if(!filter)
696             {
697                 Source->Direct.Gain = 1.0f;
698                 Source->Direct.GainHF = 1.0f;
699                 Source->Direct.HFReference = LOWPASSFREQREF;
700                 Source->Direct.GainLF = 1.0f;
701                 Source->Direct.LFReference = HIGHPASSFREQREF;
702             }
703             else
704             {
705                 Source->Direct.Gain = filter->Gain;
706                 Source->Direct.GainHF = filter->GainHF;
707                 Source->Direct.HFReference = filter->HFReference;
708                 Source->Direct.GainLF = filter->GainLF;
709                 Source->Direct.LFReference = filter->LFReference;
710             }
711             UnlockContext(Context);
712             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
713             return AL_TRUE;
714
715         case AL_DIRECT_FILTER_GAINHF_AUTO:
716             CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
717
718             Source->DryGainHFAuto = *values;
719             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
720             return AL_TRUE;
721
722         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
723             CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
724
725             Source->WetGainAuto = *values;
726             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
727             return AL_TRUE;
728
729         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
730             CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
731
732             Source->WetGainHFAuto = *values;
733             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
734             return AL_TRUE;
735
736         case AL_DIRECT_CHANNELS_SOFT:
737             CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
738
739             Source->DirectChannels = *values;
740             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
741             return AL_TRUE;
742
743         case AL_DISTANCE_MODEL:
744             CHECKVAL(*values == AL_NONE ||
745                      *values == AL_INVERSE_DISTANCE ||
746                      *values == AL_INVERSE_DISTANCE_CLAMPED ||
747                      *values == AL_LINEAR_DISTANCE ||
748                      *values == AL_LINEAR_DISTANCE_CLAMPED ||
749                      *values == AL_EXPONENT_DISTANCE ||
750                      *values == AL_EXPONENT_DISTANCE_CLAMPED);
751
752             Source->DistanceModel = *values;
753             if(Context->SourceDistanceModel)
754                 ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
755             return AL_TRUE;
756
757
758         case AL_AUXILIARY_SEND_FILTER:
759             LockContext(Context);
760             if(!((ALuint)values[1] < device->NumAuxSends &&
761                  (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) &&
762                  (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)))
763             {
764                 UnlockContext(Context);
765                 SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
766             }
767
768             /* Add refcount on the new slot, and release the previous slot */
769             if(slot) IncrementRef(&slot->ref);
770             slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot);
771             if(slot) DecrementRef(&slot->ref);
772
773             if(!filter)
774             {
775                 /* Disable filter */
776                 Source->Send[values[1]].Gain = 1.0f;
777                 Source->Send[values[1]].GainHF = 1.0f;
778                 Source->Send[values[1]].HFReference = LOWPASSFREQREF;
779                 Source->Send[values[1]].GainLF = 1.0f;
780                 Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
781             }
782             else
783             {
784                 Source->Send[values[1]].Gain = filter->Gain;
785                 Source->Send[values[1]].GainHF = filter->GainHF;
786                 Source->Send[values[1]].HFReference = filter->HFReference;
787                 Source->Send[values[1]].GainLF = filter->GainLF;
788                 Source->Send[values[1]].LFReference = filter->LFReference;
789             }
790             UnlockContext(Context);
791             ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
792             return AL_TRUE;
793
794
795         /* 1x float */
796         case AL_CONE_INNER_ANGLE:
797         case AL_CONE_OUTER_ANGLE:
798         case AL_PITCH:
799         case AL_GAIN:
800         case AL_MIN_GAIN:
801         case AL_MAX_GAIN:
802         case AL_REFERENCE_DISTANCE:
803         case AL_ROLLOFF_FACTOR:
804         case AL_CONE_OUTER_GAIN:
805         case AL_MAX_DISTANCE:
806         case AL_DOPPLER_FACTOR:
807         case AL_CONE_OUTER_GAINHF:
808         case AL_AIR_ABSORPTION_FACTOR:
809         case AL_ROOM_ROLLOFF_FACTOR:
810             fvals[0] = (ALfloat)*values;
811             return SetSourcefv(Source, Context, (int)prop, fvals);
812
813         /* 3x float */
814         case AL_POSITION:
815         case AL_VELOCITY:
816         case AL_DIRECTION:
817             fvals[0] = (ALfloat)values[0];
818             fvals[1] = (ALfloat)values[1];
819             fvals[2] = (ALfloat)values[2];
820             return SetSourcefv(Source, Context, (int)prop, fvals);
821
822         /* 6x float */
823         case AL_ORIENTATION:
824             fvals[0] = (ALfloat)values[0];
825             fvals[1] = (ALfloat)values[1];
826             fvals[2] = (ALfloat)values[2];
827             fvals[3] = (ALfloat)values[3];
828             fvals[4] = (ALfloat)values[4];
829             fvals[5] = (ALfloat)values[5];
830             return SetSourcefv(Source, Context, (int)prop, fvals);
831
832         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
833         case AL_SEC_OFFSET_LATENCY_SOFT:
834             break;
835     }
836
837     ERR("Unexpected property: 0x%04x\n", prop);
838     SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
839 }
840
841 static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
842 {
843     ALfloat fvals[6];
844     ALint   ivals[3];
845
846     switch(prop)
847     {
848         case AL_SOURCE_TYPE:
849         case AL_BUFFERS_QUEUED:
850         case AL_BUFFERS_PROCESSED:
851         case AL_SOURCE_STATE:
852         case AL_SAMPLE_RW_OFFSETS_SOFT:
853         case AL_BYTE_RW_OFFSETS_SOFT:
854         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
855         case AL_BYTE_LENGTH_SOFT:
856         case AL_SAMPLE_LENGTH_SOFT:
857         case AL_SEC_LENGTH_SOFT:
858             /* Query only */
859             SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
860
861
862         /* 1x int */
863         case AL_SOURCE_RELATIVE:
864         case AL_LOOPING:
865         case AL_SEC_OFFSET:
866         case AL_SAMPLE_OFFSET:
867         case AL_BYTE_OFFSET:
868         case AL_DIRECT_FILTER_GAINHF_AUTO:
869         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
870         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
871         case AL_DIRECT_CHANNELS_SOFT:
872         case AL_DISTANCE_MODEL:
873             CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
874
875             ivals[0] = (ALint)*values;
876             return SetSourceiv(Source, Context, (int)prop, ivals);
877
878         /* 1x uint */
879         case AL_BUFFER:
880         case AL_DIRECT_FILTER:
881             CHECKVAL(*values <= UINT_MAX && *values >= 0);
882
883             ivals[0] = (ALuint)*values;
884             return SetSourceiv(Source, Context, (int)prop, ivals);
885
886         /* 3x uint */
887         case AL_AUXILIARY_SEND_FILTER:
888             CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
889                      values[1] <= UINT_MAX && values[1] >= 0 &&
890                      values[2] <= UINT_MAX && values[2] >= 0);
891
892             ivals[0] = (ALuint)values[0];
893             ivals[1] = (ALuint)values[1];
894             ivals[2] = (ALuint)values[2];
895             return SetSourceiv(Source, Context, (int)prop, ivals);
896
897         /* 1x float */
898         case AL_CONE_INNER_ANGLE:
899         case AL_CONE_OUTER_ANGLE:
900         case AL_PITCH:
901         case AL_GAIN:
902         case AL_MIN_GAIN:
903         case AL_MAX_GAIN:
904         case AL_REFERENCE_DISTANCE:
905         case AL_ROLLOFF_FACTOR:
906         case AL_CONE_OUTER_GAIN:
907         case AL_MAX_DISTANCE:
908         case AL_DOPPLER_FACTOR:
909         case AL_CONE_OUTER_GAINHF:
910         case AL_AIR_ABSORPTION_FACTOR:
911         case AL_ROOM_ROLLOFF_FACTOR:
912             fvals[0] = (ALfloat)*values;
913             return SetSourcefv(Source, Context, (int)prop, fvals);
914
915         /* 3x float */
916         case AL_POSITION:
917         case AL_VELOCITY:
918         case AL_DIRECTION:
919             fvals[0] = (ALfloat)values[0];
920             fvals[1] = (ALfloat)values[1];
921             fvals[2] = (ALfloat)values[2];
922             return SetSourcefv(Source, Context, (int)prop, fvals);
923
924         /* 6x float */
925         case AL_ORIENTATION:
926             fvals[0] = (ALfloat)values[0];
927             fvals[1] = (ALfloat)values[1];
928             fvals[2] = (ALfloat)values[2];
929             fvals[3] = (ALfloat)values[3];
930             fvals[4] = (ALfloat)values[4];
931             fvals[5] = (ALfloat)values[5];
932             return SetSourcefv(Source, Context, (int)prop, fvals);
933
934         case AL_SEC_OFFSET_LATENCY_SOFT:
935             break;
936     }
937
938     ERR("Unexpected property: 0x%04x\n", prop);
939     SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
940 }
941
942 #undef CHECKVAL
943
944
945 static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
946 {
947     ALCdevice *device = Context->Device;
948     ALbufferlistitem *BufferList;
949     ALdouble offsets[2];
950     ALdouble updateLen;
951     ALint ivals[3];
952     ALboolean err;
953
954     switch(prop)
955     {
956         case AL_GAIN:
957             *values = Source->Gain;
958             return AL_TRUE;
959
960         case AL_PITCH:
961             *values = Source->Pitch;
962             return AL_TRUE;
963
964         case AL_MAX_DISTANCE:
965             *values = Source->MaxDistance;
966             return AL_TRUE;
967
968         case AL_ROLLOFF_FACTOR:
969             *values = Source->RollOffFactor;
970             return AL_TRUE;
971
972         case AL_REFERENCE_DISTANCE:
973             *values = Source->RefDistance;
974             return AL_TRUE;
975
976         case AL_CONE_INNER_ANGLE:
977             *values = Source->InnerAngle;
978             return AL_TRUE;
979
980         case AL_CONE_OUTER_ANGLE:
981             *values = Source->OuterAngle;
982             return AL_TRUE;
983
984         case AL_MIN_GAIN:
985             *values = Source->MinGain;
986             return AL_TRUE;
987
988         case AL_MAX_GAIN:
989             *values = Source->MaxGain;
990             return AL_TRUE;
991
992         case AL_CONE_OUTER_GAIN:
993             *values = Source->OuterGain;
994             return AL_TRUE;
995
996         case AL_SEC_OFFSET:
997         case AL_SAMPLE_OFFSET:
998         case AL_BYTE_OFFSET:
999             LockContext(Context);
1000             GetSourceOffsets(Source, prop, offsets, 0.0);
1001             UnlockContext(Context);
1002             *values = offsets[0];
1003             return AL_TRUE;
1004
1005         case AL_CONE_OUTER_GAINHF:
1006             *values = Source->OuterGainHF;
1007             return AL_TRUE;
1008
1009         case AL_AIR_ABSORPTION_FACTOR:
1010             *values = Source->AirAbsorptionFactor;
1011             return AL_TRUE;
1012
1013         case AL_ROOM_ROLLOFF_FACTOR:
1014             *values = Source->RoomRolloffFactor;
1015             return AL_TRUE;
1016
1017         case AL_DOPPLER_FACTOR:
1018             *values = Source->DopplerFactor;
1019             return AL_TRUE;
1020
1021         case AL_SEC_LENGTH_SOFT:
1022             ReadLock(&Source->queue_lock);
1023             if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1024                 *values = 0;
1025             else
1026             {
1027                 ALint length = 0;
1028                 ALsizei freq = 1;
1029                 do {
1030                     ALbuffer *buffer = BufferList->buffer;
1031                     if(buffer && buffer->SampleLen > 0)
1032                     {
1033                         freq = buffer->Frequency;
1034                         length += buffer->SampleLen;
1035                     }
1036                 } while((BufferList=BufferList->next) != NULL);
1037                 *values = (ALdouble)length / (ALdouble)freq;
1038             }
1039             ReadUnlock(&Source->queue_lock);
1040             return AL_TRUE;
1041
1042         case AL_SAMPLE_RW_OFFSETS_SOFT:
1043         case AL_BYTE_RW_OFFSETS_SOFT:
1044             LockContext(Context);
1045             updateLen = (ALdouble)device->UpdateSize / device->Frequency;
1046             GetSourceOffsets(Source, prop, values, updateLen);
1047             UnlockContext(Context);
1048             return AL_TRUE;
1049
1050         case AL_SEC_OFFSET_LATENCY_SOFT:
1051             LockContext(Context);
1052             values[0] = GetSourceSecOffset(Source);
1053             values[1] = (ALdouble)(V0(device->Backend,getLatency)()) /
1054                         1000000000.0;
1055             UnlockContext(Context);
1056             return AL_TRUE;
1057
1058         case AL_POSITION:
1059             LockContext(Context);
1060             values[0] = Source->Position.v[0];
1061             values[1] = Source->Position.v[1];
1062             values[2] = Source->Position.v[2];
1063             UnlockContext(Context);
1064             return AL_TRUE;
1065
1066         case AL_VELOCITY:
1067             LockContext(Context);
1068             values[0] = Source->Velocity.v[0];
1069             values[1] = Source->Velocity.v[1];
1070             values[2] = Source->Velocity.v[2];
1071             UnlockContext(Context);
1072             return AL_TRUE;
1073
1074         case AL_DIRECTION:
1075             LockContext(Context);
1076             values[0] = Source->Direction.v[0];
1077             values[1] = Source->Direction.v[1];
1078             values[2] = Source->Direction.v[2];
1079             UnlockContext(Context);
1080             return AL_TRUE;
1081
1082         case AL_ORIENTATION:
1083             LockContext(Context);
1084             values[0] = Source->Orientation[0][0];
1085             values[1] = Source->Orientation[0][1];
1086             values[2] = Source->Orientation[0][2];
1087             values[3] = Source->Orientation[1][0];
1088             values[4] = Source->Orientation[1][1];
1089             values[5] = Source->Orientation[1][2];
1090             UnlockContext(Context);
1091             return AL_TRUE;
1092
1093         /* 1x int */
1094         case AL_SOURCE_RELATIVE:
1095         case AL_LOOPING:
1096         case AL_SOURCE_STATE:
1097         case AL_BUFFERS_QUEUED:
1098         case AL_BUFFERS_PROCESSED:
1099         case AL_SOURCE_TYPE:
1100         case AL_DIRECT_FILTER_GAINHF_AUTO:
1101         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1102         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1103         case AL_DIRECT_CHANNELS_SOFT:
1104         case AL_BYTE_LENGTH_SOFT:
1105         case AL_SAMPLE_LENGTH_SOFT:
1106         case AL_DISTANCE_MODEL:
1107             if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
1108                 *values = (ALdouble)ivals[0];
1109             return err;
1110
1111         case AL_BUFFER:
1112         case AL_DIRECT_FILTER:
1113         case AL_AUXILIARY_SEND_FILTER:
1114         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1115             break;
1116     }
1117
1118     ERR("Unexpected property: 0x%04x\n", prop);
1119     SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1120 }
1121
1122 static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
1123 {
1124     ALbufferlistitem *BufferList;
1125     ALdouble dvals[6];
1126     ALboolean err;
1127
1128     switch(prop)
1129     {
1130         case AL_SOURCE_RELATIVE:
1131             *values = Source->HeadRelative;
1132             return AL_TRUE;
1133
1134         case AL_LOOPING:
1135             *values = Source->Looping;
1136             return AL_TRUE;
1137
1138         case AL_BUFFER:
1139             ReadLock(&Source->queue_lock);
1140             BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) :
1141                                                              ATOMIC_LOAD(&Source->current_buffer);
1142             *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
1143             ReadUnlock(&Source->queue_lock);
1144             return AL_TRUE;
1145
1146         case AL_SOURCE_STATE:
1147             *values = Source->state;
1148             return AL_TRUE;
1149
1150         case AL_BYTE_LENGTH_SOFT:
1151             ReadLock(&Source->queue_lock);
1152             if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1153                 *values = 0;
1154             else
1155             {
1156                 ALint length = 0;
1157                 do {
1158                     ALbuffer *buffer = BufferList->buffer;
1159                     if(buffer && buffer->SampleLen > 0)
1160                     {
1161                         ALuint byte_align, sample_align;
1162                         if(buffer->OriginalType == UserFmtIMA4)
1163                         {
1164                             ALsizei align = (buffer->OriginalAlign-1)/2 + 4;
1165                             byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1166                             sample_align = buffer->OriginalAlign;
1167                         }
1168                         else if(buffer->OriginalType == UserFmtMSADPCM)
1169                         {
1170                             ALsizei align = (buffer->OriginalAlign-2)/2 + 7;
1171                             byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1172                             sample_align = buffer->OriginalAlign;
1173                         }
1174                         else
1175                         {
1176                             ALsizei align = buffer->OriginalAlign;
1177                             byte_align = align * ChannelsFromFmt(buffer->FmtChannels);
1178                             sample_align = buffer->OriginalAlign;
1179                         }
1180
1181                         length += buffer->SampleLen / sample_align * byte_align;
1182                     }
1183                 } while((BufferList=BufferList->next) != NULL);
1184                 *values = length;
1185             }
1186             ReadUnlock(&Source->queue_lock);
1187             return AL_TRUE;
1188
1189         case AL_SAMPLE_LENGTH_SOFT:
1190             ReadLock(&Source->queue_lock);
1191             if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1192                 *values = 0;
1193             else
1194             {
1195                 ALint length = 0;
1196                 do {
1197                     ALbuffer *buffer = BufferList->buffer;
1198                     if(buffer) length += buffer->SampleLen;
1199                 } while((BufferList=BufferList->next) != NULL);
1200                 *values = length;
1201             }
1202             ReadUnlock(&Source->queue_lock);
1203             return AL_TRUE;
1204
1205         case AL_BUFFERS_QUEUED:
1206             ReadLock(&Source->queue_lock);
1207             if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
1208                 *values = 0;
1209             else
1210             {
1211                 ALsizei count = 0;
1212                 do {
1213                     ++count;
1214                 } while((BufferList=BufferList->next) != NULL);
1215                 *values = count;
1216             }
1217             ReadUnlock(&Source->queue_lock);
1218             return AL_TRUE;
1219
1220         case AL_BUFFERS_PROCESSED:
1221             ReadLock(&Source->queue_lock);
1222             if(Source->Looping || Source->SourceType != AL_STREAMING)
1223             {
1224                 /* Buffers on a looping source are in a perpetual state of
1225                  * PENDING, so don't report any as PROCESSED */
1226                 *values = 0;
1227             }
1228             else
1229             {
1230                 const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue);
1231                 const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer);
1232                 ALsizei played = 0;
1233                 while(BufferList && BufferList != Current)
1234                 {
1235                     played++;
1236                     BufferList = BufferList->next;
1237                 }
1238                 *values = played;
1239             }
1240             ReadUnlock(&Source->queue_lock);
1241             return AL_TRUE;
1242
1243         case AL_SOURCE_TYPE:
1244             *values = Source->SourceType;
1245             return AL_TRUE;
1246
1247         case AL_DIRECT_FILTER_GAINHF_AUTO:
1248             *values = Source->DryGainHFAuto;
1249             return AL_TRUE;
1250
1251         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1252             *values = Source->WetGainAuto;
1253             return AL_TRUE;
1254
1255         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1256             *values = Source->WetGainHFAuto;
1257             return AL_TRUE;
1258
1259         case AL_DIRECT_CHANNELS_SOFT:
1260             *values = Source->DirectChannels;
1261             return AL_TRUE;
1262
1263         case AL_DISTANCE_MODEL:
1264             *values = Source->DistanceModel;
1265             return AL_TRUE;
1266
1267         /* 1x float/double */
1268         case AL_CONE_INNER_ANGLE:
1269         case AL_CONE_OUTER_ANGLE:
1270         case AL_PITCH:
1271         case AL_GAIN:
1272         case AL_MIN_GAIN:
1273         case AL_MAX_GAIN:
1274         case AL_REFERENCE_DISTANCE:
1275         case AL_ROLLOFF_FACTOR:
1276         case AL_CONE_OUTER_GAIN:
1277         case AL_MAX_DISTANCE:
1278         case AL_SEC_OFFSET:
1279         case AL_SAMPLE_OFFSET:
1280         case AL_BYTE_OFFSET:
1281         case AL_DOPPLER_FACTOR:
1282         case AL_AIR_ABSORPTION_FACTOR:
1283         case AL_ROOM_ROLLOFF_FACTOR:
1284         case AL_CONE_OUTER_GAINHF:
1285         case AL_SEC_LENGTH_SOFT:
1286             if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1287                 *values = (ALint)dvals[0];
1288             return err;
1289
1290         /* 2x float/double */
1291         case AL_SAMPLE_RW_OFFSETS_SOFT:
1292         case AL_BYTE_RW_OFFSETS_SOFT:
1293             if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1294             {
1295                 values[0] = (ALint)dvals[0];
1296                 values[1] = (ALint)dvals[1];
1297             }
1298             return err;
1299
1300         /* 3x float/double */
1301         case AL_POSITION:
1302         case AL_VELOCITY:
1303         case AL_DIRECTION:
1304             if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1305             {
1306                 values[0] = (ALint)dvals[0];
1307                 values[1] = (ALint)dvals[1];
1308                 values[2] = (ALint)dvals[2];
1309             }
1310             return err;
1311
1312         /* 6x float/double */
1313         case AL_ORIENTATION:
1314             if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1315             {
1316                 values[0] = (ALint)dvals[0];
1317                 values[1] = (ALint)dvals[1];
1318                 values[2] = (ALint)dvals[2];
1319                 values[3] = (ALint)dvals[3];
1320                 values[4] = (ALint)dvals[4];
1321                 values[5] = (ALint)dvals[5];
1322             }
1323             return err;
1324
1325         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1326             break; /* i64 only */
1327         case AL_SEC_OFFSET_LATENCY_SOFT:
1328             break; /* Double only */
1329
1330         case AL_DIRECT_FILTER:
1331         case AL_AUXILIARY_SEND_FILTER:
1332             break; /* ??? */
1333     }
1334
1335     ERR("Unexpected property: 0x%04x\n", prop);
1336     SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1337 }
1338
1339 static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
1340 {
1341     ALCdevice *device = Context->Device;
1342     ALdouble dvals[6];
1343     ALint ivals[3];
1344     ALboolean err;
1345
1346     switch(prop)
1347     {
1348         case AL_SAMPLE_OFFSET_LATENCY_SOFT:
1349             LockContext(Context);
1350             values[0] = GetSourceSampleOffset(Source);
1351             values[1] = V0(device->Backend,getLatency)();
1352             UnlockContext(Context);
1353             return AL_TRUE;
1354
1355         /* 1x float/double */
1356         case AL_CONE_INNER_ANGLE:
1357         case AL_CONE_OUTER_ANGLE:
1358         case AL_PITCH:
1359         case AL_GAIN:
1360         case AL_MIN_GAIN:
1361         case AL_MAX_GAIN:
1362         case AL_REFERENCE_DISTANCE:
1363         case AL_ROLLOFF_FACTOR:
1364         case AL_CONE_OUTER_GAIN:
1365         case AL_MAX_DISTANCE:
1366         case AL_SEC_OFFSET:
1367         case AL_SAMPLE_OFFSET:
1368         case AL_BYTE_OFFSET:
1369         case AL_DOPPLER_FACTOR:
1370         case AL_AIR_ABSORPTION_FACTOR:
1371         case AL_ROOM_ROLLOFF_FACTOR:
1372         case AL_CONE_OUTER_GAINHF:
1373         case AL_SEC_LENGTH_SOFT:
1374             if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1375                 *values = (ALint64)dvals[0];
1376             return err;
1377
1378         /* 2x float/double */
1379         case AL_SAMPLE_RW_OFFSETS_SOFT:
1380         case AL_BYTE_RW_OFFSETS_SOFT:
1381             if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1382             {
1383                 values[0] = (ALint64)dvals[0];
1384                 values[1] = (ALint64)dvals[1];
1385             }
1386             return err;
1387
1388         /* 3x float/double */
1389         case AL_POSITION:
1390         case AL_VELOCITY:
1391         case AL_DIRECTION:
1392             if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1393             {
1394                 values[0] = (ALint64)dvals[0];
1395                 values[1] = (ALint64)dvals[1];
1396                 values[2] = (ALint64)dvals[2];
1397             }
1398             return err;
1399
1400         /* 6x float/double */
1401         case AL_ORIENTATION:
1402             if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
1403             {
1404                 values[0] = (ALint64)dvals[0];
1405                 values[1] = (ALint64)dvals[1];
1406                 values[2] = (ALint64)dvals[2];
1407                 values[3] = (ALint64)dvals[3];
1408                 values[4] = (ALint64)dvals[4];
1409                 values[5] = (ALint64)dvals[5];
1410             }
1411             return err;
1412
1413         /* 1x int */
1414         case AL_SOURCE_RELATIVE:
1415         case AL_LOOPING:
1416         case AL_SOURCE_STATE:
1417         case AL_BUFFERS_QUEUED:
1418         case AL_BUFFERS_PROCESSED:
1419         case AL_BYTE_LENGTH_SOFT:
1420         case AL_SAMPLE_LENGTH_SOFT:
1421         case AL_SOURCE_TYPE:
1422         case AL_DIRECT_FILTER_GAINHF_AUTO:
1423         case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1424         case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1425         case AL_DIRECT_CHANNELS_SOFT:
1426         case AL_DISTANCE_MODEL:
1427             if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1428                 *values = ivals[0];
1429             return err;
1430
1431         /* 1x uint */
1432         case AL_BUFFER:
1433         case AL_DIRECT_FILTER:
1434             if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1435                 *values = (ALuint)ivals[0];
1436             return err;
1437
1438         /* 3x uint */
1439         case AL_AUXILIARY_SEND_FILTER:
1440             if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
1441             {
1442                 values[0] = (ALuint)ivals[0];
1443                 values[1] = (ALuint)ivals[1];
1444                 values[2] = (ALuint)ivals[2];
1445             }
1446             return err;
1447
1448         case AL_SEC_OFFSET_LATENCY_SOFT:
1449             break; /* Double only */
1450     }
1451
1452     ERR("Unexpected property: 0x%04x\n", prop);
1453     SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
1454 }
1455
1456
1457 AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
1458 {
1459     ALCcontext *context;
1460     ALsizei cur = 0;
1461     ALenum err;
1462
1463     context = GetContextRef();
1464     if(!context) return;
1465
1466     if(!(n >= 0))
1467         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1468     for(cur = 0;cur < n;cur++)
1469     {
1470         ALsource *source = al_calloc(16, sizeof(ALsource));
1471         if(!source)
1472         {
1473             alDeleteSources(cur, sources);
1474             SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
1475         }
1476         InitSourceParams(source);
1477
1478         err = NewThunkEntry(&source->id);
1479         if(err == AL_NO_ERROR)
1480             err = InsertUIntMapEntry(&context->SourceMap, source->id, source);
1481         if(err != AL_NO_ERROR)
1482         {
1483             FreeThunkEntry(source->id);
1484             memset(source, 0, sizeof(ALsource));
1485             al_free(source);
1486
1487             alDeleteSources(cur, sources);
1488             SET_ERROR_AND_GOTO(context, err, done);
1489         }
1490
1491         sources[cur] = source->id;
1492     }
1493
1494 done:
1495     ALCcontext_DecRef(context);
1496 }
1497
1498
1499 AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
1500 {
1501     ALCcontext *context;
1502     ALbufferlistitem *BufferList;
1503     ALsource *Source;
1504     ALsizei i, j;
1505
1506     context = GetContextRef();
1507     if(!context) return;
1508
1509     if(!(n >= 0))
1510         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
1511
1512     /* Check that all Sources are valid */
1513     for(i = 0;i < n;i++)
1514     {
1515         if(LookupSource(context, sources[i]) == NULL)
1516             SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
1517     }
1518     for(i = 0;i < n;i++)
1519     {
1520         ALvoice *voice, *voice_end;
1521
1522         if((Source=RemoveSource(context, sources[i])) == NULL)
1523             continue;
1524         FreeThunkEntry(Source->id);
1525
1526         LockContext(context);
1527         voice = context->Voices;
1528         voice_end = voice + context->VoiceCount;
1529         while(voice != voice_end)
1530         {
1531             ALsource *old = Source;
1532             if(COMPARE_EXCHANGE(&voice->Source, &old, NULL))
1533                 break;
1534             voice++;
1535         }
1536         UnlockContext(context);
1537
1538         BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, NULL);
1539         while(BufferList != NULL)
1540         {
1541             ALbufferlistitem *next = BufferList->next;
1542             if(BufferList->buffer != NULL)
1543                 DecrementRef(&BufferList->buffer->ref);
1544             free(BufferList);
1545             BufferList = next;
1546         }
1547
1548         for(j = 0;j < MAX_SENDS;++j)
1549         {
1550             if(Source->Send[j].Slot)
1551                 DecrementRef(&Source->Send[j].Slot->ref);
1552             Source->Send[j].Slot = NULL;
1553         }
1554
1555         memset(Source, 0, sizeof(*Source));
1556         al_free(Source);
1557     }
1558
1559 done:
1560     ALCcontext_DecRef(context);
1561 }
1562
1563
1564 AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
1565 {
1566     ALCcontext *context;
1567     ALboolean ret;
1568
1569     context = GetContextRef();
1570     if(!context) return AL_FALSE;
1571
1572     ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE);
1573
1574     ALCcontext_DecRef(context);
1575
1576     return ret;
1577 }
1578
1579
1580 AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
1581 {
1582     ALCcontext *Context;
1583     ALsource   *Source;
1584
1585     Context = GetContextRef();
1586     if(!Context) return;
1587
1588     if((Source=LookupSource(Context, source)) == NULL)
1589         alSetError(Context, AL_INVALID_NAME);
1590     else if(!(FloatValsByProp(param) == 1))
1591         alSetError(Context, AL_INVALID_ENUM);
1592     else
1593         SetSourcefv(Source, Context, param, &value);
1594
1595     ALCcontext_DecRef(Context);
1596 }
1597
1598 AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
1599 {
1600     ALCcontext *Context;
1601     ALsource   *Source;
1602
1603     Context = GetContextRef();
1604     if(!Context) return;
1605
1606     if((Source=LookupSource(Context, source)) == NULL)
1607         alSetError(Context, AL_INVALID_NAME);
1608     else if(!(FloatValsByProp(param) == 3))
1609         alSetError(Context, AL_INVALID_ENUM);
1610     else
1611     {
1612         ALfloat fvals[3] = { value1, value2, value3 };
1613         SetSourcefv(Source, Context, param, fvals);
1614     }
1615
1616     ALCcontext_DecRef(Context);
1617 }
1618
1619 AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
1620 {
1621     ALCcontext *Context;
1622     ALsource   *Source;
1623
1624     Context = GetContextRef();
1625     if(!Context) return;
1626
1627     if((Source=LookupSource(Context, source)) == NULL)
1628         alSetError(Context, AL_INVALID_NAME);
1629     else if(!values)
1630         alSetError(Context, AL_INVALID_VALUE);
1631     else if(!(FloatValsByProp(param) > 0))
1632         alSetError(Context, AL_INVALID_ENUM);
1633     else
1634         SetSourcefv(Source, Context, param, values);
1635
1636     ALCcontext_DecRef(Context);
1637 }
1638
1639
1640 AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
1641 {
1642     ALCcontext *Context;
1643     ALsource   *Source;
1644
1645     Context = GetContextRef();
1646     if(!Context) return;
1647
1648     if((Source=LookupSource(Context, source)) == NULL)
1649         alSetError(Context, AL_INVALID_NAME);
1650     else if(!(DoubleValsByProp(param) == 1))
1651         alSetError(Context, AL_INVALID_ENUM);
1652     else
1653     {
1654         ALfloat fval = (ALfloat)value;
1655         SetSourcefv(Source, Context, param, &fval);
1656     }
1657
1658     ALCcontext_DecRef(Context);
1659 }
1660
1661 AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
1662 {
1663     ALCcontext *Context;
1664     ALsource   *Source;
1665
1666     Context = GetContextRef();
1667     if(!Context) return;
1668
1669     if((Source=LookupSource(Context, source)) == NULL)
1670         alSetError(Context, AL_INVALID_NAME);
1671     else if(!(DoubleValsByProp(param) == 3))
1672         alSetError(Context, AL_INVALID_ENUM);
1673     else
1674     {
1675         ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 };
1676         SetSourcefv(Source, Context, param, fvals);
1677     }
1678
1679     ALCcontext_DecRef(Context);
1680 }
1681
1682 AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
1683 {
1684     ALCcontext *Context;
1685     ALsource   *Source;
1686     ALint      count;
1687
1688     Context = GetContextRef();
1689     if(!Context) return;
1690
1691     if((Source=LookupSource(Context, source)) == NULL)
1692         alSetError(Context, AL_INVALID_NAME);
1693     else if(!values)
1694         alSetError(Context, AL_INVALID_VALUE);
1695     else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
1696         alSetError(Context, AL_INVALID_ENUM);
1697     else
1698     {
1699         ALfloat fvals[6];
1700         ALint i;
1701
1702         for(i = 0;i < count;i++)
1703             fvals[i] = (ALfloat)values[i];
1704         SetSourcefv(Source, Context, param, fvals);
1705     }
1706
1707     ALCcontext_DecRef(Context);
1708 }
1709
1710
1711 AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
1712 {
1713     ALCcontext *Context;
1714     ALsource   *Source;
1715
1716     Context = GetContextRef();
1717     if(!Context) return;
1718
1719     if((Source=LookupSource(Context, source)) == NULL)
1720         alSetError(Context, AL_INVALID_NAME);
1721     else if(!(IntValsByProp(param) == 1))
1722         alSetError(Context, AL_INVALID_ENUM);
1723     else
1724         SetSourceiv(Source, Context, param, &value);
1725
1726     ALCcontext_DecRef(Context);
1727 }
1728
1729 AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
1730 {
1731     ALCcontext *Context;
1732     ALsource   *Source;
1733
1734     Context = GetContextRef();
1735     if(!Context) return;
1736
1737     if((Source=LookupSource(Context, source)) == NULL)
1738         alSetError(Context, AL_INVALID_NAME);
1739     else if(!(IntValsByProp(param) == 3))
1740         alSetError(Context, AL_INVALID_ENUM);
1741     else
1742     {
1743         ALint ivals[3] = { value1, value2, value3 };
1744         SetSourceiv(Source, Context, param, ivals);
1745     }
1746
1747     ALCcontext_DecRef(Context);
1748 }
1749
1750 AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
1751 {
1752     ALCcontext *Context;
1753     ALsource   *Source;
1754
1755     Context = GetContextRef();
1756     if(!Context) return;
1757
1758     if((Source=LookupSource(Context, source)) == NULL)
1759         alSetError(Context, AL_INVALID_NAME);
1760     else if(!values)
1761         alSetError(Context, AL_INVALID_VALUE);
1762     else if(!(IntValsByProp(param) > 0))
1763         alSetError(Context, AL_INVALID_ENUM);
1764     else
1765         SetSourceiv(Source, Context, param, values);
1766
1767     ALCcontext_DecRef(Context);
1768 }
1769
1770
1771 AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
1772 {
1773     ALCcontext *Context;
1774     ALsource   *Source;
1775
1776     Context = GetContextRef();
1777     if(!Context) return;
1778
1779     if((Source=LookupSource(Context, source)) == NULL)
1780         alSetError(Context, AL_INVALID_NAME);
1781     else if(!(Int64ValsByProp(param) == 1))
1782         alSetError(Context, AL_INVALID_ENUM);
1783     else
1784         SetSourcei64v(Source, Context, param, &value);
1785
1786     ALCcontext_DecRef(Context);
1787 }
1788
1789 AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
1790 {
1791     ALCcontext *Context;
1792     ALsource   *Source;
1793
1794     Context = GetContextRef();
1795     if(!Context) return;
1796
1797     if((Source=LookupSource(Context, source)) == NULL)
1798         alSetError(Context, AL_INVALID_NAME);
1799     else if(!(Int64ValsByProp(param) == 3))
1800         alSetError(Context, AL_INVALID_ENUM);
1801     else
1802     {
1803         ALint64SOFT i64vals[3] = { value1, value2, value3 };
1804         SetSourcei64v(Source, Context, param, i64vals);
1805     }
1806
1807     ALCcontext_DecRef(Context);
1808 }
1809
1810 AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
1811 {
1812     ALCcontext *Context;
1813     ALsource   *Source;
1814
1815     Context = GetContextRef();
1816     if(!Context) return;
1817
1818     if((Source=LookupSource(Context, source)) == NULL)
1819         alSetError(Context, AL_INVALID_NAME);
1820     else if(!values)
1821         alSetError(Context, AL_INVALID_VALUE);
1822     else if(!(Int64ValsByProp(param) > 0))
1823         alSetError(Context, AL_INVALID_ENUM);
1824     else
1825         SetSourcei64v(Source, Context, param, values);
1826
1827     ALCcontext_DecRef(Context);
1828 }
1829
1830
1831 AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
1832 {
1833     ALCcontext *Context;
1834     ALsource   *Source;
1835
1836     Context = GetContextRef();
1837     if(!Context) return;
1838
1839     if((Source=LookupSource(Context, source)) == NULL)
1840         alSetError(Context, AL_INVALID_NAME);
1841     else if(!value)
1842         alSetError(Context, AL_INVALID_VALUE);
1843     else if(!(FloatValsByProp(param) == 1))
1844         alSetError(Context, AL_INVALID_ENUM);
1845     else
1846     {
1847         ALdouble dval;
1848         if(GetSourcedv(Source, Context, param, &dval))
1849             *value = (ALfloat)dval;
1850     }
1851
1852     ALCcontext_DecRef(Context);
1853 }
1854
1855
1856 AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
1857 {
1858     ALCcontext *Context;
1859     ALsource   *Source;
1860
1861     Context = GetContextRef();
1862     if(!Context) return;
1863
1864     if((Source=LookupSource(Context, source)) == NULL)
1865         alSetError(Context, AL_INVALID_NAME);
1866     else if(!(value1 && value2 && value3))
1867         alSetError(Context, AL_INVALID_VALUE);
1868     else if(!(FloatValsByProp(param) == 3))
1869         alSetError(Context, AL_INVALID_ENUM);
1870     else
1871     {
1872         ALdouble dvals[3];
1873         if(GetSourcedv(Source, Context, param, dvals))
1874         {
1875             *value1 = (ALfloat)dvals[0];
1876             *value2 = (ALfloat)dvals[1];
1877             *value3 = (ALfloat)dvals[2];
1878         }
1879     }
1880
1881     ALCcontext_DecRef(Context);
1882 }
1883
1884
1885 AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
1886 {
1887     ALCcontext *Context;
1888     ALsource   *Source;
1889     ALint      count;
1890
1891     Context = GetContextRef();
1892     if(!Context) return;
1893
1894     if((Source=LookupSource(Context, source)) == NULL)
1895         alSetError(Context, AL_INVALID_NAME);
1896     else if(!values)
1897         alSetError(Context, AL_INVALID_VALUE);
1898     else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
1899         alSetError(Context, AL_INVALID_ENUM);
1900     else
1901     {
1902         ALdouble dvals[6];
1903         if(GetSourcedv(Source, Context, param, dvals))
1904         {
1905             ALint i;
1906             for(i = 0;i < count;i++)
1907                 values[i] = (ALfloat)dvals[i];
1908         }
1909     }
1910
1911     ALCcontext_DecRef(Context);
1912 }
1913
1914
1915 AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
1916 {
1917     ALCcontext *Context;
1918     ALsource   *Source;
1919
1920     Context = GetContextRef();
1921     if(!Context) return;
1922
1923     if((Source=LookupSource(Context, source)) == NULL)
1924         alSetError(Context, AL_INVALID_NAME);
1925     else if(!value)
1926         alSetError(Context, AL_INVALID_VALUE);
1927     else if(!(DoubleValsByProp(param) == 1))
1928         alSetError(Context, AL_INVALID_ENUM);
1929     else
1930         GetSourcedv(Source, Context, param, value);
1931
1932     ALCcontext_DecRef(Context);
1933 }
1934
1935 AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
1936 {
1937     ALCcontext *Context;
1938     ALsource   *Source;
1939
1940     Context = GetContextRef();
1941     if(!Context) return;
1942
1943     if((Source=LookupSource(Context, source)) == NULL)
1944         alSetError(Context, AL_INVALID_NAME);
1945     else if(!(value1 && value2 && value3))
1946         alSetError(Context, AL_INVALID_VALUE);
1947     else if(!(DoubleValsByProp(param) == 3))
1948         alSetError(Context, AL_INVALID_ENUM);
1949     else
1950     {
1951         ALdouble dvals[3];
1952         if(GetSourcedv(Source, Context, param, dvals))
1953         {
1954             *value1 = dvals[0];
1955             *value2 = dvals[1];
1956             *value3 = dvals[2];
1957         }
1958     }
1959
1960     ALCcontext_DecRef(Context);
1961 }
1962
1963 AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
1964 {
1965     ALCcontext *Context;
1966     ALsource   *Source;
1967
1968     Context = GetContextRef();
1969     if(!Context) return;
1970
1971     if((Source=LookupSource(Context, source)) == NULL)
1972         alSetError(Context, AL_INVALID_NAME);
1973     else if(!values)
1974         alSetError(Context, AL_INVALID_VALUE);
1975     else if(!(DoubleValsByProp(param) > 0))
1976         alSetError(Context, AL_INVALID_ENUM);
1977     else
1978         GetSourcedv(Source, Context, param, values);
1979
1980     ALCcontext_DecRef(Context);
1981 }
1982
1983
1984 AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
1985 {
1986     ALCcontext *Context;
1987     ALsource   *Source;
1988
1989     Context = GetContextRef();
1990     if(!Context) return;
1991
1992     if((Source=LookupSource(Context, source)) == NULL)
1993         alSetError(Context, AL_INVALID_NAME);
1994     else if(!value)
1995         alSetError(Context, AL_INVALID_VALUE);
1996     else if(!(IntValsByProp(param) == 1))
1997         alSetError(Context, AL_INVALID_ENUM);
1998     else
1999         GetSourceiv(Source, Context, param, value);
2000
2001     ALCcontext_DecRef(Context);
2002 }
2003
2004
2005 AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
2006 {
2007     ALCcontext *Context;
2008     ALsource   *Source;
2009
2010     Context = GetContextRef();
2011     if(!Context) return;
2012
2013     if((Source=LookupSource(Context, source)) == NULL)
2014         alSetError(Context, AL_INVALID_NAME);
2015     else if(!(value1 && value2 && value3))
2016         alSetError(Context, AL_INVALID_VALUE);
2017     else if(!(IntValsByProp(param) == 3))
2018         alSetError(Context, AL_INVALID_ENUM);
2019     else
2020     {
2021         ALint ivals[3];
2022         if(GetSourceiv(Source, Context, param, ivals))
2023         {
2024             *value1 = ivals[0];
2025             *value2 = ivals[1];
2026             *value3 = ivals[2];
2027         }
2028     }
2029
2030     ALCcontext_DecRef(Context);
2031 }
2032
2033
2034 AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
2035 {
2036     ALCcontext *Context;
2037     ALsource   *Source;
2038
2039     Context = GetContextRef();
2040     if(!Context) return;
2041
2042     if((Source=LookupSource(Context, source)) == NULL)
2043         alSetError(Context, AL_INVALID_NAME);
2044     else if(!values)
2045         alSetError(Context, AL_INVALID_VALUE);
2046     else if(!(IntValsByProp(param) > 0))
2047         alSetError(Context, AL_INVALID_ENUM);
2048     else
2049         GetSourceiv(Source, Context, param, values);
2050
2051     ALCcontext_DecRef(Context);
2052 }
2053
2054
2055 AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
2056 {
2057     ALCcontext *Context;
2058     ALsource   *Source;
2059
2060     Context = GetContextRef();
2061     if(!Context) return;
2062
2063     if((Source=LookupSource(Context, source)) == NULL)
2064         alSetError(Context, AL_INVALID_NAME);
2065     else if(!value)
2066         alSetError(Context, AL_INVALID_VALUE);
2067     else if(!(Int64ValsByProp(param) == 1))
2068         alSetError(Context, AL_INVALID_ENUM);
2069     else
2070         GetSourcei64v(Source, Context, param, value);
2071
2072     ALCcontext_DecRef(Context);
2073 }
2074
2075 AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
2076 {
2077     ALCcontext *Context;
2078     ALsource   *Source;
2079
2080     Context = GetContextRef();
2081     if(!Context) return;
2082
2083     if((Source=LookupSource(Context, source)) == NULL)
2084         alSetError(Context, AL_INVALID_NAME);
2085     else if(!(value1 && value2 && value3))
2086         alSetError(Context, AL_INVALID_VALUE);
2087     else if(!(Int64ValsByProp(param) == 3))
2088         alSetError(Context, AL_INVALID_ENUM);
2089     else
2090     {
2091         ALint64 i64vals[3];
2092         if(GetSourcei64v(Source, Context, param, i64vals))
2093         {
2094             *value1 = i64vals[0];
2095             *value2 = i64vals[1];
2096             *value3 = i64vals[2];
2097         }
2098     }
2099
2100     ALCcontext_DecRef(Context);
2101 }
2102
2103 AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
2104 {
2105     ALCcontext *Context;
2106     ALsource   *Source;
2107
2108     Context = GetContextRef();
2109     if(!Context) return;
2110
2111     if((Source=LookupSource(Context, source)) == NULL)
2112         alSetError(Context, AL_INVALID_NAME);
2113     else if(!values)
2114         alSetError(Context, AL_INVALID_VALUE);
2115     else if(!(Int64ValsByProp(param) > 0))
2116         alSetError(Context, AL_INVALID_ENUM);
2117     else
2118         GetSourcei64v(Source, Context, param, values);
2119
2120     ALCcontext_DecRef(Context);
2121 }
2122
2123
2124 AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
2125 {
2126     alSourcePlayv(1, &source);
2127 }
2128 AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
2129 {
2130     ALCcontext *context;
2131     ALsource *source;
2132     ALsizei i;
2133
2134     context = GetContextRef();
2135     if(!context) return;
2136
2137     if(!(n >= 0))
2138         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2139     for(i = 0;i < n;i++)
2140     {
2141         if(!LookupSource(context, sources[i]))
2142             SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2143     }
2144
2145     LockContext(context);
2146     while(n > context->MaxVoices-context->VoiceCount)
2147     {
2148         ALvoice *temp = NULL;
2149         ALsizei newcount;
2150
2151         newcount = context->MaxVoices << 1;
2152         if(newcount > 0)
2153             temp = realloc(context->Voices, newcount * sizeof(context->Voices[0]));
2154         if(!temp)
2155         {
2156             UnlockContext(context);
2157             SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
2158         }
2159         memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0]));
2160
2161         context->Voices = temp;
2162         context->MaxVoices = newcount;
2163     }
2164
2165     for(i = 0;i < n;i++)
2166     {
2167         source = LookupSource(context, sources[i]);
2168         if(context->DeferUpdates) source->new_state = AL_PLAYING;
2169         else SetSourceState(source, context, AL_PLAYING);
2170     }
2171
2172 #ifdef __TIZEN__
2173     /* Resume device if device is paused by alcDevicePauseSOFT() in alSourcePausev() */
2174     alcDeviceResumeSOFT(context->Device);
2175 #endif
2176
2177     UnlockContext(context);
2178
2179 done:
2180     ALCcontext_DecRef(context);
2181 }
2182
2183 #ifdef __TIZEN__
2184 static ALboolean _alPlayingSourcesExists(ALCcontext *context)
2185 {
2186     ALsource *source = NULL;
2187     ALsizei i;
2188
2189     if (context == NULL)
2190     {
2191         /* As this is error case, I think device would be safe to keep active */
2192         return AL_TRUE;
2193     }
2194
2195     for(i = 0; i < context->SourceMap.size; i++)
2196     {
2197         source = (ALsource *)context->SourceMap.array[i].value;
2198         TRACE("[total:%d, index:%d, key:%d, state:%d]\n",
2199                 context->SourceMap.size, i, source->id, source->state);
2200         if(source->state == AL_PLAYING)
2201         {
2202             TRACE(" - source[%d] is still playing....\n", source->id);
2203             return AL_TRUE;
2204         }
2205     }
2206
2207     return AL_FALSE;
2208 }
2209 #endif
2210
2211 AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
2212 {
2213     alSourcePausev(1, &source);
2214 }
2215 AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
2216 {
2217     ALCcontext *context;
2218     ALsource *source;
2219     ALsizei i;
2220
2221     context = GetContextRef();
2222     if(!context) return;
2223
2224     if(!(n >= 0))
2225         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2226     for(i = 0;i < n;i++)
2227     {
2228         if(!LookupSource(context, sources[i]))
2229             SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2230     }
2231
2232     LockContext(context);
2233     for(i = 0;i < n;i++)
2234     {
2235         source = LookupSource(context, sources[i]);
2236         if(context->DeferUpdates) source->new_state = AL_PAUSED;
2237         else SetSourceState(source, context, AL_PAUSED);
2238     }
2239     UnlockContext(context);
2240
2241 #ifdef __TIZEN__
2242     /* if there are no playing sources, pause DEVICE to let backend device can suspend
2243        device will be resumed when one of source is going to be played by alSourcePlay */
2244     if(!_alPlayingSourcesExists(context))
2245     {
2246         TRACE("No playing source in this context, do alcDevicePauseSOFT()!");
2247         alcDevicePauseSOFT(context->Device);
2248      }
2249 #endif
2250
2251 done:
2252     ALCcontext_DecRef(context);
2253 }
2254
2255 AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
2256 {
2257     alSourceStopv(1, &source);
2258 }
2259 AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
2260 {
2261     ALCcontext *context;
2262     ALsource *source;
2263     ALsizei i;
2264
2265     context = GetContextRef();
2266     if(!context) return;
2267
2268     if(!(n >= 0))
2269         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2270     for(i = 0;i < n;i++)
2271     {
2272         if(!LookupSource(context, sources[i]))
2273             SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2274     }
2275
2276     LockContext(context);
2277     for(i = 0;i < n;i++)
2278     {
2279         source = LookupSource(context, sources[i]);
2280         source->new_state = AL_NONE;
2281         SetSourceState(source, context, AL_STOPPED);
2282     }
2283     UnlockContext(context);
2284
2285 done:
2286     ALCcontext_DecRef(context);
2287 }
2288
2289 AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
2290 {
2291     alSourceRewindv(1, &source);
2292 }
2293 AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
2294 {
2295     ALCcontext *context;
2296     ALsource *source;
2297     ALsizei i;
2298
2299     context = GetContextRef();
2300     if(!context) return;
2301
2302     if(!(n >= 0))
2303         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2304     for(i = 0;i < n;i++)
2305     {
2306         if(!LookupSource(context, sources[i]))
2307             SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2308     }
2309
2310     LockContext(context);
2311     for(i = 0;i < n;i++)
2312     {
2313         source = LookupSource(context, sources[i]);
2314         source->new_state = AL_NONE;
2315         SetSourceState(source, context, AL_INITIAL);
2316     }
2317     UnlockContext(context);
2318
2319 done:
2320     ALCcontext_DecRef(context);
2321 }
2322
2323
2324 AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
2325 {
2326     ALCdevice *device;
2327     ALCcontext *context;
2328     ALsource *source;
2329     ALsizei i;
2330     ALbufferlistitem *BufferListStart;
2331     ALbufferlistitem *BufferList;
2332     ALbuffer *BufferFmt = NULL;
2333
2334     if(nb == 0)
2335         return;
2336
2337     context = GetContextRef();
2338     if(!context) return;
2339
2340     device = context->Device;
2341
2342     if(!(nb >= 0))
2343         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2344     if((source=LookupSource(context, src)) == NULL)
2345         SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2346
2347     WriteLock(&source->queue_lock);
2348     if(source->SourceType == AL_STATIC)
2349     {
2350         WriteUnlock(&source->queue_lock);
2351         /* Can't queue on a Static Source */
2352         SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
2353     }
2354
2355     /* Check for a valid Buffer, for its frequency and format */
2356     BufferList = ATOMIC_LOAD(&source->queue);
2357     while(BufferList)
2358     {
2359         if(BufferList->buffer)
2360         {
2361             BufferFmt = BufferList->buffer;
2362             break;
2363         }
2364         BufferList = BufferList->next;
2365     }
2366
2367     BufferListStart = NULL;
2368     BufferList = NULL;
2369     for(i = 0;i < nb;i++)
2370     {
2371         ALbuffer *buffer = NULL;
2372         if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
2373         {
2374             WriteUnlock(&source->queue_lock);
2375             SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error);
2376         }
2377
2378         if(!BufferListStart)
2379         {
2380             BufferListStart = malloc(sizeof(ALbufferlistitem));
2381             BufferListStart->buffer = buffer;
2382             BufferListStart->next = NULL;
2383             BufferListStart->prev = NULL;
2384             BufferList = BufferListStart;
2385         }
2386         else
2387         {
2388             BufferList->next = malloc(sizeof(ALbufferlistitem));
2389             BufferList->next->buffer = buffer;
2390             BufferList->next->next = NULL;
2391             BufferList->next->prev = BufferList;
2392             BufferList = BufferList->next;
2393         }
2394         if(!buffer) continue;
2395
2396         /* Hold a read lock on each buffer being queued while checking all
2397          * provided buffers. This is done so other threads don't see an extra
2398          * reference on some buffers if this operation ends up failing. */
2399         ReadLock(&buffer->lock);
2400         IncrementRef(&buffer->ref);
2401
2402         if(BufferFmt == NULL)
2403         {
2404             BufferFmt = buffer;
2405
2406             source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
2407             source->SampleSize  = BytesFromFmt(buffer->FmtType);
2408         }
2409         else if(BufferFmt->Frequency != buffer->Frequency ||
2410                 BufferFmt->OriginalChannels != buffer->OriginalChannels ||
2411                 BufferFmt->OriginalType != buffer->OriginalType)
2412         {
2413             WriteUnlock(&source->queue_lock);
2414             SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error);
2415
2416         buffer_error:
2417             /* A buffer failed (invalid ID or format), so unlock and release
2418              * each buffer we had. */
2419             while(BufferList != NULL)
2420             {
2421                 ALbufferlistitem *prev = BufferList->prev;
2422                 if((buffer=BufferList->buffer) != NULL)
2423                 {
2424                     DecrementRef(&buffer->ref);
2425                     ReadUnlock(&buffer->lock);
2426                 }
2427                 free(BufferList);
2428                 BufferList = prev;
2429             }
2430             goto done;
2431         }
2432     }
2433     /* All buffers good, unlock them now. */
2434     while(BufferList != NULL)
2435     {
2436         ALbuffer *buffer = BufferList->buffer;
2437         if(buffer) ReadUnlock(&buffer->lock);
2438         BufferList = BufferList->prev;
2439     }
2440
2441     /* Source is now streaming */
2442     source->SourceType = AL_STREAMING;
2443
2444     BufferList = NULL;
2445     if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
2446     {
2447         /* Queue head is not NULL, append to the end of the queue */
2448         while(BufferList->next != NULL)
2449             BufferList = BufferList->next;
2450
2451         BufferListStart->prev = BufferList;
2452         BufferList->next = BufferListStart;
2453     }
2454     BufferList = NULL;
2455     ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
2456     WriteUnlock(&source->queue_lock);
2457
2458 done:
2459     ALCcontext_DecRef(context);
2460 }
2461
2462 AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
2463 {
2464     ALCcontext *context;
2465     ALsource *source;
2466     ALbufferlistitem *NewHead;
2467     ALbufferlistitem *OldHead;
2468     ALbufferlistitem *Current;
2469     ALsizei i;
2470
2471     if(nb == 0)
2472         return;
2473
2474     context = GetContextRef();
2475     if(!context) return;
2476
2477     if(!(nb >= 0))
2478         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2479
2480     if((source=LookupSource(context, src)) == NULL)
2481         SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
2482
2483     WriteLock(&source->queue_lock);
2484     /* Find the new buffer queue head */
2485     NewHead = ATOMIC_LOAD(&source->queue);
2486     Current = ATOMIC_LOAD(&source->current_buffer);
2487     for(i = 0;i < nb && NewHead;i++)
2488     {
2489         if(NewHead == Current)
2490             break;
2491         NewHead = NewHead->next;
2492     }
2493     if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
2494     {
2495         WriteUnlock(&source->queue_lock);
2496         /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
2497         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
2498     }
2499
2500     /* Swap it, and cut the new head from the old. */
2501     OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NewHead);
2502     if(NewHead)
2503     {
2504         ALCdevice *device = context->Device;
2505         ALbufferlistitem *OldTail = NewHead->prev;
2506         uint count;
2507
2508         /* Cut the new head's link back to the old body. The mixer is robust
2509          * enough to handle the link back going away. Once the active mix (if
2510          * any) is complete, it's safe to finish cutting the old tail from the
2511          * new head. */
2512         NewHead->prev = NULL;
2513         if(((count=ReadRef(&device->MixCount))&1) != 0)
2514         {
2515             while(count == ReadRef(&device->MixCount))
2516                 althrd_yield();
2517         }
2518         OldTail->next = NULL;
2519     }
2520     WriteUnlock(&source->queue_lock);
2521
2522     while(OldHead != NULL)
2523     {
2524         ALbufferlistitem *next = OldHead->next;
2525         ALbuffer *buffer = OldHead->buffer;
2526
2527         if(!buffer)
2528             *(buffers++) = 0;
2529         else
2530         {
2531             *(buffers++) = buffer->id;
2532             DecrementRef(&buffer->ref);
2533         }
2534
2535         free(OldHead);
2536         OldHead = next;
2537     }
2538
2539 done:
2540     ALCcontext_DecRef(context);
2541 }
2542
2543
2544 static ALvoid InitSourceParams(ALsource *Source)
2545 {
2546     ALuint i;
2547
2548     RWLockInit(&Source->queue_lock);
2549
2550     Source->InnerAngle = 360.0f;
2551     Source->OuterAngle = 360.0f;
2552     Source->Pitch = 1.0f;
2553     aluVectorSet(&Source->Position, 0.0f, 0.0f, 0.0f, 1.0f);
2554     aluVectorSet(&Source->Velocity, 0.0f, 0.0f, 0.0f, 0.0f);
2555     aluVectorSet(&Source->Direction, 0.0f, 0.0f, 0.0f, 0.0f);
2556     Source->Orientation[0][0] =  0.0f;
2557     Source->Orientation[0][1] =  0.0f;
2558     Source->Orientation[0][2] = -1.0f;
2559     Source->Orientation[1][0] =  0.0f;
2560     Source->Orientation[1][1] =  1.0f;
2561     Source->Orientation[1][2] =  0.0f;
2562     Source->RefDistance = 1.0f;
2563     Source->MaxDistance = FLT_MAX;
2564     Source->RollOffFactor = 1.0f;
2565     Source->Looping = AL_FALSE;
2566     Source->Gain = 1.0f;
2567     Source->MinGain = 0.0f;
2568     Source->MaxGain = 1.0f;
2569     Source->OuterGain = 0.0f;
2570     Source->OuterGainHF = 1.0f;
2571
2572     Source->DryGainHFAuto = AL_TRUE;
2573     Source->WetGainAuto = AL_TRUE;
2574     Source->WetGainHFAuto = AL_TRUE;
2575     Source->AirAbsorptionFactor = 0.0f;
2576     Source->RoomRolloffFactor = 0.0f;
2577     Source->DopplerFactor = 1.0f;
2578     Source->DirectChannels = AL_FALSE;
2579
2580     Source->Radius = 0.0f;
2581
2582     Source->DistanceModel = DefaultDistanceModel;
2583
2584     Source->state = AL_INITIAL;
2585     Source->new_state = AL_NONE;
2586     Source->SourceType = AL_UNDETERMINED;
2587     Source->Offset = -1.0;
2588
2589     ATOMIC_INIT(&Source->queue, NULL);
2590     ATOMIC_INIT(&Source->current_buffer, NULL);
2591
2592     Source->Direct.Gain = 1.0f;
2593     Source->Direct.GainHF = 1.0f;
2594     Source->Direct.HFReference = LOWPASSFREQREF;
2595     Source->Direct.GainLF = 1.0f;
2596     Source->Direct.LFReference = HIGHPASSFREQREF;
2597     for(i = 0;i < MAX_SENDS;i++)
2598     {
2599         Source->Send[i].Gain = 1.0f;
2600         Source->Send[i].GainHF = 1.0f;
2601         Source->Send[i].HFReference = LOWPASSFREQREF;
2602         Source->Send[i].GainLF = 1.0f;
2603         Source->Send[i].LFReference = HIGHPASSFREQREF;
2604     }
2605
2606     ATOMIC_INIT(&Source->NeedsUpdate, AL_TRUE);
2607 }
2608
2609
2610 /* SetSourceState
2611  *
2612  * Sets the source's new play state given its current state.
2613  */
2614 ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
2615 {
2616     WriteLock(&Source->queue_lock);
2617     if(state == AL_PLAYING)
2618     {
2619         ALCdevice *device = Context->Device;
2620         ALbufferlistitem *BufferList;
2621         ALboolean discontinuity;
2622         ALvoice *voice = NULL;
2623         ALsizei i;
2624
2625         /* Check that there is a queue containing at least one valid, non zero
2626          * length Buffer. */
2627         BufferList = ATOMIC_LOAD(&Source->queue);
2628         while(BufferList)
2629         {
2630             ALbuffer *buffer;
2631             if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0)
2632                 break;
2633             BufferList = BufferList->next;
2634         }
2635
2636         if(Source->state != AL_PAUSED)
2637         {
2638             Source->state = AL_PLAYING;
2639             Source->position = 0;
2640             Source->position_fraction = 0;
2641             ATOMIC_STORE(&Source->current_buffer, BufferList);
2642             discontinuity = AL_TRUE;
2643         }
2644         else
2645         {
2646             Source->state = AL_PLAYING;
2647             discontinuity = AL_FALSE;
2648         }
2649
2650         // Check if an Offset has been set
2651         if(Source->Offset >= 0.0)
2652         {
2653             ApplyOffset(Source);
2654             /* discontinuity = AL_TRUE;??? */
2655         }
2656
2657         /* If there's nothing to play, or device is disconnected, go right to
2658          * stopped */
2659         if(!BufferList || !device->Connected)
2660             goto do_stop;
2661
2662         /* Make sure this source isn't already active, while looking for an
2663          * unused active source slot to put it in. */
2664         for(i = 0;i < Context->VoiceCount;i++)
2665         {
2666             ALsource *old = Source;
2667             if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL))
2668             {
2669                 if(voice == NULL)
2670                 {
2671                     voice = &Context->Voices[i];
2672                     voice->Source = Source;
2673                 }
2674                 break;
2675             }
2676             old = NULL;
2677             if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source))
2678                 voice = &Context->Voices[i];
2679         }
2680         if(voice == NULL)
2681         {
2682             voice = &Context->Voices[Context->VoiceCount++];
2683             voice->Source = Source;
2684         }
2685
2686         /* Clear previous samples if playback is discontinuous. */
2687         if(discontinuity)
2688             memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
2689
2690         voice->Direct.Moving  = AL_FALSE;
2691         voice->Direct.Counter = 0;
2692         for(i = 0;i < MAX_INPUT_CHANNELS;i++)
2693         {
2694             ALsizei j;
2695             for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
2696                 voice->Direct.Hrtf[i].State.History[j] = 0.0f;
2697             for(j = 0;j < HRIR_LENGTH;j++)
2698             {
2699                 voice->Direct.Hrtf[i].State.Values[j][0] = 0.0f;
2700                 voice->Direct.Hrtf[i].State.Values[j][1] = 0.0f;
2701             }
2702         }
2703         for(i = 0;i < (ALsizei)device->NumAuxSends;i++)
2704         {
2705             voice->Send[i].Moving  = AL_FALSE;
2706             voice->Send[i].Counter = 0;
2707         }
2708
2709         if(BufferList->buffer->FmtChannels == FmtMono)
2710             voice->Update = CalcSourceParams;
2711         else
2712             voice->Update = CalcNonAttnSourceParams;
2713
2714         ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
2715     }
2716     else if(state == AL_PAUSED)
2717     {
2718         if(Source->state == AL_PLAYING)
2719             Source->state = AL_PAUSED;
2720     }
2721     else if(state == AL_STOPPED)
2722     {
2723     do_stop:
2724         if(Source->state != AL_INITIAL)
2725         {
2726             Source->state = AL_STOPPED;
2727             ATOMIC_STORE(&Source->current_buffer, NULL);
2728         }
2729         Source->Offset = -1.0;
2730     }
2731     else if(state == AL_INITIAL)
2732     {
2733         if(Source->state != AL_INITIAL)
2734         {
2735             Source->state = AL_INITIAL;
2736             Source->position = 0;
2737             Source->position_fraction = 0;
2738             ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue));
2739         }
2740         Source->Offset = -1.0;
2741     }
2742     WriteUnlock(&Source->queue_lock);
2743 }
2744
2745 /* GetSourceSampleOffset
2746  *
2747  * Gets the current read offset for the given Source, in 32.32 fixed-point
2748  * samples. The offset is relative to the start of the queue (not the start of
2749  * the current buffer).
2750  */
2751 ALint64 GetSourceSampleOffset(ALsource *Source)
2752 {
2753     const ALbufferlistitem *BufferList;
2754     const ALbufferlistitem *Current;
2755     ALuint64 readPos;
2756
2757     ReadLock(&Source->queue_lock);
2758     if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2759     {
2760         ReadUnlock(&Source->queue_lock);
2761         return 0;
2762     }
2763
2764     /* NOTE: This is the offset into the *current* buffer, so add the length of
2765      * any played buffers */
2766     readPos  = (ALuint64)Source->position << 32;
2767     readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
2768     BufferList = ATOMIC_LOAD(&Source->queue);
2769     Current = ATOMIC_LOAD(&Source->current_buffer);
2770     while(BufferList && BufferList != Current)
2771     {
2772         if(BufferList->buffer)
2773             readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
2774         BufferList = BufferList->next;
2775     }
2776
2777     ReadUnlock(&Source->queue_lock);
2778     return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
2779 }
2780
2781 /* GetSourceSecOffset
2782  *
2783  * Gets the current read offset for the given Source, in seconds. The offset is
2784  * relative to the start of the queue (not the start of the current buffer).
2785  */
2786 static ALdouble GetSourceSecOffset(ALsource *Source)
2787 {
2788     const ALbufferlistitem *BufferList;
2789     const ALbufferlistitem *Current;
2790     const ALbuffer *Buffer = NULL;
2791     ALuint64 readPos;
2792
2793     ReadLock(&Source->queue_lock);
2794     if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2795     {
2796         ReadUnlock(&Source->queue_lock);
2797         return 0.0;
2798     }
2799
2800     /* NOTE: This is the offset into the *current* buffer, so add the length of
2801      * any played buffers */
2802     readPos  = (ALuint64)Source->position << FRACTIONBITS;
2803     readPos |= (ALuint64)Source->position_fraction;
2804     BufferList = ATOMIC_LOAD(&Source->queue);
2805     Current = ATOMIC_LOAD(&Source->current_buffer);
2806     while(BufferList && BufferList != Current)
2807     {
2808         const ALbuffer *buffer = BufferList->buffer;
2809         if(buffer != NULL)
2810         {
2811             if(!Buffer) Buffer = buffer;
2812             readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS;
2813         }
2814         BufferList = BufferList->next;
2815     }
2816
2817     while(BufferList && !Buffer)
2818     {
2819         Buffer = BufferList->buffer;
2820         BufferList = BufferList->next;
2821     }
2822     assert(Buffer != NULL);
2823
2824     ReadUnlock(&Source->queue_lock);
2825     return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
2826 }
2827
2828 /* GetSourceOffsets
2829  *
2830  * Gets the current read and write offsets for the given Source, in the
2831  * appropriate format (Bytes, Samples or Seconds). The offsets are relative to
2832  * the start of the queue (not the start of the current buffer).
2833  */
2834 static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
2835 {
2836     const ALbufferlistitem *BufferList;
2837     const ALbufferlistitem *Current;
2838     const ALbuffer *Buffer = NULL;
2839     ALboolean readFin = AL_FALSE;
2840     ALuint readPos, readPosFrac, writePos;
2841     ALuint totalBufferLen;
2842
2843     ReadLock(&Source->queue_lock);
2844     if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
2845     {
2846         offset[0] = 0.0;
2847         offset[1] = 0.0;
2848         ReadUnlock(&Source->queue_lock);
2849         return;
2850     }
2851
2852     if(updateLen > 0.0 && updateLen < 0.015)
2853         updateLen = 0.015;
2854
2855     /* NOTE: This is the offset into the *current* buffer, so add the length of
2856      * any played buffers */
2857     totalBufferLen = 0;
2858     readPos = Source->position;
2859     readPosFrac = Source->position_fraction;
2860     BufferList = ATOMIC_LOAD(&Source->queue);
2861     Current = ATOMIC_LOAD(&Source->current_buffer);
2862     while(BufferList != NULL)
2863     {
2864         const ALbuffer *buffer;
2865         readFin = readFin || (BufferList == Current);
2866         if((buffer=BufferList->buffer) != NULL)
2867         {
2868             if(!Buffer) Buffer = buffer;
2869             totalBufferLen += buffer->SampleLen;
2870             if(!readFin) readPos += buffer->SampleLen;
2871         }
2872         BufferList = BufferList->next;
2873     }
2874     assert(Buffer != NULL);
2875
2876     if(Source->state == AL_PLAYING)
2877         writePos = readPos + (ALuint)(updateLen*Buffer->Frequency + 0.5f);
2878     else
2879         writePos = readPos;
2880
2881     if(Source->Looping)
2882     {
2883         readPos %= totalBufferLen;
2884         writePos %= totalBufferLen;
2885     }
2886     else
2887     {
2888         /* Wrap positions back to 0 */
2889         if(readPos >= totalBufferLen)
2890             readPos = readPosFrac = 0;
2891         if(writePos >= totalBufferLen)
2892             writePos = 0;
2893     }
2894
2895     switch(name)
2896     {
2897         case AL_SEC_OFFSET:
2898             offset[0] = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
2899             offset[1] = (ALdouble)writePos/Buffer->Frequency;
2900             break;
2901
2902         case AL_SAMPLE_OFFSET:
2903         case AL_SAMPLE_RW_OFFSETS_SOFT:
2904             offset[0] = readPos + (ALdouble)readPosFrac/FRACTIONONE;
2905             offset[1] = (ALdouble)writePos;
2906             break;
2907
2908         case AL_BYTE_OFFSET:
2909         case AL_BYTE_RW_OFFSETS_SOFT:
2910             if(Buffer->OriginalType == UserFmtIMA4)
2911             {
2912                 ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
2913                 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2914                 ALuint FrameBlockSize = Buffer->OriginalAlign;
2915
2916                 /* Round down to nearest ADPCM block */
2917                 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2918                 if(Source->state != AL_PLAYING)
2919                     offset[1] = offset[0];
2920                 else
2921                 {
2922                     /* Round up to nearest ADPCM block */
2923                     offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2924                                            FrameBlockSize * BlockSize);
2925                 }
2926             }
2927             else if(Buffer->OriginalType == UserFmtMSADPCM)
2928             {
2929                 ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
2930                 ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels);
2931                 ALuint FrameBlockSize = Buffer->OriginalAlign;
2932
2933                 /* Round down to nearest ADPCM block */
2934                 offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
2935                 if(Source->state != AL_PLAYING)
2936                     offset[1] = offset[0];
2937                 else
2938                 {
2939                     /* Round up to nearest ADPCM block */
2940                     offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
2941                                            FrameBlockSize * BlockSize);
2942                 }
2943             }
2944             else
2945             {
2946                 ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
2947                 offset[0] = (ALdouble)(readPos * FrameSize);
2948                 offset[1] = (ALdouble)(writePos * FrameSize);
2949             }
2950             break;
2951     }
2952
2953     ReadUnlock(&Source->queue_lock);
2954 }
2955
2956
2957 /* ApplyOffset
2958  *
2959  * Apply the stored playback offset to the Source. This function will update
2960  * the number of buffers "played" given the stored offset.
2961  */
2962 ALboolean ApplyOffset(ALsource *Source)
2963 {
2964     ALbufferlistitem *BufferList;
2965     const ALbuffer *Buffer;
2966     ALuint bufferLen, totalBufferLen;
2967     ALuint offset=0, frac=0;
2968
2969     /* Get sample frame offset */
2970     if(!GetSampleOffset(Source, &offset, &frac))
2971         return AL_FALSE;
2972
2973     totalBufferLen = 0;
2974     BufferList = ATOMIC_LOAD(&Source->queue);
2975     while(BufferList && totalBufferLen <= offset)
2976     {
2977         Buffer = BufferList->buffer;
2978         bufferLen = Buffer ? Buffer->SampleLen : 0;
2979
2980         if(bufferLen > offset-totalBufferLen)
2981         {
2982             /* Offset is in this buffer */
2983             ATOMIC_STORE(&Source->current_buffer, BufferList);
2984
2985             Source->position = offset - totalBufferLen;
2986             Source->position_fraction = frac;
2987             return AL_TRUE;
2988         }
2989
2990         totalBufferLen += bufferLen;
2991
2992         BufferList = BufferList->next;
2993     }
2994
2995     /* Offset is out of range of the queue */
2996     return AL_FALSE;
2997 }
2998
2999
3000 /* GetSampleOffset
3001  *
3002  * Retrieves the sample offset into the Source's queue (from the Sample, Byte
3003  * or Second offset supplied by the application). This takes into account the
3004  * fact that the buffer format may have been modifed since.
3005  */
3006 static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
3007 {
3008     const ALbuffer *Buffer = NULL;
3009     const ALbufferlistitem *BufferList;
3010     ALdouble dbloff, dblfrac;
3011
3012     /* Find the first valid Buffer in the Queue */
3013     BufferList = ATOMIC_LOAD(&Source->queue);
3014     while(BufferList)
3015     {
3016         if(BufferList->buffer)
3017         {
3018             Buffer = BufferList->buffer;
3019             break;
3020         }
3021         BufferList = BufferList->next;
3022     }
3023     if(!Buffer)
3024     {
3025         Source->Offset = -1.0;
3026         return AL_FALSE;
3027     }
3028
3029     switch(Source->OffsetType)
3030     {
3031     case AL_BYTE_OFFSET:
3032         /* Determine the ByteOffset (and ensure it is block aligned) */
3033         *offset = (ALuint)Source->Offset;
3034         if(Buffer->OriginalType == UserFmtIMA4)
3035         {
3036             ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
3037             *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3038             *offset *= Buffer->OriginalAlign;
3039         }
3040         else if(Buffer->OriginalType == UserFmtMSADPCM)
3041         {
3042             ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
3043             *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
3044             *offset *= Buffer->OriginalAlign;
3045         }
3046         else
3047             *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
3048         *frac = 0;
3049         break;
3050
3051     case AL_SAMPLE_OFFSET:
3052         dblfrac = modf(Source->Offset, &dbloff);
3053         *offset = (ALuint)mind(dbloff, UINT_MAX);
3054         *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3055         break;
3056
3057     case AL_SEC_OFFSET:
3058         dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
3059         *offset = (ALuint)mind(dbloff, UINT_MAX);
3060         *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
3061         break;
3062     }
3063     Source->Offset = -1.0;
3064
3065     return AL_TRUE;
3066 }
3067
3068
3069 /* ReleaseALSources
3070  *
3071  * Destroys all sources in the source map.
3072  */
3073 ALvoid ReleaseALSources(ALCcontext *Context)
3074 {
3075     ALbufferlistitem *item;
3076     ALsizei pos;
3077     ALuint j;
3078     for(pos = 0;pos < Context->SourceMap.size;pos++)
3079     {
3080         ALsource *temp = Context->SourceMap.array[pos].value;
3081         Context->SourceMap.array[pos].value = NULL;
3082
3083         item = ATOMIC_EXCHANGE(ALbufferlistitem*, &temp->queue, NULL);
3084         while(item != NULL)
3085         {
3086             ALbufferlistitem *next = item->next;
3087             if(item->buffer != NULL)
3088                 DecrementRef(&item->buffer->ref);
3089             free(item);
3090             item = next;
3091         }
3092
3093         for(j = 0;j < MAX_SENDS;++j)
3094         {
3095             if(temp->Send[j].Slot)
3096                 DecrementRef(&temp->Send[j].Slot->ref);
3097             temp->Send[j].Slot = NULL;
3098         }
3099
3100         FreeThunkEntry(temp->id);
3101         memset(temp, 0, sizeof(*temp));
3102         al_free(temp);
3103     }
3104 }