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 const ALchar
*NameFromUserFmtType(enum UserFmtType type
);
49 static void LoadData(ALCcontext
*context
, ALbuffer
*buffer
, ALuint freq
, ALsizei size
,
50 enum UserFmtChannels SrcChannels
, enum UserFmtType SrcType
,
51 const ALvoid
*data
, ALbitfieldSOFT access
);
52 static ALboolean
DecomposeUserFormat(ALenum format
, enum UserFmtChannels
*chans
, enum UserFmtType
*type
);
53 static ALsizei
SanitizeAlignment(enum UserFmtType type
, ALsizei align
);
56 #define INVALID_STORAGE_MASK ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT)
57 #define MAP_READ_WRITE_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT)
58 #define INVALID_MAP_FLAGS ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT)
61 AL_API ALvoid AL_APIENTRY
alGenBuffers(ALsizei n
, ALuint
*buffers
)
66 context
= GetContextRef();
70 alSetError(context
, AL_INVALID_VALUE
, "Generating %d buffers", n
);
71 else for(cur
= 0;cur
< n
;cur
++)
73 ALbuffer
*buffer
= NewBuffer(context
);
76 alDeleteBuffers(cur
, buffers
);
80 buffers
[cur
] = buffer
->id
;
83 ALCcontext_DecRef(context
);
86 AL_API ALvoid AL_APIENTRY
alDeleteBuffers(ALsizei n
, const ALuint
*buffers
)
93 context
= GetContextRef();
96 device
= context
->Device
;
98 LockBuffersWrite(device
);
101 alSetError(context
, AL_INVALID_VALUE
, "Deleting %d buffers", n
);
110 /* Check for valid Buffer ID, and make sure it's not in use. */
111 if((ALBuf
=LookupBuffer(device
, buffers
[i
])) == NULL
)
113 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffers
[i
]);
116 if(ReadRef(&ALBuf
->ref
) != 0)
118 alSetError(context
, AL_INVALID_OPERATION
, "Deleting in-use buffer %u", buffers
[i
]);
124 if((ALBuf
=LookupBuffer(device
, buffers
[i
])) != NULL
)
125 DeleteBuffer(device
, ALBuf
);
129 UnlockBuffersWrite(device
);
130 ALCcontext_DecRef(context
);
133 AL_API ALboolean AL_APIENTRY
alIsBuffer(ALuint buffer
)
138 context
= GetContextRef();
139 if(!context
) return AL_FALSE
;
141 LockBuffersRead(context
->Device
);
142 ret
= ((!buffer
|| LookupBuffer(context
->Device
, buffer
)) ?
144 UnlockBuffersRead(context
->Device
);
146 ALCcontext_DecRef(context
);
152 AL_API ALvoid AL_APIENTRY
alBufferData(ALuint buffer
, ALenum format
, const ALvoid
*data
, ALsizei size
, ALsizei freq
)
153 { alBufferStorageSOFT(buffer
, format
, data
, size
, freq
, 0); }
155 AL_API
void AL_APIENTRY
alBufferStorageSOFT(ALuint buffer
, ALenum format
, const ALvoid
*data
, ALsizei size
, ALsizei freq
, ALbitfieldSOFT flags
)
157 enum UserFmtChannels srcchannels
= UserFmtMono
;
158 enum UserFmtType srctype
= UserFmtUByte
;
163 context
= GetContextRef();
166 device
= context
->Device
;
167 LockBuffersRead(device
);
168 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
169 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
170 else if(UNLIKELY(size
< 0))
171 alSetError(context
, AL_INVALID_VALUE
, "Negative storage size %d", size
);
172 else if(UNLIKELY(freq
< 1))
173 alSetError(context
, AL_INVALID_VALUE
, "Invalid sample rate %d", freq
);
174 else if(UNLIKELY((flags
&INVALID_STORAGE_MASK
) != 0))
175 alSetError(context
, AL_INVALID_VALUE
, "Invalid storage flags 0x%x",
176 flags
&INVALID_STORAGE_MASK
);
177 else if(UNLIKELY((flags
&AL_MAP_PERSISTENT_BIT_SOFT
) && !(flags
&MAP_READ_WRITE_FLAGS
)))
178 alSetError(context
, AL_INVALID_VALUE
,
179 "Declaring persistently mapped storage without read or write access");
180 else if(UNLIKELY(DecomposeUserFormat(format
, &srcchannels
, &srctype
) == AL_FALSE
))
181 alSetError(context
, AL_INVALID_ENUM
, "Invalid format 0x%04x", format
);
184 WriteLock(&albuf
->lock
);
185 LoadData(context
, albuf
, freq
, size
, srcchannels
, srctype
, data
, flags
);
186 WriteUnlock(&albuf
->lock
);
189 UnlockBuffersRead(device
);
190 ALCcontext_DecRef(context
);
193 AL_API
void* AL_APIENTRY
alMapBufferSOFT(ALuint buffer
, ALsizei offset
, ALsizei length
, ALbitfieldSOFT access
)
200 context
= GetContextRef();
201 if(!context
) return retval
;
203 device
= context
->Device
;
204 LockBuffersRead(device
);
205 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
206 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
207 else if(UNLIKELY((access
&INVALID_MAP_FLAGS
) != 0))
208 alSetError(context
, AL_INVALID_VALUE
, "Invalid map flags 0x%x", access
&INVALID_MAP_FLAGS
);
209 else if(UNLIKELY(!(access
&MAP_READ_WRITE_FLAGS
)))
210 alSetError(context
, AL_INVALID_VALUE
, "Mapping buffer %u without read or write access",
214 ALbitfieldSOFT unavailable
;
215 WriteLock(&albuf
->lock
);
216 unavailable
= (albuf
->Access
^access
) & access
;
217 if(UNLIKELY(ReadRef(&albuf
->ref
) != 0 && !(access
&AL_MAP_PERSISTENT_BIT_SOFT
)))
218 alSetError(context
, AL_INVALID_OPERATION
,
219 "Mapping in-use buffer %u without persistent mapping", buffer
);
220 else if(UNLIKELY(albuf
->MappedAccess
!= 0))
221 alSetError(context
, AL_INVALID_OPERATION
, "Mapping already-mapped buffer %u", buffer
);
222 else if(UNLIKELY((unavailable
&AL_MAP_READ_BIT_SOFT
)))
223 alSetError(context
, AL_INVALID_VALUE
,
224 "Mapping buffer %u for reading without read access", buffer
);
225 else if(UNLIKELY((unavailable
&AL_MAP_WRITE_BIT_SOFT
)))
226 alSetError(context
, AL_INVALID_VALUE
,
227 "Mapping buffer %u for writing without write access", buffer
);
228 else if(UNLIKELY((unavailable
&AL_MAP_PERSISTENT_BIT_SOFT
)))
229 alSetError(context
, AL_INVALID_VALUE
,
230 "Mapping buffer %u persistently without persistent access", buffer
);
231 else if(UNLIKELY(offset
< 0 || offset
>= albuf
->OriginalSize
||
232 length
<= 0 || length
> albuf
->OriginalSize
- offset
))
233 alSetError(context
, AL_INVALID_VALUE
, "Mapping invalid range %d+%d for buffer %u",
234 offset
, length
, buffer
);
237 retval
= (ALbyte
*)albuf
->data
+ offset
;
238 albuf
->MappedAccess
= access
;
239 albuf
->MappedOffset
= offset
;
240 albuf
->MappedSize
= length
;
243 WriteUnlock(&albuf
->lock
);
245 UnlockBuffersRead(device
);
247 ALCcontext_DecRef(context
);
251 AL_API
void AL_APIENTRY
alUnmapBufferSOFT(ALuint buffer
)
257 context
= GetContextRef();
260 device
= context
->Device
;
261 LockBuffersRead(device
);
262 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
263 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
266 WriteLock(&albuf
->lock
);
267 if(albuf
->MappedAccess
== 0)
268 alSetError(context
, AL_INVALID_OPERATION
, "Unmapping unmapped buffer %u", buffer
);
271 albuf
->MappedAccess
= 0;
272 albuf
->MappedOffset
= 0;
273 albuf
->MappedSize
= 0;
275 WriteUnlock(&albuf
->lock
);
277 UnlockBuffersRead(device
);
279 ALCcontext_DecRef(context
);
282 AL_API
void AL_APIENTRY
alFlushMappedBufferSOFT(ALuint buffer
, ALsizei offset
, ALsizei length
)
288 context
= GetContextRef();
291 device
= context
->Device
;
292 LockBuffersRead(device
);
293 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
294 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
297 WriteLock(&albuf
->lock
);
298 if(UNLIKELY(!(albuf
->MappedAccess
&AL_MAP_WRITE_BIT_SOFT
)))
299 alSetError(context
, AL_INVALID_OPERATION
,
300 "Flushing buffer %u while not mapped for writing", buffer
);
301 else if(UNLIKELY(offset
< albuf
->MappedOffset
||
302 offset
>= albuf
->MappedOffset
+albuf
->MappedSize
||
303 length
<= 0 || length
> albuf
->MappedOffset
+albuf
->MappedSize
-offset
))
304 alSetError(context
, AL_INVALID_VALUE
, "Flushing invalid range %d+%d on buffer %u",
305 offset
, length
, buffer
);
308 /* FIXME: Need to use some method of double-buffering for the mixer
309 * and app to hold separate memory, which can be safely transfered
310 * asynchronously. Currently we just say the app shouldn't write
311 * where OpenAL's reading, and hope for the best...
313 ATOMIC_THREAD_FENCE(almemory_order_seq_cst
);
315 WriteUnlock(&albuf
->lock
);
317 UnlockBuffersRead(device
);
319 ALCcontext_DecRef(context
);
322 AL_API ALvoid AL_APIENTRY
alBufferSubDataSOFT(ALuint buffer
, ALenum format
, const ALvoid
*data
, ALsizei offset
, ALsizei length
)
324 enum UserFmtChannels srcchannels
= UserFmtMono
;
325 enum UserFmtType srctype
= UserFmtUByte
;
330 context
= GetContextRef();
333 device
= context
->Device
;
334 LockBuffersRead(device
);
335 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
336 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
337 else if(UNLIKELY(DecomposeUserFormat(format
, &srcchannels
, &srctype
) == AL_FALSE
))
338 alSetError(context
, AL_INVALID_ENUM
, "Invalid format 0x%04x", format
);
341 ALsizei unpack_align
, align
;
347 WriteLock(&albuf
->lock
);
348 unpack_align
= ATOMIC_LOAD_SEQ(&albuf
->UnpackAlign
);
349 align
= SanitizeAlignment(srctype
, unpack_align
);
350 if(UNLIKELY(align
< 1))
351 alSetError(context
, AL_INVALID_VALUE
, "Invalid unpack alignment %d", unpack_align
);
352 else if(UNLIKELY((long)srcchannels
!= (long)albuf
->FmtChannels
||
353 srctype
!= albuf
->OriginalType
))
354 alSetError(context
, AL_INVALID_ENUM
, "Unpacking data with mismatched format");
355 else if(UNLIKELY(align
!= albuf
->OriginalAlign
))
356 alSetError(context
, AL_INVALID_VALUE
,
357 "Unpacking data with alignment %u does not match original alignment %u",
358 align
, albuf
->OriginalAlign
);
359 else if(UNLIKELY(albuf
->MappedAccess
!= 0))
360 alSetError(context
, AL_INVALID_OPERATION
, "Unpacking data into mapped buffer %u",
364 num_chans
= ChannelsFromFmt(albuf
->FmtChannels
);
365 frame_size
= num_chans
* BytesFromFmt(albuf
->FmtType
);
366 if(albuf
->OriginalType
== UserFmtIMA4
)
367 byte_align
= ((align
-1)/2 + 4) * num_chans
;
368 else if(albuf
->OriginalType
== UserFmtMSADPCM
)
369 byte_align
= ((align
-2)/2 + 7) * num_chans
;
371 byte_align
= align
* frame_size
;
373 if(UNLIKELY(offset
< 0 || length
< 0 || offset
> albuf
->OriginalSize
||
374 length
> albuf
->OriginalSize
-offset
))
375 alSetError(context
, AL_INVALID_VALUE
, "Invalid data sub-range %d+%d on buffer %u",
376 offset
, length
, buffer
);
377 else if(UNLIKELY((offset
%byte_align
) != 0))
378 alSetError(context
, AL_INVALID_VALUE
,
379 "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)",
380 offset
, byte_align
, align
);
381 else if(UNLIKELY((length
%byte_align
) != 0))
382 alSetError(context
, AL_INVALID_VALUE
,
383 "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)",
384 length
, byte_align
, align
);
387 /* offset -> byte offset, length -> sample count */
388 offset
= offset
/byte_align
* align
* frame_size
;
389 length
= length
/byte_align
* align
;
391 dst
= (ALbyte
*)albuf
->data
+ offset
;
392 if(srctype
== UserFmtIMA4
&& albuf
->FmtType
== FmtShort
)
393 Convert_ALshort_ALima4(dst
, data
, num_chans
, length
, align
);
394 else if(srctype
== UserFmtMSADPCM
&& albuf
->FmtType
== FmtShort
)
395 Convert_ALshort_ALmsadpcm(dst
, data
, num_chans
, length
, align
);
398 assert((long)srctype
== (long)albuf
->FmtType
);
399 memcpy(dst
, data
, length
*frame_size
);
404 WriteUnlock(&albuf
->lock
);
406 UnlockBuffersRead(device
);
408 ALCcontext_DecRef(context
);
412 AL_API
void AL_APIENTRY
alBufferSamplesSOFT(ALuint
UNUSED(buffer
),
413 ALuint
UNUSED(samplerate
), ALenum
UNUSED(internalformat
), ALsizei
UNUSED(samples
),
414 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), const ALvoid
*UNUSED(data
))
418 context
= GetContextRef();
421 alSetError(context
, AL_INVALID_OPERATION
, "alBufferSamplesSOFT not supported");
423 ALCcontext_DecRef(context
);
426 AL_API
void AL_APIENTRY
alBufferSubSamplesSOFT(ALuint
UNUSED(buffer
),
427 ALsizei
UNUSED(offset
), ALsizei
UNUSED(samples
),
428 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), const ALvoid
*UNUSED(data
))
432 context
= GetContextRef();
435 alSetError(context
, AL_INVALID_OPERATION
, "alBufferSubSamplesSOFT not supported");
437 ALCcontext_DecRef(context
);
440 AL_API
void AL_APIENTRY
alGetBufferSamplesSOFT(ALuint
UNUSED(buffer
),
441 ALsizei
UNUSED(offset
), ALsizei
UNUSED(samples
),
442 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), ALvoid
*UNUSED(data
))
446 context
= GetContextRef();
449 alSetError(context
, AL_INVALID_OPERATION
, "alGetBufferSamplesSOFT not supported");
451 ALCcontext_DecRef(context
);
454 AL_API ALboolean AL_APIENTRY
alIsBufferFormatSupportedSOFT(ALenum
UNUSED(format
))
458 context
= GetContextRef();
459 if(!context
) return AL_FALSE
;
461 alSetError(context
, AL_INVALID_OPERATION
, "alIsBufferFormatSupportedSOFT not supported");
463 ALCcontext_DecRef(context
);
468 AL_API
void AL_APIENTRY
alBufferf(ALuint buffer
, ALenum param
, ALfloat
UNUSED(value
))
473 context
= GetContextRef();
476 device
= context
->Device
;
477 LockBuffersRead(device
);
478 if(UNLIKELY(LookupBuffer(device
, buffer
) == NULL
))
479 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
483 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer float property 0x%04x", param
);
485 UnlockBuffersRead(device
);
487 ALCcontext_DecRef(context
);
491 AL_API
void AL_APIENTRY
alBuffer3f(ALuint buffer
, ALenum param
, ALfloat
UNUSED(value1
), ALfloat
UNUSED(value2
), ALfloat
UNUSED(value3
))
496 context
= GetContextRef();
499 device
= context
->Device
;
500 LockBuffersRead(device
);
501 if(UNLIKELY(LookupBuffer(device
, buffer
) == NULL
))
502 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
506 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer 3-float property 0x%04x", param
);
508 UnlockBuffersRead(device
);
510 ALCcontext_DecRef(context
);
514 AL_API
void AL_APIENTRY
alBufferfv(ALuint buffer
, ALenum param
, const ALfloat
*values
)
519 context
= GetContextRef();
522 device
= context
->Device
;
523 LockBuffersRead(device
);
524 if(UNLIKELY(LookupBuffer(device
, buffer
) == NULL
))
525 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
526 else if(UNLIKELY(!values
))
527 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
531 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer float-vector property 0x%04x", param
);
533 UnlockBuffersRead(device
);
535 ALCcontext_DecRef(context
);
539 AL_API
void AL_APIENTRY
alBufferi(ALuint buffer
, ALenum param
, ALint value
)
545 context
= GetContextRef();
548 device
= context
->Device
;
549 LockBuffersRead(device
);
550 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
551 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
554 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
555 if(UNLIKELY(value
< 0))
556 alSetError(context
, AL_INVALID_VALUE
, "Invalid unpack block alignment %d", value
);
558 ATOMIC_STORE_SEQ(&albuf
->UnpackAlign
, value
);
561 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
562 if(UNLIKELY(value
< 0))
563 alSetError(context
, AL_INVALID_VALUE
, "Invalid pack block alignment %d", value
);
565 ATOMIC_STORE_SEQ(&albuf
->PackAlign
, value
);
569 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer integer property 0x%04x", param
);
571 UnlockBuffersRead(device
);
573 ALCcontext_DecRef(context
);
577 AL_API
void AL_APIENTRY
alBuffer3i(ALuint buffer
, ALenum param
, ALint
UNUSED(value1
), ALint
UNUSED(value2
), ALint
UNUSED(value3
))
582 context
= GetContextRef();
585 device
= context
->Device
;
586 LockBuffersRead(device
);
587 if(UNLIKELY(LookupBuffer(device
, buffer
) == NULL
))
588 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
592 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer 3-integer property 0x%04x", param
);
594 UnlockBuffersRead(device
);
596 ALCcontext_DecRef(context
);
600 AL_API
void AL_APIENTRY
alBufferiv(ALuint buffer
, ALenum param
, const ALint
*values
)
610 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
611 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
612 alBufferi(buffer
, param
, values
[0]);
617 context
= GetContextRef();
620 device
= context
->Device
;
621 LockBuffersRead(device
);
622 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
623 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
624 else if(UNLIKELY(!values
))
625 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
628 case AL_LOOP_POINTS_SOFT
:
629 WriteLock(&albuf
->lock
);
630 if(UNLIKELY(ReadRef(&albuf
->ref
) != 0))
631 alSetError(context
, AL_INVALID_OPERATION
, "Modifying in-use buffer %u's loop points",
633 else if(UNLIKELY(values
[0] >= values
[1] || values
[0] < 0 || values
[1] > albuf
->SampleLen
))
634 alSetError(context
, AL_INVALID_VALUE
, "Invalid loop point range %d -> %d o buffer %u",
635 values
[0], values
[1], buffer
);
638 albuf
->LoopStart
= values
[0];
639 albuf
->LoopEnd
= values
[1];
641 WriteUnlock(&albuf
->lock
);
645 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer integer-vector property 0x%04x",
648 UnlockBuffersRead(device
);
650 ALCcontext_DecRef(context
);
654 AL_API ALvoid AL_APIENTRY
alGetBufferf(ALuint buffer
, ALenum param
, ALfloat
*value
)
660 context
= GetContextRef();
663 device
= context
->Device
;
664 LockBuffersRead(device
);
665 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
666 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
667 else if(UNLIKELY(!value
))
668 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
672 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer float property 0x%04x", param
);
674 UnlockBuffersRead(device
);
676 ALCcontext_DecRef(context
);
680 AL_API
void AL_APIENTRY
alGetBuffer3f(ALuint buffer
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
685 context
= GetContextRef();
688 device
= context
->Device
;
689 LockBuffersRead(device
);
690 if(UNLIKELY(LookupBuffer(device
, buffer
) == NULL
))
691 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
692 else if(UNLIKELY(!value1
|| !value2
|| !value3
))
693 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
697 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer 3-float property 0x%04x", param
);
699 UnlockBuffersRead(device
);
701 ALCcontext_DecRef(context
);
705 AL_API
void AL_APIENTRY
alGetBufferfv(ALuint buffer
, ALenum param
, ALfloat
*values
)
712 case AL_SEC_LENGTH_SOFT
:
713 alGetBufferf(buffer
, param
, values
);
717 context
= GetContextRef();
720 device
= context
->Device
;
721 LockBuffersRead(device
);
722 if(UNLIKELY(LookupBuffer(device
, buffer
) == NULL
))
723 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
724 else if(UNLIKELY(!values
))
725 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
729 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer float-vector property 0x%04x", param
);
731 UnlockBuffersRead(device
);
733 ALCcontext_DecRef(context
);
737 AL_API ALvoid AL_APIENTRY
alGetBufferi(ALuint buffer
, ALenum param
, ALint
*value
)
743 context
= GetContextRef();
746 device
= context
->Device
;
747 LockBuffersRead(device
);
748 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
749 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
750 else if(UNLIKELY(!value
))
751 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
755 *value
= albuf
->Frequency
;
759 *value
= BytesFromFmt(albuf
->FmtType
) * 8;
763 *value
= ChannelsFromFmt(albuf
->FmtChannels
);
767 ReadLock(&albuf
->lock
);
768 *value
= albuf
->SampleLen
* FrameSizeFromFmt(albuf
->FmtChannels
,
770 ReadUnlock(&albuf
->lock
);
773 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
774 *value
= ATOMIC_LOAD_SEQ(&albuf
->UnpackAlign
);
777 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
778 *value
= ATOMIC_LOAD_SEQ(&albuf
->PackAlign
);
782 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer integer property 0x%04x", param
);
784 UnlockBuffersRead(device
);
786 ALCcontext_DecRef(context
);
790 AL_API
void AL_APIENTRY
alGetBuffer3i(ALuint buffer
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
795 context
= GetContextRef();
798 device
= context
->Device
;
799 LockBuffersRead(device
);
800 if(UNLIKELY(LookupBuffer(device
, buffer
) == NULL
))
801 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
802 else if(UNLIKELY(!value1
|| !value2
|| !value3
))
803 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
807 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer 3-integer property 0x%04x", param
);
809 UnlockBuffersRead(device
);
811 ALCcontext_DecRef(context
);
815 AL_API
void AL_APIENTRY
alGetBufferiv(ALuint buffer
, ALenum param
, ALint
*values
)
827 case AL_INTERNAL_FORMAT_SOFT
:
828 case AL_BYTE_LENGTH_SOFT
:
829 case AL_SAMPLE_LENGTH_SOFT
:
830 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
831 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
832 alGetBufferi(buffer
, param
, values
);
836 context
= GetContextRef();
839 device
= context
->Device
;
840 LockBuffersRead(device
);
841 if(UNLIKELY((albuf
=LookupBuffer(device
, buffer
)) == NULL
))
842 alSetError(context
, AL_INVALID_NAME
, "Invalid buffer ID %u", buffer
);
843 else if(UNLIKELY(!values
))
844 alSetError(context
, AL_INVALID_VALUE
, "NULL pointer");
847 case AL_LOOP_POINTS_SOFT
:
848 ReadLock(&albuf
->lock
);
849 values
[0] = albuf
->LoopStart
;
850 values
[1] = albuf
->LoopEnd
;
851 ReadUnlock(&albuf
->lock
);
855 alSetError(context
, AL_INVALID_ENUM
, "Invalid buffer integer-vector property 0x%04x",
858 UnlockBuffersRead(device
);
860 ALCcontext_DecRef(context
);
864 static const ALchar
*NameFromUserFmtType(enum UserFmtType type
)
868 case UserFmtUByte
: return "Unsigned Byte";
869 case UserFmtShort
: return "Signed Short";
870 case UserFmtFloat
: return "Float32";
871 case UserFmtDouble
: return "Float64";
872 case UserFmtMulaw
: return "muLaw";
873 case UserFmtAlaw
: return "aLaw";
874 case UserFmtIMA4
: return "IMA4 ADPCM";
875 case UserFmtMSADPCM
: return "MSADPCM";
877 return "<internal type error>";
883 * Loads the specified data into the buffer, using the specified format.
885 static void LoadData(ALCcontext
*context
, ALbuffer
*ALBuf
, ALuint freq
, ALsizei size
, enum UserFmtChannels SrcChannels
, enum UserFmtType SrcType
, const ALvoid
*data
, ALbitfieldSOFT access
)
887 enum FmtChannels DstChannels
= FmtMono
;
888 enum FmtType DstType
= FmtUByte
;
889 ALsizei NumChannels
, FrameSize
;
890 ALsizei SrcByteAlign
;
896 if(UNLIKELY(ReadRef(&ALBuf
->ref
) != 0 || ALBuf
->MappedAccess
!= 0))
897 SETERR_RETURN(context
, AL_INVALID_OPERATION
,, "Modifying storage for in-use buffer %u",
900 /* Currently no channel configurations need to be converted. */
903 case UserFmtMono
: DstChannels
= FmtMono
; break;
904 case UserFmtStereo
: DstChannels
= FmtStereo
; break;
905 case UserFmtRear
: DstChannels
= FmtRear
; break;
906 case UserFmtQuad
: DstChannels
= FmtQuad
; break;
907 case UserFmtX51
: DstChannels
= FmtX51
; break;
908 case UserFmtX61
: DstChannels
= FmtX61
; break;
909 case UserFmtX71
: DstChannels
= FmtX71
; break;
910 case UserFmtBFormat2D
: DstChannels
= FmtBFormat2D
; break;
911 case UserFmtBFormat3D
: DstChannels
= FmtBFormat3D
; break;
913 if(UNLIKELY((long)SrcChannels
!= (long)DstChannels
))
914 SETERR_RETURN(context
, AL_INVALID_ENUM
,, "Invalid format");
916 /* IMA4 and MSADPCM convert to 16-bit short. */
919 case UserFmtUByte
: DstType
= FmtUByte
; break;
920 case UserFmtShort
: DstType
= FmtShort
; break;
921 case UserFmtFloat
: DstType
= FmtFloat
; break;
922 case UserFmtDouble
: DstType
= FmtDouble
; break;
923 case UserFmtAlaw
: DstType
= FmtAlaw
; break;
924 case UserFmtMulaw
: DstType
= FmtMulaw
; break;
925 case UserFmtIMA4
: DstType
= FmtShort
; break;
926 case UserFmtMSADPCM
: DstType
= FmtShort
; break;
929 /* TODO: Currently we can only map samples when they're not converted. To
930 * allow it would need some kind of double-buffering to hold onto a copy of
933 if((access
&MAP_READ_WRITE_FLAGS
))
935 if(UNLIKELY((long)SrcType
!= (long)DstType
))
936 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "%s samples cannot be mapped",
937 NameFromUserFmtType(SrcType
));
940 unpackalign
= ATOMIC_LOAD_SEQ(&ALBuf
->UnpackAlign
);
941 if(UNLIKELY((align
=SanitizeAlignment(SrcType
, unpackalign
)) < 1))
942 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Invalid unpack alignment %d for %s samples",
943 unpackalign
, NameFromUserFmtType(SrcType
));
945 if((access
&AL_PRESERVE_DATA_BIT_SOFT
))
947 /* Can only preserve data with the same format and alignment. */
948 if(UNLIKELY(ALBuf
->FmtChannels
!= DstChannels
|| ALBuf
->OriginalType
!= SrcType
))
949 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Preserving data of mismatched format");
950 if(UNLIKELY(ALBuf
->OriginalAlign
!= align
))
951 SETERR_RETURN(context
, AL_INVALID_VALUE
,, "Preserving data of mismatched alignment");
954 /* Convert the input/source size in bytes to sample frames using the unpack
957 if(SrcType
== UserFmtIMA4
)
958 SrcByteAlign
= ((align
-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels
);
959 else if(SrcType
== UserFmtMSADPCM
)
960 SrcByteAlign
= ((align
-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels
);
962 SrcByteAlign
= align
* FrameSizeFromUserFmt(SrcChannels
, SrcType
);
963 if(UNLIKELY((size
%SrcByteAlign
) != 0))
964 SETERR_RETURN(context
, AL_INVALID_VALUE
,,
965 "Data size %d is not a multiple of frame size %d (%d unpack alignment)",
966 size
, SrcByteAlign
, align
);
968 if(UNLIKELY(size
/ SrcByteAlign
> INT_MAX
/ align
))
969 SETERR_RETURN(context
, AL_OUT_OF_MEMORY
,,
970 "Buffer size overflow, %d blocks x %d samples per block", size
/SrcByteAlign
, align
);
971 frames
= size
/ SrcByteAlign
* align
;
973 /* Convert the sample frames to the number of bytes needed for internal
976 NumChannels
= ChannelsFromFmt(DstChannels
);
977 FrameSize
= NumChannels
* BytesFromFmt(DstType
);
978 if(UNLIKELY(frames
> INT_MAX
/FrameSize
))
979 SETERR_RETURN(context
, AL_OUT_OF_MEMORY
,,
980 "Buffer size overflow, %d frames x %d bytes per frame", frames
, FrameSize
);
981 newsize
= frames
*FrameSize
;
983 /* Round up to the next 16-byte multiple. This could reallocate only when
984 * increasing or the new size is less than half the current, but then the
985 * buffer's AL_SIZE would not be very reliable for accounting buffer memory
986 * usage, and reporting the real size could cause problems for apps that
987 * use AL_SIZE to try to get the buffer's play length.
989 if(LIKELY(newsize
<= INT_MAX
-15))
990 newsize
= (newsize
+15) & ~0xf;
991 if(newsize
!= ALBuf
->BytesAlloc
)
993 void *temp
= al_malloc(16, (size_t)newsize
);
994 if(UNLIKELY(!temp
&& newsize
))
995 SETERR_RETURN(context
, AL_OUT_OF_MEMORY
,, "Failed to allocate %d bytes of storage",
997 if((access
&AL_PRESERVE_DATA_BIT_SOFT
))
999 ALsizei tocopy
= mini(newsize
, ALBuf
->BytesAlloc
);
1000 if(tocopy
> 0) memcpy(temp
, ALBuf
->data
, tocopy
);
1002 al_free(ALBuf
->data
);
1004 ALBuf
->BytesAlloc
= newsize
;
1007 if(SrcType
== UserFmtIMA4
)
1009 assert(DstType
== FmtShort
);
1010 if(data
!= NULL
&& ALBuf
->data
!= NULL
)
1011 Convert_ALshort_ALima4(ALBuf
->data
, data
, NumChannels
, frames
, align
);
1012 ALBuf
->OriginalAlign
= align
;
1014 else if(SrcType
== UserFmtMSADPCM
)
1016 assert(DstType
== FmtShort
);
1017 if(data
!= NULL
&& ALBuf
->data
!= NULL
)
1018 Convert_ALshort_ALmsadpcm(ALBuf
->data
, data
, NumChannels
, frames
, align
);
1019 ALBuf
->OriginalAlign
= align
;
1023 assert((long)SrcType
== (long)DstType
);
1024 if(data
!= NULL
&& ALBuf
->data
!= NULL
)
1025 memcpy(ALBuf
->data
, data
, frames
*FrameSize
);
1026 ALBuf
->OriginalAlign
= 1;
1028 ALBuf
->OriginalSize
= size
;
1029 ALBuf
->OriginalType
= SrcType
;
1031 ALBuf
->Frequency
= freq
;
1032 ALBuf
->FmtChannels
= DstChannels
;
1033 ALBuf
->FmtType
= DstType
;
1034 ALBuf
->Access
= access
;
1036 ALBuf
->SampleLen
= frames
;
1037 ALBuf
->LoopStart
= 0;
1038 ALBuf
->LoopEnd
= ALBuf
->SampleLen
;
1042 ALsizei
BytesFromUserFmt(enum UserFmtType type
)
1046 case UserFmtUByte
: return sizeof(ALubyte
);
1047 case UserFmtShort
: return sizeof(ALshort
);
1048 case UserFmtFloat
: return sizeof(ALfloat
);
1049 case UserFmtDouble
: return sizeof(ALdouble
);
1050 case UserFmtMulaw
: return sizeof(ALubyte
);
1051 case UserFmtAlaw
: return sizeof(ALubyte
);
1052 case UserFmtIMA4
: break; /* not handled here */
1053 case UserFmtMSADPCM
: break; /* not handled here */
1057 ALsizei
ChannelsFromUserFmt(enum UserFmtChannels chans
)
1061 case UserFmtMono
: return 1;
1062 case UserFmtStereo
: return 2;
1063 case UserFmtRear
: return 2;
1064 case UserFmtQuad
: return 4;
1065 case UserFmtX51
: return 6;
1066 case UserFmtX61
: return 7;
1067 case UserFmtX71
: return 8;
1068 case UserFmtBFormat2D
: return 3;
1069 case UserFmtBFormat3D
: return 4;
1073 static ALboolean
DecomposeUserFormat(ALenum format
, enum UserFmtChannels
*chans
,
1074 enum UserFmtType
*type
)
1076 static const struct {
1078 enum UserFmtChannels channels
;
1079 enum UserFmtType type
;
1081 { AL_FORMAT_MONO8
, UserFmtMono
, UserFmtUByte
},
1082 { AL_FORMAT_MONO16
, UserFmtMono
, UserFmtShort
},
1083 { AL_FORMAT_MONO_FLOAT32
, UserFmtMono
, UserFmtFloat
},
1084 { AL_FORMAT_MONO_DOUBLE_EXT
, UserFmtMono
, UserFmtDouble
},
1085 { AL_FORMAT_MONO_IMA4
, UserFmtMono
, UserFmtIMA4
},
1086 { AL_FORMAT_MONO_MSADPCM_SOFT
, UserFmtMono
, UserFmtMSADPCM
},
1087 { AL_FORMAT_MONO_MULAW
, UserFmtMono
, UserFmtMulaw
},
1088 { AL_FORMAT_MONO_ALAW_EXT
, UserFmtMono
, UserFmtAlaw
},
1090 { AL_FORMAT_STEREO8
, UserFmtStereo
, UserFmtUByte
},
1091 { AL_FORMAT_STEREO16
, UserFmtStereo
, UserFmtShort
},
1092 { AL_FORMAT_STEREO_FLOAT32
, UserFmtStereo
, UserFmtFloat
},
1093 { AL_FORMAT_STEREO_DOUBLE_EXT
, UserFmtStereo
, UserFmtDouble
},
1094 { AL_FORMAT_STEREO_IMA4
, UserFmtStereo
, UserFmtIMA4
},
1095 { AL_FORMAT_STEREO_MSADPCM_SOFT
, UserFmtStereo
, UserFmtMSADPCM
},
1096 { AL_FORMAT_STEREO_MULAW
, UserFmtStereo
, UserFmtMulaw
},
1097 { AL_FORMAT_STEREO_ALAW_EXT
, UserFmtStereo
, UserFmtAlaw
},
1099 { AL_FORMAT_REAR8
, UserFmtRear
, UserFmtUByte
},
1100 { AL_FORMAT_REAR16
, UserFmtRear
, UserFmtShort
},
1101 { AL_FORMAT_REAR32
, UserFmtRear
, UserFmtFloat
},
1102 { AL_FORMAT_REAR_MULAW
, UserFmtRear
, UserFmtMulaw
},
1104 { AL_FORMAT_QUAD8_LOKI
, UserFmtQuad
, UserFmtUByte
},
1105 { AL_FORMAT_QUAD16_LOKI
, UserFmtQuad
, UserFmtShort
},
1107 { AL_FORMAT_QUAD8
, UserFmtQuad
, UserFmtUByte
},
1108 { AL_FORMAT_QUAD16
, UserFmtQuad
, UserFmtShort
},
1109 { AL_FORMAT_QUAD32
, UserFmtQuad
, UserFmtFloat
},
1110 { AL_FORMAT_QUAD_MULAW
, UserFmtQuad
, UserFmtMulaw
},
1112 { AL_FORMAT_51CHN8
, UserFmtX51
, UserFmtUByte
},
1113 { AL_FORMAT_51CHN16
, UserFmtX51
, UserFmtShort
},
1114 { AL_FORMAT_51CHN32
, UserFmtX51
, UserFmtFloat
},
1115 { AL_FORMAT_51CHN_MULAW
, UserFmtX51
, UserFmtMulaw
},
1117 { AL_FORMAT_61CHN8
, UserFmtX61
, UserFmtUByte
},
1118 { AL_FORMAT_61CHN16
, UserFmtX61
, UserFmtShort
},
1119 { AL_FORMAT_61CHN32
, UserFmtX61
, UserFmtFloat
},
1120 { AL_FORMAT_61CHN_MULAW
, UserFmtX61
, UserFmtMulaw
},
1122 { AL_FORMAT_71CHN8
, UserFmtX71
, UserFmtUByte
},
1123 { AL_FORMAT_71CHN16
, UserFmtX71
, UserFmtShort
},
1124 { AL_FORMAT_71CHN32
, UserFmtX71
, UserFmtFloat
},
1125 { AL_FORMAT_71CHN_MULAW
, UserFmtX71
, UserFmtMulaw
},
1127 { AL_FORMAT_BFORMAT2D_8
, UserFmtBFormat2D
, UserFmtUByte
},
1128 { AL_FORMAT_BFORMAT2D_16
, UserFmtBFormat2D
, UserFmtShort
},
1129 { AL_FORMAT_BFORMAT2D_FLOAT32
, UserFmtBFormat2D
, UserFmtFloat
},
1130 { AL_FORMAT_BFORMAT2D_MULAW
, UserFmtBFormat2D
, UserFmtMulaw
},
1132 { AL_FORMAT_BFORMAT3D_8
, UserFmtBFormat3D
, UserFmtUByte
},
1133 { AL_FORMAT_BFORMAT3D_16
, UserFmtBFormat3D
, UserFmtShort
},
1134 { AL_FORMAT_BFORMAT3D_FLOAT32
, UserFmtBFormat3D
, UserFmtFloat
},
1135 { AL_FORMAT_BFORMAT3D_MULAW
, UserFmtBFormat3D
, UserFmtMulaw
},
1139 for(i
= 0;i
< COUNTOF(list
);i
++)
1141 if(list
[i
].format
== format
)
1143 *chans
= list
[i
].channels
;
1144 *type
= list
[i
].type
;
1152 ALsizei
BytesFromFmt(enum FmtType type
)
1156 case FmtUByte
: return sizeof(ALubyte
);
1157 case FmtShort
: return sizeof(ALshort
);
1158 case FmtFloat
: return sizeof(ALfloat
);
1159 case FmtDouble
: return sizeof(ALdouble
);
1160 case FmtMulaw
: return sizeof(ALubyte
);
1161 case FmtAlaw
: return sizeof(ALubyte
);
1165 ALsizei
ChannelsFromFmt(enum FmtChannels chans
)
1169 case FmtMono
: return 1;
1170 case FmtStereo
: return 2;
1171 case FmtRear
: return 2;
1172 case FmtQuad
: return 4;
1173 case FmtX51
: return 6;
1174 case FmtX61
: return 7;
1175 case FmtX71
: return 8;
1176 case FmtBFormat2D
: return 3;
1177 case FmtBFormat3D
: return 4;
1182 static ALsizei
SanitizeAlignment(enum UserFmtType type
, ALsizei align
)
1189 if(type
== UserFmtIMA4
)
1191 /* Here is where things vary:
1192 * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
1193 * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
1197 if(type
== UserFmtMSADPCM
)
1202 if(type
== UserFmtIMA4
)
1204 /* IMA4 block alignment must be a multiple of 8, plus 1. */
1205 if((align
&7) == 1) return align
;
1208 if(type
== UserFmtMSADPCM
)
1210 /* MSADPCM block alignment must be a multiple of 2. */
1211 if((align
&1) == 0) return align
;
1219 ALbuffer
*NewBuffer(ALCcontext
*context
)
1221 ALCdevice
*device
= context
->Device
;
1225 buffer
= al_calloc(16, sizeof(ALbuffer
));
1227 SETERR_RETURN(context
, AL_OUT_OF_MEMORY
, NULL
, "Failed to allocate buffer object");
1228 RWLockInit(&buffer
->lock
);
1230 buffer
->MappedAccess
= 0;
1232 err
= NewThunkEntry(&buffer
->id
);
1233 if(err
== AL_NO_ERROR
)
1234 err
= InsertUIntMapEntry(&device
->BufferMap
, buffer
->id
, buffer
);
1235 if(err
!= AL_NO_ERROR
)
1237 FreeThunkEntry(buffer
->id
);
1238 memset(buffer
, 0, sizeof(ALbuffer
));
1241 SETERR_RETURN(context
, err
, NULL
, "Failed to set buffer ID");
1247 void DeleteBuffer(ALCdevice
*device
, ALbuffer
*buffer
)
1249 RemoveBuffer(device
, buffer
->id
);
1250 FreeThunkEntry(buffer
->id
);
1252 al_free(buffer
->data
);
1254 memset(buffer
, 0, sizeof(*buffer
));
1260 * ReleaseALBuffers()
1262 * INTERNAL: Called to destroy any buffers that still exist on the device
1264 ALvoid
ReleaseALBuffers(ALCdevice
*device
)
1267 for(i
= 0;i
< device
->BufferMap
.size
;i
++)
1269 ALbuffer
*temp
= device
->BufferMap
.values
[i
];
1270 device
->BufferMap
.values
[i
] = NULL
;
1272 al_free(temp
->data
);
1274 FreeThunkEntry(temp
->id
);
1275 memset(temp
, 0, sizeof(ALbuffer
));