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