2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
36 #include "sample_cvt.h"
39 extern inline void LockBuffersRead(ALCdevice
*device
);
40 extern inline void UnlockBuffersRead(ALCdevice
*device
);
41 extern inline void LockBuffersWrite(ALCdevice
*device
);
42 extern inline void UnlockBuffersWrite(ALCdevice
*device
);
43 extern inline struct ALbuffer
*LookupBuffer(ALCdevice
*device
, ALuint id
);
44 extern inline struct ALbuffer
*RemoveBuffer(ALCdevice
*device
, ALuint id
);
45 extern inline ALsizei
FrameSizeFromUserFmt(enum UserFmtChannels chans
, enum UserFmtType type
);
46 extern inline ALsizei
FrameSizeFromFmt(enum FmtChannels chans
, enum FmtType type
);
48 static void LoadData(ALCcontext
*context
, ALbuffer
*buffer
, ALuint freq
, ALsizei frames
,
49 enum UserFmtChannels SrcChannels
, enum UserFmtType SrcType
,
50 const ALvoid
*data
, ALsizei align
, ALbitfieldSOFT access
);
51 static ALboolean
DecomposeUserFormat(ALenum format
, enum UserFmtChannels
*chans
, enum UserFmtType
*type
);
52 static ALsizei
SanitizeAlignment(enum UserFmtType type
, ALsizei align
);
55 #define INVALID_STORAGE_MASK ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT)
56 #define MAP_READ_WRITE_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT)
57 #define INVALID_MAP_FLAGS ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT)
60 AL_API ALvoid AL_APIENTRY
alGenBuffers(ALsizei n
, ALuint
*buffers
)
65 context
= GetContextRef();
69 alSetError(context
, AL_INVALID_VALUE
, "Generating %d buffers", n
);
70 else for(cur
= 0;cur
< n
;cur
++)
72 ALbuffer
*buffer
= NewBuffer(context
);
75 alDeleteBuffers(cur
, buffers
);
79 buffers
[cur
] = buffer
->id
;
82 ALCcontext_DecRef(context
);
85 AL_API ALvoid AL_APIENTRY
alDeleteBuffers(ALsizei n
, const ALuint
*buffers
)
92 context
= GetContextRef();
95 device
= context
->Device
;
97 LockBuffersWrite(device
);
100 alSetError(context
, AL_INVALID_VALUE
, "Deleting %d buffers", n
);
109 /* Check for valid Buffer ID, and make sure it's not in use. */
110 if((ALBuf
=LookupBuffer(device
, buffers
[i
])) == NULL
)
112 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffers
[i
]);
115 if(ReadRef(&ALBuf
->ref
) != 0)
117 alSetError(context
, AL_INVALID_OPERATION
, "Deleting in-use buffer %u", buffers
[i
]);
123 if((ALBuf
=LookupBuffer(device
, buffers
[i
])) != NULL
)
124 DeleteBuffer(device
, ALBuf
);
128 UnlockBuffersWrite(device
);
129 ALCcontext_DecRef(context
);
132 AL_API ALboolean AL_APIENTRY
alIsBuffer(ALuint buffer
)
137 context
= GetContextRef();
138 if(!context
) return AL_FALSE
;
140 LockBuffersRead(context
->Device
);
141 ret
= ((!buffer
|| LookupBuffer(context
->Device
, buffer
)) ?
143 UnlockBuffersRead(context
->Device
);
145 ALCcontext_DecRef(context
);
151 AL_API ALvoid AL_APIENTRY
alBufferData(ALuint buffer
, ALenum format
, const ALvoid
*data
, ALsizei size
, ALsizei freq
)
152 { alBufferStorageSOFT(buffer
, format
, data
, size
, freq
, 0); }
154 AL_API
void AL_APIENTRY
alBufferStorageSOFT(ALuint buffer
, ALenum format
, const ALvoid
*data
, ALsizei size
, ALsizei freq
, ALbitfieldSOFT flags
)
156 enum UserFmtChannels srcchannels
= UserFmtMono
;
157 enum UserFmtType srctype
= UserFmtUByte
;
161 ALsizei framesize
= 1;
164 context
= GetContextRef();
167 device
= context
->Device
;
168 LockBuffersRead(device
);
169 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
170 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
171 else if(UNLIKELY(size
< 0))
172 alSetError(context
, AL_INVALID_VALUE
, "Negative storage size %d", size
);
173 else if(UNLIKELY(freq
< 1))
174 alSetError(context
, AL_INVALID_VALUE
, "Invalid sample rate %d", freq
);
175 else if(UNLIKELY((flags
&INVALID_STORAGE_MASK
) != 0))
176 alSetError(context
, AL_INVALID_VALUE
, "Invalid storage flags 0x%x",
177 flags
&INVALID_STORAGE_MASK
);
178 else if(UNLIKELY((flags
&AL_MAP_PERSISTENT_BIT_SOFT
) && !(flags
&MAP_READ_WRITE_FLAGS
)))
179 alSetError(context
, AL_INVALID_VALUE
,
180 "Declaring persistently mapped storage without read or write access");
181 else if(UNLIKELY(DecomposeUserFormat(format
, &srcchannels
, &srctype
) == AL_FALSE
))
182 alSetError(context
, AL_INVALID_ENUM
, "Invalid format 0x%04x", format
);
183 else if(UNLIKELY((align
=SanitizeAlignment(srctype
, ATOMIC_LOAD_SEQ(&albuf
->UnpackAlign
))) < 1))
184 alSetError(context
, AL_INVALID_VALUE
, "Invalid unpack alignment");
195 framesize
= FrameSizeFromUserFmt(srcchannels
, srctype
) * align
;
199 framesize
= ((align
-1)/2 + 4) * ChannelsFromUserFmt(srcchannels
);
203 framesize
= ((align
-2)/2 + 7) * ChannelsFromUserFmt(srcchannels
);
206 if((size
%framesize
) != 0)
207 alSetError(context
, AL_INVALID_VALUE
,
208 "Data size %d is not a multiple of frame size %d (%d unpack alignment)",
209 size
, framesize
, align
);
211 LoadData(context
, albuf
, freq
, size
/framesize
*align
, srcchannels
, srctype
, data
, align
,
215 UnlockBuffersRead(device
);
216 ALCcontext_DecRef(context
);
219 AL_API
void* AL_APIENTRY
alMapBufferSOFT(ALuint buffer
, ALsizei offset
, ALsizei length
, ALbitfieldSOFT access
)
226 context
= GetContextRef();
227 if(!context
) return retval
;
229 device
= context
->Device
;
230 LockBuffersRead(device
);
231 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
232 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
233 else if(UNLIKELY((access
&INVALID_MAP_FLAGS
) != 0))
234 alSetError(context
, AL_INVALID_VALUE
, "Invalid map flags 0x%x", access
&INVALID_MAP_FLAGS
);
235 else if(UNLIKELY(!(access
&MAP_READ_WRITE_FLAGS
)))
236 alSetError(context
, AL_INVALID_VALUE
, "Mapping buffer %u without read or write access",
240 ALbitfieldSOFT unavailable
;
241 WriteLock(&albuf
->lock
);
242 unavailable
= (albuf
->Access
^access
) & access
;
243 if(UNLIKELY(ReadRef(&albuf
->ref
) != 0 && !(access
&AL_MAP_PERSISTENT_BIT_SOFT
)))
244 alSetError(context
, AL_INVALID_OPERATION
,
245 "Mapping in-use buffer %u without persistent mapping", buffer
);
246 else if(UNLIKELY(albuf
->MappedAccess
!= 0))
247 alSetError(context
, AL_INVALID_OPERATION
, "Mapping already-mapped buffer %u", buffer
);
248 else if(UNLIKELY((unavailable
&AL_MAP_READ_BIT_SOFT
)))
249 alSetError(context
, AL_INVALID_VALUE
,
250 "Mapping buffer %u for reading without read access", buffer
);
251 else if(UNLIKELY((unavailable
&AL_MAP_WRITE_BIT_SOFT
)))
252 alSetError(context
, AL_INVALID_VALUE
,
253 "Mapping buffer %u for writing without write access", buffer
);
254 else if(UNLIKELY((unavailable
&AL_MAP_PERSISTENT_BIT_SOFT
)))
255 alSetError(context
, AL_INVALID_VALUE
,
256 "Mapping buffer %u persistently without persistent access", buffer
);
257 else if(UNLIKELY(offset
< 0 || offset
>= albuf
->OriginalSize
||
258 length
<= 0 || length
> albuf
->OriginalSize
- offset
))
259 alSetError(context
, AL_INVALID_VALUE
, "Mapping invalid range %d+%d for buffer %u",
260 offset
, length
, buffer
);
263 retval
= (ALbyte
*)albuf
->data
+ offset
;
264 albuf
->MappedAccess
= access
;
265 albuf
->MappedOffset
= offset
;
266 albuf
->MappedSize
= length
;
269 WriteUnlock(&albuf
->lock
);
271 UnlockBuffersRead(device
);
273 ALCcontext_DecRef(context
);
277 AL_API
void AL_APIENTRY
alUnmapBufferSOFT(ALuint buffer
)
283 context
= GetContextRef();
286 device
= context
->Device
;
287 LockBuffersRead(device
);
288 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
289 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
292 WriteLock(&albuf
->lock
);
293 if(albuf
->MappedAccess
== 0)
294 alSetError(context
, AL_INVALID_OPERATION
, "Unmapping unmapped buffer %u", buffer
);
297 albuf
->MappedAccess
= 0;
298 albuf
->MappedOffset
= 0;
299 albuf
->MappedSize
= 0;
301 WriteUnlock(&albuf
->lock
);
303 UnlockBuffersRead(device
);
305 ALCcontext_DecRef(context
);
308 AL_API
void AL_APIENTRY
alFlushMappedBufferSOFT(ALuint buffer
, ALsizei offset
, ALsizei length
)
314 context
= GetContextRef();
317 device
= context
->Device
;
318 LockBuffersRead(device
);
319 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
320 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
323 WriteLock(&albuf
->lock
);
324 if(UNLIKELY(!(albuf
->MappedAccess
&AL_MAP_WRITE_BIT_SOFT
)))
325 alSetError(context
, AL_INVALID_OPERATION
,
326 "Flushing buffer %u while not mapped for writing", buffer
);
327 else if(UNLIKELY(offset
< albuf
->MappedOffset
||
328 offset
>= albuf
->MappedOffset
+albuf
->MappedSize
||
329 length
<= 0 || length
> albuf
->MappedOffset
+albuf
->MappedSize
-offset
))
330 alSetError(context
, AL_INVALID_VALUE
, "Flushing invalid range %d+%d on buffer %u",
331 offset
, length
, buffer
);
334 /* FIXME: Need to use some method of double-buffering for the mixer
335 * and app to hold separate memory, which can be safely transfered
336 * asynchronously. Currently we just say the app shouldn't write
337 * where OpenAL's reading, and hope for the best...
339 ATOMIC_THREAD_FENCE(almemory_order_seq_cst
);
341 WriteUnlock(&albuf
->lock
);
343 UnlockBuffersRead(device
);
345 ALCcontext_DecRef(context
);
348 AL_API ALvoid AL_APIENTRY
alBufferSubDataSOFT(ALuint buffer
, ALenum format
, const ALvoid
*data
, ALsizei offset
, ALsizei length
)
350 enum UserFmtChannels srcchannels
= UserFmtMono
;
351 enum UserFmtType srctype
= UserFmtUByte
;
356 context
= GetContextRef();
359 device
= context
->Device
;
360 LockBuffersRead(device
);
361 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
362 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
363 else if(UNLIKELY(DecomposeUserFormat(format
, &srcchannels
, &srctype
) == AL_FALSE
))
364 alSetError(context
, AL_INVALID_ENUM
, "Invalid format 0x%04x", format
);
367 ALsizei unpack_align
, align
;
373 WriteLock(&albuf
->lock
);
374 unpack_align
= ATOMIC_LOAD_SEQ(&albuf
->UnpackAlign
);
375 align
= SanitizeAlignment(srctype
, unpack_align
);
376 if(UNLIKELY(align
< 1))
377 alSetError(context
, AL_INVALID_VALUE
, "Invalid unpack alignment %d", unpack_align
);
378 else if(UNLIKELY((long)srcchannels
!= (long)albuf
->FmtChannels
||
379 srctype
!= albuf
->OriginalType
))
380 alSetError(context
, AL_INVALID_ENUM
, "Unpacking data with mismatched format");
381 else if(UNLIKELY(align
!= albuf
->OriginalAlign
))
382 alSetError(context
, AL_INVALID_VALUE
,
383 "Unpacking data with alignment %u does not match original alignment %u",
384 align
, albuf
->OriginalAlign
);
385 else if(UNLIKELY(albuf
->MappedAccess
!= 0))
386 alSetError(context
, AL_INVALID_OPERATION
, "Unpacking data into mapped buffer %u",
390 num_chans
= ChannelsFromFmt(albuf
->FmtChannels
);
391 frame_size
= num_chans
* BytesFromFmt(albuf
->FmtType
);
392 if(albuf
->OriginalType
== UserFmtIMA4
)
393 byte_align
= ((align
-1)/2 + 4) * num_chans
;
394 else if(albuf
->OriginalType
== UserFmtMSADPCM
)
395 byte_align
= ((align
-2)/2 + 7) * num_chans
;
397 byte_align
= align
* frame_size
;
399 if(UNLIKELY(offset
< 0 || length
< 0 || offset
> albuf
->OriginalSize
||
400 length
> albuf
->OriginalSize
-offset
))
401 alSetError(context
, AL_INVALID_VALUE
, "Invalid data sub-range %d+%d on buffer %u",
402 offset
, length
, buffer
);
403 else if(UNLIKELY((offset
%byte_align
) != 0))
404 alSetError(context
, AL_INVALID_VALUE
,
405 "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)",
406 offset
, byte_align
, align
);
407 else if(UNLIKELY((length
%byte_align
) != 0))
408 alSetError(context
, AL_INVALID_VALUE
,
409 "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)",
410 length
, byte_align
, align
);
413 /* offset -> byte offset, length -> sample count */
414 offset
= offset
/byte_align
* align
* frame_size
;
415 length
= length
/byte_align
* align
;
417 dst
= (ALbyte
*)albuf
->data
+ offset
;
418 if(srctype
== UserFmtIMA4
&& albuf
->FmtType
== FmtShort
)
419 Convert_ALshort_ALima4(dst
, data
, num_chans
, length
, align
);
420 else if(srctype
== UserFmtMSADPCM
&& albuf
->FmtType
== FmtShort
)
421 Convert_ALshort_ALmsadpcm(dst
, data
, num_chans
, length
, align
);
424 assert((long)srctype
== (long)albuf
->FmtType
);
425 memcpy(dst
, data
, length
*frame_size
);
430 WriteUnlock(&albuf
->lock
);
432 UnlockBuffersRead(device
);
434 ALCcontext_DecRef(context
);
438 AL_API
void AL_APIENTRY
alBufferSamplesSOFT(ALuint
UNUSED(buffer
),
439 ALuint
UNUSED(samplerate
), ALenum
UNUSED(internalformat
), ALsizei
UNUSED(samples
),
440 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), const ALvoid
*UNUSED(data
))
444 context
= GetContextRef();
447 alSetError(context
, AL_INVALID_OPERATION
, "alBufferSamplesSOFT not supported");
449 ALCcontext_DecRef(context
);
452 AL_API
void AL_APIENTRY
alBufferSubSamplesSOFT(ALuint
UNUSED(buffer
),
453 ALsizei
UNUSED(offset
), ALsizei
UNUSED(samples
),
454 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), const ALvoid
*UNUSED(data
))
458 context
= GetContextRef();
461 alSetError(context
, AL_INVALID_OPERATION
, "alBufferSubSamplesSOFT not supported");
463 ALCcontext_DecRef(context
);
466 AL_API
void AL_APIENTRY
alGetBufferSamplesSOFT(ALuint
UNUSED(buffer
),
467 ALsizei
UNUSED(offset
), ALsizei
UNUSED(samples
),
468 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), ALvoid
*UNUSED(data
))
472 context
= GetContextRef();
475 alSetError(context
, AL_INVALID_OPERATION
, "alGetBufferSamplesSOFT not supported");
477 ALCcontext_DecRef(context
);
480 AL_API ALboolean AL_APIENTRY
alIsBufferFormatSupportedSOFT(ALenum
UNUSED(format
))
484 context
= GetContextRef();
485 if(!context
) return AL_FALSE
;
487 alSetError(context
, AL_INVALID_OPERATION
, "alIsBufferFormatSupportedSOFT not supported");
489 ALCcontext_DecRef(context
);
494 AL_API
void AL_APIENTRY
alBufferf(ALuint buffer
, ALenum param
, ALfloat
UNUSED(value
))
499 context
= GetContextRef();
502 device
= context
->Device
;
503 LockBuffersRead(device
);
504 if(UNLIKELY(LookupBuffer(device
, buffer
) == NULL
))
505 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
509 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer float property 0x%04x", param
);
511 UnlockBuffersRead(device
);
513 ALCcontext_DecRef(context
);
517 AL_API
void AL_APIENTRY
alBuffer3f(ALuint buffer
, ALenum param
, ALfloat
UNUSED(value1
), ALfloat
UNUSED(value2
), ALfloat
UNUSED(value3
))
522 context
= GetContextRef();
525 device
= context
->Device
;
526 LockBuffersRead(device
);
527 if(UNLIKELY(LookupBuffer(device
, buffer
) == NULL
))
528 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
532 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer 3-float property 0x%04x", param
);
534 UnlockBuffersRead(device
);
536 ALCcontext_DecRef(context
);
540 AL_API
void AL_APIENTRY
alBufferfv(ALuint buffer
, ALenum param
, const ALfloat
*values
)
545 context
= GetContextRef();
548 device
= context
->Device
;
549 LockBuffersRead(device
);
550 if(UNLIKELY(LookupBuffer(device
, buffer
) == NULL
))
551 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
552 else if(UNLIKELY(!values
))
553 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
557 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer float-vector property 0x%04x", param
);
559 UnlockBuffersRead(device
);
561 ALCcontext_DecRef(context
);
565 AL_API
void AL_APIENTRY
alBufferi(ALuint buffer
, ALenum param
, ALint value
)
571 context
= GetContextRef();
574 device
= context
->Device
;
575 LockBuffersRead(device
);
576 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
577 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
580 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
581 if(UNLIKELY(value
< 0))
582 alSetError(context
, AL_INVALID_VALUE
, "Invalid unpack block alignment %d", value
);
584 ATOMIC_STORE_SEQ(&albuf
->UnpackAlign
, value
);
587 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
588 if(UNLIKELY(value
< 0))
589 alSetError(context
, AL_INVALID_VALUE
, "Invalid pack block alignment %d", value
);
591 ATOMIC_STORE_SEQ(&albuf
->PackAlign
, value
);
595 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer integer property 0x%04x", param
);
597 UnlockBuffersRead(device
);
599 ALCcontext_DecRef(context
);
603 AL_API
void AL_APIENTRY
alBuffer3i(ALuint buffer
, ALenum param
, ALint
UNUSED(value1
), ALint
UNUSED(value2
), ALint
UNUSED(value3
))
608 context
= GetContextRef();
611 device
= context
->Device
;
612 LockBuffersRead(device
);
613 if(UNLIKELY(LookupBuffer(device
, buffer
) == NULL
))
614 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
618 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer 3-integer property 0x%04x", param
);
620 UnlockBuffersRead(device
);
622 ALCcontext_DecRef(context
);
626 AL_API
void AL_APIENTRY
alBufferiv(ALuint buffer
, ALenum param
, const ALint
*values
)
636 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
637 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
638 alBufferi(buffer
, param
, values
[0]);
643 context
= GetContextRef();
646 device
= context
->Device
;
647 LockBuffersRead(device
);
648 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
649 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
650 else if(UNLIKELY(!values
))
651 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
654 case AL_LOOP_POINTS_SOFT
:
655 WriteLock(&albuf
->lock
);
656 if(UNLIKELY(ReadRef(&albuf
->ref
) != 0))
657 alSetError(context
, AL_INVALID_OPERATION
, "Modifying in-use buffer %u's loop points",
659 else if(UNLIKELY(values
[0] >= values
[1] || values
[0] < 0 || values
[1] > albuf
->SampleLen
))
660 alSetError(context
, AL_INVALID_VALUE
, "Invalid loop point range %d -> %d o buffer %u",
661 values
[0], values
[1], buffer
);
664 albuf
->LoopStart
= values
[0];
665 albuf
->LoopEnd
= values
[1];
667 WriteUnlock(&albuf
->lock
);
671 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer integer-vector property 0x%04x",
674 UnlockBuffersRead(device
);
676 ALCcontext_DecRef(context
);
680 AL_API ALvoid AL_APIENTRY
alGetBufferf(ALuint buffer
, ALenum param
, ALfloat
*value
)
686 context
= GetContextRef();
689 device
= context
->Device
;
690 LockBuffersRead(device
);
691 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
692 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
693 else if(UNLIKELY(!value
))
694 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
698 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer float property 0x%04x", param
);
700 UnlockBuffersRead(device
);
702 ALCcontext_DecRef(context
);
706 AL_API
void AL_APIENTRY
alGetBuffer3f(ALuint buffer
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
711 context
= GetContextRef();
714 device
= context
->Device
;
715 LockBuffersRead(device
);
716 if(UNLIKELY(LookupBuffer(device
, buffer
) == NULL
))
717 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
718 else if(UNLIKELY(!value1
|| !value2
|| !value3
))
719 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
723 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer 3-float property 0x%04x", param
);
725 UnlockBuffersRead(device
);
727 ALCcontext_DecRef(context
);
731 AL_API
void AL_APIENTRY
alGetBufferfv(ALuint buffer
, ALenum param
, ALfloat
*values
)
738 case AL_SEC_LENGTH_SOFT
:
739 alGetBufferf(buffer
, param
, values
);
743 context
= GetContextRef();
746 device
= context
->Device
;
747 LockBuffersRead(device
);
748 if(UNLIKELY(LookupBuffer(device
, buffer
) == NULL
))
749 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
750 else if(UNLIKELY(!values
))
751 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
755 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer float-vector property 0x%04x", param
);
757 UnlockBuffersRead(device
);
759 ALCcontext_DecRef(context
);
763 AL_API ALvoid AL_APIENTRY
alGetBufferi(ALuint buffer
, ALenum param
, ALint
*value
)
769 context
= GetContextRef();
772 device
= context
->Device
;
773 LockBuffersRead(device
);
774 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
775 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
776 else if(UNLIKELY(!value
))
777 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
781 *value
= albuf
->Frequency
;
785 *value
= BytesFromFmt(albuf
->FmtType
) * 8;
789 *value
= ChannelsFromFmt(albuf
->FmtChannels
);
793 ReadLock(&albuf
->lock
);
794 *value
= albuf
->SampleLen
* FrameSizeFromFmt(albuf
->FmtChannels
,
796 ReadUnlock(&albuf
->lock
);
799 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
800 *value
= ATOMIC_LOAD_SEQ(&albuf
->UnpackAlign
);
803 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
804 *value
= ATOMIC_LOAD_SEQ(&albuf
->PackAlign
);
808 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer integer property 0x%04x", param
);
810 UnlockBuffersRead(device
);
812 ALCcontext_DecRef(context
);
816 AL_API
void AL_APIENTRY
alGetBuffer3i(ALuint buffer
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
821 context
= GetContextRef();
824 device
= context
->Device
;
825 LockBuffersRead(device
);
826 if(UNLIKELY(LookupBuffer(device
, buffer
) == NULL
))
827 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
828 else if(UNLIKELY(!value1
|| !value2
|| !value3
))
829 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
833 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer 3-integer property 0x%04x", param
);
835 UnlockBuffersRead(device
);
837 ALCcontext_DecRef(context
);
841 AL_API
void AL_APIENTRY
alGetBufferiv(ALuint buffer
, ALenum param
, ALint
*values
)
853 case AL_INTERNAL_FORMAT_SOFT
:
854 case AL_BYTE_LENGTH_SOFT
:
855 case AL_SAMPLE_LENGTH_SOFT
:
856 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
857 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
858 alGetBufferi(buffer
, param
, values
);
862 context
= GetContextRef();
865 device
= context
->Device
;
866 LockBuffersRead(device
);
867 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
868 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
869 else if(UNLIKELY(!values
))
870 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
873 case AL_LOOP_POINTS_SOFT
:
874 ReadLock(&albuf
->lock
);
875 values
[0] = albuf
->LoopStart
;
876 values
[1] = albuf
->LoopEnd
;
877 ReadUnlock(&albuf
->lock
);
881 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer integer-vector property 0x%04x",
884 UnlockBuffersRead(device
);
886 ALCcontext_DecRef(context
);
893 * Loads the specified data into the buffer, using the specified format.
895 static void LoadData(ALCcontext
*context
, ALbuffer
*ALBuf
, ALuint freq
, ALsizei frames
, enum UserFmtChannels SrcChannels
, enum UserFmtType SrcType
, const ALvoid
*data
, ALsizei align
, ALbitfieldSOFT access
)
897 enum FmtChannels DstChannels
= FmtMono
;
898 enum FmtType DstType
= FmtUByte
;
899 ALsizei NumChannels
, FrameSize
;
902 /* Currently no channels need to be converted. */
905 case UserFmtMono
: DstChannels
= FmtMono
; break;
906 case UserFmtStereo
: DstChannels
= FmtStereo
; break;
907 case UserFmtRear
: DstChannels
= FmtRear
; break;
908 case UserFmtQuad
: DstChannels
= FmtQuad
; break;
909 case UserFmtX51
: DstChannels
= FmtX51
; break;
910 case UserFmtX61
: DstChannels
= FmtX61
; break;
911 case UserFmtX71
: DstChannels
= FmtX71
; break;
912 case UserFmtBFormat2D
: DstChannels
= FmtBFormat2D
; break;
913 case UserFmtBFormat3D
: DstChannels
= FmtBFormat3D
; break;
915 if(UNLIKELY((long)SrcChannels
!= (long)DstChannels
))
916 SETERR_RETURN(context
, AL_INVALID_ENUM
,, "Invalid format");
918 /* IMA4 and MSADPCM convert to 16-bit short. */
921 case UserFmtUByte
: DstType
= FmtUByte
; break;
922 case UserFmtShort
: DstType
= FmtShort
; break;
923 case UserFmtFloat
: DstType
= FmtFloat
; break;
924 case UserFmtDouble
: DstType
= FmtDouble
; break;
925 case UserFmtAlaw
: DstType
= FmtAlaw
; break;
926 case UserFmtMulaw
: DstType
= FmtMulaw
; break;
927 case UserFmtIMA4
: DstType
= FmtShort
; break;
928 case UserFmtMSADPCM
: DstType
= FmtShort
; break;
933 if(UNLIKELY((long)SrcType
!= (long)DstType
))
934 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Format cannot be mapped or preserved");
937 NumChannels
= ChannelsFromFmt(DstChannels
);
938 FrameSize
= NumChannels
* BytesFromFmt(DstType
);
940 if(UNLIKELY(frames
> INT_MAX
/FrameSize
))
941 SETERR_RETURN(context
, AL_OUT_OF_MEMORY
,,
942 "Buffer size overflow, %d frames x %d bytes per frame", frames
, FrameSize
);
943 newsize
= frames
*FrameSize
;
945 WriteLock(&ALBuf
->lock
);
946 if(UNLIKELY(ReadRef(&ALBuf
->ref
) != 0 || ALBuf
->MappedAccess
!= 0))
948 WriteUnlock(&ALBuf
->lock
);
949 SETERR_RETURN(context
, AL_INVALID_OPERATION
,, "Modifying storage for in-use buffer");
952 if((access
&AL_PRESERVE_DATA_BIT_SOFT
))
954 /* Can only preserve data with the same format and alignment. */
955 if(UNLIKELY(ALBuf
->FmtChannels
!= DstChannels
|| ALBuf
->OriginalType
!= SrcType
))
957 WriteUnlock(&ALBuf
->lock
);
958 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Preserving data of mismatched format");
960 if(UNLIKELY(ALBuf
->OriginalAlign
!= align
))
962 WriteUnlock(&ALBuf
->lock
);
963 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Preserving data of mismatched alignment");
967 /* Round up to the next 16-byte multiple. This could reallocate only when
968 * increasing or the new size is less than half the current, but then the
969 * buffer's AL_SIZE would not be very reliable for accounting buffer memory
970 * usage, and reporting the real size could cause problems for apps that
971 * use AL_SIZE to try to get the buffer's play length.
973 if(LIKELY(newsize
<= INT_MAX
-15))
974 newsize
= (newsize
+15) & ~0xf;
975 if(newsize
!= ALBuf
->BytesAlloc
)
977 void *temp
= al_malloc(16, (size_t)newsize
);
978 if(UNLIKELY(!temp
&& newsize
))
980 WriteUnlock(&ALBuf
->lock
);
981 SETERR_RETURN(context
, AL_OUT_OF_MEMORY
,, "Failed to allocate %d bytes of storage",
984 if((access
&AL_PRESERVE_DATA_BIT_SOFT
))
986 ALsizei tocopy
= mini(newsize
, ALBuf
->BytesAlloc
);
987 if(tocopy
> 0) memcpy(temp
, ALBuf
->data
, tocopy
);
989 al_free(ALBuf
->data
);
991 ALBuf
->BytesAlloc
= newsize
;
994 ALBuf
->OriginalType
= SrcType
;
995 if(SrcType
== UserFmtIMA4
)
997 ALsizei byte_align
= ((align
-1)/2 + 4) * NumChannels
;
998 ALBuf
->OriginalSize
= frames
/ align
* byte_align
;
999 ALBuf
->OriginalAlign
= align
;
1000 assert(DstType
== FmtShort
);
1001 if(data
!= NULL
&& ALBuf
->data
!= NULL
)
1002 Convert_ALshort_ALima4(ALBuf
->data
, data
, NumChannels
, frames
, align
);
1004 else if(SrcType
== UserFmtMSADPCM
)
1006 ALsizei byte_align
= ((align
-2)/2 + 7) * NumChannels
;
1007 ALBuf
->OriginalSize
= frames
/ align
* byte_align
;
1008 ALBuf
->OriginalAlign
= align
;
1009 assert(DstType
== FmtShort
);
1010 if(data
!= NULL
&& ALBuf
->data
!= NULL
)
1011 Convert_ALshort_ALmsadpcm(ALBuf
->data
, data
, NumChannels
, frames
, align
);
1015 ALBuf
->OriginalSize
= frames
* FrameSize
;
1016 ALBuf
->OriginalAlign
= 1;
1017 assert((long)SrcType
== (long)DstType
);
1018 if(data
!= NULL
&& ALBuf
->data
!= NULL
)
1019 memcpy(ALBuf
->data
, data
, frames
*FrameSize
);
1022 ALBuf
->Frequency
= freq
;
1023 ALBuf
->FmtChannels
= DstChannels
;
1024 ALBuf
->FmtType
= DstType
;
1025 ALBuf
->Access
= access
;
1027 ALBuf
->SampleLen
= frames
;
1028 ALBuf
->LoopStart
= 0;
1029 ALBuf
->LoopEnd
= ALBuf
->SampleLen
;
1031 WriteUnlock(&ALBuf
->lock
);
1035 ALsizei
BytesFromUserFmt(enum UserFmtType type
)
1039 case UserFmtUByte
: return sizeof(ALubyte
);
1040 case UserFmtShort
: return sizeof(ALshort
);
1041 case UserFmtFloat
: return sizeof(ALfloat
);
1042 case UserFmtDouble
: return sizeof(ALdouble
);
1043 case UserFmtMulaw
: return sizeof(ALubyte
);
1044 case UserFmtAlaw
: return sizeof(ALubyte
);
1045 case UserFmtIMA4
: break; /* not handled here */
1046 case UserFmtMSADPCM
: break; /* not handled here */
1050 ALsizei
ChannelsFromUserFmt(enum UserFmtChannels chans
)
1054 case UserFmtMono
: return 1;
1055 case UserFmtStereo
: return 2;
1056 case UserFmtRear
: return 2;
1057 case UserFmtQuad
: return 4;
1058 case UserFmtX51
: return 6;
1059 case UserFmtX61
: return 7;
1060 case UserFmtX71
: return 8;
1061 case UserFmtBFormat2D
: return 3;
1062 case UserFmtBFormat3D
: return 4;
1066 static ALboolean
DecomposeUserFormat(ALenum format
, enum UserFmtChannels
*chans
,
1067 enum UserFmtType
*type
)
1069 static const struct {
1071 enum UserFmtChannels channels
;
1072 enum UserFmtType type
;
1074 { AL_FORMAT_MONO8
, UserFmtMono
, UserFmtUByte
},
1075 { AL_FORMAT_MONO16
, UserFmtMono
, UserFmtShort
},
1076 { AL_FORMAT_MONO_FLOAT32
, UserFmtMono
, UserFmtFloat
},
1077 { AL_FORMAT_MONO_DOUBLE_EXT
, UserFmtMono
, UserFmtDouble
},
1078 { AL_FORMAT_MONO_IMA4
, UserFmtMono
, UserFmtIMA4
},
1079 { AL_FORMAT_MONO_MSADPCM_SOFT
, UserFmtMono
, UserFmtMSADPCM
},
1080 { AL_FORMAT_MONO_MULAW
, UserFmtMono
, UserFmtMulaw
},
1081 { AL_FORMAT_MONO_ALAW_EXT
, UserFmtMono
, UserFmtAlaw
},
1083 { AL_FORMAT_STEREO8
, UserFmtStereo
, UserFmtUByte
},
1084 { AL_FORMAT_STEREO16
, UserFmtStereo
, UserFmtShort
},
1085 { AL_FORMAT_STEREO_FLOAT32
, UserFmtStereo
, UserFmtFloat
},
1086 { AL_FORMAT_STEREO_DOUBLE_EXT
, UserFmtStereo
, UserFmtDouble
},
1087 { AL_FORMAT_STEREO_IMA4
, UserFmtStereo
, UserFmtIMA4
},
1088 { AL_FORMAT_STEREO_MSADPCM_SOFT
, UserFmtStereo
, UserFmtMSADPCM
},
1089 { AL_FORMAT_STEREO_MULAW
, UserFmtStereo
, UserFmtMulaw
},
1090 { AL_FORMAT_STEREO_ALAW_EXT
, UserFmtStereo
, UserFmtAlaw
},
1092 { AL_FORMAT_REAR8
, UserFmtRear
, UserFmtUByte
},
1093 { AL_FORMAT_REAR16
, UserFmtRear
, UserFmtShort
},
1094 { AL_FORMAT_REAR32
, UserFmtRear
, UserFmtFloat
},
1095 { AL_FORMAT_REAR_MULAW
, UserFmtRear
, UserFmtMulaw
},
1097 { AL_FORMAT_QUAD8_LOKI
, UserFmtQuad
, UserFmtUByte
},
1098 { AL_FORMAT_QUAD16_LOKI
, UserFmtQuad
, UserFmtShort
},
1100 { AL_FORMAT_QUAD8
, UserFmtQuad
, UserFmtUByte
},
1101 { AL_FORMAT_QUAD16
, UserFmtQuad
, UserFmtShort
},
1102 { AL_FORMAT_QUAD32
, UserFmtQuad
, UserFmtFloat
},
1103 { AL_FORMAT_QUAD_MULAW
, UserFmtQuad
, UserFmtMulaw
},
1105 { AL_FORMAT_51CHN8
, UserFmtX51
, UserFmtUByte
},
1106 { AL_FORMAT_51CHN16
, UserFmtX51
, UserFmtShort
},
1107 { AL_FORMAT_51CHN32
, UserFmtX51
, UserFmtFloat
},
1108 { AL_FORMAT_51CHN_MULAW
, UserFmtX51
, UserFmtMulaw
},
1110 { AL_FORMAT_61CHN8
, UserFmtX61
, UserFmtUByte
},
1111 { AL_FORMAT_61CHN16
, UserFmtX61
, UserFmtShort
},
1112 { AL_FORMAT_61CHN32
, UserFmtX61
, UserFmtFloat
},
1113 { AL_FORMAT_61CHN_MULAW
, UserFmtX61
, UserFmtMulaw
},
1115 { AL_FORMAT_71CHN8
, UserFmtX71
, UserFmtUByte
},
1116 { AL_FORMAT_71CHN16
, UserFmtX71
, UserFmtShort
},
1117 { AL_FORMAT_71CHN32
, UserFmtX71
, UserFmtFloat
},
1118 { AL_FORMAT_71CHN_MULAW
, UserFmtX71
, UserFmtMulaw
},
1120 { AL_FORMAT_BFORMAT2D_8
, UserFmtBFormat2D
, UserFmtUByte
},
1121 { AL_FORMAT_BFORMAT2D_16
, UserFmtBFormat2D
, UserFmtShort
},
1122 { AL_FORMAT_BFORMAT2D_FLOAT32
, UserFmtBFormat2D
, UserFmtFloat
},
1123 { AL_FORMAT_BFORMAT2D_MULAW
, UserFmtBFormat2D
, UserFmtMulaw
},
1125 { AL_FORMAT_BFORMAT3D_8
, UserFmtBFormat3D
, UserFmtUByte
},
1126 { AL_FORMAT_BFORMAT3D_16
, UserFmtBFormat3D
, UserFmtShort
},
1127 { AL_FORMAT_BFORMAT3D_FLOAT32
, UserFmtBFormat3D
, UserFmtFloat
},
1128 { AL_FORMAT_BFORMAT3D_MULAW
, UserFmtBFormat3D
, UserFmtMulaw
},
1132 for(i
= 0;i
< COUNTOF(list
);i
++)
1134 if(list
[i
].format
== format
)
1136 *chans
= list
[i
].channels
;
1137 *type
= list
[i
].type
;
1145 ALsizei
BytesFromFmt(enum FmtType type
)
1149 case FmtUByte
: return sizeof(ALubyte
);
1150 case FmtShort
: return sizeof(ALshort
);
1151 case FmtFloat
: return sizeof(ALfloat
);
1152 case FmtDouble
: return sizeof(ALdouble
);
1153 case FmtMulaw
: return sizeof(ALubyte
);
1154 case FmtAlaw
: return sizeof(ALubyte
);
1158 ALsizei
ChannelsFromFmt(enum FmtChannels chans
)
1162 case FmtMono
: return 1;
1163 case FmtStereo
: return 2;
1164 case FmtRear
: return 2;
1165 case FmtQuad
: return 4;
1166 case FmtX51
: return 6;
1167 case FmtX61
: return 7;
1168 case FmtX71
: return 8;
1169 case FmtBFormat2D
: return 3;
1170 case FmtBFormat3D
: return 4;
1175 static ALsizei
SanitizeAlignment(enum UserFmtType type
, ALsizei align
)
1182 if(type
== UserFmtIMA4
)
1184 /* Here is where things vary:
1185 * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
1186 * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
1190 if(type
== UserFmtMSADPCM
)
1195 if(type
== UserFmtIMA4
)
1197 /* IMA4 block alignment must be a multiple of 8, plus 1. */
1198 if((align
&7) == 1) return align
;
1201 if(type
== UserFmtMSADPCM
)
1203 /* MSADPCM block alignment must be a multiple of 2. */
1204 if((align
&1) == 0) return align
;
1212 ALbuffer
*NewBuffer(ALCcontext
*context
)
1214 ALCdevice
*device
= context
->Device
;
1218 buffer
= al_calloc(16, sizeof(ALbuffer
));
1220 SETERR_RETURN(context
, AL_OUT_OF_MEMORY
, NULL
, "Failed to allocate buffer object");
1221 RWLockInit(&buffer
->lock
);
1223 buffer
->MappedAccess
= 0;
1225 err
= NewThunkEntry(&buffer
->id
);
1226 if(err
== AL_NO_ERROR
)
1227 err
= InsertUIntMapEntry(&device
->BufferMap
, buffer
->id
, buffer
);
1228 if(err
!= AL_NO_ERROR
)
1230 FreeThunkEntry(buffer
->id
);
1231 memset(buffer
, 0, sizeof(ALbuffer
));
1234 SETERR_RETURN(context
, err
, NULL
, "Failed to set buffer ID");
1240 void DeleteBuffer(ALCdevice
*device
, ALbuffer
*buffer
)
1242 RemoveBuffer(device
, buffer
->id
);
1243 FreeThunkEntry(buffer
->id
);
1245 al_free(buffer
->data
);
1247 memset(buffer
, 0, sizeof(*buffer
));
1253 * ReleaseALBuffers()
1255 * INTERNAL: Called to destroy any buffers that still exist on the device
1257 ALvoid
ReleaseALBuffers(ALCdevice
*device
)
1260 for(i
= 0;i
< device
->BufferMap
.size
;i
++)
1262 ALbuffer
*temp
= device
->BufferMap
.values
[i
];
1263 device
->BufferMap
.values
[i
] = NULL
;
1265 al_free(temp
->data
);
1267 FreeThunkEntry(temp
->id
);
1268 memset(temp
, 0, sizeof(ALbuffer
));