comparison ext/openal-soft/OpenAL32/alSource.c @ 0:4a0efb7baf70

* Datasets becomes the new trunk and retires after that :-)
author mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222
date Sun, 29 Jun 2008 18:44:17 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4a0efb7baf70
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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, 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 <math.h>
25 #include <float.h>
26 #include "alMain.h"
27 #include "AL/al.h"
28 #include "AL/alc.h"
29 #include "alError.h"
30 #include "alSource.h"
31 #include "alBuffer.h"
32 #include "alThunk.h"
33 #include "alAuxEffectSlot.h"
34
35 static ALvoid InitSourceParams(ALsource *pSource);
36 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset);
37 static ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext);
38 static ALint GetByteOffset(ALsource *pSource);
39
40 ALAPI ALvoid ALAPIENTRY alGenSources(ALsizei n,ALuint *sources)
41 {
42 ALCcontext *Context;
43 ALCdevice *Device;
44 ALsizei i=0;
45
46 Context = alcGetCurrentContext();
47 if (Context)
48 {
49 SuspendContext(Context);
50
51 if (n > 0)
52 {
53 Device = alcGetContextsDevice(Context);
54
55 if (Device)
56 {
57 // Check that enough memory has been allocted in the 'sources' array for n Sources
58 if (!IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
59 {
60 // Check that the requested number of sources can be generated
61 if ((Context->SourceCount + n) <= Device->MaxNoOfSources)
62 {
63 ALsource **list = &Context->Source;
64 while(*list)
65 list = &(*list)->next;
66
67 // Add additional sources to the list (Source->next points to the location for the next Source structure)
68 while(i < n)
69 {
70 *list = calloc(1, sizeof(ALsource));
71 if(!(*list))
72 {
73 alDeleteSources(i, sources);
74 alSetError(AL_OUT_OF_MEMORY);
75 break;
76 }
77
78 sources[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
79 (*list)->source = sources[i];
80
81 InitSourceParams(*list);
82 Context->SourceCount++;
83 i++;
84
85 list = &(*list)->next;
86 }
87 }
88 else
89 {
90 // Not enough resources to create the Sources
91 alSetError(AL_INVALID_VALUE);
92 }
93 }
94 else
95 {
96 // Bad pointer
97 alSetError(AL_INVALID_VALUE);
98 }
99 }
100 else
101 {
102 // No Device created, or attached to Context
103 alSetError(AL_INVALID_OPERATION);
104 }
105 }
106
107 ProcessContext(Context);
108 }
109 else
110 {
111 // Invalid Context
112 alSetError(AL_INVALID_OPERATION);
113 }
114
115 return;
116 }
117
118
119 ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
120 {
121 ALCcontext *Context;
122 ALCdevice *Device;
123 ALsource *ALSource;
124 ALsource **list;
125 ALsizei i, j;
126 ALbufferlistitem *ALBufferList;
127 ALboolean bSourcesValid = AL_TRUE;
128
129 Context = alcGetCurrentContext();
130 if (Context)
131 {
132 SuspendContext(Context);
133
134 if (n >= 0)
135 {
136 Device = alcGetContextsDevice(Context);
137
138 if (Device)
139 {
140 if ((ALuint)n <= Context->SourceCount)
141 {
142 // Check that all Sources are valid (and can therefore be deleted)
143 for (i = 0; i < n; i++)
144 {
145 if (!alIsSource(sources[i]))
146 {
147 alSetError(AL_INVALID_NAME);
148 bSourcesValid = AL_FALSE;
149 break;
150 }
151 }
152
153 if (bSourcesValid)
154 {
155 // All Sources are valid, and can be deleted
156 for (i = 0; i < n; i++)
157 {
158 // Recheck that the Source is valid, because there could be duplicated Source names
159 if (alIsSource(sources[i]))
160 {
161 ALSource=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
162 alSourceStop((ALuint)ALSource->source);
163
164 // For each buffer in the source's queue, decrement its reference counter and remove it
165 while (ALSource->queue != NULL)
166 {
167 ALBufferList = ALSource->queue;
168 // Decrement buffer's reference counter
169 if (ALBufferList->buffer != 0)
170 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
171 // Update queue to point to next element in list
172 ALSource->queue = ALBufferList->next;
173 // Release memory allocated for buffer list item
174 free(ALBufferList);
175 }
176
177 for(j = 0;j < MAX_SENDS;++j)
178 {
179 if(ALSource->Send[j].Slot)
180 ALSource->Send[j].Slot->refcount--;
181 ALSource->Send[j].Slot = NULL;
182 }
183
184 // Decrement Source count
185 Context->SourceCount--;
186
187 // Remove Source from list of Sources
188 list = &Context->Source;
189 while(*list && *list != ALSource)
190 list = &(*list)->next;
191
192 if(*list)
193 *list = (*list)->next;
194 ALTHUNK_REMOVEENTRY(ALSource->source);
195
196 memset(ALSource,0,sizeof(ALsource));
197 free(ALSource);
198 }
199 }
200
201 }
202 }
203 else
204 {
205 // Trying to delete more Sources than have been generated
206 alSetError(AL_INVALID_NAME);
207 }
208 }
209 else
210 {
211 // No Device created, or attached to Context
212 alSetError(AL_INVALID_OPERATION);
213 }
214 }
215 else
216 alSetError(AL_INVALID_VALUE);
217
218 ProcessContext(Context);
219 }
220 else
221 {
222 // Invalid Context
223 alSetError(AL_INVALID_OPERATION);
224 }
225
226 return;
227 }
228
229
230 ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source)
231 {
232 ALboolean result=AL_FALSE;
233 ALCcontext *Context;
234 ALsource *Source;
235
236 Context=alcGetCurrentContext();
237 if (Context)
238 {
239 SuspendContext(Context);
240
241 // To determine if this is a valid Source name, look through the list of generated Sources
242 Source = Context->Source;
243 while(Source)
244 {
245 if (Source == (ALsource*)ALTHUNK_LOOKUPENTRY(source))
246 {
247 result = AL_TRUE;
248 break;
249 }
250
251 Source = Source->next;
252 }
253
254 ProcessContext(Context);
255 }
256 else
257 {
258 // Invalid Context
259 alSetError(AL_INVALID_OPERATION);
260 }
261
262 return result;
263 }
264
265
266 ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
267 {
268 ALCcontext *pContext;
269 ALsource *pSource;
270
271 pContext = alcGetCurrentContext();
272 if (pContext)
273 {
274 SuspendContext(pContext);
275
276 if (alIsSource(source))
277 {
278 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
279
280 switch (eParam)
281 {
282 case AL_PITCH:
283 if (flValue >= 0.0f)
284 {
285 pSource->flPitch = flValue;
286 if(pSource->flPitch < 0.001f)
287 pSource->flPitch = 0.001f;
288 }
289 else
290 alSetError(AL_INVALID_VALUE);
291 break;
292
293 case AL_CONE_INNER_ANGLE:
294 if ((flValue >= 0.0f) && (flValue <= 360.0f))
295 pSource->flInnerAngle = flValue;
296 else
297 alSetError(AL_INVALID_VALUE);
298 break;
299
300 case AL_CONE_OUTER_ANGLE:
301 if ((flValue >= 0.0f) && (flValue <= 360.0f))
302 pSource->flOuterAngle = flValue;
303 else
304 alSetError(AL_INVALID_VALUE);
305 break;
306
307 case AL_GAIN:
308 if (flValue >= 0.0f)
309 pSource->flGain = flValue;
310 else
311 alSetError(AL_INVALID_VALUE);
312 break;
313
314 case AL_MAX_DISTANCE:
315 if (flValue >= 0.0f)
316 pSource->flMaxDistance = flValue;
317 else
318 alSetError(AL_INVALID_VALUE);
319 break;
320
321 case AL_ROLLOFF_FACTOR:
322 if (flValue >= 0.0f)
323 pSource->flRollOffFactor = flValue;
324 else
325 alSetError(AL_INVALID_VALUE);
326 break;
327
328 case AL_REFERENCE_DISTANCE:
329 if (flValue >= 0.0f)
330 pSource->flRefDistance = flValue;
331 else
332 alSetError(AL_INVALID_VALUE);
333 break;
334
335 case AL_MIN_GAIN:
336 if ((flValue >= 0.0f) && (flValue <= 1.0f))
337 pSource->flMinGain = flValue;
338 else
339 alSetError(AL_INVALID_VALUE);
340 break;
341
342 case AL_MAX_GAIN:
343 if ((flValue >= 0.0f) && (flValue <= 1.0f))
344 pSource->flMaxGain = flValue;
345 else
346 alSetError(AL_INVALID_VALUE);
347 break;
348
349 case AL_CONE_OUTER_GAIN:
350 if ((flValue >= 0.0f) && (flValue <= 1.0f))
351 pSource->flOuterGain = flValue;
352 else
353 alSetError(AL_INVALID_VALUE);
354 break;
355
356 case AL_CONE_OUTER_GAINHF:
357 if ((flValue >= 0.0f) && (flValue <= 1.0f))
358 pSource->OuterGainHF = flValue;
359 else
360 alSetError(AL_INVALID_VALUE);
361 break;
362
363 case AL_AIR_ABSORPTION_FACTOR:
364 if (flValue >= 0.0f && flValue <= 10.0f)
365 pSource->AirAbsorptionFactor = flValue;
366 else
367 alSetError(AL_INVALID_VALUE);
368 break;
369
370 case AL_ROOM_ROLLOFF_FACTOR:
371 if (flValue >= 0.0f && flValue <= 1.0f)
372 pSource->RoomRolloffFactor = flValue;
373 else
374 alSetError(AL_INVALID_VALUE);
375 break;
376
377 case AL_SEC_OFFSET:
378 case AL_SAMPLE_OFFSET:
379 case AL_BYTE_OFFSET:
380 if (flValue >= 0.0f)
381 {
382 pSource->lOffsetType = eParam;
383
384 // Store Offset (convert Seconds into Milliseconds)
385 if (eParam == AL_SEC_OFFSET)
386 pSource->lOffset = (ALint)(flValue * 1000.0f);
387 else
388 pSource->lOffset = (ALint)flValue;
389
390 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
391 ApplyOffset(pSource, AL_TRUE);
392 }
393 else
394 alSetError(AL_INVALID_VALUE);
395 break;
396
397 default:
398 alSetError(AL_INVALID_ENUM);
399 break;
400 }
401 }
402 else
403 {
404 // Invalid Source Name
405 alSetError(AL_INVALID_NAME);
406 }
407
408 ProcessContext(pContext);
409 }
410 else
411 {
412 // Invalid context
413 alSetError(AL_INVALID_OPERATION);
414 }
415
416 return;
417 }
418
419
420 ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
421 {
422 ALCcontext *pContext;
423 ALsource *pSource;
424
425 pContext = alcGetCurrentContext();
426 if (pContext)
427 {
428 SuspendContext(pContext);
429
430 if (alIsSource(source))
431 {
432 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
433 switch(eParam)
434 {
435 case AL_POSITION:
436 pSource->vPosition[0] = flValue1;
437 pSource->vPosition[1] = flValue2;
438 pSource->vPosition[2] = flValue3;
439 break;
440
441 case AL_VELOCITY:
442 pSource->vVelocity[0] = flValue1;
443 pSource->vVelocity[1] = flValue2;
444 pSource->vVelocity[2] = flValue3;
445 break;
446
447 case AL_DIRECTION:
448 pSource->vOrientation[0] = flValue1;
449 pSource->vOrientation[1] = flValue2;
450 pSource->vOrientation[2] = flValue3;
451 break;
452
453 default:
454 alSetError(AL_INVALID_ENUM);
455 break;
456 }
457 }
458 else
459 alSetError(AL_INVALID_NAME);
460
461 ProcessContext(pContext);
462 }
463 else
464 {
465 alSetError(AL_INVALID_OPERATION);
466 }
467
468 return;
469 }
470
471
472 ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
473 {
474 ALCcontext *pContext;
475
476 pContext = alcGetCurrentContext();
477 if (pContext)
478 {
479 SuspendContext(pContext);
480
481 if (pflValues)
482 {
483 if (alIsSource(source))
484 {
485 switch (eParam)
486 {
487 case AL_PITCH:
488 case AL_CONE_INNER_ANGLE:
489 case AL_CONE_OUTER_ANGLE:
490 case AL_GAIN:
491 case AL_MAX_DISTANCE:
492 case AL_ROLLOFF_FACTOR:
493 case AL_REFERENCE_DISTANCE:
494 case AL_MIN_GAIN:
495 case AL_MAX_GAIN:
496 case AL_CONE_OUTER_GAIN:
497 case AL_CONE_OUTER_GAINHF:
498 case AL_SEC_OFFSET:
499 case AL_SAMPLE_OFFSET:
500 case AL_BYTE_OFFSET:
501 case AL_AIR_ABSORPTION_FACTOR:
502 case AL_ROOM_ROLLOFF_FACTOR:
503 alSourcef(source, eParam, pflValues[0]);
504 break;
505
506 case AL_POSITION:
507 case AL_VELOCITY:
508 case AL_DIRECTION:
509 alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
510 break;
511
512 default:
513 alSetError(AL_INVALID_ENUM);
514 break;
515 }
516 }
517 else
518 alSetError(AL_INVALID_NAME);
519 }
520 else
521 alSetError(AL_INVALID_VALUE);
522
523 ProcessContext(pContext);
524 }
525 else
526 alSetError(AL_INVALID_OPERATION);
527
528 return;
529 }
530
531
532 ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
533 {
534 ALCcontext *pContext;
535 ALsource *pSource;
536 ALbufferlistitem *pALBufferListItem;
537 ALint Counter = 0;
538 ALint DataSize = 0;
539 ALint BufferSize;
540
541 pContext = alcGetCurrentContext();
542 if (pContext)
543 {
544 SuspendContext(pContext);
545
546 if (alIsSource(source))
547 {
548 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
549
550 switch(eParam)
551 {
552 case AL_MAX_DISTANCE:
553 case AL_ROLLOFF_FACTOR:
554 case AL_REFERENCE_DISTANCE:
555 alSourcef(source, eParam, (ALfloat)lValue);
556 break;
557
558 case AL_SOURCE_RELATIVE:
559 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
560 pSource->bHeadRelative = (ALboolean)lValue;
561 else
562 alSetError(AL_INVALID_VALUE);
563 break;
564
565 case AL_CONE_INNER_ANGLE:
566 if ((lValue >= 0) && (lValue <= 360))
567 pSource->flInnerAngle = (float)lValue;
568 else
569 alSetError(AL_INVALID_VALUE);
570 break;
571
572 case AL_CONE_OUTER_ANGLE:
573 if ((lValue >= 0) && (lValue <= 360))
574 pSource->flOuterAngle = (float)lValue;
575 else
576 alSetError(AL_INVALID_VALUE);
577 break;
578
579 case AL_LOOPING:
580 if ((lValue == AL_FALSE) || (lValue == AL_TRUE))
581 pSource->bLooping = (ALboolean)lValue;
582 else
583 alSetError(AL_INVALID_VALUE);
584 break;
585
586 case AL_BUFFER:
587 if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL))
588 {
589 if (alIsBuffer(lValue))
590 {
591 // Remove all elements in the queue
592 while (pSource->queue != NULL)
593 {
594 pALBufferListItem = pSource->queue;
595 pSource->queue = pALBufferListItem->next;
596 // Decrement reference counter for buffer
597 if (pALBufferListItem->buffer)
598 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--;
599 // Record size of buffer
600 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size;
601 DataSize += BufferSize;
602 // Increment the number of buffers removed from queue
603 Counter++;
604 // Release memory for buffer list item
605 free(pALBufferListItem);
606 // Decrement the number of buffers in the queue
607 pSource->BuffersInQueue--;
608 }
609
610 // Add the buffer to the queue (as long as it is NOT the NULL buffer)
611 if (lValue != 0)
612 {
613 // Source is now in STATIC mode
614 pSource->lSourceType = AL_STATIC;
615
616 // Add the selected buffer to the queue
617 pALBufferListItem = malloc(sizeof(ALbufferlistitem));
618 pALBufferListItem->buffer = lValue;
619 pALBufferListItem->bufferstate = PENDING;
620 pALBufferListItem->flag = 0;
621 pALBufferListItem->next = NULL;
622
623 pSource->queue = pALBufferListItem;
624 pSource->BuffersInQueue = 1;
625
626 DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size;
627
628 // Increment reference counter for buffer
629 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++;
630 }
631 else
632 {
633 // Source is now in UNDETERMINED mode
634 pSource->lSourceType = AL_UNDETERMINED;
635 }
636
637 // Set Buffers Processed
638 pSource->BuffersProcessed = 0;
639
640 // Update AL_BUFFER parameter
641 pSource->ulBufferID = lValue;
642 }
643 else
644 alSetError(AL_INVALID_VALUE);
645 }
646 else
647 alSetError(AL_INVALID_OPERATION);
648 break;
649
650 case AL_SOURCE_STATE:
651 // Query only
652 alSetError(AL_INVALID_OPERATION);
653 break;
654
655 case AL_SEC_OFFSET:
656 case AL_SAMPLE_OFFSET:
657 case AL_BYTE_OFFSET:
658 if (lValue >= 0)
659 {
660 pSource->lOffsetType = eParam;
661
662 // Store Offset (convert Seconds into Milliseconds)
663 if (eParam == AL_SEC_OFFSET)
664 pSource->lOffset = lValue * 1000;
665 else
666 pSource->lOffset = lValue;
667
668 if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED))
669 ApplyOffset(pSource, AL_TRUE);
670 }
671 else
672 alSetError(AL_INVALID_VALUE);
673 break;
674
675 case AL_DIRECT_FILTER:
676 if(alIsFilter(lValue))
677 {
678 ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
679 if(!filter)
680 {
681 pSource->DirectFilter.type = AL_FILTER_NULL;
682 pSource->DirectFilter.filter = 0;
683 }
684 else
685 memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
686 }
687 else
688 alSetError(AL_INVALID_VALUE);
689 break;
690
691 case AL_DIRECT_FILTER_GAINHF_AUTO:
692 if(lValue == AL_TRUE || lValue == AL_FALSE)
693 pSource->DryGainHFAuto = lValue;
694 else
695 alSetError(AL_INVALID_VALUE);
696 break;
697
698 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
699 if(lValue == AL_TRUE || lValue == AL_FALSE)
700 pSource->WetGainAuto = lValue;
701 else
702 alSetError(AL_INVALID_VALUE);
703 break;
704
705 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
706 if(lValue == AL_TRUE || lValue == AL_FALSE)
707 pSource->WetGainHFAuto = lValue;
708 else
709 alSetError(AL_INVALID_VALUE);
710 break;
711
712 default:
713 alSetError(AL_INVALID_ENUM);
714 break;
715 }
716 }
717 else
718 alSetError(AL_INVALID_NAME);
719
720 ProcessContext(pContext);
721 }
722 else
723 alSetError(AL_INVALID_OPERATION);
724
725 return;
726 }
727
728
729 ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
730 {
731 ALCcontext *pContext;
732
733 pContext = alcGetCurrentContext();
734 if (pContext)
735 {
736 SuspendContext(pContext);
737
738 if (alIsSource(source))
739 {
740 ALsource *pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
741
742 switch (eParam)
743 {
744 case AL_POSITION:
745 case AL_VELOCITY:
746 case AL_DIRECTION:
747 alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
748 break;
749
750 case AL_AUXILIARY_SEND_FILTER:
751 if(lValue2 >= 0 && lValue2 < MAX_SENDS &&
752 (alIsAuxiliaryEffectSlot(lValue1) || lValue1 == 0) &&
753 alIsFilter(lValue3))
754 {
755 ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
756 ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
757
758 /* Release refcount on the previous slot, and add one for
759 * the new slot */
760 if(pSource->Send[lValue2].Slot)
761 pSource->Send[lValue2].Slot->refcount--;
762 pSource->Send[lValue2].Slot = ALEffectSlot;
763 if(pSource->Send[lValue2].Slot)
764 pSource->Send[lValue2].Slot->refcount++;
765
766 if(!ALFilter)
767 {
768 /* Disable filter */
769 pSource->Send[lValue2].WetFilter.type = 0;
770 pSource->Send[lValue2].WetFilter.filter = 0;
771 }
772 else
773 memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
774 }
775 else
776 alSetError(AL_INVALID_VALUE);
777 break;
778
779 default:
780 alSetError(AL_INVALID_ENUM);
781 break;
782 }
783 }
784 else
785 alSetError(AL_INVALID_NAME);
786
787 ProcessContext(pContext);
788 }
789 else
790 alSetError(AL_INVALID_OPERATION);
791
792 return;
793 }
794
795
796 ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
797 {
798 ALCcontext *pContext;
799
800 pContext = alcGetCurrentContext();
801 if (pContext)
802 {
803 SuspendContext(pContext);
804
805 if (plValues)
806 {
807 if (alIsSource(source))
808 {
809 switch (eParam)
810 {
811 case AL_SOURCE_RELATIVE:
812 case AL_CONE_INNER_ANGLE:
813 case AL_CONE_OUTER_ANGLE:
814 case AL_LOOPING:
815 case AL_BUFFER:
816 case AL_SOURCE_STATE:
817 case AL_SEC_OFFSET:
818 case AL_SAMPLE_OFFSET:
819 case AL_BYTE_OFFSET:
820 case AL_MAX_DISTANCE:
821 case AL_ROLLOFF_FACTOR:
822 case AL_REFERENCE_DISTANCE:
823 case AL_DIRECT_FILTER:
824 case AL_DIRECT_FILTER_GAINHF_AUTO:
825 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
826 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
827 alSourcei(source, eParam, plValues[0]);
828 break;
829
830 case AL_POSITION:
831 case AL_VELOCITY:
832 case AL_DIRECTION:
833 case AL_AUXILIARY_SEND_FILTER:
834 alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
835 break;
836
837 default:
838 alSetError(AL_INVALID_ENUM);
839 break;
840 }
841 }
842 else
843 alSetError(AL_INVALID_NAME);
844 }
845 else
846 alSetError(AL_INVALID_VALUE);
847
848 ProcessContext(pContext);
849 }
850 else
851 alSetError(AL_INVALID_OPERATION);
852
853 return;
854 }
855
856
857 ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
858 {
859 ALCcontext *pContext;
860 ALsource *pSource;
861 ALfloat flOffset;
862
863 pContext = alcGetCurrentContext();
864 if (pContext)
865 {
866 SuspendContext(pContext);
867
868 if (pflValue)
869 {
870 if (alIsSource(source))
871 {
872 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
873
874 switch(eParam)
875 {
876 case AL_PITCH:
877 *pflValue = pSource->flPitch;
878 break;
879
880 case AL_GAIN:
881 *pflValue = pSource->flGain;
882 break;
883
884 case AL_MIN_GAIN:
885 *pflValue = pSource->flMinGain;
886 break;
887
888 case AL_MAX_GAIN:
889 *pflValue = pSource->flMaxGain;
890 break;
891
892 case AL_MAX_DISTANCE:
893 *pflValue = pSource->flMaxDistance;
894 break;
895
896 case AL_ROLLOFF_FACTOR:
897 *pflValue = pSource->flRollOffFactor;
898 break;
899
900 case AL_CONE_OUTER_GAIN:
901 *pflValue = pSource->flOuterGain;
902 break;
903
904 case AL_CONE_OUTER_GAINHF:
905 *pflValue = pSource->OuterGainHF;
906 break;
907
908 case AL_SEC_OFFSET:
909 case AL_SAMPLE_OFFSET:
910 case AL_BYTE_OFFSET:
911 if (GetSourceOffset(pSource, eParam, &flOffset))
912 *pflValue = flOffset;
913 else
914 alSetError(AL_INVALID_OPERATION);
915 break;
916
917 case AL_CONE_INNER_ANGLE:
918 *pflValue = pSource->flInnerAngle;
919 break;
920
921 case AL_CONE_OUTER_ANGLE:
922 *pflValue = pSource->flOuterAngle;
923 break;
924
925 case AL_REFERENCE_DISTANCE:
926 *pflValue = pSource->flRefDistance;
927 break;
928
929 case AL_AIR_ABSORPTION_FACTOR:
930 *pflValue = pSource->AirAbsorptionFactor;
931 break;
932
933 case AL_ROOM_ROLLOFF_FACTOR:
934 *pflValue = pSource->RoomRolloffFactor;
935 break;
936
937 default:
938 alSetError(AL_INVALID_ENUM);
939 break;
940 }
941 }
942 else
943 alSetError(AL_INVALID_NAME);
944 }
945 else
946 alSetError(AL_INVALID_VALUE);
947
948 ProcessContext(pContext);
949 }
950 else
951 alSetError(AL_INVALID_OPERATION);
952
953 return;
954 }
955
956
957 ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
958 {
959 ALCcontext *pContext;
960 ALsource *pSource;
961
962 pContext = alcGetCurrentContext();
963 if (pContext)
964 {
965 SuspendContext(pContext);
966
967 if ((pflValue1) && (pflValue2) && (pflValue3))
968 {
969 if (alIsSource(source))
970 {
971 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
972
973 switch(eParam)
974 {
975 case AL_POSITION:
976 *pflValue1 = pSource->vPosition[0];
977 *pflValue2 = pSource->vPosition[1];
978 *pflValue3 = pSource->vPosition[2];
979 break;
980
981 case AL_VELOCITY:
982 *pflValue1 = pSource->vVelocity[0];
983 *pflValue2 = pSource->vVelocity[1];
984 *pflValue3 = pSource->vVelocity[2];
985 break;
986
987 case AL_DIRECTION:
988 *pflValue1 = pSource->vOrientation[0];
989 *pflValue2 = pSource->vOrientation[1];
990 *pflValue3 = pSource->vOrientation[2];
991 break;
992
993 default:
994 alSetError(AL_INVALID_ENUM);
995 break;
996 }
997 }
998 else
999 alSetError(AL_INVALID_NAME);
1000 }
1001 else
1002 alSetError(AL_INVALID_VALUE);
1003
1004 ProcessContext(pContext);
1005 }
1006 else
1007 alSetError(AL_INVALID_OPERATION);
1008
1009 return;
1010 }
1011
1012
1013 ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
1014 {
1015 ALCcontext *pContext;
1016 ALsource *pSource;
1017
1018 pContext = alcGetCurrentContext();
1019 if (pContext)
1020 {
1021 SuspendContext(pContext);
1022
1023 if (pflValues)
1024 {
1025 if (alIsSource(source))
1026 {
1027 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1028
1029 switch(eParam)
1030 {
1031 case AL_PITCH:
1032 case AL_GAIN:
1033 case AL_MIN_GAIN:
1034 case AL_MAX_GAIN:
1035 case AL_MAX_DISTANCE:
1036 case AL_ROLLOFF_FACTOR:
1037 case AL_CONE_OUTER_GAIN:
1038 case AL_SEC_OFFSET:
1039 case AL_SAMPLE_OFFSET:
1040 case AL_BYTE_OFFSET:
1041 case AL_CONE_INNER_ANGLE:
1042 case AL_CONE_OUTER_ANGLE:
1043 case AL_REFERENCE_DISTANCE:
1044 case AL_CONE_OUTER_GAINHF:
1045 case AL_AIR_ABSORPTION_FACTOR:
1046 case AL_ROOM_ROLLOFF_FACTOR:
1047 alGetSourcef(source, eParam, pflValues);
1048 break;
1049
1050 case AL_POSITION:
1051 pflValues[0] = pSource->vPosition[0];
1052 pflValues[1] = pSource->vPosition[1];
1053 pflValues[2] = pSource->vPosition[2];
1054 break;
1055
1056 case AL_VELOCITY:
1057 pflValues[0] = pSource->vVelocity[0];
1058 pflValues[1] = pSource->vVelocity[1];
1059 pflValues[2] = pSource->vVelocity[2];
1060 break;
1061
1062 case AL_DIRECTION:
1063 pflValues[0] = pSource->vOrientation[0];
1064 pflValues[1] = pSource->vOrientation[1];
1065 pflValues[2] = pSource->vOrientation[2];
1066 break;
1067
1068 default:
1069 alSetError(AL_INVALID_ENUM);
1070 break;
1071 }
1072 }
1073 else
1074 alSetError(AL_INVALID_NAME);
1075 }
1076 else
1077 alSetError(AL_INVALID_VALUE);
1078
1079 ProcessContext(pContext);
1080 }
1081 else
1082 alSetError(AL_INVALID_OPERATION);
1083
1084 return;
1085 }
1086
1087
1088 ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
1089 {
1090 ALCcontext *pContext;
1091 ALsource *pSource;
1092 ALfloat flOffset;
1093
1094 pContext = alcGetCurrentContext();
1095 if (pContext)
1096 {
1097 SuspendContext(pContext);
1098
1099 if (plValue)
1100 {
1101 if (alIsSource(source))
1102 {
1103 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1104
1105 switch(eParam)
1106 {
1107 case AL_MAX_DISTANCE:
1108 *plValue = (ALint)pSource->flMaxDistance;
1109 break;
1110
1111 case AL_ROLLOFF_FACTOR:
1112 *plValue = (ALint)pSource->flRollOffFactor;
1113 break;
1114
1115 case AL_REFERENCE_DISTANCE:
1116 *plValue = (ALint)pSource->flRefDistance;
1117 break;
1118
1119 case AL_SOURCE_RELATIVE:
1120 *plValue = pSource->bHeadRelative;
1121 break;
1122
1123 case AL_CONE_INNER_ANGLE:
1124 *plValue = (ALint)pSource->flInnerAngle;
1125 break;
1126
1127 case AL_CONE_OUTER_ANGLE:
1128 *plValue = (ALint)pSource->flOuterAngle;
1129 break;
1130
1131 case AL_LOOPING:
1132 *plValue = pSource->bLooping;
1133 break;
1134
1135 case AL_BUFFER:
1136 *plValue = pSource->ulBufferID;
1137 break;
1138
1139 case AL_SOURCE_STATE:
1140 *plValue = pSource->state;
1141 break;
1142
1143 case AL_BUFFERS_QUEUED:
1144 *plValue = pSource->BuffersInQueue;
1145 break;
1146
1147 case AL_BUFFERS_PROCESSED:
1148 if(pSource->bLooping)
1149 {
1150 /* Buffers on a looping source are in a perpetual state
1151 * of PENDING, so don't report any as PROCESSED */
1152 *plValue = 0;
1153 }
1154 else
1155 *plValue = pSource->BuffersProcessed;
1156 break;
1157
1158 case AL_SOURCE_TYPE:
1159 *plValue = pSource->lSourceType;
1160 break;
1161
1162 case AL_SEC_OFFSET:
1163 case AL_SAMPLE_OFFSET:
1164 case AL_BYTE_OFFSET:
1165 if (GetSourceOffset(pSource, eParam, &flOffset))
1166 *plValue = (ALint)flOffset;
1167 else
1168 alSetError(AL_INVALID_OPERATION);
1169 break;
1170
1171 case AL_DIRECT_FILTER:
1172 *plValue = pSource->DirectFilter.filter;
1173 break;
1174
1175 case AL_DIRECT_FILTER_GAINHF_AUTO:
1176 *plValue = pSource->DryGainHFAuto;
1177 break;
1178
1179 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1180 *plValue = pSource->WetGainAuto;
1181 break;
1182
1183 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1184 *plValue = pSource->WetGainHFAuto;
1185 break;
1186
1187 default:
1188 alSetError(AL_INVALID_ENUM);
1189 break;
1190 }
1191 }
1192 else
1193 alSetError(AL_INVALID_NAME);
1194 }
1195 else
1196 alSetError(AL_INVALID_VALUE);
1197
1198 ProcessContext(pContext);
1199 }
1200 else
1201 alSetError(AL_INVALID_OPERATION);
1202
1203 return;
1204 }
1205
1206
1207 ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
1208 {
1209 ALCcontext *pContext;
1210 ALsource *pSource;
1211
1212 pContext = alcGetCurrentContext();
1213 if (pContext)
1214 {
1215 SuspendContext(pContext);
1216
1217 if ((plValue1) && (plValue2) && (plValue3))
1218 {
1219 if (alIsSource(source))
1220 {
1221 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1222
1223 switch(eParam)
1224 {
1225 case AL_POSITION:
1226 *plValue1 = (ALint)pSource->vPosition[0];
1227 *plValue2 = (ALint)pSource->vPosition[1];
1228 *plValue3 = (ALint)pSource->vPosition[2];
1229 break;
1230
1231 case AL_VELOCITY:
1232 *plValue1 = (ALint)pSource->vVelocity[0];
1233 *plValue2 = (ALint)pSource->vVelocity[1];
1234 *plValue3 = (ALint)pSource->vVelocity[2];
1235 break;
1236
1237 case AL_DIRECTION:
1238 *plValue1 = (ALint)pSource->vOrientation[0];
1239 *plValue2 = (ALint)pSource->vOrientation[1];
1240 *plValue3 = (ALint)pSource->vOrientation[2];
1241 break;
1242
1243 default:
1244 alSetError(AL_INVALID_ENUM);
1245 break;
1246 }
1247 }
1248 else
1249 alSetError(AL_INVALID_NAME);
1250 }
1251 else
1252 alSetError(AL_INVALID_VALUE);
1253
1254 ProcessContext(pContext);
1255 }
1256 else
1257 alSetError(AL_INVALID_OPERATION);
1258
1259 return;
1260 }
1261
1262
1263 ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
1264 {
1265 ALCcontext *pContext;
1266 ALsource *pSource;
1267
1268 pContext = alcGetCurrentContext();
1269 if (pContext)
1270 {
1271 SuspendContext(pContext);
1272
1273 if (plValues)
1274 {
1275 if (alIsSource(source))
1276 {
1277 pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
1278
1279 switch (eParam)
1280 {
1281 case AL_SOURCE_RELATIVE:
1282 case AL_CONE_INNER_ANGLE:
1283 case AL_CONE_OUTER_ANGLE:
1284 case AL_LOOPING:
1285 case AL_BUFFER:
1286 case AL_SOURCE_STATE:
1287 case AL_BUFFERS_QUEUED:
1288 case AL_BUFFERS_PROCESSED:
1289 case AL_SEC_OFFSET:
1290 case AL_SAMPLE_OFFSET:
1291 case AL_BYTE_OFFSET:
1292 case AL_MAX_DISTANCE:
1293 case AL_ROLLOFF_FACTOR:
1294 case AL_REFERENCE_DISTANCE:
1295 case AL_SOURCE_TYPE:
1296 case AL_DIRECT_FILTER:
1297 case AL_DIRECT_FILTER_GAINHF_AUTO:
1298 case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
1299 case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
1300 alGetSourcei(source, eParam, plValues);
1301 break;
1302
1303 case AL_POSITION:
1304 plValues[0] = (ALint)pSource->vPosition[0];
1305 plValues[1] = (ALint)pSource->vPosition[1];
1306 plValues[2] = (ALint)pSource->vPosition[2];
1307 break;
1308
1309 case AL_VELOCITY:
1310 plValues[0] = (ALint)pSource->vVelocity[0];
1311 plValues[1] = (ALint)pSource->vVelocity[1];
1312 plValues[2] = (ALint)pSource->vVelocity[2];
1313 break;
1314
1315 case AL_DIRECTION:
1316 plValues[0] = (ALint)pSource->vOrientation[0];
1317 plValues[1] = (ALint)pSource->vOrientation[1];
1318 plValues[2] = (ALint)pSource->vOrientation[2];
1319 break;
1320
1321 default:
1322 alSetError(AL_INVALID_ENUM);
1323 break;
1324 }
1325 }
1326 else
1327 alSetError(AL_INVALID_NAME);
1328 }
1329 else
1330 alSetError(AL_INVALID_VALUE);
1331
1332 ProcessContext(pContext);
1333 }
1334 else
1335 alSetError(AL_INVALID_OPERATION);
1336
1337 return;
1338 }
1339
1340
1341 ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
1342 {
1343 alSourcePlayv(1, &source);
1344 return;
1345 }
1346
1347 ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
1348 {
1349 ALCcontext *pContext;
1350 ALsource *pSource;
1351 ALbufferlistitem *ALBufferList;
1352 ALboolean bSourcesValid = AL_TRUE;
1353 ALboolean bPlay;
1354 ALsizei i;
1355
1356 pContext = alcGetCurrentContext();
1357 if (pContext)
1358 {
1359 SuspendContext(pContext);
1360
1361 if (pSourceList)
1362 {
1363 // Check that all the Sources are valid
1364 for (i = 0; i < n; i++)
1365 {
1366 if (!alIsSource(pSourceList[i]))
1367 {
1368 alSetError(AL_INVALID_NAME);
1369 bSourcesValid = AL_FALSE;
1370 break;
1371 }
1372 }
1373
1374 if (bSourcesValid)
1375 {
1376 for (i = 0; i < n; i++)
1377 {
1378 // Assume Source won't need to play
1379 bPlay = AL_FALSE;
1380
1381 pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i]));
1382
1383 // Check that there is a queue containing at least one non-null, non zero length AL Buffer
1384 ALBufferList = pSource->queue;
1385 while (ALBufferList)
1386 {
1387 if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size))
1388 {
1389 bPlay = AL_TRUE;
1390 break;
1391 }
1392 ALBufferList = ALBufferList->next;
1393 }
1394
1395 if (bPlay)
1396 {
1397 if (pSource->state != AL_PAUSED)
1398 {
1399 pSource->state = AL_PLAYING;
1400 pSource->inuse = AL_TRUE;
1401 pSource->play = AL_TRUE;
1402 pSource->position = 0;
1403 pSource->position_fraction = 0;
1404 pSource->BuffersProcessed = 0;
1405 pSource->BuffersPlayed = 0;
1406 pSource->BufferPosition = 0;
1407 pSource->lBytesPlayed = 0;
1408
1409 pSource->ulBufferID = pSource->queue->buffer;
1410
1411 // Make sure all the Buffers in the queue are marked as PENDING
1412 ALBufferList = pSource->queue;
1413 while (ALBufferList)
1414 {
1415 ALBufferList->bufferstate = PENDING;
1416 ALBufferList = ALBufferList->next;
1417 }
1418 }
1419 else
1420 {
1421 pSource->state = AL_PLAYING;
1422 pSource->inuse = AL_TRUE;
1423 pSource->play = AL_TRUE;
1424 }
1425
1426 // Check if an Offset has been set
1427 if (pSource->lOffset)
1428 ApplyOffset(pSource, AL_FALSE);
1429 }
1430 else
1431 {
1432 // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed
1433 ALBufferList = pSource->queue;
1434 while (ALBufferList)
1435 {
1436 ALBufferList->bufferstate = PROCESSED;
1437 ALBufferList = ALBufferList->next;
1438 }
1439
1440 pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
1441 }
1442 }
1443 }
1444 }
1445 else
1446 {
1447 // sources is a NULL pointer
1448 alSetError(AL_INVALID_VALUE);
1449 }
1450
1451 ProcessContext(pContext);
1452 }
1453 else
1454 {
1455 // Invalid Context
1456 alSetError(AL_INVALID_OPERATION);
1457 }
1458
1459 return;
1460 }
1461
1462 ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source)
1463 {
1464 alSourcePausev(1, &source);
1465 return;
1466 }
1467
1468 ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
1469 {
1470 ALCcontext *Context;
1471 ALsource *Source;
1472 ALsizei i;
1473 ALboolean bSourcesValid = AL_TRUE;
1474
1475 Context=alcGetCurrentContext();
1476 if (Context)
1477 {
1478 SuspendContext(Context);
1479
1480 if (sources)
1481 {
1482 // Check all the Sources are valid
1483 for (i=0;i<n;i++)
1484 {
1485 if (!alIsSource(sources[i]))
1486 {
1487 alSetError(AL_INVALID_NAME);
1488 bSourcesValid = AL_FALSE;
1489 break;
1490 }
1491 }
1492
1493 if (bSourcesValid)
1494 {
1495 for (i=0;i<n;i++)
1496 {
1497 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1498 if (Source->state==AL_PLAYING)
1499 {
1500 Source->state=AL_PAUSED;
1501 Source->inuse=AL_FALSE;
1502 }
1503 }
1504 }
1505 }
1506 else
1507 {
1508 // sources is a NULL pointer
1509 alSetError(AL_INVALID_VALUE);
1510 }
1511
1512 ProcessContext(Context);
1513 }
1514 else
1515 {
1516 // Invalid Context
1517 alSetError(AL_INVALID_OPERATION);
1518 }
1519
1520 return;
1521 }
1522
1523 ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source)
1524 {
1525 alSourceStopv(1, &source);
1526 return;
1527 }
1528
1529 ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
1530 {
1531 ALCcontext *Context;
1532 ALsource *Source;
1533 ALsizei i;
1534 ALbufferlistitem *ALBufferListItem;
1535 ALboolean bSourcesValid = AL_TRUE;
1536
1537 Context=alcGetCurrentContext();
1538 if (Context)
1539 {
1540 SuspendContext(Context);
1541
1542 if (sources)
1543 {
1544 // Check all the Sources are valid
1545 for (i=0;i<n;i++)
1546 {
1547 if (!alIsSource(sources[i]))
1548 {
1549 alSetError(AL_INVALID_NAME);
1550 bSourcesValid = AL_FALSE;
1551 break;
1552 }
1553 }
1554
1555 if (bSourcesValid)
1556 {
1557 for (i=0;i<n;i++)
1558 {
1559 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1560 if (Source->state!=AL_INITIAL)
1561 {
1562 Source->state=AL_STOPPED;
1563 Source->inuse=AL_FALSE;
1564 Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
1565 ALBufferListItem= Source->queue;
1566 while (ALBufferListItem != NULL)
1567 {
1568 ALBufferListItem->bufferstate = PROCESSED;
1569 ALBufferListItem = ALBufferListItem->next;
1570 }
1571 }
1572 Source->lOffset = 0;
1573 }
1574 }
1575 }
1576 else
1577 {
1578 // sources is a NULL pointer
1579 alSetError(AL_INVALID_VALUE);
1580 }
1581
1582 ProcessContext(Context);
1583 }
1584 else
1585 {
1586 // Invalid Context
1587 alSetError(AL_INVALID_OPERATION);
1588 }
1589
1590 return;
1591 }
1592
1593 ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source)
1594 {
1595 alSourceRewindv(1, &source);
1596 return;
1597 }
1598
1599 ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
1600 {
1601 ALCcontext *Context;
1602 ALsource *Source;
1603 ALsizei i;
1604 ALbufferlistitem *ALBufferListItem;
1605 ALboolean bSourcesValid = AL_TRUE;
1606
1607 Context=alcGetCurrentContext();
1608 if (Context)
1609 {
1610 SuspendContext(Context);
1611
1612 if (sources)
1613 {
1614 // Check all the Sources are valid
1615 for (i=0;i<n;i++)
1616 {
1617 if (!alIsSource(sources[i]))
1618 {
1619 alSetError(AL_INVALID_NAME);
1620 bSourcesValid = AL_FALSE;
1621 break;
1622 }
1623 }
1624
1625 if (bSourcesValid)
1626 {
1627 for (i=0;i<n;i++)
1628 {
1629 Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
1630 if (Source->state!=AL_INITIAL)
1631 {
1632 Source->state=AL_INITIAL;
1633 Source->inuse=AL_FALSE;
1634 Source->position=0;
1635 Source->position_fraction=0;
1636 Source->BuffersProcessed = 0;
1637 ALBufferListItem= Source->queue;
1638 while (ALBufferListItem != NULL)
1639 {
1640 ALBufferListItem->bufferstate = PENDING;
1641 ALBufferListItem = ALBufferListItem->next;
1642 }
1643 if (Source->queue)
1644 Source->ulBufferID = Source->queue->buffer;
1645 }
1646 Source->lOffset = 0;
1647 }
1648 }
1649 }
1650 else
1651 {
1652 // sources is a NULL pointer
1653 alSetError(AL_INVALID_VALUE);
1654 }
1655
1656 ProcessContext(Context);
1657 }
1658 else
1659 {
1660 // Invalid Context
1661 alSetError(AL_INVALID_OPERATION);
1662 }
1663
1664 return;
1665 }
1666
1667
1668 ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers )
1669 {
1670 ALCcontext *Context;
1671 ALsource *ALSource;
1672 ALsizei i;
1673 ALbufferlistitem *ALBufferList;
1674 ALbufferlistitem *ALBufferListStart;
1675 ALuint DataSize;
1676 ALuint BufferSize;
1677 ALint iFrequency;
1678 ALint iFormat;
1679 ALboolean bBuffersValid = AL_TRUE;
1680
1681 if (n == 0)
1682 return;
1683
1684 Context=alcGetCurrentContext();
1685 if (Context)
1686 {
1687 SuspendContext(Context);
1688
1689 DataSize = 0;
1690 BufferSize = 0;
1691
1692 // Check that all buffers are valid or zero and that the source is valid
1693
1694 // Check that this is a valid source
1695 if (alIsSource(source))
1696 {
1697 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1698
1699 // Check that this is not a STATIC Source
1700 if (ALSource->lSourceType != AL_STATIC)
1701 {
1702 iFrequency = -1;
1703 iFormat = -1;
1704
1705 // Check existing Queue (if any) for a valid Buffers and get its frequency and format
1706 ALBufferList = ALSource->queue;
1707 while (ALBufferList)
1708 {
1709 if (ALBufferList->buffer)
1710 {
1711 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency;
1712 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format;
1713 break;
1714 }
1715 ALBufferList = ALBufferList->next;
1716 }
1717
1718 for (i = 0; i < n; i++)
1719 {
1720 if (alIsBuffer(buffers[i]))
1721 {
1722 if (buffers[i])
1723 {
1724 if ((iFrequency == -1) && (iFormat == -1))
1725 {
1726 iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency;
1727 iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format;
1728 }
1729 else
1730 {
1731 if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) ||
1732 (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format))
1733 {
1734 alSetError(AL_INVALID_OPERATION);
1735 bBuffersValid = AL_FALSE;
1736 break;
1737 }
1738 }
1739 }
1740 }
1741 else
1742 {
1743 alSetError(AL_INVALID_NAME);
1744 bBuffersValid = AL_FALSE;
1745 break;
1746 }
1747 }
1748
1749 if (bBuffersValid)
1750 {
1751 // Change Source Type
1752 ALSource->lSourceType = AL_STREAMING;
1753
1754 // All buffers are valid - so add them to the list
1755 ALBufferListStart = malloc(sizeof(ALbufferlistitem));
1756 ALBufferListStart->buffer = buffers[0];
1757 ALBufferListStart->bufferstate = PENDING;
1758 ALBufferListStart->flag = 0;
1759 ALBufferListStart->next = NULL;
1760
1761 if (buffers[0])
1762 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size;
1763 else
1764 BufferSize = 0;
1765
1766 DataSize += BufferSize;
1767
1768 // Increment reference counter for buffer
1769 if (buffers[0])
1770 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++;
1771
1772 ALBufferList = ALBufferListStart;
1773
1774 for (i = 1; i < n; i++)
1775 {
1776 ALBufferList->next = malloc(sizeof(ALbufferlistitem));
1777 ALBufferList->next->buffer = buffers[i];
1778 ALBufferList->next->bufferstate = PENDING;
1779 ALBufferList->next->flag = 0;
1780 ALBufferList->next->next = NULL;
1781
1782 if (buffers[i])
1783 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size;
1784 else
1785 BufferSize = 0;
1786
1787 DataSize += BufferSize;
1788
1789 // Increment reference counter for buffer
1790 if (buffers[i])
1791 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++;
1792
1793 ALBufferList = ALBufferList->next;
1794 }
1795
1796 if (ALSource->queue == NULL)
1797 {
1798 ALSource->queue = ALBufferListStart;
1799 // Update Current Buffer
1800 ALSource->ulBufferID = ALBufferListStart->buffer;
1801 }
1802 else
1803 {
1804 // Find end of queue
1805 ALBufferList = ALSource->queue;
1806 while (ALBufferList->next != NULL)
1807 {
1808 ALBufferList = ALBufferList->next;
1809 }
1810
1811 ALBufferList->next = ALBufferListStart;
1812 }
1813
1814 // Update number of buffers in queue
1815 ALSource->BuffersInQueue += n;
1816 }
1817 }
1818 else
1819 {
1820 // Invalid Source Type (can't queue on a Static Source)
1821 alSetError(AL_INVALID_OPERATION);
1822 }
1823 }
1824 else
1825 {
1826 // Invalid Source Name
1827 alSetError(AL_INVALID_NAME);
1828 }
1829
1830 ProcessContext(Context);
1831 }
1832 else
1833 {
1834 // Invalid Context
1835 alSetError(AL_INVALID_OPERATION);
1836 }
1837
1838 return;
1839 }
1840
1841
1842 // Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
1843 // an array of buffer IDs that are to be filled with the names of the buffers removed
1844 ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
1845 {
1846 ALCcontext *Context;
1847 ALsource *ALSource;
1848 ALsizei i;
1849 ALbufferlistitem *ALBufferList;
1850 ALuint DataSize;
1851 ALuint BufferSize;
1852 ALuint BufferID;
1853 ALboolean bBuffersProcessed;
1854
1855 if (n == 0)
1856 return;
1857
1858 DataSize = 0;
1859 BufferSize = 0;
1860 bBuffersProcessed = AL_TRUE;
1861
1862 Context=alcGetCurrentContext();
1863 if (Context)
1864 {
1865 SuspendContext(Context);
1866
1867 if (alIsSource(source))
1868 {
1869 ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source);
1870
1871 // Check that all 'n' buffers have been processed
1872 ALBufferList = ALSource->queue;
1873 for (i = 0; i < n; i++)
1874 {
1875 if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED))
1876 {
1877 ALBufferList = ALBufferList->next;
1878 }
1879 else
1880 {
1881 bBuffersProcessed = AL_FALSE;
1882 break;
1883 }
1884 }
1885
1886 // If all 'n' buffers have been processed, remove them from the queue
1887 if (bBuffersProcessed)
1888 {
1889 for (i = 0; i < n; i++)
1890 {
1891 ALBufferList = ALSource->queue;
1892
1893 ALSource->queue = ALBufferList->next;
1894 // Record name of buffer
1895 buffers[i] = ALBufferList->buffer;
1896 // Decrement buffer reference counter
1897 if (ALBufferList->buffer)
1898 ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
1899 // Record size of buffer
1900 if (ALBufferList->buffer)
1901 BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size;
1902 else
1903 BufferSize = 0;
1904
1905 DataSize += BufferSize;
1906 // Release memory for buffer list item
1907 free(ALBufferList);
1908 ALSource->BuffersInQueue--;
1909 ALSource->BuffersProcessed--;
1910 }
1911
1912 if (ALSource->state != AL_PLAYING)
1913 {
1914 if (ALSource->queue)
1915 BufferID = ALSource->queue->buffer;
1916 else
1917 BufferID = 0;
1918
1919 ALSource->ulBufferID = BufferID;
1920 }
1921
1922 if((ALuint)n > ALSource->BuffersPlayed)
1923 {
1924 ALSource->BuffersPlayed = 0;
1925 ALSource->BufferPosition = 0;
1926 }
1927 else
1928 ALSource->BuffersPlayed -= n;
1929 }
1930 else
1931 {
1932 // Some buffers can't be unqueue because they have not been processed
1933 alSetError(AL_INVALID_VALUE);
1934 }
1935 }
1936 else
1937 {
1938 // Invalid Source Name
1939 alSetError(AL_INVALID_NAME);
1940 }
1941
1942 ProcessContext(Context);
1943 }
1944 else
1945 {
1946 // Invalid Context
1947 alSetError(AL_INVALID_OPERATION);
1948 }
1949
1950 return;
1951 }
1952
1953
1954 static ALvoid InitSourceParams(ALsource *pSource)
1955 {
1956 pSource->flInnerAngle = 360.0f;
1957 pSource->flOuterAngle = 360.0f;
1958 pSource->flPitch = 1.0f;
1959 pSource->vPosition[0] = 0.0f;
1960 pSource->vPosition[1] = 0.0f;
1961 pSource->vPosition[2] = 0.0f;
1962 pSource->vOrientation[0] = 0.0f;
1963 pSource->vOrientation[1] = 0.0f;
1964 pSource->vOrientation[2] = 0.0f;
1965 pSource->vVelocity[0] = 0.0f;
1966 pSource->vVelocity[1] = 0.0f;
1967 pSource->vVelocity[2] = 0.0f;
1968 pSource->flRefDistance = 1.0f;
1969 pSource->flMaxDistance = FLT_MAX;
1970 pSource->flRollOffFactor = 1.0f;
1971 pSource->bLooping = AL_FALSE;
1972 pSource->flGain = 1.0f;
1973 pSource->flMinGain = 0.0f;
1974 pSource->flMaxGain = 1.0f;
1975 pSource->flOuterGain = 0.0f;
1976 pSource->OuterGainHF = 1.0f;
1977
1978 pSource->DryGainHFAuto = AL_TRUE;
1979 pSource->WetGainAuto = AL_TRUE;
1980 pSource->WetGainHFAuto = AL_TRUE;
1981 pSource->AirAbsorptionFactor = 0.0f;
1982 pSource->RoomRolloffFactor = 0.0f;
1983
1984 pSource->state = AL_INITIAL;
1985 pSource->lSourceType = AL_UNDETERMINED;
1986
1987 pSource->ulBufferID= 0;
1988 }
1989
1990
1991 /*
1992 GetSourceOffset
1993
1994 Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
1995 The offset is relative to the start of the queue (not the start of the current buffer)
1996 */
1997 static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
1998 {
1999 ALbufferlistitem *pBufferList;
2000 ALbuffer *pBuffer;
2001 ALfloat flBufferFreq;
2002 ALint lBytesPlayed, lChannels;
2003 ALenum eOriginalFormat;
2004 ALboolean bReturn = AL_TRUE;
2005 ALint lTotalBufferDataSize;
2006
2007 if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
2008 {
2009 pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
2010 // Get Current Buffer Size and frequency (in milliseconds)
2011 flBufferFreq = (ALfloat)pBuffer->frequency;
2012 eOriginalFormat = pBuffer->eOriginalFormat;
2013 lChannels = aluChannelsFromFormat(pBuffer->format);
2014
2015 // Get Current BytesPlayed
2016 lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
2017 // Add byte length of any processed buffers in the queue
2018 pBufferList = pSource->queue;
2019 while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
2020 {
2021 lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2022 pBufferList = pBufferList->next;
2023 }
2024
2025 lTotalBufferDataSize = 0;
2026 pBufferList = pSource->queue;
2027 while (pBufferList)
2028 {
2029 if (pBufferList->buffer)
2030 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2031 pBufferList = pBufferList->next;
2032 }
2033
2034 if (pSource->bLooping)
2035 {
2036 if (lBytesPlayed < 0)
2037 lBytesPlayed = 0;
2038 else
2039 lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
2040 }
2041 else
2042 {
2043 // Clamp BytesPlayed to within 0 and lTotalBufferDataSize
2044 if(lBytesPlayed < 0)
2045 lBytesPlayed = 0;
2046 if(lBytesPlayed > lTotalBufferDataSize)
2047 lBytesPlayed = lTotalBufferDataSize;
2048 }
2049
2050 switch (eName)
2051 {
2052 case AL_SEC_OFFSET:
2053 *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
2054 break;
2055 case AL_SAMPLE_OFFSET:
2056 *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
2057 break;
2058 case AL_BYTE_OFFSET:
2059 // Take into account the original format of the Buffer
2060 if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2061 (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2062 {
2063 // Compression rate of the ADPCM supported is 3.6111 to 1
2064 lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
2065 // Round down to nearest ADPCM block
2066 *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
2067 }
2068 else if (eOriginalFormat == AL_FORMAT_REAR8)
2069 {
2070 *pflOffset = (ALfloat)(lBytesPlayed >> 2);
2071 }
2072 else if (eOriginalFormat == AL_FORMAT_REAR16)
2073 {
2074 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2075 }
2076 else if (aluBytesFromFormat(eOriginalFormat) == 1)
2077 {
2078 *pflOffset = (ALfloat)(lBytesPlayed >> 1);
2079 }
2080 else if (aluBytesFromFormat(eOriginalFormat) == 4)
2081 {
2082 *pflOffset = (ALfloat)(lBytesPlayed << 1);
2083 }
2084 else
2085 {
2086 *pflOffset = (ALfloat)lBytesPlayed;
2087 }
2088 break;
2089 }
2090 }
2091 else
2092 {
2093 *pflOffset = 0.0f;
2094 }
2095
2096 return bReturn;
2097 }
2098
2099
2100 /*
2101 ApplyOffset
2102
2103 Apply a playback offset to the Source. This function will update the queue (to correctly
2104 mark buffers as 'pending' or 'processed' depending upon the new offset.
2105 */
2106 static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
2107 {
2108 ALbufferlistitem *pBufferList;
2109 ALbuffer *pBuffer;
2110 ALint lBufferSize, lTotalBufferSize;
2111 ALint lByteOffset;
2112
2113 // Get true byte offset
2114 lByteOffset = GetByteOffset(pSource);
2115
2116 // If this is a valid offset apply it
2117 if (lByteOffset != -1)
2118 {
2119 // Sort out the queue (pending and processed states)
2120 pBufferList = pSource->queue;
2121 lTotalBufferSize = 0;
2122 pSource->BuffersPlayed = 0;
2123 pSource->BuffersProcessed = 0;
2124 while (pBufferList)
2125 {
2126 pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2127 lBufferSize = pBuffer ? pBuffer->size : 0;
2128
2129 if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
2130 {
2131 // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping
2132 // update the state to PROCESSED
2133 pSource->BuffersPlayed++;
2134
2135 if (!pSource->bLooping)
2136 {
2137 pBufferList->bufferstate = PROCESSED;
2138 pSource->BuffersProcessed++;
2139 }
2140 }
2141 else if (lTotalBufferSize <= lByteOffset)
2142 {
2143 // Offset is within this buffer
2144 pBufferList->bufferstate = PENDING;
2145
2146 // Set Current Buffer ID
2147 pSource->ulBufferID = pBufferList->buffer;
2148
2149 // Set current position in this buffer
2150 pSource->BufferPosition = lByteOffset - lTotalBufferSize;
2151
2152 // Set Total Bytes Played to Offset
2153 pSource->lBytesPlayed = lByteOffset;
2154
2155 // SW Mixer Positions are in Samples
2156 pSource->position = pSource->BufferPosition /
2157 aluBytesFromFormat(pBuffer->format) /
2158 aluChannelsFromFormat(pBuffer->format);
2159 }
2160 else
2161 {
2162 // Offset is before this buffer, so mark as pending
2163 pBufferList->bufferstate = PENDING;
2164 }
2165
2166 // Increment the TotalBufferSize
2167 lTotalBufferSize += lBufferSize;
2168
2169 // Move on to next buffer in the Queue
2170 pBufferList = pBufferList->next;
2171 }
2172 }
2173 else
2174 {
2175 if (bUpdateContext)
2176 alSetError(AL_INVALID_VALUE);
2177 }
2178
2179 // Clear Offset
2180 pSource->lOffset = 0;
2181 }
2182
2183
2184 /*
2185 GetByteOffset
2186
2187 Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
2188 offset supplied by the application). This takes into account the fact that the buffer format
2189 may have been modifed by AL (e.g 8bit samples are converted to 16bit)
2190 */
2191 static ALint GetByteOffset(ALsource *pSource)
2192 {
2193 ALbuffer *pBuffer = NULL;
2194 ALbufferlistitem *pBufferList;
2195 ALfloat flBufferFreq;
2196 ALint lChannels;
2197 ALint lByteOffset = -1;
2198 ALint lTotalBufferDataSize;
2199
2200 // Find the first non-NULL Buffer in the Queue
2201 pBufferList = pSource->queue;
2202 while (pBufferList)
2203 {
2204 if (pBufferList->buffer)
2205 {
2206 pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
2207 break;
2208 }
2209 pBufferList = pBufferList->next;
2210 }
2211
2212 if (pBuffer)
2213 {
2214 flBufferFreq = ((ALfloat)pBuffer->frequency);
2215 lChannels = aluChannelsFromFormat(pBuffer->format);
2216
2217 // Determine the ByteOffset (and ensure it is block aligned)
2218 switch (pSource->lOffsetType)
2219 {
2220 case AL_BYTE_OFFSET:
2221 // Take into consideration the original format
2222 if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
2223 (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
2224 {
2225 // Round down to nearest ADPCM block
2226 lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
2227 // Multiply by compression rate
2228 lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
2229 lByteOffset -= (lByteOffset % (lChannels * 2));
2230 }
2231 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
2232 {
2233 lByteOffset = pSource->lOffset * 4;
2234 lByteOffset -= (lByteOffset % (lChannels * 2));
2235 }
2236 else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
2237 {
2238 lByteOffset = pSource->lOffset * 2;
2239 lByteOffset -= (lByteOffset % (lChannels * 2));
2240 }
2241 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
2242 {
2243 lByteOffset = pSource->lOffset * 2;
2244 lByteOffset -= (lByteOffset % (lChannels * 2));
2245 }
2246 else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
2247 {
2248 lByteOffset = pSource->lOffset / 2;
2249 lByteOffset -= (lByteOffset % (lChannels * 2));
2250 }
2251 else
2252 {
2253 lByteOffset = pSource->lOffset;
2254 lByteOffset -= (lByteOffset % (lChannels * 2));
2255 }
2256 break;
2257
2258 case AL_SAMPLE_OFFSET:
2259 lByteOffset = pSource->lOffset * lChannels * 2;
2260 break;
2261
2262 case AL_SEC_OFFSET:
2263 // Note - lOffset is internally stored as Milliseconds
2264 lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f);
2265 lByteOffset -= (lByteOffset % (lChannels * 2));
2266 break;
2267 }
2268
2269 lTotalBufferDataSize = 0;
2270 pBufferList = pSource->queue;
2271 while (pBufferList)
2272 {
2273 if (pBufferList->buffer)
2274 lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
2275 pBufferList = pBufferList->next;
2276 }
2277
2278 // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1
2279 if (lByteOffset >= lTotalBufferDataSize)
2280 lByteOffset = -1;
2281 }
2282
2283 return lByteOffset;
2284 }
2285
2286
2287 ALvoid ReleaseALSources(ALCcontext *Context)
2288 {
2289 #ifdef _DEBUG
2290 if(Context->SourceCount > 0)
2291 AL_PRINT("alcDestroyContext(): %d Source(s) NOT deleted\n", Context->SourceCount);
2292 #endif
2293
2294 while(Context->Source)
2295 {
2296 ALsource *temp = Context->Source;
2297 Context->Source = Context->Source->next;
2298
2299 // Release source structure
2300 ALTHUNK_REMOVEENTRY(temp->source);
2301 memset(temp, 0, sizeof(ALsource));
2302 free(temp);
2303 }
2304 Context->SourceCount = 0;
2305 }