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