Slightly simplify alBufferSubDataSOFT
[openal-soft.git] / OpenAL32 / alBuffer.c
blob9e4249ec3fbb9447323446295e139e0e7b7b542f
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
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
21 #include "config.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <assert.h>
26 #include <limits.h>
27 #ifdef HAVE_MALLOC_H
28 #include <malloc.h>
29 #endif
31 #include "alMain.h"
32 #include "alu.h"
33 #include "alError.h"
34 #include "alBuffer.h"
35 #include "alThunk.h"
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)
61 ALCcontext *context;
62 ALsizei cur = 0;
64 context = GetContextRef();
65 if(!context) return;
67 if(!(n >= 0))
68 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
70 for(cur = 0;cur < n;cur++)
72 ALbuffer *buffer = NewBuffer(context);
73 if(!buffer)
75 alDeleteBuffers(cur, buffers);
76 break;
79 buffers[cur] = buffer->id;
82 done:
83 ALCcontext_DecRef(context);
86 AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers)
88 ALCdevice *device;
89 ALCcontext *context;
90 ALbuffer *ALBuf;
91 ALsizei i;
93 context = GetContextRef();
94 if(!context) return;
96 device = context->Device;
98 LockBuffersWrite(device);
99 if(!(n >= 0))
100 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
102 for(i = 0;i < n;i++)
104 if(!buffers[i])
105 continue;
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);
114 for(i = 0;i < n;i++)
116 if((ALBuf=LookupBuffer(device, buffers[i])) != NULL)
117 DeleteBuffer(device, ALBuf);
120 done:
121 UnlockBuffersWrite(device);
122 ALCcontext_DecRef(context);
125 AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer)
127 ALCcontext *context;
128 ALboolean ret;
130 context = GetContextRef();
131 if(!context) return AL_FALSE;
133 LockBuffersRead(context->Device);
134 ret = ((!buffer || LookupBuffer(context->Device, buffer)) ?
135 AL_TRUE : AL_FALSE);
136 UnlockBuffersRead(context->Device);
138 ALCcontext_DecRef(context);
140 return ret;
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;
148 ALCdevice *device;
149 ALCcontext *context;
150 ALbuffer *albuf;
151 ALsizei framesize;
152 ALsizei align;
153 ALenum err;
155 context = GetContextRef();
156 if(!context) return;
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);
170 switch(srctype)
172 case UserFmtUByte:
173 case UserFmtShort:
174 case UserFmtFloat:
175 case UserFmtDouble:
176 case UserFmtMulaw:
177 case UserFmtAlaw:
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);
186 break;
188 case UserFmtIMA4:
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);
197 break;
199 case UserFmtMSADPCM:
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);
208 break;
211 done:
212 UnlockBuffersRead(device);
213 ALCcontext_DecRef(context);
216 AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access)
218 void *retval = NULL;
219 ALCdevice *device;
220 ALCcontext *context;
221 ALbuffer *albuf;
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);
248 unlock_done:
249 WriteUnlock(&albuf->lock);
251 done:
252 UnlockBuffersRead(device);
253 ALCcontext_DecRef(context);
255 return retval;
258 AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer)
260 ALCdevice *device;
261 ALCcontext *context;
262 ALbuffer *albuf;
264 context = GetContextRef();
265 if(!context) return;
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);
275 else
276 albuf->MappedAccess = 0;
277 WriteUnlock(&albuf->lock);
279 done:
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;
288 ALCdevice *device;
289 ALCcontext *context;
290 ALbuffer *albuf;
291 ALsizei byte_align;
292 ALsizei frame_size;
293 ALsizei num_chans;
294 ALsizei align;
295 void *dst;
297 context = GetContextRef();
298 if(!context) return;
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;
325 else
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);
341 else
343 assert((long)srctype == (long)albuf->FmtType);
344 memcpy(dst, data, length*frame_size);
347 unlock_done:
348 WriteUnlock(&albuf->lock);
350 done:
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))
360 ALCcontext *context;
362 context = GetContextRef();
363 if(!context) return;
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))
374 ALCcontext *context;
376 context = GetContextRef();
377 if(!context) return;
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))
388 ALCcontext *context;
390 context = GetContextRef();
391 if(!context) return;
393 alSetError(context, AL_INVALID_OPERATION);
395 ALCcontext_DecRef(context);
398 AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum UNUSED(format))
400 ALCcontext *context;
402 context = GetContextRef();
403 if(!context) return AL_FALSE;
405 alSetError(context, AL_INVALID_OPERATION);
407 ALCcontext_DecRef(context);
408 return AL_FALSE;
412 AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(value))
414 ALCdevice *device;
415 ALCcontext *context;
417 context = GetContextRef();
418 if(!context) return;
420 device = context->Device;
421 LockBuffersRead(device);
422 if(LookupBuffer(device, buffer) == NULL)
423 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
425 switch(param)
427 default:
428 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
431 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))
439 ALCdevice *device;
440 ALCcontext *context;
442 context = GetContextRef();
443 if(!context) return;
445 device = context->Device;
446 LockBuffersRead(device);
447 if(LookupBuffer(device, buffer) == NULL)
448 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
450 switch(param)
452 default:
453 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
456 done:
457 UnlockBuffersRead(device);
458 ALCcontext_DecRef(context);
462 AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values)
464 ALCdevice *device;
465 ALCcontext *context;
467 context = GetContextRef();
468 if(!context) return;
470 device = context->Device;
471 LockBuffersRead(device);
472 if(LookupBuffer(device, buffer) == NULL)
473 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
475 if(!(values))
476 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
477 switch(param)
479 default:
480 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
483 done:
484 UnlockBuffersRead(device);
485 ALCcontext_DecRef(context);
489 AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value)
491 ALCdevice *device;
492 ALCcontext *context;
493 ALbuffer *albuf;
495 context = GetContextRef();
496 if(!context) return;
498 device = context->Device;
499 LockBuffersRead(device);
500 if((albuf=LookupBuffer(device, buffer)) == NULL)
501 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
503 switch(param)
505 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
506 if(!(value >= 0))
507 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
508 ATOMIC_STORE_SEQ(&albuf->UnpackAlign, value);
509 break;
511 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
512 if(!(value >= 0))
513 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
514 ATOMIC_STORE_SEQ(&albuf->PackAlign, value);
515 break;
517 default:
518 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
521 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))
529 ALCdevice *device;
530 ALCcontext *context;
532 context = GetContextRef();
533 if(!context) return;
535 device = context->Device;
536 if(LookupBuffer(device, buffer) == NULL)
537 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
539 switch(param)
541 default:
542 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
545 done:
546 ALCcontext_DecRef(context);
550 AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values)
552 ALCdevice *device;
553 ALCcontext *context;
554 ALbuffer *albuf;
556 if(values)
558 switch(param)
560 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
561 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
562 alBufferi(buffer, param, values[0]);
563 return;
567 context = GetContextRef();
568 if(!context) return;
570 device = context->Device;
571 LockBuffersRead(device);
572 if((albuf=LookupBuffer(device, buffer)) == NULL)
573 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
575 if(!(values))
576 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
577 switch(param)
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);
596 break;
598 default:
599 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
602 done:
603 UnlockBuffersRead(device);
604 ALCcontext_DecRef(context);
608 AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value)
610 ALCdevice *device;
611 ALCcontext *context;
612 ALbuffer *albuf;
614 context = GetContextRef();
615 if(!context) return;
617 device = context->Device;
618 LockBuffersRead(device);
619 if((albuf=LookupBuffer(device, buffer)) == NULL)
620 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
622 if(!(value))
623 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
624 switch(param)
626 default:
627 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
630 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)
638 ALCdevice *device;
639 ALCcontext *context;
641 context = GetContextRef();
642 if(!context) return;
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);
651 switch(param)
653 default:
654 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
657 done:
658 UnlockBuffersRead(device);
659 ALCcontext_DecRef(context);
663 AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values)
665 ALCdevice *device;
666 ALCcontext *context;
668 switch(param)
670 case AL_SEC_LENGTH_SOFT:
671 alGetBufferf(buffer, param, values);
672 return;
675 context = GetContextRef();
676 if(!context) return;
678 device = context->Device;
679 LockBuffersRead(device);
680 if(LookupBuffer(device, buffer) == NULL)
681 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
683 if(!(values))
684 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
685 switch(param)
687 default:
688 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
691 done:
692 UnlockBuffersRead(device);
693 ALCcontext_DecRef(context);
697 AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value)
699 ALCdevice *device;
700 ALCcontext *context;
701 ALbuffer *albuf;
703 context = GetContextRef();
704 if(!context) return;
706 device = context->Device;
707 LockBuffersRead(device);
708 if((albuf=LookupBuffer(device, buffer)) == NULL)
709 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
711 if(!(value))
712 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
713 switch(param)
715 case AL_FREQUENCY:
716 *value = albuf->Frequency;
717 break;
719 case AL_BITS:
720 *value = BytesFromFmt(albuf->FmtType) * 8;
721 break;
723 case AL_CHANNELS:
724 *value = ChannelsFromFmt(albuf->FmtChannels);
725 break;
727 case AL_SIZE:
728 ReadLock(&albuf->lock);
729 *value = albuf->SampleLen * FrameSizeFromFmt(albuf->FmtChannels,
730 albuf->FmtType);
731 ReadUnlock(&albuf->lock);
732 break;
734 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
735 *value = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign);
736 break;
738 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
739 *value = ATOMIC_LOAD_SEQ(&albuf->PackAlign);
740 break;
742 default:
743 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
746 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)
754 ALCdevice *device;
755 ALCcontext *context;
757 context = GetContextRef();
758 if(!context) return;
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);
767 switch(param)
769 default:
770 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
773 done:
774 UnlockBuffersRead(device);
775 ALCcontext_DecRef(context);
779 AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values)
781 ALCdevice *device;
782 ALCcontext *context;
783 ALbuffer *albuf;
785 switch(param)
787 case AL_FREQUENCY:
788 case AL_BITS:
789 case AL_CHANNELS:
790 case AL_SIZE:
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);
797 return;
800 context = GetContextRef();
801 if(!context) return;
803 device = context->Device;
804 LockBuffersRead(device);
805 if((albuf=LookupBuffer(device, buffer)) == NULL)
806 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
808 if(!(values))
809 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
810 switch(param)
812 case AL_LOOP_POINTS_SOFT:
813 ReadLock(&albuf->lock);
814 values[0] = albuf->LoopStart;
815 values[1] = albuf->LoopEnd;
816 ReadUnlock(&albuf->lock);
817 break;
819 default:
820 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
823 done:
824 UnlockBuffersRead(device);
825 ALCcontext_DecRef(context);
830 * LoadData
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
834 * original format.
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;
841 ALsizei newsize;
843 /* Currently no channels need to be converted. */
844 switch(SrcChannels)
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. */
860 switch(SrcType)
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;
872 if(access != 0)
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);
914 if(!temp && 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);
925 ALBuf->data = temp;
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);
948 else
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);
967 return AL_NO_ERROR;
971 ALsizei BytesFromUserFmt(enum UserFmtType type)
973 switch(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 */
984 return 0;
986 ALsizei ChannelsFromUserFmt(enum UserFmtChannels chans)
988 switch(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;
1000 return 0;
1002 static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
1003 enum UserFmtType *type)
1005 static const struct {
1006 ALenum format;
1007 enum UserFmtChannels channels;
1008 enum UserFmtType type;
1009 } list[] = {
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 },
1066 ALuint i;
1068 for(i = 0;i < COUNTOF(list);i++)
1070 if(list[i].format == format)
1072 *chans = list[i].channels;
1073 *type = list[i].type;
1074 return AL_TRUE;
1078 return AL_FALSE;
1081 ALsizei BytesFromFmt(enum FmtType type)
1083 switch(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);
1092 return 0;
1094 ALsizei ChannelsFromFmt(enum FmtChannels chans)
1096 switch(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;
1108 return 0;
1111 static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align)
1113 if(align < 0)
1114 return 0;
1116 if(align == 0)
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
1124 return 65;
1126 if(type == UserFmtMSADPCM)
1127 return 64;
1128 return 1;
1131 if(type == UserFmtIMA4)
1133 /* IMA4 block alignment must be a multiple of 8, plus 1. */
1134 if((align&7) == 1) return align;
1135 return 0;
1137 if(type == UserFmtMSADPCM)
1139 /* MSADPCM block alignment must be a multiple of 2. */
1140 if((align&1) == 0) return align;
1141 return 0;
1144 return align;
1148 ALbuffer *NewBuffer(ALCcontext *context)
1150 ALCdevice *device = context->Device;
1151 ALbuffer *buffer;
1152 ALenum err;
1154 buffer = al_calloc(16, sizeof(ALbuffer));
1155 if(!buffer)
1156 SET_ERROR_AND_RETURN_VALUE(context, AL_OUT_OF_MEMORY, NULL);
1157 RWLockInit(&buffer->lock);
1158 buffer->Access = 0;
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));
1168 al_free(buffer);
1170 SET_ERROR_AND_RETURN_VALUE(context, err, NULL);
1173 return buffer;
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));
1184 al_free(buffer);
1189 * ReleaseALBuffers()
1191 * INTERNAL: Called to destroy any buffers that still exist on the device
1193 ALvoid ReleaseALBuffers(ALCdevice *device)
1195 ALsizei i;
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));
1205 al_free(temp);