Mercurial > fife-parpg
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 } |