Standardize some New/Delete methods
[openal-soft.git] / OpenAL32 / alBuffer.c
blob9f12128e2694d8f498c64ae35555ea097ddd34f5
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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, 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 struct ALbuffer *LookupBuffer(ALCdevice *device, ALuint id);
40 extern inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id);
41 extern inline ALuint FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type);
42 extern inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type);
44 static ALboolean IsValidType(ALenum type) DECL_CONST;
45 static ALboolean IsValidChannels(ALenum channels) DECL_CONST;
46 static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type) DECL_CONST;
47 static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type) DECL_CONST;
48 static ALboolean SanitizeAlignment(enum UserFmtType type, ALsizei *align);
51 AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers)
53 ALCdevice *device;
54 ALCcontext *context;
55 ALsizei cur = 0;
57 context = GetContextRef();
58 if(!context) return;
60 if(!(n >= 0))
61 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
63 device = context->Device;
64 for(cur = 0;cur < n;cur++)
66 ALbuffer *buffer = NewBuffer(context);
67 if(!buffer)
69 alDeleteBuffers(cur, buffers);
70 break;
73 buffers[cur] = buffer->id;
76 done:
77 ALCcontext_DecRef(context);
80 AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers)
82 ALCdevice *device;
83 ALCcontext *context;
84 ALbuffer *ALBuf;
85 ALsizei i;
87 context = GetContextRef();
88 if(!context) return;
90 if(!(n >= 0))
91 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
93 device = context->Device;
94 for(i = 0;i < n;i++)
96 if(!buffers[i])
97 continue;
99 /* Check for valid Buffer ID */
100 if((ALBuf=LookupBuffer(device, buffers[i])) == NULL)
101 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
102 if(ReadRef(&ALBuf->ref) != 0)
103 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
106 for(i = 0;i < n;i++)
108 if((ALBuf=LookupBuffer(device, buffers[i])) != NULL)
109 DeleteBuffer(device, ALBuf);
112 done:
113 ALCcontext_DecRef(context);
116 AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer)
118 ALCcontext *context;
119 ALboolean ret;
121 context = GetContextRef();
122 if(!context) return AL_FALSE;
124 ret = ((!buffer || LookupBuffer(context->Device, buffer)) ?
125 AL_TRUE : AL_FALSE);
127 ALCcontext_DecRef(context);
129 return ret;
133 AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq)
135 enum UserFmtChannels srcchannels;
136 enum UserFmtType srctype;
137 ALCdevice *device;
138 ALCcontext *context;
139 ALbuffer *albuf;
140 ALenum newformat = AL_NONE;
141 ALuint framesize;
142 ALsizei align;
143 ALenum err;
145 context = GetContextRef();
146 if(!context) return;
148 device = context->Device;
149 if((albuf=LookupBuffer(device, buffer)) == NULL)
150 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
151 if(!(size >= 0 && freq > 0))
152 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
153 if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
154 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
156 align = albuf->UnpackAlign;
157 if(SanitizeAlignment(srctype, &align) == AL_FALSE)
158 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
159 switch(srctype)
161 case UserFmtByte:
162 case UserFmtUByte:
163 case UserFmtShort:
164 case UserFmtUShort:
165 case UserFmtFloat:
166 framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
167 if((size%framesize) != 0)
168 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
170 err = LoadData(albuf, freq, format, size/framesize*align,
171 srcchannels, srctype, data, align, AL_TRUE);
172 if(err != AL_NO_ERROR)
173 SET_ERROR_AND_GOTO(context, err, done);
174 break;
176 case UserFmtInt:
177 case UserFmtUInt:
178 case UserFmtByte3:
179 case UserFmtUByte3:
180 case UserFmtDouble:
181 framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
182 if((size%framesize) != 0)
183 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
185 switch(srcchannels)
187 case UserFmtMono: newformat = AL_FORMAT_MONO_FLOAT32; break;
188 case UserFmtStereo: newformat = AL_FORMAT_STEREO_FLOAT32; break;
189 case UserFmtRear: newformat = AL_FORMAT_REAR32; break;
190 case UserFmtQuad: newformat = AL_FORMAT_QUAD32; break;
191 case UserFmtX51: newformat = AL_FORMAT_51CHN32; break;
192 case UserFmtX61: newformat = AL_FORMAT_61CHN32; break;
193 case UserFmtX71: newformat = AL_FORMAT_71CHN32; break;
195 err = LoadData(albuf, freq, newformat, size/framesize*align,
196 srcchannels, srctype, data, align, AL_TRUE);
197 if(err != AL_NO_ERROR)
198 SET_ERROR_AND_GOTO(context, err, done);
199 break;
201 case UserFmtMulaw:
202 case UserFmtAlaw:
203 framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
204 if((size%framesize) != 0)
205 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
207 switch(srcchannels)
209 case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
210 case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
211 case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
212 case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
213 case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
214 case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
215 case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
217 err = LoadData(albuf, freq, newformat, size/framesize*align,
218 srcchannels, srctype, data, align, AL_TRUE);
219 if(err != AL_NO_ERROR)
220 SET_ERROR_AND_GOTO(context, err, done);
221 break;
223 case UserFmtIMA4:
224 framesize = (align-1)/2 + 4;
225 framesize *= ChannelsFromUserFmt(srcchannels);
226 if((size%framesize) != 0)
227 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
229 switch(srcchannels)
231 case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
232 case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
233 case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
234 case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
235 case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
236 case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
237 case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
239 err = LoadData(albuf, freq, newformat, size/framesize*align,
240 srcchannels, srctype, data, align, AL_TRUE);
241 if(err != AL_NO_ERROR)
242 SET_ERROR_AND_GOTO(context, err, done);
243 break;
245 case UserFmtMSADPCM:
246 framesize = (align-2)/2 + 7;
247 framesize *= ChannelsFromUserFmt(srcchannels);
248 if((size%framesize) != 0)
249 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
251 switch(srcchannels)
253 case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
254 case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
255 case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
256 case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
257 case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
258 case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
259 case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
261 err = LoadData(albuf, freq, newformat, size/framesize*align,
262 srcchannels, srctype, data, align, AL_TRUE);
263 if(err != AL_NO_ERROR)
264 SET_ERROR_AND_GOTO(context, err, done);
265 break;
268 done:
269 ALCcontext_DecRef(context);
272 AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length)
274 enum UserFmtChannels srcchannels;
275 enum UserFmtType srctype;
276 ALCdevice *device;
277 ALCcontext *context;
278 ALbuffer *albuf;
279 ALuint byte_align;
280 ALuint channels;
281 ALuint bytes;
282 ALsizei align;
284 context = GetContextRef();
285 if(!context) return;
287 device = context->Device;
288 if((albuf=LookupBuffer(device, buffer)) == NULL)
289 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
290 if(!(length >= 0 && offset >= 0))
291 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
292 if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
293 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
295 WriteLock(&albuf->lock);
296 align = albuf->UnpackAlign;
297 if(SanitizeAlignment(srctype, &align) == AL_FALSE)
299 WriteUnlock(&albuf->lock);
300 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
302 if(srcchannels != albuf->OriginalChannels || srctype != albuf->OriginalType)
304 WriteUnlock(&albuf->lock);
305 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
307 if(align != albuf->OriginalAlign)
309 WriteUnlock(&albuf->lock);
310 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
313 if(albuf->OriginalType == UserFmtIMA4)
315 byte_align = (albuf->OriginalAlign-1)/2 + 4;
316 byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels);
318 else if(albuf->OriginalType == UserFmtMSADPCM)
320 byte_align = (albuf->OriginalAlign-2)/2 + 7;
321 byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels);
323 else
325 byte_align = albuf->OriginalAlign;
326 byte_align *= FrameSizeFromUserFmt(albuf->OriginalChannels,
327 albuf->OriginalType);
330 if(offset > albuf->OriginalSize || length > albuf->OriginalSize-offset ||
331 (offset%byte_align) != 0 || (length%byte_align) != 0)
333 WriteUnlock(&albuf->lock);
334 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
337 channels = ChannelsFromFmt(albuf->FmtChannels);
338 bytes = BytesFromFmt(albuf->FmtType);
339 /* offset -> byte offset, length -> sample count */
340 offset = offset/byte_align * channels*bytes;
341 length = length/byte_align * albuf->OriginalAlign;
343 ConvertData((char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
344 data, srctype, channels, length, align);
345 WriteUnlock(&albuf->lock);
347 done:
348 ALCcontext_DecRef(context);
352 AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer,
353 ALuint samplerate, ALenum internalformat, ALsizei samples,
354 ALenum channels, ALenum type, const ALvoid *data)
356 ALCdevice *device;
357 ALCcontext *context;
358 ALbuffer *albuf;
359 ALsizei align;
360 ALenum err;
362 context = GetContextRef();
363 if(!context) return;
365 device = context->Device;
366 if((albuf=LookupBuffer(device, buffer)) == NULL)
367 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
368 if(!(samples >= 0 && samplerate != 0))
369 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
370 if(IsValidType(type) == AL_FALSE || IsValidChannels(channels) == AL_FALSE)
371 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
373 align = albuf->UnpackAlign;
374 if(SanitizeAlignment(type, &align) == AL_FALSE)
375 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
376 if((samples%align) != 0)
377 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
379 err = LoadData(albuf, samplerate, internalformat, samples,
380 channels, type, data, align, AL_FALSE);
381 if(err != AL_NO_ERROR)
382 SET_ERROR_AND_GOTO(context, err, done);
384 done:
385 ALCcontext_DecRef(context);
388 AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer,
389 ALsizei offset, ALsizei samples,
390 ALenum channels, ALenum type, const ALvoid *data)
392 ALCdevice *device;
393 ALCcontext *context;
394 ALbuffer *albuf;
395 ALsizei align;
397 context = GetContextRef();
398 if(!context) return;
400 device = context->Device;
401 if((albuf=LookupBuffer(device, buffer)) == NULL)
402 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
403 if(!(samples >= 0 && offset >= 0))
404 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
405 if(IsValidType(type) == AL_FALSE)
406 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
408 WriteLock(&albuf->lock);
409 align = albuf->UnpackAlign;
410 if(SanitizeAlignment(type, &align) == AL_FALSE)
412 WriteUnlock(&albuf->lock);
413 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
415 if(channels != (ALenum)albuf->FmtChannels)
417 WriteUnlock(&albuf->lock);
418 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
420 if(offset > albuf->SampleLen || samples > albuf->SampleLen-offset)
422 WriteUnlock(&albuf->lock);
423 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
425 if((samples%align) != 0)
427 WriteUnlock(&albuf->lock);
428 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
431 /* offset -> byte offset */
432 offset *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType);
433 ConvertData((char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
434 data, type, ChannelsFromFmt(albuf->FmtChannels), samples, align);
435 WriteUnlock(&albuf->lock);
437 done:
438 ALCcontext_DecRef(context);
441 AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer,
442 ALsizei offset, ALsizei samples,
443 ALenum channels, ALenum type, ALvoid *data)
445 ALCdevice *device;
446 ALCcontext *context;
447 ALbuffer *albuf;
448 ALsizei align;
450 context = GetContextRef();
451 if(!context) return;
453 device = context->Device;
454 if((albuf=LookupBuffer(device, buffer)) == NULL)
455 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
456 if(!(samples >= 0 && offset >= 0))
457 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
458 if(IsValidType(type) == AL_FALSE)
459 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
461 ReadLock(&albuf->lock);
462 align = albuf->PackAlign;
463 if(SanitizeAlignment(type, &align) == AL_FALSE)
465 ReadUnlock(&albuf->lock);
466 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
468 if(channels != (ALenum)albuf->FmtChannels)
470 ReadUnlock(&albuf->lock);
471 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
473 if(offset > albuf->SampleLen || samples > albuf->SampleLen-offset)
475 ReadUnlock(&albuf->lock);
476 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
478 if((samples%align) != 0)
480 ReadUnlock(&albuf->lock);
481 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
484 /* offset -> byte offset */
485 offset *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType);
486 ConvertData(data, type, (char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
487 ChannelsFromFmt(albuf->FmtChannels), samples, align);
488 ReadUnlock(&albuf->lock);
490 done:
491 ALCcontext_DecRef(context);
494 AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format)
496 enum FmtChannels dstchannels;
497 enum FmtType dsttype;
498 ALCcontext *context;
499 ALboolean ret;
501 context = GetContextRef();
502 if(!context) return AL_FALSE;
504 ret = DecomposeFormat(format, &dstchannels, &dsttype);
506 ALCcontext_DecRef(context);
508 return ret;
512 AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(value))
514 ALCdevice *device;
515 ALCcontext *context;
517 context = GetContextRef();
518 if(!context) return;
520 device = context->Device;
521 if(LookupBuffer(device, buffer) == NULL)
522 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
524 switch(param)
526 default:
527 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
530 done:
531 ALCcontext_DecRef(context);
535 AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(value1), ALfloat UNUSED(value2), ALfloat UNUSED(value3))
537 ALCdevice *device;
538 ALCcontext *context;
540 context = GetContextRef();
541 if(!context) return;
543 device = context->Device;
544 if(LookupBuffer(device, buffer) == NULL)
545 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
547 switch(param)
549 default:
550 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
553 done:
554 ALCcontext_DecRef(context);
558 AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values)
560 ALCdevice *device;
561 ALCcontext *context;
563 context = GetContextRef();
564 if(!context) return;
566 device = context->Device;
567 if(LookupBuffer(device, buffer) == NULL)
568 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
570 if(!(values))
571 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
572 switch(param)
574 default:
575 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
578 done:
579 ALCcontext_DecRef(context);
583 AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value)
585 ALCdevice *device;
586 ALCcontext *context;
587 ALbuffer *albuf;
589 context = GetContextRef();
590 if(!context) return;
592 device = context->Device;
593 if((albuf=LookupBuffer(device, buffer)) == NULL)
594 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
596 switch(param)
598 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
599 if(!(value >= 0))
600 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
601 ExchangeInt(&albuf->UnpackAlign, value);
602 break;
604 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
605 if(!(value >= 0))
606 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
607 ExchangeInt(&albuf->PackAlign, value);
608 break;
610 default:
611 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
614 done:
615 ALCcontext_DecRef(context);
619 AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(value1), ALint UNUSED(value2), ALint UNUSED(value3))
621 ALCdevice *device;
622 ALCcontext *context;
624 context = GetContextRef();
625 if(!context) return;
627 device = context->Device;
628 if(LookupBuffer(device, buffer) == NULL)
629 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
631 switch(param)
633 default:
634 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
637 done:
638 ALCcontext_DecRef(context);
642 AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values)
644 ALCdevice *device;
645 ALCcontext *context;
646 ALbuffer *albuf;
648 if(values)
650 switch(param)
652 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
653 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
654 alBufferi(buffer, param, values[0]);
655 return;
659 context = GetContextRef();
660 if(!context) return;
662 device = context->Device;
663 if((albuf=LookupBuffer(device, buffer)) == NULL)
664 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
666 if(!(values))
667 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
668 switch(param)
670 case AL_LOOP_POINTS_SOFT:
671 WriteLock(&albuf->lock);
672 if(ReadRef(&albuf->ref) != 0)
674 WriteUnlock(&albuf->lock);
675 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
677 if(values[0] >= values[1] || values[0] < 0 ||
678 values[1] > albuf->SampleLen)
680 WriteUnlock(&albuf->lock);
681 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
684 albuf->LoopStart = values[0];
685 albuf->LoopEnd = values[1];
686 WriteUnlock(&albuf->lock);
687 break;
689 default:
690 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
693 done:
694 ALCcontext_DecRef(context);
698 AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value)
700 ALCdevice *device;
701 ALCcontext *context;
702 ALbuffer *albuf;
704 context = GetContextRef();
705 if(!context) return;
707 device = context->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_SEC_LENGTH_SOFT:
716 ReadLock(&albuf->lock);
717 if(albuf->SampleLen != 0)
718 *value = albuf->SampleLen / (ALfloat)albuf->Frequency;
719 else
720 *value = 0.0f;
721 ReadUnlock(&albuf->lock);
722 break;
724 default:
725 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
728 done:
729 ALCcontext_DecRef(context);
733 AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
735 ALCdevice *device;
736 ALCcontext *context;
738 context = GetContextRef();
739 if(!context) return;
741 device = context->Device;
742 if(LookupBuffer(device, buffer) == NULL)
743 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
745 if(!(value1 && value2 && value3))
746 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
747 switch(param)
749 default:
750 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
753 done:
754 ALCcontext_DecRef(context);
758 AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values)
760 ALCdevice *device;
761 ALCcontext *context;
763 switch(param)
765 case AL_SEC_LENGTH_SOFT:
766 alGetBufferf(buffer, param, values);
767 return;
770 context = GetContextRef();
771 if(!context) return;
773 device = context->Device;
774 if(LookupBuffer(device, buffer) == NULL)
775 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
777 if(!(values))
778 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
779 switch(param)
781 default:
782 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
785 done:
786 ALCcontext_DecRef(context);
790 AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value)
792 ALCdevice *device;
793 ALCcontext *context;
794 ALbuffer *albuf;
796 context = GetContextRef();
797 if(!context) return;
799 device = context->Device;
800 if((albuf=LookupBuffer(device, buffer)) == NULL)
801 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
803 if(!(value))
804 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
805 switch(param)
807 case AL_FREQUENCY:
808 *value = albuf->Frequency;
809 break;
811 case AL_BITS:
812 *value = BytesFromFmt(albuf->FmtType) * 8;
813 break;
815 case AL_CHANNELS:
816 *value = ChannelsFromFmt(albuf->FmtChannels);
817 break;
819 case AL_SIZE:
820 ReadLock(&albuf->lock);
821 *value = albuf->SampleLen * FrameSizeFromFmt(albuf->FmtChannels,
822 albuf->FmtType);
823 ReadUnlock(&albuf->lock);
824 break;
826 case AL_INTERNAL_FORMAT_SOFT:
827 *value = albuf->Format;
828 break;
830 case AL_BYTE_LENGTH_SOFT:
831 *value = albuf->OriginalSize;
832 break;
834 case AL_SAMPLE_LENGTH_SOFT:
835 *value = albuf->SampleLen;
836 break;
838 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
839 *value = albuf->UnpackAlign;
840 break;
842 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
843 *value = albuf->PackAlign;
844 break;
846 default:
847 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
850 done:
851 ALCcontext_DecRef(context);
855 AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3)
857 ALCdevice *device;
858 ALCcontext *context;
860 context = GetContextRef();
861 if(!context) return;
863 device = context->Device;
864 if(LookupBuffer(device, buffer) == NULL)
865 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
867 if(!(value1 && value2 && value3))
868 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
869 switch(param)
871 default:
872 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
875 done:
876 ALCcontext_DecRef(context);
880 AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values)
882 ALCdevice *device;
883 ALCcontext *context;
884 ALbuffer *albuf;
886 switch(param)
888 case AL_FREQUENCY:
889 case AL_BITS:
890 case AL_CHANNELS:
891 case AL_SIZE:
892 case AL_INTERNAL_FORMAT_SOFT:
893 case AL_BYTE_LENGTH_SOFT:
894 case AL_SAMPLE_LENGTH_SOFT:
895 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
896 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
897 alGetBufferi(buffer, param, values);
898 return;
901 context = GetContextRef();
902 if(!context) return;
904 device = context->Device;
905 if((albuf=LookupBuffer(device, buffer)) == NULL)
906 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
908 if(!(values))
909 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
910 switch(param)
912 case AL_LOOP_POINTS_SOFT:
913 ReadLock(&albuf->lock);
914 values[0] = albuf->LoopStart;
915 values[1] = albuf->LoopEnd;
916 ReadUnlock(&albuf->lock);
917 break;
919 default:
920 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
923 done:
924 ALCcontext_DecRef(context);
929 * LoadData
931 * Loads the specified data into the buffer, using the specified formats.
932 * Currently, the new format must have the same channel configuration as the
933 * original format.
935 ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc)
937 ALuint NewChannels, NewBytes;
938 enum FmtChannels DstChannels;
939 enum FmtType DstType;
940 ALuint64 newsize;
941 ALvoid *temp;
943 if(DecomposeFormat(NewFormat, &DstChannels, &DstType) == AL_FALSE ||
944 (long)SrcChannels != (long)DstChannels)
945 return AL_INVALID_ENUM;
947 NewChannels = ChannelsFromFmt(DstChannels);
948 NewBytes = BytesFromFmt(DstType);
950 newsize = frames;
951 newsize *= NewBytes;
952 newsize *= NewChannels;
953 if(newsize > INT_MAX)
954 return AL_OUT_OF_MEMORY;
956 WriteLock(&ALBuf->lock);
957 if(ReadRef(&ALBuf->ref) != 0)
959 WriteUnlock(&ALBuf->lock);
960 return AL_INVALID_OPERATION;
963 temp = realloc(ALBuf->data, (size_t)newsize);
964 if(!temp && newsize)
966 WriteUnlock(&ALBuf->lock);
967 return AL_OUT_OF_MEMORY;
969 ALBuf->data = temp;
971 if(data != NULL)
972 ConvertData(ALBuf->data, (enum UserFmtType)DstType, data, SrcType, NewChannels, frames, align);
974 if(storesrc)
976 ALBuf->OriginalChannels = SrcChannels;
977 ALBuf->OriginalType = SrcType;
978 if(SrcType == UserFmtIMA4)
980 ALsizei byte_align = ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels);
981 ALBuf->OriginalSize = frames / align * byte_align;
982 ALBuf->OriginalAlign = align;
984 else if(SrcType == UserFmtMSADPCM)
986 ALsizei byte_align = ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels);
987 ALBuf->OriginalSize = frames / align * byte_align;
988 ALBuf->OriginalAlign = align;
990 else
992 ALBuf->OriginalSize = frames * FrameSizeFromUserFmt(SrcChannels, SrcType);
993 ALBuf->OriginalAlign = 1;
996 else
998 ALBuf->OriginalChannels = (enum UserFmtChannels)DstChannels;
999 ALBuf->OriginalType = (enum UserFmtType)DstType;
1000 ALBuf->OriginalSize = frames * NewBytes * NewChannels;
1001 ALBuf->OriginalAlign = 1;
1004 ALBuf->Frequency = freq;
1005 ALBuf->FmtChannels = DstChannels;
1006 ALBuf->FmtType = DstType;
1007 ALBuf->Format = NewFormat;
1009 ALBuf->SampleLen = frames;
1010 ALBuf->LoopStart = 0;
1011 ALBuf->LoopEnd = ALBuf->SampleLen;
1013 WriteUnlock(&ALBuf->lock);
1014 return AL_NO_ERROR;
1018 ALuint BytesFromUserFmt(enum UserFmtType type)
1020 switch(type)
1022 case UserFmtByte: return sizeof(ALbyte);
1023 case UserFmtUByte: return sizeof(ALubyte);
1024 case UserFmtShort: return sizeof(ALshort);
1025 case UserFmtUShort: return sizeof(ALushort);
1026 case UserFmtInt: return sizeof(ALint);
1027 case UserFmtUInt: return sizeof(ALuint);
1028 case UserFmtFloat: return sizeof(ALfloat);
1029 case UserFmtDouble: return sizeof(ALdouble);
1030 case UserFmtByte3: return sizeof(ALbyte[3]);
1031 case UserFmtUByte3: return sizeof(ALubyte[3]);
1032 case UserFmtMulaw: return sizeof(ALubyte);
1033 case UserFmtAlaw: return sizeof(ALubyte);
1034 case UserFmtIMA4: break; /* not handled here */
1035 case UserFmtMSADPCM: break; /* not handled here */
1037 return 0;
1039 ALuint ChannelsFromUserFmt(enum UserFmtChannels chans)
1041 switch(chans)
1043 case UserFmtMono: return 1;
1044 case UserFmtStereo: return 2;
1045 case UserFmtRear: return 2;
1046 case UserFmtQuad: return 4;
1047 case UserFmtX51: return 6;
1048 case UserFmtX61: return 7;
1049 case UserFmtX71: return 8;
1051 return 0;
1053 static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
1054 enum UserFmtType *type)
1056 static const struct {
1057 ALenum format;
1058 enum UserFmtChannels channels;
1059 enum UserFmtType type;
1060 } list[] = {
1061 { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte },
1062 { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort },
1063 { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat },
1064 { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble },
1065 { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 },
1066 { AL_FORMAT_MONO_MSADPCM_SOFT, UserFmtMono, UserFmtMSADPCM },
1067 { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw },
1068 { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw },
1070 { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte },
1071 { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort },
1072 { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat },
1073 { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble },
1074 { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 },
1075 { AL_FORMAT_STEREO_MSADPCM_SOFT, UserFmtStereo, UserFmtMSADPCM },
1076 { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw },
1077 { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw },
1079 { AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte },
1080 { AL_FORMAT_REAR16, UserFmtRear, UserFmtShort },
1081 { AL_FORMAT_REAR32, UserFmtRear, UserFmtFloat },
1082 { AL_FORMAT_REAR_MULAW, UserFmtRear, UserFmtMulaw },
1084 { AL_FORMAT_QUAD8_LOKI, UserFmtQuad, UserFmtUByte },
1085 { AL_FORMAT_QUAD16_LOKI, UserFmtQuad, UserFmtShort },
1087 { AL_FORMAT_QUAD8, UserFmtQuad, UserFmtUByte },
1088 { AL_FORMAT_QUAD16, UserFmtQuad, UserFmtShort },
1089 { AL_FORMAT_QUAD32, UserFmtQuad, UserFmtFloat },
1090 { AL_FORMAT_QUAD_MULAW, UserFmtQuad, UserFmtMulaw },
1092 { AL_FORMAT_51CHN8, UserFmtX51, UserFmtUByte },
1093 { AL_FORMAT_51CHN16, UserFmtX51, UserFmtShort },
1094 { AL_FORMAT_51CHN32, UserFmtX51, UserFmtFloat },
1095 { AL_FORMAT_51CHN_MULAW, UserFmtX51, UserFmtMulaw },
1097 { AL_FORMAT_61CHN8, UserFmtX61, UserFmtUByte },
1098 { AL_FORMAT_61CHN16, UserFmtX61, UserFmtShort },
1099 { AL_FORMAT_61CHN32, UserFmtX61, UserFmtFloat },
1100 { AL_FORMAT_61CHN_MULAW, UserFmtX61, UserFmtMulaw },
1102 { AL_FORMAT_71CHN8, UserFmtX71, UserFmtUByte },
1103 { AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort },
1104 { AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat },
1105 { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw },
1107 ALuint i;
1109 for(i = 0;i < COUNTOF(list);i++)
1111 if(list[i].format == format)
1113 *chans = list[i].channels;
1114 *type = list[i].type;
1115 return AL_TRUE;
1119 return AL_FALSE;
1122 ALuint BytesFromFmt(enum FmtType type)
1124 switch(type)
1126 case FmtByte: return sizeof(ALbyte);
1127 case FmtShort: return sizeof(ALshort);
1128 case FmtFloat: return sizeof(ALfloat);
1130 return 0;
1132 ALuint ChannelsFromFmt(enum FmtChannels chans)
1134 switch(chans)
1136 case FmtMono: return 1;
1137 case FmtStereo: return 2;
1138 case FmtRear: return 2;
1139 case FmtQuad: return 4;
1140 case FmtX51: return 6;
1141 case FmtX61: return 7;
1142 case FmtX71: return 8;
1144 return 0;
1146 static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type)
1148 static const struct {
1149 ALenum format;
1150 enum FmtChannels channels;
1151 enum FmtType type;
1152 } list[] = {
1153 { AL_MONO8_SOFT, FmtMono, FmtByte },
1154 { AL_MONO16_SOFT, FmtMono, FmtShort },
1155 { AL_MONO32F_SOFT, FmtMono, FmtFloat },
1157 { AL_STEREO8_SOFT, FmtStereo, FmtByte },
1158 { AL_STEREO16_SOFT, FmtStereo, FmtShort },
1159 { AL_STEREO32F_SOFT, FmtStereo, FmtFloat },
1161 { AL_REAR8_SOFT, FmtRear, FmtByte },
1162 { AL_REAR16_SOFT, FmtRear, FmtShort },
1163 { AL_REAR32F_SOFT, FmtRear, FmtFloat },
1165 { AL_FORMAT_QUAD8_LOKI, FmtQuad, FmtByte },
1166 { AL_FORMAT_QUAD16_LOKI, FmtQuad, FmtShort },
1168 { AL_QUAD8_SOFT, FmtQuad, FmtByte },
1169 { AL_QUAD16_SOFT, FmtQuad, FmtShort },
1170 { AL_QUAD32F_SOFT, FmtQuad, FmtFloat },
1172 { AL_5POINT1_8_SOFT, FmtX51, FmtByte },
1173 { AL_5POINT1_16_SOFT, FmtX51, FmtShort },
1174 { AL_5POINT1_32F_SOFT, FmtX51, FmtFloat },
1176 { AL_6POINT1_8_SOFT, FmtX61, FmtByte },
1177 { AL_6POINT1_16_SOFT, FmtX61, FmtShort },
1178 { AL_6POINT1_32F_SOFT, FmtX61, FmtFloat },
1180 { AL_7POINT1_8_SOFT, FmtX71, FmtByte },
1181 { AL_7POINT1_16_SOFT, FmtX71, FmtShort },
1182 { AL_7POINT1_32F_SOFT, FmtX71, FmtFloat },
1184 ALuint i;
1186 for(i = 0;i < COUNTOF(list);i++)
1188 if(list[i].format == format)
1190 *chans = list[i].channels;
1191 *type = list[i].type;
1192 return AL_TRUE;
1196 return AL_FALSE;
1199 static ALboolean SanitizeAlignment(enum UserFmtType type, ALsizei *align)
1201 if(*align < 0)
1202 return AL_FALSE;
1204 if(*align == 0)
1206 if(type == UserFmtIMA4)
1208 /* Here is where things vary:
1209 * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
1210 * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
1212 *align = 65;
1214 else if(type == UserFmtMSADPCM)
1215 *align = 64;
1216 else
1217 *align = 1;
1218 return AL_TRUE;
1221 if(type == UserFmtIMA4)
1223 /* IMA4 block alignment must be a multiple of 8, plus 1. */
1224 return ((*align)&7) == 1;
1226 if(type == UserFmtMSADPCM)
1228 /* MSADPCM block alignment must be a multiple of 2. */
1229 /* FIXME: Too strict? Might only require align*channels to be a
1230 * multiple of 2. */
1231 return ((*align)&1) == 0;
1234 return AL_TRUE;
1238 static ALboolean IsValidType(ALenum type)
1240 switch(type)
1242 case AL_BYTE_SOFT:
1243 case AL_UNSIGNED_BYTE_SOFT:
1244 case AL_SHORT_SOFT:
1245 case AL_UNSIGNED_SHORT_SOFT:
1246 case AL_INT_SOFT:
1247 case AL_UNSIGNED_INT_SOFT:
1248 case AL_FLOAT_SOFT:
1249 case AL_DOUBLE_SOFT:
1250 case AL_BYTE3_SOFT:
1251 case AL_UNSIGNED_BYTE3_SOFT:
1252 return AL_TRUE;
1254 return AL_FALSE;
1257 static ALboolean IsValidChannels(ALenum channels)
1259 switch(channels)
1261 case AL_MONO_SOFT:
1262 case AL_STEREO_SOFT:
1263 case AL_REAR_SOFT:
1264 case AL_QUAD_SOFT:
1265 case AL_5POINT1_SOFT:
1266 case AL_6POINT1_SOFT:
1267 case AL_7POINT1_SOFT:
1268 return AL_TRUE;
1270 return AL_FALSE;
1274 ALbuffer *NewBuffer(ALCcontext *context)
1276 ALCdevice *device = context->Device;
1277 ALbuffer *buffer;
1278 ALenum err;
1280 buffer = calloc(1, sizeof(ALbuffer));
1281 if(!buffer)
1282 SET_ERROR_AND_RETURN_VALUE(context, AL_OUT_OF_MEMORY, NULL);
1283 RWLockInit(&buffer->lock);
1285 err = NewThunkEntry(&buffer->id);
1286 if(err == AL_NO_ERROR)
1287 err = InsertUIntMapEntry(&device->BufferMap, buffer->id, buffer);
1288 if(err != AL_NO_ERROR)
1290 FreeThunkEntry(buffer->id);
1291 memset(buffer, 0, sizeof(ALbuffer));
1292 free(buffer);
1294 SET_ERROR_AND_RETURN_VALUE(context, err, NULL);
1297 return buffer;
1300 void DeleteBuffer(ALCdevice *device, ALbuffer *buffer)
1302 RemoveBuffer(device, buffer->id);
1303 FreeThunkEntry(buffer->id);
1305 free(buffer->data);
1307 memset(buffer, 0, sizeof(*buffer));
1308 free(buffer);
1313 * ReleaseALBuffers()
1315 * INTERNAL: Called to destroy any buffers that still exist on the device
1317 ALvoid ReleaseALBuffers(ALCdevice *device)
1319 ALsizei i;
1320 for(i = 0;i < device->BufferMap.size;i++)
1322 ALbuffer *temp = device->BufferMap.array[i].value;
1323 device->BufferMap.array[i].value = NULL;
1325 free(temp->data);
1327 FreeThunkEntry(temp->id);
1328 memset(temp, 0, sizeof(ALbuffer));
1329 free(temp);