PATH_MAX not MAX_PATH
[openal-soft.git] / OpenAL32 / alBuffer.c
blobed71243483ab4ea296e5a4d038b77c719e65e38e
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 "sample_cvt.h"
38 extern inline void LockBufferList(ALCdevice *device);
39 extern inline void UnlockBufferList(ALCdevice *device);
40 extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type);
41 extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type);
43 static ALbuffer *AllocBuffer(ALCcontext *context);
44 static void FreeBuffer(ALCdevice *device, ALbuffer *buffer);
45 static const ALchar *NameFromUserFmtType(enum UserFmtType type);
46 static void LoadData(ALCcontext *context, ALbuffer *buffer, ALuint freq, ALsizei size,
47 enum UserFmtChannels SrcChannels, enum UserFmtType SrcType,
48 const ALvoid *data, ALbitfieldSOFT access);
49 static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type);
50 static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align);
52 static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id)
54 BufferSubList *sublist;
55 ALuint lidx = (id-1) >> 6;
56 ALsizei slidx = (id-1) & 0x3f;
58 if(UNLIKELY(lidx >= VECTOR_SIZE(device->BufferList)))
59 return NULL;
60 sublist = &VECTOR_ELEM(device->BufferList, lidx);
61 if(UNLIKELY(sublist->FreeMask & (U64(1)<<slidx)))
62 return NULL;
63 return sublist->Buffers + slidx;
67 #define INVALID_STORAGE_MASK ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT)
68 #define MAP_READ_WRITE_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT)
69 #define INVALID_MAP_FLAGS ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT)
72 AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers)
74 ALCcontext *context;
75 ALsizei cur = 0;
77 context = GetContextRef();
78 if(!context) return;
80 if(!(n >= 0))
81 alSetError(context, AL_INVALID_VALUE, "Generating %d buffers", n);
82 else for(cur = 0;cur < n;cur++)
84 ALbuffer *buffer = AllocBuffer(context);
85 if(!buffer)
87 alDeleteBuffers(cur, buffers);
88 break;
91 buffers[cur] = buffer->id;
94 ALCcontext_DecRef(context);
97 AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers)
99 ALCdevice *device;
100 ALCcontext *context;
101 ALbuffer *ALBuf;
102 ALsizei i;
104 context = GetContextRef();
105 if(!context) return;
107 device = context->Device;
109 LockBufferList(device);
110 if(UNLIKELY(n < 0))
112 alSetError(context, AL_INVALID_VALUE, "Deleting %d buffers", n);
113 goto done;
116 for(i = 0;i < n;i++)
118 if(!buffers[i])
119 continue;
121 /* Check for valid Buffer ID, and make sure it's not in use. */
122 if((ALBuf=LookupBuffer(device, buffers[i])) == NULL)
124 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffers[i]);
125 goto done;
127 if(ReadRef(&ALBuf->ref) != 0)
129 alSetError(context, AL_INVALID_OPERATION, "Deleting in-use buffer %u", buffers[i]);
130 goto done;
133 for(i = 0;i < n;i++)
135 if((ALBuf=LookupBuffer(device, buffers[i])) != NULL)
136 FreeBuffer(device, ALBuf);
139 done:
140 UnlockBufferList(device);
141 ALCcontext_DecRef(context);
144 AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer)
146 ALCcontext *context;
147 ALboolean ret;
149 context = GetContextRef();
150 if(!context) return AL_FALSE;
152 LockBufferList(context->Device);
153 ret = ((!buffer || LookupBuffer(context->Device, buffer)) ?
154 AL_TRUE : AL_FALSE);
155 UnlockBufferList(context->Device);
157 ALCcontext_DecRef(context);
159 return ret;
163 AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq)
164 { alBufferStorageSOFT(buffer, format, data, size, freq, 0); }
166 AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags)
168 enum UserFmtChannels srcchannels = UserFmtMono;
169 enum UserFmtType srctype = UserFmtUByte;
170 ALCdevice *device;
171 ALCcontext *context;
172 ALbuffer *albuf;
174 context = GetContextRef();
175 if(!context) return;
177 device = context->Device;
178 LockBufferList(device);
179 if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
180 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
181 else if(UNLIKELY(size < 0))
182 alSetError(context, AL_INVALID_VALUE, "Negative storage size %d", size);
183 else if(UNLIKELY(freq < 1))
184 alSetError(context, AL_INVALID_VALUE, "Invalid sample rate %d", freq);
185 else if(UNLIKELY((flags&INVALID_STORAGE_MASK) != 0))
186 alSetError(context, AL_INVALID_VALUE, "Invalid storage flags 0x%x",
187 flags&INVALID_STORAGE_MASK);
188 else if(UNLIKELY((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS)))
189 alSetError(context, AL_INVALID_VALUE,
190 "Declaring persistently mapped storage without read or write access");
191 else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE))
192 alSetError(context, AL_INVALID_ENUM, "Invalid format 0x%04x", format);
193 else
194 LoadData(context, albuf, freq, size, srcchannels, srctype, data, flags);
196 UnlockBufferList(device);
197 ALCcontext_DecRef(context);
200 AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access)
202 void *retval = NULL;
203 ALCdevice *device;
204 ALCcontext *context;
205 ALbuffer *albuf;
207 context = GetContextRef();
208 if(!context) return retval;
210 device = context->Device;
211 LockBufferList(device);
212 if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
213 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
214 else if(UNLIKELY((access&INVALID_MAP_FLAGS) != 0))
215 alSetError(context, AL_INVALID_VALUE, "Invalid map flags 0x%x", access&INVALID_MAP_FLAGS);
216 else if(UNLIKELY(!(access&MAP_READ_WRITE_FLAGS)))
217 alSetError(context, AL_INVALID_VALUE, "Mapping buffer %u without read or write access",
218 buffer);
219 else
221 ALbitfieldSOFT unavailable = (albuf->Access^access) & access;
222 if(UNLIKELY(ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT)))
223 alSetError(context, AL_INVALID_OPERATION,
224 "Mapping in-use buffer %u without persistent mapping", buffer);
225 else if(UNLIKELY(albuf->MappedAccess != 0))
226 alSetError(context, AL_INVALID_OPERATION, "Mapping already-mapped buffer %u", buffer);
227 else if(UNLIKELY((unavailable&AL_MAP_READ_BIT_SOFT)))
228 alSetError(context, AL_INVALID_VALUE,
229 "Mapping buffer %u for reading without read access", buffer);
230 else if(UNLIKELY((unavailable&AL_MAP_WRITE_BIT_SOFT)))
231 alSetError(context, AL_INVALID_VALUE,
232 "Mapping buffer %u for writing without write access", buffer);
233 else if(UNLIKELY((unavailable&AL_MAP_PERSISTENT_BIT_SOFT)))
234 alSetError(context, AL_INVALID_VALUE,
235 "Mapping buffer %u persistently without persistent access", buffer);
236 else if(UNLIKELY(offset < 0 || offset >= albuf->OriginalSize ||
237 length <= 0 || length > albuf->OriginalSize - offset))
238 alSetError(context, AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u",
239 offset, length, buffer);
240 else
242 retval = (ALbyte*)albuf->data + offset;
243 albuf->MappedAccess = access;
244 albuf->MappedOffset = offset;
245 albuf->MappedSize = length;
248 UnlockBufferList(device);
250 ALCcontext_DecRef(context);
251 return retval;
254 AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer)
256 ALCdevice *device;
257 ALCcontext *context;
258 ALbuffer *albuf;
260 context = GetContextRef();
261 if(!context) return;
263 device = context->Device;
264 LockBufferList(device);
265 if((albuf=LookupBuffer(device, buffer)) == NULL)
266 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
267 else if(albuf->MappedAccess == 0)
268 alSetError(context, AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer);
269 else
271 albuf->MappedAccess = 0;
272 albuf->MappedOffset = 0;
273 albuf->MappedSize = 0;
275 UnlockBufferList(device);
277 ALCcontext_DecRef(context);
280 AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length)
282 ALCdevice *device;
283 ALCcontext *context;
284 ALbuffer *albuf;
286 context = GetContextRef();
287 if(!context) return;
289 device = context->Device;
290 LockBufferList(device);
291 if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
292 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
293 else if(UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT)))
294 alSetError(context, AL_INVALID_OPERATION,
295 "Flushing buffer %u while not mapped for writing", buffer);
296 else if(UNLIKELY(offset < albuf->MappedOffset ||
297 offset >= albuf->MappedOffset+albuf->MappedSize ||
298 length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset))
299 alSetError(context, AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u",
300 offset, length, buffer);
301 else
303 /* FIXME: Need to use some method of double-buffering for the mixer and
304 * app to hold separate memory, which can be safely transfered
305 * asynchronously. Currently we just say the app shouldn't write where
306 * OpenAL's reading, and hope for the best...
308 ATOMIC_THREAD_FENCE(almemory_order_seq_cst);
310 UnlockBufferList(device);
312 ALCcontext_DecRef(context);
315 AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length)
317 enum UserFmtChannels srcchannels = UserFmtMono;
318 enum UserFmtType srctype = UserFmtUByte;
319 ALCdevice *device;
320 ALCcontext *context;
321 ALbuffer *albuf;
323 context = GetContextRef();
324 if(!context) return;
326 device = context->Device;
327 LockBufferList(device);
328 if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
329 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
330 else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE))
331 alSetError(context, AL_INVALID_ENUM, "Invalid format 0x%04x", format);
332 else
334 ALsizei unpack_align, align;
335 ALsizei byte_align;
336 ALsizei frame_size;
337 ALsizei num_chans;
338 void *dst;
340 unpack_align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign);
341 align = SanitizeAlignment(srctype, unpack_align);
342 if(UNLIKELY(align < 1))
343 alSetError(context, AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align);
344 else if(UNLIKELY((long)srcchannels != (long)albuf->FmtChannels ||
345 srctype != albuf->OriginalType))
346 alSetError(context, AL_INVALID_ENUM, "Unpacking data with mismatched format");
347 else if(UNLIKELY(align != albuf->OriginalAlign))
348 alSetError(context, AL_INVALID_VALUE,
349 "Unpacking data with alignment %u does not match original alignment %u",
350 align, albuf->OriginalAlign);
351 else if(UNLIKELY(albuf->MappedAccess != 0))
352 alSetError(context, AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u",
353 buffer);
354 else
356 num_chans = ChannelsFromFmt(albuf->FmtChannels);
357 frame_size = num_chans * BytesFromFmt(albuf->FmtType);
358 if(albuf->OriginalType == UserFmtIMA4)
359 byte_align = ((align-1)/2 + 4) * num_chans;
360 else if(albuf->OriginalType == UserFmtMSADPCM)
361 byte_align = ((align-2)/2 + 7) * num_chans;
362 else
363 byte_align = align * frame_size;
365 if(UNLIKELY(offset < 0 || length < 0 || offset > albuf->OriginalSize ||
366 length > albuf->OriginalSize-offset))
367 alSetError(context, AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u",
368 offset, length, buffer);
369 else if(UNLIKELY((offset%byte_align) != 0))
370 alSetError(context, AL_INVALID_VALUE,
371 "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)",
372 offset, byte_align, align);
373 else if(UNLIKELY((length%byte_align) != 0))
374 alSetError(context, AL_INVALID_VALUE,
375 "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)",
376 length, byte_align, align);
377 else
379 /* offset -> byte offset, length -> sample count */
380 offset = offset/byte_align * align * frame_size;
381 length = length/byte_align * align;
383 dst = (ALbyte*)albuf->data + offset;
384 if(srctype == UserFmtIMA4 && albuf->FmtType == FmtShort)
385 Convert_ALshort_ALima4(dst, data, num_chans, length, align);
386 else if(srctype == UserFmtMSADPCM && albuf->FmtType == FmtShort)
387 Convert_ALshort_ALmsadpcm(dst, data, num_chans, length, align);
388 else
390 assert((long)srctype == (long)albuf->FmtType);
391 memcpy(dst, data, length*frame_size);
396 UnlockBufferList(device);
398 ALCcontext_DecRef(context);
402 AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint UNUSED(buffer),
403 ALuint UNUSED(samplerate), ALenum UNUSED(internalformat), ALsizei UNUSED(samples),
404 ALenum UNUSED(channels), ALenum UNUSED(type), const ALvoid *UNUSED(data))
406 ALCcontext *context;
408 context = GetContextRef();
409 if(!context) return;
411 alSetError(context, AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported");
413 ALCcontext_DecRef(context);
416 AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint UNUSED(buffer),
417 ALsizei UNUSED(offset), ALsizei UNUSED(samples),
418 ALenum UNUSED(channels), ALenum UNUSED(type), const ALvoid *UNUSED(data))
420 ALCcontext *context;
422 context = GetContextRef();
423 if(!context) return;
425 alSetError(context, AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported");
427 ALCcontext_DecRef(context);
430 AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint UNUSED(buffer),
431 ALsizei UNUSED(offset), ALsizei UNUSED(samples),
432 ALenum UNUSED(channels), ALenum UNUSED(type), ALvoid *UNUSED(data))
434 ALCcontext *context;
436 context = GetContextRef();
437 if(!context) return;
439 alSetError(context, AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported");
441 ALCcontext_DecRef(context);
444 AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum UNUSED(format))
446 ALCcontext *context;
448 context = GetContextRef();
449 if(!context) return AL_FALSE;
451 alSetError(context, AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported");
453 ALCcontext_DecRef(context);
454 return AL_FALSE;
458 AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(value))
460 ALCdevice *device;
461 ALCcontext *context;
463 context = GetContextRef();
464 if(!context) return;
466 device = context->Device;
467 LockBufferList(device);
468 if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
469 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
470 else switch(param)
472 default:
473 alSetError(context, AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param);
475 UnlockBufferList(device);
477 ALCcontext_DecRef(context);
481 AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(value1), ALfloat UNUSED(value2), ALfloat UNUSED(value3))
483 ALCdevice *device;
484 ALCcontext *context;
486 context = GetContextRef();
487 if(!context) return;
489 device = context->Device;
490 LockBufferList(device);
491 if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
492 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
493 else switch(param)
495 default:
496 alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param);
498 UnlockBufferList(device);
500 ALCcontext_DecRef(context);
504 AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values)
506 ALCdevice *device;
507 ALCcontext *context;
509 context = GetContextRef();
510 if(!context) return;
512 device = context->Device;
513 LockBufferList(device);
514 if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
515 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
516 else if(UNLIKELY(!values))
517 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
518 else switch(param)
520 default:
521 alSetError(context, AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param);
523 UnlockBufferList(device);
525 ALCcontext_DecRef(context);
529 AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value)
531 ALCdevice *device;
532 ALCcontext *context;
533 ALbuffer *albuf;
535 context = GetContextRef();
536 if(!context) return;
538 device = context->Device;
539 LockBufferList(device);
540 if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
541 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
542 else switch(param)
544 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
545 if(UNLIKELY(value < 0))
546 alSetError(context, AL_INVALID_VALUE, "Invalid unpack block alignment %d", value);
547 else
548 ATOMIC_STORE_SEQ(&albuf->UnpackAlign, value);
549 break;
551 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
552 if(UNLIKELY(value < 0))
553 alSetError(context, AL_INVALID_VALUE, "Invalid pack block alignment %d", value);
554 else
555 ATOMIC_STORE_SEQ(&albuf->PackAlign, value);
556 break;
558 default:
559 alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param);
561 UnlockBufferList(device);
563 ALCcontext_DecRef(context);
567 AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(value1), ALint UNUSED(value2), ALint UNUSED(value3))
569 ALCdevice *device;
570 ALCcontext *context;
572 context = GetContextRef();
573 if(!context) return;
575 device = context->Device;
576 LockBufferList(device);
577 if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
578 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
579 else switch(param)
581 default:
582 alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param);
584 UnlockBufferList(device);
586 ALCcontext_DecRef(context);
590 AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values)
592 ALCdevice *device;
593 ALCcontext *context;
594 ALbuffer *albuf;
596 if(values)
598 switch(param)
600 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
601 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
602 alBufferi(buffer, param, values[0]);
603 return;
607 context = GetContextRef();
608 if(!context) return;
610 device = context->Device;
611 LockBufferList(device);
612 if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
613 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
614 else if(UNLIKELY(!values))
615 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
616 else switch(param)
618 case AL_LOOP_POINTS_SOFT:
619 if(UNLIKELY(ReadRef(&albuf->ref) != 0))
620 alSetError(context, AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points",
621 buffer);
622 else if(UNLIKELY(values[0] >= values[1] || values[0] < 0 || values[1] > albuf->SampleLen))
623 alSetError(context, AL_INVALID_VALUE, "Invalid loop point range %d -> %d o buffer %u",
624 values[0], values[1], buffer);
625 else
627 albuf->LoopStart = values[0];
628 albuf->LoopEnd = values[1];
630 break;
632 default:
633 alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x",
634 param);
636 UnlockBufferList(device);
638 ALCcontext_DecRef(context);
642 AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value)
644 ALCdevice *device;
645 ALCcontext *context;
646 ALbuffer *albuf;
648 context = GetContextRef();
649 if(!context) return;
651 device = context->Device;
652 LockBufferList(device);
653 if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
654 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
655 else if(UNLIKELY(!value))
656 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
657 else switch(param)
659 default:
660 alSetError(context, AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param);
662 UnlockBufferList(device);
664 ALCcontext_DecRef(context);
668 AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
670 ALCdevice *device;
671 ALCcontext *context;
673 context = GetContextRef();
674 if(!context) return;
676 device = context->Device;
677 LockBufferList(device);
678 if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
679 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
680 else if(UNLIKELY(!value1 || !value2 || !value3))
681 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
682 else switch(param)
684 default:
685 alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param);
687 UnlockBufferList(device);
689 ALCcontext_DecRef(context);
693 AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values)
695 ALCdevice *device;
696 ALCcontext *context;
698 switch(param)
700 case AL_SEC_LENGTH_SOFT:
701 alGetBufferf(buffer, param, values);
702 return;
705 context = GetContextRef();
706 if(!context) return;
708 device = context->Device;
709 LockBufferList(device);
710 if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
711 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
712 else if(UNLIKELY(!values))
713 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
714 else switch(param)
716 default:
717 alSetError(context, AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param);
719 UnlockBufferList(device);
721 ALCcontext_DecRef(context);
725 AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value)
727 ALCdevice *device;
728 ALCcontext *context;
729 ALbuffer *albuf;
731 context = GetContextRef();
732 if(!context) return;
734 device = context->Device;
735 LockBufferList(device);
736 if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
737 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
738 else if(UNLIKELY(!value))
739 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
740 else switch(param)
742 case AL_FREQUENCY:
743 *value = albuf->Frequency;
744 break;
746 case AL_BITS:
747 *value = BytesFromFmt(albuf->FmtType) * 8;
748 break;
750 case AL_CHANNELS:
751 *value = ChannelsFromFmt(albuf->FmtChannels);
752 break;
754 case AL_SIZE:
755 *value = albuf->SampleLen * FrameSizeFromFmt(albuf->FmtChannels,
756 albuf->FmtType);
757 break;
759 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
760 *value = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign);
761 break;
763 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
764 *value = ATOMIC_LOAD_SEQ(&albuf->PackAlign);
765 break;
767 default:
768 alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param);
770 UnlockBufferList(device);
772 ALCcontext_DecRef(context);
776 AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3)
778 ALCdevice *device;
779 ALCcontext *context;
781 context = GetContextRef();
782 if(!context) return;
784 device = context->Device;
785 LockBufferList(device);
786 if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
787 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
788 else if(UNLIKELY(!value1 || !value2 || !value3))
789 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
790 else switch(param)
792 default:
793 alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param);
795 UnlockBufferList(device);
797 ALCcontext_DecRef(context);
801 AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values)
803 ALCdevice *device;
804 ALCcontext *context;
805 ALbuffer *albuf;
807 switch(param)
809 case AL_FREQUENCY:
810 case AL_BITS:
811 case AL_CHANNELS:
812 case AL_SIZE:
813 case AL_INTERNAL_FORMAT_SOFT:
814 case AL_BYTE_LENGTH_SOFT:
815 case AL_SAMPLE_LENGTH_SOFT:
816 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
817 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
818 alGetBufferi(buffer, param, values);
819 return;
822 context = GetContextRef();
823 if(!context) return;
825 device = context->Device;
826 LockBufferList(device);
827 if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
828 alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
829 else if(UNLIKELY(!values))
830 alSetError(context, AL_INVALID_VALUE, "NULL pointer");
831 else switch(param)
833 case AL_LOOP_POINTS_SOFT:
834 values[0] = albuf->LoopStart;
835 values[1] = albuf->LoopEnd;
836 break;
838 default:
839 alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x",
840 param);
842 UnlockBufferList(device);
844 ALCcontext_DecRef(context);
848 static const ALchar *NameFromUserFmtType(enum UserFmtType type)
850 switch(type)
852 case UserFmtUByte: return "Unsigned Byte";
853 case UserFmtShort: return "Signed Short";
854 case UserFmtFloat: return "Float32";
855 case UserFmtDouble: return "Float64";
856 case UserFmtMulaw: return "muLaw";
857 case UserFmtAlaw: return "aLaw";
858 case UserFmtIMA4: return "IMA4 ADPCM";
859 case UserFmtMSADPCM: return "MSADPCM";
861 return "<internal type error>";
865 * LoadData
867 * Loads the specified data into the buffer, using the specified format.
869 static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALbitfieldSOFT access)
871 enum FmtChannels DstChannels = FmtMono;
872 enum FmtType DstType = FmtUByte;
873 ALsizei NumChannels, FrameSize;
874 ALsizei SrcByteAlign;
875 ALsizei unpackalign;
876 ALsizei newsize;
877 ALsizei frames;
878 ALsizei align;
880 if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0))
881 SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u",
882 ALBuf->id);
884 /* Currently no channel configurations need to be converted. */
885 switch(SrcChannels)
887 case UserFmtMono: DstChannels = FmtMono; break;
888 case UserFmtStereo: DstChannels = FmtStereo; break;
889 case UserFmtRear: DstChannels = FmtRear; break;
890 case UserFmtQuad: DstChannels = FmtQuad; break;
891 case UserFmtX51: DstChannels = FmtX51; break;
892 case UserFmtX61: DstChannels = FmtX61; break;
893 case UserFmtX71: DstChannels = FmtX71; break;
894 case UserFmtBFormat2D: DstChannels = FmtBFormat2D; break;
895 case UserFmtBFormat3D: DstChannels = FmtBFormat3D; break;
897 if(UNLIKELY((long)SrcChannels != (long)DstChannels))
898 SETERR_RETURN(context, AL_INVALID_ENUM,, "Invalid format");
900 /* IMA4 and MSADPCM convert to 16-bit short. */
901 switch(SrcType)
903 case UserFmtUByte: DstType = FmtUByte; break;
904 case UserFmtShort: DstType = FmtShort; break;
905 case UserFmtFloat: DstType = FmtFloat; break;
906 case UserFmtDouble: DstType = FmtDouble; break;
907 case UserFmtAlaw: DstType = FmtAlaw; break;
908 case UserFmtMulaw: DstType = FmtMulaw; break;
909 case UserFmtIMA4: DstType = FmtShort; break;
910 case UserFmtMSADPCM: DstType = FmtShort; break;
913 /* TODO: Currently we can only map samples when they're not converted. To
914 * allow it would need some kind of double-buffering to hold onto a copy of
915 * the original data.
917 if((access&MAP_READ_WRITE_FLAGS))
919 if(UNLIKELY((long)SrcType != (long)DstType))
920 SETERR_RETURN(context, AL_INVALID_VALUE,, "%s samples cannot be mapped",
921 NameFromUserFmtType(SrcType));
924 unpackalign = ATOMIC_LOAD_SEQ(&ALBuf->UnpackAlign);
925 if(UNLIKELY((align=SanitizeAlignment(SrcType, unpackalign)) < 1))
926 SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %d for %s samples",
927 unpackalign, NameFromUserFmtType(SrcType));
929 if((access&AL_PRESERVE_DATA_BIT_SOFT))
931 /* Can only preserve data with the same format and alignment. */
932 if(UNLIKELY(ALBuf->FmtChannels != DstChannels || ALBuf->OriginalType != SrcType))
933 SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format");
934 if(UNLIKELY(ALBuf->OriginalAlign != align))
935 SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment");
938 /* Convert the input/source size in bytes to sample frames using the unpack
939 * block alignment.
941 if(SrcType == UserFmtIMA4)
942 SrcByteAlign = ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels);
943 else if(SrcType == UserFmtMSADPCM)
944 SrcByteAlign = ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels);
945 else
946 SrcByteAlign = align * FrameSizeFromUserFmt(SrcChannels, SrcType);
947 if(UNLIKELY((size%SrcByteAlign) != 0))
948 SETERR_RETURN(context, AL_INVALID_VALUE,,
949 "Data size %d is not a multiple of frame size %d (%d unpack alignment)",
950 size, SrcByteAlign, align);
952 if(UNLIKELY(size / SrcByteAlign > INT_MAX / align))
953 SETERR_RETURN(context, AL_OUT_OF_MEMORY,,
954 "Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align);
955 frames = size / SrcByteAlign * align;
957 /* Convert the sample frames to the number of bytes needed for internal
958 * storage.
960 NumChannels = ChannelsFromFmt(DstChannels);
961 FrameSize = NumChannels * BytesFromFmt(DstType);
962 if(UNLIKELY(frames > INT_MAX/FrameSize))
963 SETERR_RETURN(context, AL_OUT_OF_MEMORY,,
964 "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize);
965 newsize = frames*FrameSize;
967 /* Round up to the next 16-byte multiple. This could reallocate only when
968 * increasing or the new size is less than half the current, but then the
969 * buffer's AL_SIZE would not be very reliable for accounting buffer memory
970 * usage, and reporting the real size could cause problems for apps that
971 * use AL_SIZE to try to get the buffer's play length.
973 if(LIKELY(newsize <= INT_MAX-15))
974 newsize = (newsize+15) & ~0xf;
975 if(newsize != ALBuf->BytesAlloc)
977 void *temp = al_malloc(16, (size_t)newsize);
978 if(UNLIKELY(!temp && newsize))
979 SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Failed to allocate %d bytes of storage",
980 newsize);
981 if((access&AL_PRESERVE_DATA_BIT_SOFT))
983 ALsizei tocopy = mini(newsize, ALBuf->BytesAlloc);
984 if(tocopy > 0) memcpy(temp, ALBuf->data, tocopy);
986 al_free(ALBuf->data);
987 ALBuf->data = temp;
988 ALBuf->BytesAlloc = newsize;
991 if(SrcType == UserFmtIMA4)
993 assert(DstType == FmtShort);
994 if(data != NULL && ALBuf->data != NULL)
995 Convert_ALshort_ALima4(ALBuf->data, data, NumChannels, frames, align);
996 ALBuf->OriginalAlign = align;
998 else if(SrcType == UserFmtMSADPCM)
1000 assert(DstType == FmtShort);
1001 if(data != NULL && ALBuf->data != NULL)
1002 Convert_ALshort_ALmsadpcm(ALBuf->data, data, NumChannels, frames, align);
1003 ALBuf->OriginalAlign = align;
1005 else
1007 assert((long)SrcType == (long)DstType);
1008 if(data != NULL && ALBuf->data != NULL)
1009 memcpy(ALBuf->data, data, frames*FrameSize);
1010 ALBuf->OriginalAlign = 1;
1012 ALBuf->OriginalSize = size;
1013 ALBuf->OriginalType = SrcType;
1015 ALBuf->Frequency = freq;
1016 ALBuf->FmtChannels = DstChannels;
1017 ALBuf->FmtType = DstType;
1018 ALBuf->Access = access;
1020 ALBuf->SampleLen = frames;
1021 ALBuf->LoopStart = 0;
1022 ALBuf->LoopEnd = ALBuf->SampleLen;
1026 ALsizei BytesFromUserFmt(enum UserFmtType type)
1028 switch(type)
1030 case UserFmtUByte: return sizeof(ALubyte);
1031 case UserFmtShort: return sizeof(ALshort);
1032 case UserFmtFloat: return sizeof(ALfloat);
1033 case UserFmtDouble: return sizeof(ALdouble);
1034 case UserFmtMulaw: return sizeof(ALubyte);
1035 case UserFmtAlaw: return sizeof(ALubyte);
1036 case UserFmtIMA4: break; /* not handled here */
1037 case UserFmtMSADPCM: break; /* not handled here */
1039 return 0;
1041 ALsizei ChannelsFromUserFmt(enum UserFmtChannels chans)
1043 switch(chans)
1045 case UserFmtMono: return 1;
1046 case UserFmtStereo: return 2;
1047 case UserFmtRear: return 2;
1048 case UserFmtQuad: return 4;
1049 case UserFmtX51: return 6;
1050 case UserFmtX61: return 7;
1051 case UserFmtX71: return 8;
1052 case UserFmtBFormat2D: return 3;
1053 case UserFmtBFormat3D: return 4;
1055 return 0;
1057 static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
1058 enum UserFmtType *type)
1060 static const struct {
1061 ALenum format;
1062 enum UserFmtChannels channels;
1063 enum UserFmtType type;
1064 } list[] = {
1065 { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte },
1066 { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort },
1067 { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat },
1068 { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble },
1069 { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 },
1070 { AL_FORMAT_MONO_MSADPCM_SOFT, UserFmtMono, UserFmtMSADPCM },
1071 { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw },
1072 { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw },
1074 { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte },
1075 { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort },
1076 { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat },
1077 { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble },
1078 { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 },
1079 { AL_FORMAT_STEREO_MSADPCM_SOFT, UserFmtStereo, UserFmtMSADPCM },
1080 { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw },
1081 { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw },
1083 { AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte },
1084 { AL_FORMAT_REAR16, UserFmtRear, UserFmtShort },
1085 { AL_FORMAT_REAR32, UserFmtRear, UserFmtFloat },
1086 { AL_FORMAT_REAR_MULAW, UserFmtRear, UserFmtMulaw },
1088 { AL_FORMAT_QUAD8_LOKI, UserFmtQuad, UserFmtUByte },
1089 { AL_FORMAT_QUAD16_LOKI, UserFmtQuad, UserFmtShort },
1091 { AL_FORMAT_QUAD8, UserFmtQuad, UserFmtUByte },
1092 { AL_FORMAT_QUAD16, UserFmtQuad, UserFmtShort },
1093 { AL_FORMAT_QUAD32, UserFmtQuad, UserFmtFloat },
1094 { AL_FORMAT_QUAD_MULAW, UserFmtQuad, UserFmtMulaw },
1096 { AL_FORMAT_51CHN8, UserFmtX51, UserFmtUByte },
1097 { AL_FORMAT_51CHN16, UserFmtX51, UserFmtShort },
1098 { AL_FORMAT_51CHN32, UserFmtX51, UserFmtFloat },
1099 { AL_FORMAT_51CHN_MULAW, UserFmtX51, UserFmtMulaw },
1101 { AL_FORMAT_61CHN8, UserFmtX61, UserFmtUByte },
1102 { AL_FORMAT_61CHN16, UserFmtX61, UserFmtShort },
1103 { AL_FORMAT_61CHN32, UserFmtX61, UserFmtFloat },
1104 { AL_FORMAT_61CHN_MULAW, UserFmtX61, UserFmtMulaw },
1106 { AL_FORMAT_71CHN8, UserFmtX71, UserFmtUByte },
1107 { AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort },
1108 { AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat },
1109 { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw },
1111 { AL_FORMAT_BFORMAT2D_8, UserFmtBFormat2D, UserFmtUByte },
1112 { AL_FORMAT_BFORMAT2D_16, UserFmtBFormat2D, UserFmtShort },
1113 { AL_FORMAT_BFORMAT2D_FLOAT32, UserFmtBFormat2D, UserFmtFloat },
1114 { AL_FORMAT_BFORMAT2D_MULAW, UserFmtBFormat2D, UserFmtMulaw },
1116 { AL_FORMAT_BFORMAT3D_8, UserFmtBFormat3D, UserFmtUByte },
1117 { AL_FORMAT_BFORMAT3D_16, UserFmtBFormat3D, UserFmtShort },
1118 { AL_FORMAT_BFORMAT3D_FLOAT32, UserFmtBFormat3D, UserFmtFloat },
1119 { AL_FORMAT_BFORMAT3D_MULAW, UserFmtBFormat3D, UserFmtMulaw },
1121 ALuint i;
1123 for(i = 0;i < COUNTOF(list);i++)
1125 if(list[i].format == format)
1127 *chans = list[i].channels;
1128 *type = list[i].type;
1129 return AL_TRUE;
1133 return AL_FALSE;
1136 ALsizei BytesFromFmt(enum FmtType type)
1138 switch(type)
1140 case FmtUByte: return sizeof(ALubyte);
1141 case FmtShort: return sizeof(ALshort);
1142 case FmtFloat: return sizeof(ALfloat);
1143 case FmtDouble: return sizeof(ALdouble);
1144 case FmtMulaw: return sizeof(ALubyte);
1145 case FmtAlaw: return sizeof(ALubyte);
1147 return 0;
1149 ALsizei ChannelsFromFmt(enum FmtChannels chans)
1151 switch(chans)
1153 case FmtMono: return 1;
1154 case FmtStereo: return 2;
1155 case FmtRear: return 2;
1156 case FmtQuad: return 4;
1157 case FmtX51: return 6;
1158 case FmtX61: return 7;
1159 case FmtX71: return 8;
1160 case FmtBFormat2D: return 3;
1161 case FmtBFormat3D: return 4;
1163 return 0;
1166 static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align)
1168 if(align < 0)
1169 return 0;
1171 if(align == 0)
1173 if(type == UserFmtIMA4)
1175 /* Here is where things vary:
1176 * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
1177 * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
1179 return 65;
1181 if(type == UserFmtMSADPCM)
1182 return 64;
1183 return 1;
1186 if(type == UserFmtIMA4)
1188 /* IMA4 block alignment must be a multiple of 8, plus 1. */
1189 if((align&7) == 1) return align;
1190 return 0;
1192 if(type == UserFmtMSADPCM)
1194 /* MSADPCM block alignment must be a multiple of 2. */
1195 if((align&1) == 0) return align;
1196 return 0;
1199 return align;
1203 static ALbuffer *AllocBuffer(ALCcontext *context)
1205 ALCdevice *device = context->Device;
1206 BufferSubList *sublist, *subend;
1207 ALbuffer *buffer = NULL;
1208 ALsizei lidx = 0;
1209 ALsizei slidx;
1211 almtx_lock(&device->BufferLock);
1212 sublist = VECTOR_BEGIN(device->BufferList);
1213 subend = VECTOR_END(device->BufferList);
1214 for(;sublist != subend;++sublist)
1216 if(sublist->FreeMask)
1218 slidx = CTZ64(sublist->FreeMask);
1219 buffer = sublist->Buffers + slidx;
1220 break;
1222 ++lidx;
1224 if(UNLIKELY(!buffer))
1226 const BufferSubList empty_sublist = { 0, NULL };
1227 /* Don't allocate so many list entries that the 32-bit ID could
1228 * overflow...
1230 if(UNLIKELY(VECTOR_SIZE(device->BufferList) >= 1<<25))
1232 almtx_unlock(&device->BufferLock);
1233 alSetError(context, AL_OUT_OF_MEMORY, "Too many buffers allocated");
1234 return NULL;
1236 lidx = (ALsizei)VECTOR_SIZE(device->BufferList);
1237 VECTOR_PUSH_BACK(device->BufferList, empty_sublist);
1238 sublist = &VECTOR_BACK(device->BufferList);
1239 sublist->FreeMask = ~U64(0);
1240 sublist->Buffers = al_calloc(16, sizeof(ALbuffer)*64);
1241 if(UNLIKELY(!sublist->Buffers))
1243 VECTOR_POP_BACK(device->BufferList);
1244 almtx_unlock(&device->BufferLock);
1245 alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate buffer batch");
1246 return NULL;
1249 slidx = 0;
1250 buffer = sublist->Buffers + slidx;
1253 memset(buffer, 0, sizeof(*buffer));
1255 /* Add 1 to avoid buffer ID 0. */
1256 buffer->id = ((lidx<<6) | slidx) + 1;
1258 sublist->FreeMask &= ~(U64(1)<<slidx);
1259 almtx_unlock(&device->BufferLock);
1261 return buffer;
1264 static void FreeBuffer(ALCdevice *device, ALbuffer *buffer)
1266 ALuint id = buffer->id - 1;
1267 ALsizei lidx = id >> 6;
1268 ALsizei slidx = id & 0x3f;
1270 al_free(buffer->data);
1271 memset(buffer, 0, sizeof(*buffer));
1273 VECTOR_ELEM(device->BufferList, lidx).FreeMask |= U64(1) << slidx;
1278 * ReleaseALBuffers()
1280 * INTERNAL: Called to destroy any buffers that still exist on the device
1282 ALvoid ReleaseALBuffers(ALCdevice *device)
1284 BufferSubList *sublist = VECTOR_BEGIN(device->BufferList);
1285 BufferSubList *subend = VECTOR_END(device->BufferList);
1286 size_t leftover = 0;
1287 for(;sublist != subend;++sublist)
1289 ALuint64 usemask = ~sublist->FreeMask;
1290 while(usemask)
1292 ALsizei idx = CTZ64(usemask);
1293 ALbuffer *buffer = sublist->Buffers + idx;
1295 al_free(buffer->data);
1296 memset(buffer, 0, sizeof(*buffer));
1297 ++leftover;
1299 usemask &= ~(U64(1) << idx);
1301 sublist->FreeMask = ~usemask;
1303 if(leftover > 0)
1304 WARN("(%p) Deleted "SZFMT" Buffer%s\n", device, leftover, (leftover==1)?"":"s");