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 ALenum
LoadData(ALbuffer
*buffer
, ALuint freq
, ALsizei frames
, enum UserFmtChannels SrcChannels
, enum UserFmtType SrcType
, const ALvoid
*data
, ALsizei align
, ALbitfieldSOFT access
);
49 static ALboolean
DecomposeUserFormat(ALenum format
, enum UserFmtChannels
*chans
, enum UserFmtType
*type
);
50 static ALsizei
SanitizeAlignment(enum UserFmtType type
, ALsizei align
);
53 #define FORMAT_MASK 0x00ffffff
54 #define CONSTRUCT_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT)
55 #define INVALID_FORMAT_MASK ~(FORMAT_MASK | CONSTRUCT_FLAGS)
56 #define MAP_READ_WRITE_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT)
57 #define MAP_ACCESS_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 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
71 for(cur
= 0;cur
< n
;cur
++)
73 ALbuffer
*buffer
= NewBuffer(context
);
76 alDeleteBuffers(cur
, buffers
);
80 buffers
[cur
] = buffer
->id
;
84 ALCcontext_DecRef(context
);
87 AL_API ALvoid AL_APIENTRY
alDeleteBuffers(ALsizei n
, const ALuint
*buffers
)
94 context
= GetContextRef();
97 device
= context
->Device
;
99 LockBuffersWrite(device
);
101 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
108 /* Check for valid Buffer ID */
109 if((ALBuf
=LookupBuffer(device
, buffers
[i
])) == NULL
)
110 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
111 if(ReadRef(&ALBuf
->ref
) != 0)
112 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
117 if((ALBuf
=LookupBuffer(device
, buffers
[i
])) != NULL
)
118 DeleteBuffer(device
, ALBuf
);
122 UnlockBuffersWrite(device
);
123 ALCcontext_DecRef(context
);
126 AL_API ALboolean AL_APIENTRY
alIsBuffer(ALuint buffer
)
131 context
= GetContextRef();
132 if(!context
) return AL_FALSE
;
134 LockBuffersRead(context
->Device
);
135 ret
= ((!buffer
|| LookupBuffer(context
->Device
, buffer
)) ?
137 UnlockBuffersRead(context
->Device
);
139 ALCcontext_DecRef(context
);
145 AL_API ALvoid AL_APIENTRY
alBufferData(ALuint buffer
, ALenum format
, const ALvoid
*data
, ALsizei size
, ALsizei freq
)
147 enum UserFmtChannels srcchannels
= UserFmtMono
;
148 enum UserFmtType srctype
= UserFmtUByte
;
156 context
= GetContextRef();
159 device
= context
->Device
;
160 LockBuffersRead(device
);
161 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
162 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
163 if(!(size
>= 0 && freq
> 0) || (format
&INVALID_FORMAT_MASK
) != 0)
164 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
165 if((format
&AL_MAP_PERSISTENT_BIT_SOFT
) && !(format
&MAP_READ_WRITE_FLAGS
))
166 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
167 if(DecomposeUserFormat(format
&FORMAT_MASK
, &srcchannels
, &srctype
) == AL_FALSE
)
168 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
170 align
= SanitizeAlignment(srctype
, ATOMIC_LOAD_SEQ(&albuf
->UnpackAlign
));
171 if(align
< 1) SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
181 framesize
= FrameSizeFromUserFmt(srcchannels
, srctype
) * align
;
182 if((size
%framesize
) != 0)
183 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
185 err
= LoadData(albuf
, freq
, size
/framesize
*align
, srcchannels
, srctype
,
186 data
, align
, format
&CONSTRUCT_FLAGS
);
187 if(err
!= AL_NO_ERROR
)
188 SET_ERROR_AND_GOTO(context
, err
, done
);
192 framesize
= ((align
-1)/2 + 4) * ChannelsFromUserFmt(srcchannels
);
193 if((size
%framesize
) != 0)
194 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
196 err
= LoadData(albuf
, freq
, size
/framesize
*align
, srcchannels
, srctype
,
197 data
, align
, format
&CONSTRUCT_FLAGS
);
198 if(err
!= AL_NO_ERROR
)
199 SET_ERROR_AND_GOTO(context
, err
, done
);
203 framesize
= ((align
-2)/2 + 7) * ChannelsFromUserFmt(srcchannels
);
204 if((size
%framesize
) != 0)
205 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
207 err
= LoadData(albuf
, freq
, size
/framesize
*align
, srcchannels
, srctype
,
208 data
, align
, format
&CONSTRUCT_FLAGS
);
209 if(err
!= AL_NO_ERROR
)
210 SET_ERROR_AND_GOTO(context
, err
, done
);
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((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
232 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
233 if(!(access
&MAP_READ_WRITE_FLAGS
) || (access
&~MAP_ACCESS_FLAGS
) != 0)
234 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
236 WriteLock(&albuf
->lock
);
237 if((ReadRef(&albuf
->ref
) != 0 && !(access
&AL_MAP_PERSISTENT_BIT_SOFT
)) ||
238 albuf
->MappedAccess
!= 0)
239 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, unlock_done
);
240 if(((access
&AL_MAP_READ_BIT_SOFT
) && !(albuf
->Access
&AL_MAP_READ_BIT_SOFT
)) ||
241 ((access
&AL_MAP_WRITE_BIT_SOFT
) && !(albuf
->Access
&AL_MAP_WRITE_BIT_SOFT
)) ||
242 ((access
&AL_MAP_PERSISTENT_BIT_SOFT
) && !(albuf
->Access
&AL_MAP_PERSISTENT_BIT_SOFT
)))
243 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, unlock_done
);
244 if(offset
< 0 || offset
>= albuf
->OriginalSize
||
245 length
<= 0 || length
> albuf
->OriginalSize
- offset
)
246 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, unlock_done
);
248 retval
= (ALbyte
*)albuf
->data
+ offset
;
249 albuf
->MappedAccess
= access
;
250 albuf
->MappedOffset
= offset
;
251 albuf
->MappedSize
= length
;
254 WriteUnlock(&albuf
->lock
);
257 UnlockBuffersRead(device
);
258 ALCcontext_DecRef(context
);
263 AL_API
void AL_APIENTRY
alUnmapBufferSOFT(ALuint buffer
)
269 context
= GetContextRef();
272 device
= context
->Device
;
273 LockBuffersRead(device
);
274 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
275 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
277 WriteLock(&albuf
->lock
);
278 if(albuf
->MappedAccess
== 0)
279 alSetError(context
, AL_INVALID_OPERATION
);
282 albuf
->MappedAccess
= 0;
283 albuf
->MappedOffset
= 0;
284 albuf
->MappedSize
= 0;
286 WriteUnlock(&albuf
->lock
);
289 UnlockBuffersRead(device
);
290 ALCcontext_DecRef(context
);
293 AL_API
void AL_APIENTRY
alFlushMappedBufferSOFT(ALuint buffer
, ALsizei offset
, ALsizei length
)
299 context
= GetContextRef();
302 device
= context
->Device
;
303 LockBuffersRead(device
);
304 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
305 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
307 WriteLock(&albuf
->lock
);
308 if(albuf
->MappedAccess
== 0 || !(albuf
->MappedAccess
&AL_MAP_WRITE_BIT_SOFT
))
309 alSetError(context
, AL_INVALID_OPERATION
);
310 else if(offset
< albuf
->MappedOffset
|| offset
>= albuf
->MappedOffset
+albuf
->MappedSize
||
311 length
<= 0 || length
> albuf
->MappedOffset
+albuf
->MappedSize
-offset
)
312 alSetError(context
, AL_INVALID_VALUE
);
315 /* FIXME: Need to use some method of double-buffering for the mixer and
316 * app to hold separate memory, which can be safely transfered
317 * asynchronously. Currently we just say the app shouldn't write where
318 * OpenAL's reading, and hope for the best...
320 ATOMIC_THREAD_FENCE(almemory_order_seq_cst
);
322 WriteUnlock(&albuf
->lock
);
325 UnlockBuffersRead(device
);
326 ALCcontext_DecRef(context
);
329 AL_API ALvoid AL_APIENTRY
alBufferSubDataSOFT(ALuint buffer
, ALenum format
, const ALvoid
*data
, ALsizei offset
, ALsizei length
)
331 enum UserFmtChannels srcchannels
= UserFmtMono
;
332 enum UserFmtType srctype
= UserFmtUByte
;
342 context
= GetContextRef();
345 device
= context
->Device
;
346 LockBuffersRead(device
);
347 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
348 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
349 if(!(length
>= 0 && offset
>= 0))
350 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
351 if(DecomposeUserFormat(format
, &srcchannels
, &srctype
) == AL_FALSE
)
352 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
353 WriteLock(&albuf
->lock
);
354 align
= SanitizeAlignment(srctype
, ATOMIC_LOAD_SEQ(&albuf
->UnpackAlign
));
355 if(align
< 1) SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, unlock_done
);
357 if((long)srcchannels
!= (long)albuf
->FmtChannels
|| srctype
!= albuf
->OriginalType
)
358 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, unlock_done
);
359 if(align
!= albuf
->OriginalAlign
)
360 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, unlock_done
);
361 if(albuf
->MappedAccess
!= 0)
362 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, unlock_done
);
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(offset
> albuf
->OriginalSize
|| length
> albuf
->OriginalSize
-offset
||
374 (offset
%byte_align
) != 0 || (length
%byte_align
) != 0)
375 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, unlock_done
);
377 /* offset -> byte offset, length -> sample count */
378 offset
= offset
/byte_align
* frame_size
;
379 length
= length
/byte_align
* albuf
->OriginalAlign
;
381 dst
= (ALbyte
*)albuf
->data
+ offset
;
382 if(srctype
== UserFmtIMA4
&& albuf
->FmtType
== FmtShort
)
383 Convert_ALshort_ALima4(dst
, data
, num_chans
, length
, align
);
384 else if(srctype
== UserFmtMSADPCM
&& albuf
->FmtType
== FmtShort
)
385 Convert_ALshort_ALmsadpcm(dst
, data
, num_chans
, length
, align
);
388 assert((long)srctype
== (long)albuf
->FmtType
);
389 memcpy(dst
, data
, length
*frame_size
);
393 WriteUnlock(&albuf
->lock
);
396 UnlockBuffersRead(device
);
397 ALCcontext_DecRef(context
);
401 AL_API
void AL_APIENTRY
alBufferSamplesSOFT(ALuint
UNUSED(buffer
),
402 ALuint
UNUSED(samplerate
), ALenum
UNUSED(internalformat
), ALsizei
UNUSED(samples
),
403 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), const ALvoid
*UNUSED(data
))
407 context
= GetContextRef();
410 alSetError(context
, AL_INVALID_OPERATION
);
412 ALCcontext_DecRef(context
);
415 AL_API
void AL_APIENTRY
alBufferSubSamplesSOFT(ALuint
UNUSED(buffer
),
416 ALsizei
UNUSED(offset
), ALsizei
UNUSED(samples
),
417 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), const ALvoid
*UNUSED(data
))
421 context
= GetContextRef();
424 alSetError(context
, AL_INVALID_OPERATION
);
426 ALCcontext_DecRef(context
);
429 AL_API
void AL_APIENTRY
alGetBufferSamplesSOFT(ALuint
UNUSED(buffer
),
430 ALsizei
UNUSED(offset
), ALsizei
UNUSED(samples
),
431 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), ALvoid
*UNUSED(data
))
435 context
= GetContextRef();
438 alSetError(context
, AL_INVALID_OPERATION
);
440 ALCcontext_DecRef(context
);
443 AL_API ALboolean AL_APIENTRY
alIsBufferFormatSupportedSOFT(ALenum
UNUSED(format
))
447 context
= GetContextRef();
448 if(!context
) return AL_FALSE
;
450 alSetError(context
, AL_INVALID_OPERATION
);
452 ALCcontext_DecRef(context
);
457 AL_API
void AL_APIENTRY
alBufferf(ALuint buffer
, ALenum param
, ALfloat
UNUSED(value
))
462 context
= GetContextRef();
465 device
= context
->Device
;
466 LockBuffersRead(device
);
467 if(LookupBuffer(device
, buffer
) == NULL
)
468 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
473 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
477 UnlockBuffersRead(device
);
478 ALCcontext_DecRef(context
);
482 AL_API
void AL_APIENTRY
alBuffer3f(ALuint buffer
, ALenum param
, ALfloat
UNUSED(value1
), ALfloat
UNUSED(value2
), ALfloat
UNUSED(value3
))
487 context
= GetContextRef();
490 device
= context
->Device
;
491 LockBuffersRead(device
);
492 if(LookupBuffer(device
, buffer
) == NULL
)
493 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
498 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
502 UnlockBuffersRead(device
);
503 ALCcontext_DecRef(context
);
507 AL_API
void AL_APIENTRY
alBufferfv(ALuint buffer
, ALenum param
, const ALfloat
*values
)
512 context
= GetContextRef();
515 device
= context
->Device
;
516 LockBuffersRead(device
);
517 if(LookupBuffer(device
, buffer
) == NULL
)
518 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
521 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
525 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
529 UnlockBuffersRead(device
);
530 ALCcontext_DecRef(context
);
534 AL_API
void AL_APIENTRY
alBufferi(ALuint buffer
, ALenum param
, ALint value
)
540 context
= GetContextRef();
543 device
= context
->Device
;
544 LockBuffersRead(device
);
545 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
546 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
550 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
552 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
553 ATOMIC_STORE_SEQ(&albuf
->UnpackAlign
, value
);
556 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
558 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
559 ATOMIC_STORE_SEQ(&albuf
->PackAlign
, value
);
563 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
567 UnlockBuffersRead(device
);
568 ALCcontext_DecRef(context
);
572 AL_API
void AL_APIENTRY
alBuffer3i(ALuint buffer
, ALenum param
, ALint
UNUSED(value1
), ALint
UNUSED(value2
), ALint
UNUSED(value3
))
577 context
= GetContextRef();
580 device
= context
->Device
;
581 if(LookupBuffer(device
, buffer
) == NULL
)
582 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
587 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
591 ALCcontext_DecRef(context
);
595 AL_API
void AL_APIENTRY
alBufferiv(ALuint buffer
, ALenum param
, const ALint
*values
)
605 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
606 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
607 alBufferi(buffer
, param
, values
[0]);
612 context
= GetContextRef();
615 device
= context
->Device
;
616 LockBuffersRead(device
);
617 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
618 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
621 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
624 case AL_LOOP_POINTS_SOFT
:
625 WriteLock(&albuf
->lock
);
626 if(ReadRef(&albuf
->ref
) != 0)
628 WriteUnlock(&albuf
->lock
);
629 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
631 if(values
[0] >= values
[1] || values
[0] < 0 ||
632 values
[1] > albuf
->SampleLen
)
634 WriteUnlock(&albuf
->lock
);
635 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
638 albuf
->LoopStart
= values
[0];
639 albuf
->LoopEnd
= values
[1];
640 WriteUnlock(&albuf
->lock
);
644 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
648 UnlockBuffersRead(device
);
649 ALCcontext_DecRef(context
);
653 AL_API ALvoid AL_APIENTRY
alGetBufferf(ALuint buffer
, ALenum param
, ALfloat
*value
)
659 context
= GetContextRef();
662 device
= context
->Device
;
663 LockBuffersRead(device
);
664 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
665 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
668 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
672 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
676 UnlockBuffersRead(device
);
677 ALCcontext_DecRef(context
);
681 AL_API
void AL_APIENTRY
alGetBuffer3f(ALuint buffer
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
686 context
= GetContextRef();
689 device
= context
->Device
;
690 LockBuffersRead(device
);
691 if(LookupBuffer(device
, buffer
) == NULL
)
692 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
694 if(!(value1
&& value2
&& value3
))
695 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
699 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
703 UnlockBuffersRead(device
);
704 ALCcontext_DecRef(context
);
708 AL_API
void AL_APIENTRY
alGetBufferfv(ALuint buffer
, ALenum param
, ALfloat
*values
)
715 case AL_SEC_LENGTH_SOFT
:
716 alGetBufferf(buffer
, param
, values
);
720 context
= GetContextRef();
723 device
= context
->Device
;
724 LockBuffersRead(device
);
725 if(LookupBuffer(device
, buffer
) == NULL
)
726 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
729 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
733 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
737 UnlockBuffersRead(device
);
738 ALCcontext_DecRef(context
);
742 AL_API ALvoid AL_APIENTRY
alGetBufferi(ALuint buffer
, ALenum param
, ALint
*value
)
748 context
= GetContextRef();
751 device
= context
->Device
;
752 LockBuffersRead(device
);
753 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
754 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
757 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
761 *value
= albuf
->Frequency
;
765 *value
= BytesFromFmt(albuf
->FmtType
) * 8;
769 *value
= ChannelsFromFmt(albuf
->FmtChannels
);
773 ReadLock(&albuf
->lock
);
774 *value
= albuf
->SampleLen
* FrameSizeFromFmt(albuf
->FmtChannels
,
776 ReadUnlock(&albuf
->lock
);
779 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
780 *value
= ATOMIC_LOAD_SEQ(&albuf
->UnpackAlign
);
783 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
784 *value
= ATOMIC_LOAD_SEQ(&albuf
->PackAlign
);
788 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
792 UnlockBuffersRead(device
);
793 ALCcontext_DecRef(context
);
797 AL_API
void AL_APIENTRY
alGetBuffer3i(ALuint buffer
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
802 context
= GetContextRef();
805 device
= context
->Device
;
806 LockBuffersRead(device
);
807 if(LookupBuffer(device
, buffer
) == NULL
)
808 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
810 if(!(value1
&& value2
&& value3
))
811 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
815 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
819 UnlockBuffersRead(device
);
820 ALCcontext_DecRef(context
);
824 AL_API
void AL_APIENTRY
alGetBufferiv(ALuint buffer
, ALenum param
, ALint
*values
)
836 case AL_INTERNAL_FORMAT_SOFT
:
837 case AL_BYTE_LENGTH_SOFT
:
838 case AL_SAMPLE_LENGTH_SOFT
:
839 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
840 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
841 alGetBufferi(buffer
, param
, values
);
845 context
= GetContextRef();
848 device
= context
->Device
;
849 LockBuffersRead(device
);
850 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
851 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
854 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
857 case AL_LOOP_POINTS_SOFT
:
858 ReadLock(&albuf
->lock
);
859 values
[0] = albuf
->LoopStart
;
860 values
[1] = albuf
->LoopEnd
;
861 ReadUnlock(&albuf
->lock
);
865 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
869 UnlockBuffersRead(device
);
870 ALCcontext_DecRef(context
);
877 * Loads the specified data into the buffer, using the specified formats.
878 * Currently, the new format must have the same channel configuration as the
881 static ALenum
LoadData(ALbuffer
*ALBuf
, ALuint freq
, ALsizei frames
, enum UserFmtChannels SrcChannels
, enum UserFmtType SrcType
, const ALvoid
*data
, ALsizei align
, ALbitfieldSOFT access
)
883 enum FmtChannels DstChannels
= FmtMono
;
884 enum FmtType DstType
= FmtUByte
;
885 ALsizei NumChannels
, FrameSize
;
888 /* Currently no channels need to be converted. */
891 case UserFmtMono
: DstChannels
= FmtMono
; break;
892 case UserFmtStereo
: DstChannels
= FmtStereo
; break;
893 case UserFmtRear
: DstChannels
= FmtRear
; break;
894 case UserFmtQuad
: DstChannels
= FmtQuad
; break;
895 case UserFmtX51
: DstChannels
= FmtX51
; break;
896 case UserFmtX61
: DstChannels
= FmtX61
; break;
897 case UserFmtX71
: DstChannels
= FmtX71
; break;
898 case UserFmtBFormat2D
: DstChannels
= FmtBFormat2D
; break;
899 case UserFmtBFormat3D
: DstChannels
= FmtBFormat3D
; break;
901 if((long)SrcChannels
!= (long)DstChannels
)
902 return AL_INVALID_ENUM
;
904 /* IMA4 and MSADPCM convert to 16-bit short. */
907 case UserFmtUByte
: DstType
= FmtUByte
; break;
908 case UserFmtShort
: DstType
= FmtShort
; break;
909 case UserFmtFloat
: DstType
= FmtFloat
; break;
910 case UserFmtDouble
: DstType
= FmtDouble
; break;
911 case UserFmtAlaw
: DstType
= FmtAlaw
; break;
912 case UserFmtMulaw
: DstType
= FmtMulaw
; break;
913 case UserFmtIMA4
: DstType
= FmtShort
; break;
914 case UserFmtMSADPCM
: DstType
= FmtShort
; break;
919 if((long)SrcType
!= (long)DstType
)
920 return AL_INVALID_VALUE
;
923 NumChannels
= ChannelsFromFmt(DstChannels
);
924 FrameSize
= NumChannels
* BytesFromFmt(DstType
);
926 if(frames
> INT_MAX
/FrameSize
)
927 return AL_OUT_OF_MEMORY
;
928 newsize
= frames
*FrameSize
;
930 WriteLock(&ALBuf
->lock
);
931 if(ReadRef(&ALBuf
->ref
) != 0 || ALBuf
->MappedAccess
!= 0)
933 WriteUnlock(&ALBuf
->lock
);
934 return AL_INVALID_OPERATION
;
937 if((access
&AL_PRESERVE_DATA_BIT_SOFT
))
939 /* Can only preserve data with the same format and alignment. */
940 if(ALBuf
->FmtChannels
!= DstChannels
|| ALBuf
->OriginalType
!= SrcType
||
941 ALBuf
->OriginalAlign
!= align
)
943 WriteUnlock(&ALBuf
->lock
);
944 return AL_INVALID_VALUE
;
948 /* Round up to the next 16-byte multiple. This could reallocate only when
949 * increasing or the new size is less than half the current, but then the
950 * buffer's AL_SIZE would not be very reliable for accounting buffer memory
951 * usage, and reporting the real size could cause problems for apps that
952 * use AL_SIZE to try to get the buffer's play length.
954 if(newsize
<= INT_MAX
-15)
955 newsize
= (newsize
+15) & ~0xf;
956 if(newsize
!= ALBuf
->BytesAlloc
)
958 void *temp
= al_malloc(16, (size_t)newsize
);
961 WriteUnlock(&ALBuf
->lock
);
962 return AL_OUT_OF_MEMORY
;
964 if((access
&AL_PRESERVE_DATA_BIT_SOFT
))
966 ALsizei tocopy
= mini(newsize
, ALBuf
->BytesAlloc
);
967 if(tocopy
> 0) memcpy(temp
, ALBuf
->data
, tocopy
);
969 al_free(ALBuf
->data
);
971 ALBuf
->BytesAlloc
= newsize
;
974 ALBuf
->OriginalType
= SrcType
;
975 if(SrcType
== UserFmtIMA4
)
977 ALsizei byte_align
= ((align
-1)/2 + 4) * NumChannels
;
978 ALBuf
->OriginalSize
= frames
/ align
* byte_align
;
979 ALBuf
->OriginalAlign
= align
;
980 assert(DstType
== FmtShort
);
981 if(data
!= NULL
&& ALBuf
->data
!= NULL
)
982 Convert_ALshort_ALima4(ALBuf
->data
, data
, NumChannels
, frames
, align
);
984 else if(SrcType
== UserFmtMSADPCM
)
986 ALsizei byte_align
= ((align
-2)/2 + 7) * NumChannels
;
987 ALBuf
->OriginalSize
= frames
/ align
* byte_align
;
988 ALBuf
->OriginalAlign
= align
;
989 assert(DstType
== FmtShort
);
990 if(data
!= NULL
&& ALBuf
->data
!= NULL
)
991 Convert_ALshort_ALmsadpcm(ALBuf
->data
, data
, NumChannels
, frames
, align
);
995 ALBuf
->OriginalSize
= frames
* FrameSize
;
996 ALBuf
->OriginalAlign
= 1;
997 assert((long)SrcType
== (long)DstType
);
998 if(data
!= NULL
&& ALBuf
->data
!= NULL
)
999 memcpy(ALBuf
->data
, data
, frames
*FrameSize
);
1002 ALBuf
->Frequency
= freq
;
1003 ALBuf
->FmtChannels
= DstChannels
;
1004 ALBuf
->FmtType
= DstType
;
1005 ALBuf
->Access
= access
;
1007 ALBuf
->SampleLen
= frames
;
1008 ALBuf
->LoopStart
= 0;
1009 ALBuf
->LoopEnd
= ALBuf
->SampleLen
;
1011 WriteUnlock(&ALBuf
->lock
);
1016 ALsizei
BytesFromUserFmt(enum UserFmtType type
)
1020 case UserFmtUByte
: return sizeof(ALubyte
);
1021 case UserFmtShort
: return sizeof(ALshort
);
1022 case UserFmtFloat
: return sizeof(ALfloat
);
1023 case UserFmtDouble
: return sizeof(ALdouble
);
1024 case UserFmtMulaw
: return sizeof(ALubyte
);
1025 case UserFmtAlaw
: return sizeof(ALubyte
);
1026 case UserFmtIMA4
: break; /* not handled here */
1027 case UserFmtMSADPCM
: break; /* not handled here */
1031 ALsizei
ChannelsFromUserFmt(enum UserFmtChannels chans
)
1035 case UserFmtMono
: return 1;
1036 case UserFmtStereo
: return 2;
1037 case UserFmtRear
: return 2;
1038 case UserFmtQuad
: return 4;
1039 case UserFmtX51
: return 6;
1040 case UserFmtX61
: return 7;
1041 case UserFmtX71
: return 8;
1042 case UserFmtBFormat2D
: return 3;
1043 case UserFmtBFormat3D
: return 4;
1047 static ALboolean
DecomposeUserFormat(ALenum format
, enum UserFmtChannels
*chans
,
1048 enum UserFmtType
*type
)
1050 static const struct {
1052 enum UserFmtChannels channels
;
1053 enum UserFmtType type
;
1055 { AL_FORMAT_MONO8
, UserFmtMono
, UserFmtUByte
},
1056 { AL_FORMAT_MONO16
, UserFmtMono
, UserFmtShort
},
1057 { AL_FORMAT_MONO_FLOAT32
, UserFmtMono
, UserFmtFloat
},
1058 { AL_FORMAT_MONO_DOUBLE_EXT
, UserFmtMono
, UserFmtDouble
},
1059 { AL_FORMAT_MONO_IMA4
, UserFmtMono
, UserFmtIMA4
},
1060 { AL_FORMAT_MONO_MSADPCM_SOFT
, UserFmtMono
, UserFmtMSADPCM
},
1061 { AL_FORMAT_MONO_MULAW
, UserFmtMono
, UserFmtMulaw
},
1062 { AL_FORMAT_MONO_ALAW_EXT
, UserFmtMono
, UserFmtAlaw
},
1064 { AL_FORMAT_STEREO8
, UserFmtStereo
, UserFmtUByte
},
1065 { AL_FORMAT_STEREO16
, UserFmtStereo
, UserFmtShort
},
1066 { AL_FORMAT_STEREO_FLOAT32
, UserFmtStereo
, UserFmtFloat
},
1067 { AL_FORMAT_STEREO_DOUBLE_EXT
, UserFmtStereo
, UserFmtDouble
},
1068 { AL_FORMAT_STEREO_IMA4
, UserFmtStereo
, UserFmtIMA4
},
1069 { AL_FORMAT_STEREO_MSADPCM_SOFT
, UserFmtStereo
, UserFmtMSADPCM
},
1070 { AL_FORMAT_STEREO_MULAW
, UserFmtStereo
, UserFmtMulaw
},
1071 { AL_FORMAT_STEREO_ALAW_EXT
, UserFmtStereo
, UserFmtAlaw
},
1073 { AL_FORMAT_REAR8
, UserFmtRear
, UserFmtUByte
},
1074 { AL_FORMAT_REAR16
, UserFmtRear
, UserFmtShort
},
1075 { AL_FORMAT_REAR32
, UserFmtRear
, UserFmtFloat
},
1076 { AL_FORMAT_REAR_MULAW
, UserFmtRear
, UserFmtMulaw
},
1078 { AL_FORMAT_QUAD8_LOKI
, UserFmtQuad
, UserFmtUByte
},
1079 { AL_FORMAT_QUAD16_LOKI
, UserFmtQuad
, UserFmtShort
},
1081 { AL_FORMAT_QUAD8
, UserFmtQuad
, UserFmtUByte
},
1082 { AL_FORMAT_QUAD16
, UserFmtQuad
, UserFmtShort
},
1083 { AL_FORMAT_QUAD32
, UserFmtQuad
, UserFmtFloat
},
1084 { AL_FORMAT_QUAD_MULAW
, UserFmtQuad
, UserFmtMulaw
},
1086 { AL_FORMAT_51CHN8
, UserFmtX51
, UserFmtUByte
},
1087 { AL_FORMAT_51CHN16
, UserFmtX51
, UserFmtShort
},
1088 { AL_FORMAT_51CHN32
, UserFmtX51
, UserFmtFloat
},
1089 { AL_FORMAT_51CHN_MULAW
, UserFmtX51
, UserFmtMulaw
},
1091 { AL_FORMAT_61CHN8
, UserFmtX61
, UserFmtUByte
},
1092 { AL_FORMAT_61CHN16
, UserFmtX61
, UserFmtShort
},
1093 { AL_FORMAT_61CHN32
, UserFmtX61
, UserFmtFloat
},
1094 { AL_FORMAT_61CHN_MULAW
, UserFmtX61
, UserFmtMulaw
},
1096 { AL_FORMAT_71CHN8
, UserFmtX71
, UserFmtUByte
},
1097 { AL_FORMAT_71CHN16
, UserFmtX71
, UserFmtShort
},
1098 { AL_FORMAT_71CHN32
, UserFmtX71
, UserFmtFloat
},
1099 { AL_FORMAT_71CHN_MULAW
, UserFmtX71
, UserFmtMulaw
},
1101 { AL_FORMAT_BFORMAT2D_8
, UserFmtBFormat2D
, UserFmtUByte
},
1102 { AL_FORMAT_BFORMAT2D_16
, UserFmtBFormat2D
, UserFmtShort
},
1103 { AL_FORMAT_BFORMAT2D_FLOAT32
, UserFmtBFormat2D
, UserFmtFloat
},
1104 { AL_FORMAT_BFORMAT2D_MULAW
, UserFmtBFormat2D
, UserFmtMulaw
},
1106 { AL_FORMAT_BFORMAT3D_8
, UserFmtBFormat3D
, UserFmtUByte
},
1107 { AL_FORMAT_BFORMAT3D_16
, UserFmtBFormat3D
, UserFmtShort
},
1108 { AL_FORMAT_BFORMAT3D_FLOAT32
, UserFmtBFormat3D
, UserFmtFloat
},
1109 { AL_FORMAT_BFORMAT3D_MULAW
, UserFmtBFormat3D
, UserFmtMulaw
},
1113 for(i
= 0;i
< COUNTOF(list
);i
++)
1115 if(list
[i
].format
== format
)
1117 *chans
= list
[i
].channels
;
1118 *type
= list
[i
].type
;
1126 ALsizei
BytesFromFmt(enum FmtType type
)
1130 case FmtUByte
: return sizeof(ALubyte
);
1131 case FmtShort
: return sizeof(ALshort
);
1132 case FmtFloat
: return sizeof(ALfloat
);
1133 case FmtDouble
: return sizeof(ALdouble
);
1134 case FmtMulaw
: return sizeof(ALubyte
);
1135 case FmtAlaw
: return sizeof(ALubyte
);
1139 ALsizei
ChannelsFromFmt(enum FmtChannels chans
)
1143 case FmtMono
: return 1;
1144 case FmtStereo
: return 2;
1145 case FmtRear
: return 2;
1146 case FmtQuad
: return 4;
1147 case FmtX51
: return 6;
1148 case FmtX61
: return 7;
1149 case FmtX71
: return 8;
1150 case FmtBFormat2D
: return 3;
1151 case FmtBFormat3D
: return 4;
1156 static ALsizei
SanitizeAlignment(enum UserFmtType type
, ALsizei align
)
1163 if(type
== UserFmtIMA4
)
1165 /* Here is where things vary:
1166 * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
1167 * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
1171 if(type
== UserFmtMSADPCM
)
1176 if(type
== UserFmtIMA4
)
1178 /* IMA4 block alignment must be a multiple of 8, plus 1. */
1179 if((align
&7) == 1) return align
;
1182 if(type
== UserFmtMSADPCM
)
1184 /* MSADPCM block alignment must be a multiple of 2. */
1185 if((align
&1) == 0) return align
;
1193 ALbuffer
*NewBuffer(ALCcontext
*context
)
1195 ALCdevice
*device
= context
->Device
;
1199 buffer
= al_calloc(16, sizeof(ALbuffer
));
1201 SET_ERROR_AND_RETURN_VALUE(context
, AL_OUT_OF_MEMORY
, NULL
);
1202 RWLockInit(&buffer
->lock
);
1204 buffer
->MappedAccess
= 0;
1206 err
= NewThunkEntry(&buffer
->id
);
1207 if(err
== AL_NO_ERROR
)
1208 err
= InsertUIntMapEntry(&device
->BufferMap
, buffer
->id
, buffer
);
1209 if(err
!= AL_NO_ERROR
)
1211 FreeThunkEntry(buffer
->id
);
1212 memset(buffer
, 0, sizeof(ALbuffer
));
1215 SET_ERROR_AND_RETURN_VALUE(context
, err
, NULL
);
1221 void DeleteBuffer(ALCdevice
*device
, ALbuffer
*buffer
)
1223 RemoveBuffer(device
, buffer
->id
);
1224 FreeThunkEntry(buffer
->id
);
1226 al_free(buffer
->data
);
1228 memset(buffer
, 0, sizeof(*buffer
));
1234 * ReleaseALBuffers()
1236 * INTERNAL: Called to destroy any buffers that still exist on the device
1238 ALvoid
ReleaseALBuffers(ALCdevice
*device
)
1241 for(i
= 0;i
< device
->BufferMap
.size
;i
++)
1243 ALbuffer
*temp
= device
->BufferMap
.values
[i
];
1244 device
->BufferMap
.values
[i
] = NULL
;
1246 al_free(temp
->data
);
1248 FreeThunkEntry(temp
->id
);
1249 memset(temp
, 0, sizeof(ALbuffer
));