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)
55 #define INVALID_FORMAT_MASK ~(FORMAT_MASK | CONSTRUCT_FLAGS)
56 #define MAP_ACCESS_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT)
59 AL_API ALvoid AL_APIENTRY
alGenBuffers(ALsizei n
, ALuint
*buffers
)
64 context
= GetContextRef();
68 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
70 for(cur
= 0;cur
< n
;cur
++)
72 ALbuffer
*buffer
= NewBuffer(context
);
75 alDeleteBuffers(cur
, buffers
);
79 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
);
100 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
107 /* Check for valid Buffer ID */
108 if((ALBuf
=LookupBuffer(device
, buffers
[i
])) == NULL
)
109 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
110 if(ReadRef(&ALBuf
->ref
) != 0)
111 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
116 if((ALBuf
=LookupBuffer(device
, buffers
[i
])) != NULL
)
117 DeleteBuffer(device
, ALBuf
);
121 UnlockBuffersWrite(device
);
122 ALCcontext_DecRef(context
);
125 AL_API ALboolean AL_APIENTRY
alIsBuffer(ALuint buffer
)
130 context
= GetContextRef();
131 if(!context
) return AL_FALSE
;
133 LockBuffersRead(context
->Device
);
134 ret
= ((!buffer
|| LookupBuffer(context
->Device
, buffer
)) ?
136 UnlockBuffersRead(context
->Device
);
138 ALCcontext_DecRef(context
);
144 AL_API ALvoid AL_APIENTRY
alBufferData(ALuint buffer
, ALenum format
, const ALvoid
*data
, ALsizei size
, ALsizei freq
)
146 enum UserFmtChannels srcchannels
= UserFmtMono
;
147 enum UserFmtType srctype
= UserFmtUByte
;
155 context
= GetContextRef();
158 device
= context
->Device
;
159 LockBuffersRead(device
);
160 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
161 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
162 if(!(size
>= 0 && freq
> 0) || (format
&INVALID_FORMAT_MASK
) != 0)
163 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
164 if(DecomposeUserFormat(format
&FORMAT_MASK
, &srcchannels
, &srctype
) == AL_FALSE
)
165 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
167 align
= SanitizeAlignment(srctype
, ATOMIC_LOAD_SEQ(&albuf
->UnpackAlign
));
168 if(align
< 1) SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
178 framesize
= FrameSizeFromUserFmt(srcchannels
, srctype
) * align
;
179 if((size
%framesize
) != 0)
180 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
182 err
= LoadData(albuf
, freq
, size
/framesize
*align
, srcchannels
, srctype
,
183 data
, align
, format
&CONSTRUCT_FLAGS
);
184 if(err
!= AL_NO_ERROR
)
185 SET_ERROR_AND_GOTO(context
, err
, done
);
189 framesize
= ((align
-1)/2 + 4) * ChannelsFromUserFmt(srcchannels
);
190 if((size
%framesize
) != 0)
191 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
193 err
= LoadData(albuf
, freq
, size
/framesize
*align
, srcchannels
, srctype
,
194 data
, align
, format
&CONSTRUCT_FLAGS
);
195 if(err
!= AL_NO_ERROR
)
196 SET_ERROR_AND_GOTO(context
, err
, done
);
200 framesize
= ((align
-2)/2 + 7) * ChannelsFromUserFmt(srcchannels
);
201 if((size
%framesize
) != 0)
202 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
204 err
= LoadData(albuf
, freq
, size
/framesize
*align
, srcchannels
, srctype
,
205 data
, align
, format
&CONSTRUCT_FLAGS
);
206 if(err
!= AL_NO_ERROR
)
207 SET_ERROR_AND_GOTO(context
, err
, done
);
212 UnlockBuffersRead(device
);
213 ALCcontext_DecRef(context
);
216 AL_API
void* AL_APIENTRY
alMapBufferSOFT(ALuint buffer
, ALsizei offset
, ALsizei length
, ALbitfieldSOFT access
)
223 context
= GetContextRef();
224 if(!context
) return retval
;
226 device
= context
->Device
;
227 LockBuffersRead(device
);
228 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
229 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
230 if(!access
|| (access
&~MAP_ACCESS_FLAGS
) != 0)
231 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
233 WriteLock(&albuf
->lock
);
234 if(((access
&AL_MAP_READ_BIT_SOFT
) && !(albuf
->Access
&AL_MAP_READ_BIT_SOFT
)) ||
235 ((access
&AL_MAP_WRITE_BIT_SOFT
) && !(albuf
->Access
&AL_MAP_WRITE_BIT_SOFT
)))
236 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, unlock_done
);
237 if(offset
< 0 || offset
>= albuf
->OriginalSize
||
238 length
<= 0 || length
> albuf
->OriginalSize
- offset
)
239 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, unlock_done
);
240 if(ReadRef(&albuf
->ref
) != 0 || albuf
->MappedAccess
!= 0)
241 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, unlock_done
);
243 retval
= (ALbyte
*)albuf
->data
+ offset
;
244 albuf
->MappedAccess
= access
;
245 if((access
&AL_MAP_WRITE_BIT_SOFT
) && !(access
&AL_MAP_READ_BIT_SOFT
))
246 memset(retval
, 0x55, length
);
249 WriteUnlock(&albuf
->lock
);
252 UnlockBuffersRead(device
);
253 ALCcontext_DecRef(context
);
258 AL_API
void AL_APIENTRY
alUnmapBufferSOFT(ALuint buffer
)
264 context
= GetContextRef();
267 device
= context
->Device
;
268 LockBuffersRead(device
);
269 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
270 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
272 WriteLock(&albuf
->lock
);
273 if(albuf
->MappedAccess
== 0)
274 alSetError(context
, AL_INVALID_OPERATION
);
276 albuf
->MappedAccess
= 0;
277 WriteUnlock(&albuf
->lock
);
280 UnlockBuffersRead(device
);
281 ALCcontext_DecRef(context
);
284 AL_API ALvoid AL_APIENTRY
alBufferSubDataSOFT(ALuint buffer
, ALenum format
, const ALvoid
*data
, ALsizei offset
, ALsizei length
)
286 enum UserFmtChannels srcchannels
= UserFmtMono
;
287 enum UserFmtType srctype
= UserFmtUByte
;
297 context
= GetContextRef();
300 device
= context
->Device
;
301 LockBuffersRead(device
);
302 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
303 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
304 if(!(length
>= 0 && offset
>= 0))
305 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
306 if(DecomposeUserFormat(format
, &srcchannels
, &srctype
) == AL_FALSE
)
307 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
308 WriteLock(&albuf
->lock
);
309 align
= SanitizeAlignment(srctype
, ATOMIC_LOAD_SEQ(&albuf
->UnpackAlign
));
310 if(align
< 1) SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, unlock_done
);
312 if((long)srcchannels
!= (long)albuf
->FmtChannels
|| srctype
!= albuf
->OriginalType
)
313 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, unlock_done
);
314 if(align
!= albuf
->OriginalAlign
)
315 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, unlock_done
);
316 if(albuf
->MappedAccess
!= 0)
317 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, unlock_done
);
319 num_chans
= ChannelsFromFmt(albuf
->FmtChannels
);
320 frame_size
= num_chans
* BytesFromFmt(albuf
->FmtType
);
321 if(albuf
->OriginalType
== UserFmtIMA4
)
322 byte_align
= ((align
-1)/2 + 4) * num_chans
;
323 else if(albuf
->OriginalType
== UserFmtMSADPCM
)
324 byte_align
= ((align
-2)/2 + 7) * num_chans
;
326 byte_align
= align
* frame_size
;
328 if(offset
> albuf
->OriginalSize
|| length
> albuf
->OriginalSize
-offset
||
329 (offset
%byte_align
) != 0 || (length
%byte_align
) != 0)
330 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, unlock_done
);
332 /* offset -> byte offset, length -> sample count */
333 offset
= offset
/byte_align
* frame_size
;
334 length
= length
/byte_align
* albuf
->OriginalAlign
;
336 dst
= (ALbyte
*)albuf
->data
+ offset
;
337 if(srctype
== UserFmtIMA4
&& albuf
->FmtType
== FmtShort
)
338 Convert_ALshort_ALima4(dst
, data
, num_chans
, length
, align
);
339 else if(srctype
== UserFmtMSADPCM
&& albuf
->FmtType
== FmtShort
)
340 Convert_ALshort_ALmsadpcm(dst
, data
, num_chans
, length
, align
);
343 assert((long)srctype
== (long)albuf
->FmtType
);
344 memcpy(dst
, data
, length
*frame_size
);
348 WriteUnlock(&albuf
->lock
);
351 UnlockBuffersRead(device
);
352 ALCcontext_DecRef(context
);
356 AL_API
void AL_APIENTRY
alBufferSamplesSOFT(ALuint
UNUSED(buffer
),
357 ALuint
UNUSED(samplerate
), ALenum
UNUSED(internalformat
), ALsizei
UNUSED(samples
),
358 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), const ALvoid
*UNUSED(data
))
362 context
= GetContextRef();
365 alSetError(context
, AL_INVALID_OPERATION
);
367 ALCcontext_DecRef(context
);
370 AL_API
void AL_APIENTRY
alBufferSubSamplesSOFT(ALuint
UNUSED(buffer
),
371 ALsizei
UNUSED(offset
), ALsizei
UNUSED(samples
),
372 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), const ALvoid
*UNUSED(data
))
376 context
= GetContextRef();
379 alSetError(context
, AL_INVALID_OPERATION
);
381 ALCcontext_DecRef(context
);
384 AL_API
void AL_APIENTRY
alGetBufferSamplesSOFT(ALuint
UNUSED(buffer
),
385 ALsizei
UNUSED(offset
), ALsizei
UNUSED(samples
),
386 ALenum
UNUSED(channels
), ALenum
UNUSED(type
), ALvoid
*UNUSED(data
))
390 context
= GetContextRef();
393 alSetError(context
, AL_INVALID_OPERATION
);
395 ALCcontext_DecRef(context
);
398 AL_API ALboolean AL_APIENTRY
alIsBufferFormatSupportedSOFT(ALenum
UNUSED(format
))
402 context
= GetContextRef();
403 if(!context
) return AL_FALSE
;
405 alSetError(context
, AL_INVALID_OPERATION
);
407 ALCcontext_DecRef(context
);
412 AL_API
void AL_APIENTRY
alBufferf(ALuint buffer
, ALenum param
, ALfloat
UNUSED(value
))
417 context
= GetContextRef();
420 device
= context
->Device
;
421 LockBuffersRead(device
);
422 if(LookupBuffer(device
, buffer
) == NULL
)
423 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
428 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
432 UnlockBuffersRead(device
);
433 ALCcontext_DecRef(context
);
437 AL_API
void AL_APIENTRY
alBuffer3f(ALuint buffer
, ALenum param
, ALfloat
UNUSED(value1
), ALfloat
UNUSED(value2
), ALfloat
UNUSED(value3
))
442 context
= GetContextRef();
445 device
= context
->Device
;
446 LockBuffersRead(device
);
447 if(LookupBuffer(device
, buffer
) == NULL
)
448 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
453 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
457 UnlockBuffersRead(device
);
458 ALCcontext_DecRef(context
);
462 AL_API
void AL_APIENTRY
alBufferfv(ALuint buffer
, ALenum param
, const ALfloat
*values
)
467 context
= GetContextRef();
470 device
= context
->Device
;
471 LockBuffersRead(device
);
472 if(LookupBuffer(device
, buffer
) == NULL
)
473 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
476 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
480 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
484 UnlockBuffersRead(device
);
485 ALCcontext_DecRef(context
);
489 AL_API
void AL_APIENTRY
alBufferi(ALuint buffer
, ALenum param
, ALint value
)
495 context
= GetContextRef();
498 device
= context
->Device
;
499 LockBuffersRead(device
);
500 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
501 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
505 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
507 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
508 ATOMIC_STORE_SEQ(&albuf
->UnpackAlign
, value
);
511 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
513 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
514 ATOMIC_STORE_SEQ(&albuf
->PackAlign
, value
);
518 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
522 UnlockBuffersRead(device
);
523 ALCcontext_DecRef(context
);
527 AL_API
void AL_APIENTRY
alBuffer3i(ALuint buffer
, ALenum param
, ALint
UNUSED(value1
), ALint
UNUSED(value2
), ALint
UNUSED(value3
))
532 context
= GetContextRef();
535 device
= context
->Device
;
536 if(LookupBuffer(device
, buffer
) == NULL
)
537 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
542 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
546 ALCcontext_DecRef(context
);
550 AL_API
void AL_APIENTRY
alBufferiv(ALuint buffer
, ALenum param
, const ALint
*values
)
560 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
561 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
562 alBufferi(buffer
, param
, values
[0]);
567 context
= GetContextRef();
570 device
= context
->Device
;
571 LockBuffersRead(device
);
572 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
573 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
576 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
579 case AL_LOOP_POINTS_SOFT
:
580 WriteLock(&albuf
->lock
);
581 if(ReadRef(&albuf
->ref
) != 0)
583 WriteUnlock(&albuf
->lock
);
584 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
586 if(values
[0] >= values
[1] || values
[0] < 0 ||
587 values
[1] > albuf
->SampleLen
)
589 WriteUnlock(&albuf
->lock
);
590 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
593 albuf
->LoopStart
= values
[0];
594 albuf
->LoopEnd
= values
[1];
595 WriteUnlock(&albuf
->lock
);
599 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
603 UnlockBuffersRead(device
);
604 ALCcontext_DecRef(context
);
608 AL_API ALvoid AL_APIENTRY
alGetBufferf(ALuint buffer
, ALenum param
, ALfloat
*value
)
614 context
= GetContextRef();
617 device
= context
->Device
;
618 LockBuffersRead(device
);
619 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
620 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
623 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
627 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
631 UnlockBuffersRead(device
);
632 ALCcontext_DecRef(context
);
636 AL_API
void AL_APIENTRY
alGetBuffer3f(ALuint buffer
, ALenum param
, ALfloat
*value1
, ALfloat
*value2
, ALfloat
*value3
)
641 context
= GetContextRef();
644 device
= context
->Device
;
645 LockBuffersRead(device
);
646 if(LookupBuffer(device
, buffer
) == NULL
)
647 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
649 if(!(value1
&& value2
&& value3
))
650 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
654 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
658 UnlockBuffersRead(device
);
659 ALCcontext_DecRef(context
);
663 AL_API
void AL_APIENTRY
alGetBufferfv(ALuint buffer
, ALenum param
, ALfloat
*values
)
670 case AL_SEC_LENGTH_SOFT
:
671 alGetBufferf(buffer
, param
, values
);
675 context
= GetContextRef();
678 device
= context
->Device
;
679 LockBuffersRead(device
);
680 if(LookupBuffer(device
, buffer
) == NULL
)
681 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
684 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
688 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
692 UnlockBuffersRead(device
);
693 ALCcontext_DecRef(context
);
697 AL_API ALvoid AL_APIENTRY
alGetBufferi(ALuint buffer
, ALenum param
, ALint
*value
)
703 context
= GetContextRef();
706 device
= context
->Device
;
707 LockBuffersRead(device
);
708 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
709 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
712 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
716 *value
= albuf
->Frequency
;
720 *value
= BytesFromFmt(albuf
->FmtType
) * 8;
724 *value
= ChannelsFromFmt(albuf
->FmtChannels
);
728 ReadLock(&albuf
->lock
);
729 *value
= albuf
->SampleLen
* FrameSizeFromFmt(albuf
->FmtChannels
,
731 ReadUnlock(&albuf
->lock
);
734 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
735 *value
= ATOMIC_LOAD_SEQ(&albuf
->UnpackAlign
);
738 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
739 *value
= ATOMIC_LOAD_SEQ(&albuf
->PackAlign
);
743 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
747 UnlockBuffersRead(device
);
748 ALCcontext_DecRef(context
);
752 AL_API
void AL_APIENTRY
alGetBuffer3i(ALuint buffer
, ALenum param
, ALint
*value1
, ALint
*value2
, ALint
*value3
)
757 context
= GetContextRef();
760 device
= context
->Device
;
761 LockBuffersRead(device
);
762 if(LookupBuffer(device
, buffer
) == NULL
)
763 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
765 if(!(value1
&& value2
&& value3
))
766 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
770 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
774 UnlockBuffersRead(device
);
775 ALCcontext_DecRef(context
);
779 AL_API
void AL_APIENTRY
alGetBufferiv(ALuint buffer
, ALenum param
, ALint
*values
)
791 case AL_INTERNAL_FORMAT_SOFT
:
792 case AL_BYTE_LENGTH_SOFT
:
793 case AL_SAMPLE_LENGTH_SOFT
:
794 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT
:
795 case AL_PACK_BLOCK_ALIGNMENT_SOFT
:
796 alGetBufferi(buffer
, param
, values
);
800 context
= GetContextRef();
803 device
= context
->Device
;
804 LockBuffersRead(device
);
805 if((albuf
=LookupBuffer(device
, buffer
)) == NULL
)
806 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
809 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
812 case AL_LOOP_POINTS_SOFT
:
813 ReadLock(&albuf
->lock
);
814 values
[0] = albuf
->LoopStart
;
815 values
[1] = albuf
->LoopEnd
;
816 ReadUnlock(&albuf
->lock
);
820 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
824 UnlockBuffersRead(device
);
825 ALCcontext_DecRef(context
);
832 * Loads the specified data into the buffer, using the specified formats.
833 * Currently, the new format must have the same channel configuration as the
836 static ALenum
LoadData(ALbuffer
*ALBuf
, ALuint freq
, ALsizei frames
, enum UserFmtChannels SrcChannels
, enum UserFmtType SrcType
, const ALvoid
*data
, ALsizei align
, ALbitfieldSOFT access
)
838 enum FmtChannels DstChannels
= FmtMono
;
839 enum FmtType DstType
= FmtUByte
;
840 ALsizei NumChannels
, FrameSize
;
843 /* Currently no channels need to be converted. */
846 case UserFmtMono
: DstChannels
= FmtMono
; break;
847 case UserFmtStereo
: DstChannels
= FmtStereo
; break;
848 case UserFmtRear
: DstChannels
= FmtRear
; break;
849 case UserFmtQuad
: DstChannels
= FmtQuad
; break;
850 case UserFmtX51
: DstChannels
= FmtX51
; break;
851 case UserFmtX61
: DstChannels
= FmtX61
; break;
852 case UserFmtX71
: DstChannels
= FmtX71
; break;
853 case UserFmtBFormat2D
: DstChannels
= FmtBFormat2D
; break;
854 case UserFmtBFormat3D
: DstChannels
= FmtBFormat3D
; break;
856 if((long)SrcChannels
!= (long)DstChannels
)
857 return AL_INVALID_ENUM
;
859 /* IMA4 and MSADPCM convert to 16-bit short. */
862 case UserFmtUByte
: DstType
= FmtUByte
; break;
863 case UserFmtShort
: DstType
= FmtShort
; break;
864 case UserFmtFloat
: DstType
= FmtFloat
; break;
865 case UserFmtDouble
: DstType
= FmtDouble
; break;
866 case UserFmtAlaw
: DstType
= FmtAlaw
; break;
867 case UserFmtMulaw
: DstType
= FmtMulaw
; break;
868 case UserFmtIMA4
: DstType
= FmtShort
; break;
869 case UserFmtMSADPCM
: DstType
= FmtShort
; break;
874 if((long)SrcType
!= (long)DstType
)
875 return AL_INVALID_VALUE
;
878 NumChannels
= ChannelsFromFmt(DstChannels
);
879 FrameSize
= NumChannels
* BytesFromFmt(DstType
);
881 if(frames
> INT_MAX
/FrameSize
)
882 return AL_OUT_OF_MEMORY
;
883 newsize
= frames
*FrameSize
;
885 WriteLock(&ALBuf
->lock
);
886 if(ReadRef(&ALBuf
->ref
) != 0 || ALBuf
->MappedAccess
!= 0)
888 WriteUnlock(&ALBuf
->lock
);
889 return AL_INVALID_OPERATION
;
892 if((access
&AL_PRESERVE_DATA_BIT_SOFT
))
894 /* Can only preserve data with the same format and alignment. */
895 if(ALBuf
->FmtChannels
!= DstChannels
|| ALBuf
->OriginalType
!= SrcType
||
896 ALBuf
->OriginalAlign
!= align
)
898 WriteUnlock(&ALBuf
->lock
);
899 return AL_INVALID_VALUE
;
903 /* Round up to the next 16-byte multiple. This could reallocate only when
904 * increasing or the new size is less than half the current, but then the
905 * buffer's AL_SIZE would not be very reliable for accounting buffer memory
906 * usage, and reporting the real size could cause problems for apps that
907 * use AL_SIZE to try to get the buffer's play length.
909 if(newsize
<= INT_MAX
-15)
910 newsize
= (newsize
+15) & ~0xf;
911 if(newsize
!= ALBuf
->BytesAlloc
)
913 void *temp
= al_malloc(16, (size_t)newsize
);
916 WriteUnlock(&ALBuf
->lock
);
917 return AL_OUT_OF_MEMORY
;
919 if((access
&AL_PRESERVE_DATA_BIT_SOFT
))
921 ALsizei tocopy
= mini(newsize
, ALBuf
->BytesAlloc
);
922 if(tocopy
> 0) memcpy(temp
, ALBuf
->data
, tocopy
);
924 al_free(ALBuf
->data
);
926 ALBuf
->BytesAlloc
= newsize
;
929 ALBuf
->OriginalType
= SrcType
;
930 if(SrcType
== UserFmtIMA4
)
932 ALsizei byte_align
= ((align
-1)/2 + 4) * NumChannels
;
933 ALBuf
->OriginalSize
= frames
/ align
* byte_align
;
934 ALBuf
->OriginalAlign
= align
;
935 assert(DstType
== FmtShort
);
936 if(data
!= NULL
&& ALBuf
->data
!= NULL
)
937 Convert_ALshort_ALima4(ALBuf
->data
, data
, NumChannels
, frames
, align
);
939 else if(SrcType
== UserFmtMSADPCM
)
941 ALsizei byte_align
= ((align
-2)/2 + 7) * NumChannels
;
942 ALBuf
->OriginalSize
= frames
/ align
* byte_align
;
943 ALBuf
->OriginalAlign
= align
;
944 assert(DstType
== FmtShort
);
945 if(data
!= NULL
&& ALBuf
->data
!= NULL
)
946 Convert_ALshort_ALmsadpcm(ALBuf
->data
, data
, NumChannels
, frames
, align
);
950 ALBuf
->OriginalSize
= frames
* FrameSize
;
951 ALBuf
->OriginalAlign
= 1;
952 assert((long)SrcType
== (long)DstType
);
953 if(data
!= NULL
&& ALBuf
->data
!= NULL
)
954 memcpy(ALBuf
->data
, data
, frames
*FrameSize
);
957 ALBuf
->Frequency
= freq
;
958 ALBuf
->FmtChannels
= DstChannels
;
959 ALBuf
->FmtType
= DstType
;
960 ALBuf
->Access
= access
;
962 ALBuf
->SampleLen
= frames
;
963 ALBuf
->LoopStart
= 0;
964 ALBuf
->LoopEnd
= ALBuf
->SampleLen
;
966 WriteUnlock(&ALBuf
->lock
);
971 ALsizei
BytesFromUserFmt(enum UserFmtType type
)
975 case UserFmtUByte
: return sizeof(ALubyte
);
976 case UserFmtShort
: return sizeof(ALshort
);
977 case UserFmtFloat
: return sizeof(ALfloat
);
978 case UserFmtDouble
: return sizeof(ALdouble
);
979 case UserFmtMulaw
: return sizeof(ALubyte
);
980 case UserFmtAlaw
: return sizeof(ALubyte
);
981 case UserFmtIMA4
: break; /* not handled here */
982 case UserFmtMSADPCM
: break; /* not handled here */
986 ALsizei
ChannelsFromUserFmt(enum UserFmtChannels chans
)
990 case UserFmtMono
: return 1;
991 case UserFmtStereo
: return 2;
992 case UserFmtRear
: return 2;
993 case UserFmtQuad
: return 4;
994 case UserFmtX51
: return 6;
995 case UserFmtX61
: return 7;
996 case UserFmtX71
: return 8;
997 case UserFmtBFormat2D
: return 3;
998 case UserFmtBFormat3D
: return 4;
1002 static ALboolean
DecomposeUserFormat(ALenum format
, enum UserFmtChannels
*chans
,
1003 enum UserFmtType
*type
)
1005 static const struct {
1007 enum UserFmtChannels channels
;
1008 enum UserFmtType type
;
1010 { AL_FORMAT_MONO8
, UserFmtMono
, UserFmtUByte
},
1011 { AL_FORMAT_MONO16
, UserFmtMono
, UserFmtShort
},
1012 { AL_FORMAT_MONO_FLOAT32
, UserFmtMono
, UserFmtFloat
},
1013 { AL_FORMAT_MONO_DOUBLE_EXT
, UserFmtMono
, UserFmtDouble
},
1014 { AL_FORMAT_MONO_IMA4
, UserFmtMono
, UserFmtIMA4
},
1015 { AL_FORMAT_MONO_MSADPCM_SOFT
, UserFmtMono
, UserFmtMSADPCM
},
1016 { AL_FORMAT_MONO_MULAW
, UserFmtMono
, UserFmtMulaw
},
1017 { AL_FORMAT_MONO_ALAW_EXT
, UserFmtMono
, UserFmtAlaw
},
1019 { AL_FORMAT_STEREO8
, UserFmtStereo
, UserFmtUByte
},
1020 { AL_FORMAT_STEREO16
, UserFmtStereo
, UserFmtShort
},
1021 { AL_FORMAT_STEREO_FLOAT32
, UserFmtStereo
, UserFmtFloat
},
1022 { AL_FORMAT_STEREO_DOUBLE_EXT
, UserFmtStereo
, UserFmtDouble
},
1023 { AL_FORMAT_STEREO_IMA4
, UserFmtStereo
, UserFmtIMA4
},
1024 { AL_FORMAT_STEREO_MSADPCM_SOFT
, UserFmtStereo
, UserFmtMSADPCM
},
1025 { AL_FORMAT_STEREO_MULAW
, UserFmtStereo
, UserFmtMulaw
},
1026 { AL_FORMAT_STEREO_ALAW_EXT
, UserFmtStereo
, UserFmtAlaw
},
1028 { AL_FORMAT_REAR8
, UserFmtRear
, UserFmtUByte
},
1029 { AL_FORMAT_REAR16
, UserFmtRear
, UserFmtShort
},
1030 { AL_FORMAT_REAR32
, UserFmtRear
, UserFmtFloat
},
1031 { AL_FORMAT_REAR_MULAW
, UserFmtRear
, UserFmtMulaw
},
1033 { AL_FORMAT_QUAD8_LOKI
, UserFmtQuad
, UserFmtUByte
},
1034 { AL_FORMAT_QUAD16_LOKI
, UserFmtQuad
, UserFmtShort
},
1036 { AL_FORMAT_QUAD8
, UserFmtQuad
, UserFmtUByte
},
1037 { AL_FORMAT_QUAD16
, UserFmtQuad
, UserFmtShort
},
1038 { AL_FORMAT_QUAD32
, UserFmtQuad
, UserFmtFloat
},
1039 { AL_FORMAT_QUAD_MULAW
, UserFmtQuad
, UserFmtMulaw
},
1041 { AL_FORMAT_51CHN8
, UserFmtX51
, UserFmtUByte
},
1042 { AL_FORMAT_51CHN16
, UserFmtX51
, UserFmtShort
},
1043 { AL_FORMAT_51CHN32
, UserFmtX51
, UserFmtFloat
},
1044 { AL_FORMAT_51CHN_MULAW
, UserFmtX51
, UserFmtMulaw
},
1046 { AL_FORMAT_61CHN8
, UserFmtX61
, UserFmtUByte
},
1047 { AL_FORMAT_61CHN16
, UserFmtX61
, UserFmtShort
},
1048 { AL_FORMAT_61CHN32
, UserFmtX61
, UserFmtFloat
},
1049 { AL_FORMAT_61CHN_MULAW
, UserFmtX61
, UserFmtMulaw
},
1051 { AL_FORMAT_71CHN8
, UserFmtX71
, UserFmtUByte
},
1052 { AL_FORMAT_71CHN16
, UserFmtX71
, UserFmtShort
},
1053 { AL_FORMAT_71CHN32
, UserFmtX71
, UserFmtFloat
},
1054 { AL_FORMAT_71CHN_MULAW
, UserFmtX71
, UserFmtMulaw
},
1056 { AL_FORMAT_BFORMAT2D_8
, UserFmtBFormat2D
, UserFmtUByte
},
1057 { AL_FORMAT_BFORMAT2D_16
, UserFmtBFormat2D
, UserFmtShort
},
1058 { AL_FORMAT_BFORMAT2D_FLOAT32
, UserFmtBFormat2D
, UserFmtFloat
},
1059 { AL_FORMAT_BFORMAT2D_MULAW
, UserFmtBFormat2D
, UserFmtMulaw
},
1061 { AL_FORMAT_BFORMAT3D_8
, UserFmtBFormat3D
, UserFmtUByte
},
1062 { AL_FORMAT_BFORMAT3D_16
, UserFmtBFormat3D
, UserFmtShort
},
1063 { AL_FORMAT_BFORMAT3D_FLOAT32
, UserFmtBFormat3D
, UserFmtFloat
},
1064 { AL_FORMAT_BFORMAT3D_MULAW
, UserFmtBFormat3D
, UserFmtMulaw
},
1068 for(i
= 0;i
< COUNTOF(list
);i
++)
1070 if(list
[i
].format
== format
)
1072 *chans
= list
[i
].channels
;
1073 *type
= list
[i
].type
;
1081 ALsizei
BytesFromFmt(enum FmtType type
)
1085 case FmtUByte
: return sizeof(ALubyte
);
1086 case FmtShort
: return sizeof(ALshort
);
1087 case FmtFloat
: return sizeof(ALfloat
);
1088 case FmtDouble
: return sizeof(ALdouble
);
1089 case FmtMulaw
: return sizeof(ALubyte
);
1090 case FmtAlaw
: return sizeof(ALubyte
);
1094 ALsizei
ChannelsFromFmt(enum FmtChannels chans
)
1098 case FmtMono
: return 1;
1099 case FmtStereo
: return 2;
1100 case FmtRear
: return 2;
1101 case FmtQuad
: return 4;
1102 case FmtX51
: return 6;
1103 case FmtX61
: return 7;
1104 case FmtX71
: return 8;
1105 case FmtBFormat2D
: return 3;
1106 case FmtBFormat3D
: return 4;
1111 static ALsizei
SanitizeAlignment(enum UserFmtType type
, ALsizei align
)
1118 if(type
== UserFmtIMA4
)
1120 /* Here is where things vary:
1121 * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
1122 * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
1126 if(type
== UserFmtMSADPCM
)
1131 if(type
== UserFmtIMA4
)
1133 /* IMA4 block alignment must be a multiple of 8, plus 1. */
1134 if((align
&7) == 1) return align
;
1137 if(type
== UserFmtMSADPCM
)
1139 /* MSADPCM block alignment must be a multiple of 2. */
1140 if((align
&1) == 0) return align
;
1148 ALbuffer
*NewBuffer(ALCcontext
*context
)
1150 ALCdevice
*device
= context
->Device
;
1154 buffer
= al_calloc(16, sizeof(ALbuffer
));
1156 SET_ERROR_AND_RETURN_VALUE(context
, AL_OUT_OF_MEMORY
, NULL
);
1157 RWLockInit(&buffer
->lock
);
1159 buffer
->MappedAccess
= 0;
1161 err
= NewThunkEntry(&buffer
->id
);
1162 if(err
== AL_NO_ERROR
)
1163 err
= InsertUIntMapEntry(&device
->BufferMap
, buffer
->id
, buffer
);
1164 if(err
!= AL_NO_ERROR
)
1166 FreeThunkEntry(buffer
->id
);
1167 memset(buffer
, 0, sizeof(ALbuffer
));
1170 SET_ERROR_AND_RETURN_VALUE(context
, err
, NULL
);
1176 void DeleteBuffer(ALCdevice
*device
, ALbuffer
*buffer
)
1178 RemoveBuffer(device
, buffer
->id
);
1179 FreeThunkEntry(buffer
->id
);
1181 al_free(buffer
->data
);
1183 memset(buffer
, 0, sizeof(*buffer
));
1189 * ReleaseALBuffers()
1191 * INTERNAL: Called to destroy any buffers that still exist on the device
1193 ALvoid
ReleaseALBuffers(ALCdevice
*device
)
1196 for(i
= 0;i
< device
->BufferMap
.size
;i
++)
1198 ALbuffer
*temp
= device
->BufferMap
.values
[i
];
1199 device
->BufferMap
.values
[i
] = NULL
;
1201 al_free(temp
->data
);
1203 FreeThunkEntry(temp
->id
);
1204 memset(temp
, 0, sizeof(ALbuffer
));