Load soundfont samples into an ALbuffer
[openal-soft.git] / OpenAL32 / alBuffer.c
blobb906da14f8e90f1052e269b69f3b2640f204bf96
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++)
107 DeleteBuffer(device, buffers[i]);
109 done:
110 ALCcontext_DecRef(context);
113 AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer)
115 ALCcontext *context;
116 ALboolean ret;
118 context = GetContextRef();
119 if(!context) return AL_FALSE;
121 ret = ((!buffer || LookupBuffer(context->Device, buffer)) ?
122 AL_TRUE : AL_FALSE);
124 ALCcontext_DecRef(context);
126 return ret;
130 AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq)
132 enum UserFmtChannels srcchannels;
133 enum UserFmtType srctype;
134 ALCdevice *device;
135 ALCcontext *context;
136 ALbuffer *albuf;
137 ALenum newformat = AL_NONE;
138 ALuint framesize;
139 ALsizei align;
140 ALenum err;
142 context = GetContextRef();
143 if(!context) return;
145 device = context->Device;
146 if((albuf=LookupBuffer(device, buffer)) == NULL)
147 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
148 if(!(size >= 0 && freq > 0))
149 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
150 if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
151 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
153 align = albuf->UnpackAlign;
154 if(SanitizeAlignment(srctype, &align) == AL_FALSE)
155 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
156 switch(srctype)
158 case UserFmtByte:
159 case UserFmtUByte:
160 case UserFmtShort:
161 case UserFmtUShort:
162 case UserFmtFloat:
163 framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
164 if((size%framesize) != 0)
165 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
167 err = LoadData(albuf, freq, format, size/framesize*align,
168 srcchannels, srctype, data, align, AL_TRUE);
169 if(err != AL_NO_ERROR)
170 SET_ERROR_AND_GOTO(context, err, done);
171 break;
173 case UserFmtInt:
174 case UserFmtUInt:
175 case UserFmtByte3:
176 case UserFmtUByte3:
177 case UserFmtDouble:
178 framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
179 if((size%framesize) != 0)
180 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
182 switch(srcchannels)
184 case UserFmtMono: newformat = AL_FORMAT_MONO_FLOAT32; break;
185 case UserFmtStereo: newformat = AL_FORMAT_STEREO_FLOAT32; break;
186 case UserFmtRear: newformat = AL_FORMAT_REAR32; break;
187 case UserFmtQuad: newformat = AL_FORMAT_QUAD32; break;
188 case UserFmtX51: newformat = AL_FORMAT_51CHN32; break;
189 case UserFmtX61: newformat = AL_FORMAT_61CHN32; break;
190 case UserFmtX71: newformat = AL_FORMAT_71CHN32; break;
192 err = LoadData(albuf, freq, newformat, size/framesize*align,
193 srcchannels, srctype, data, align, AL_TRUE);
194 if(err != AL_NO_ERROR)
195 SET_ERROR_AND_GOTO(context, err, done);
196 break;
198 case UserFmtMulaw:
199 case UserFmtAlaw:
200 framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
201 if((size%framesize) != 0)
202 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
204 switch(srcchannels)
206 case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
207 case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
208 case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
209 case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
210 case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
211 case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
212 case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
214 err = LoadData(albuf, freq, newformat, size/framesize*align,
215 srcchannels, srctype, data, align, AL_TRUE);
216 if(err != AL_NO_ERROR)
217 SET_ERROR_AND_GOTO(context, err, done);
218 break;
220 case UserFmtIMA4:
221 framesize = (align-1)/2 + 4;
222 framesize *= ChannelsFromUserFmt(srcchannels);
223 if((size%framesize) != 0)
224 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
226 switch(srcchannels)
228 case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
229 case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
230 case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
231 case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
232 case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
233 case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
234 case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
236 err = LoadData(albuf, freq, newformat, size/framesize*align,
237 srcchannels, srctype, data, align, AL_TRUE);
238 if(err != AL_NO_ERROR)
239 SET_ERROR_AND_GOTO(context, err, done);
240 break;
242 case UserFmtMSADPCM:
243 framesize = (align-2)/2 + 7;
244 framesize *= ChannelsFromUserFmt(srcchannels);
245 if((size%framesize) != 0)
246 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
248 switch(srcchannels)
250 case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
251 case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
252 case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
253 case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
254 case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
255 case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
256 case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
258 err = LoadData(albuf, freq, newformat, size/framesize*align,
259 srcchannels, srctype, data, align, AL_TRUE);
260 if(err != AL_NO_ERROR)
261 SET_ERROR_AND_GOTO(context, err, done);
262 break;
265 done:
266 ALCcontext_DecRef(context);
269 AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length)
271 enum UserFmtChannels srcchannels;
272 enum UserFmtType srctype;
273 ALCdevice *device;
274 ALCcontext *context;
275 ALbuffer *albuf;
276 ALuint byte_align;
277 ALuint channels;
278 ALuint bytes;
279 ALsizei align;
281 context = GetContextRef();
282 if(!context) return;
284 device = context->Device;
285 if((albuf=LookupBuffer(device, buffer)) == NULL)
286 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
287 if(!(length >= 0 && offset >= 0))
288 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
289 if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
290 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
292 WriteLock(&albuf->lock);
293 align = albuf->UnpackAlign;
294 if(SanitizeAlignment(srctype, &align) == AL_FALSE)
296 WriteUnlock(&albuf->lock);
297 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
299 if(srcchannels != albuf->OriginalChannels || srctype != albuf->OriginalType)
301 WriteUnlock(&albuf->lock);
302 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
304 if(align != albuf->OriginalAlign)
306 WriteUnlock(&albuf->lock);
307 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
310 if(albuf->OriginalType == UserFmtIMA4)
312 byte_align = (albuf->OriginalAlign-1)/2 + 4;
313 byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels);
315 else if(albuf->OriginalType == UserFmtMSADPCM)
317 byte_align = (albuf->OriginalAlign-2)/2 + 7;
318 byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels);
320 else
322 byte_align = albuf->OriginalAlign;
323 byte_align *= FrameSizeFromUserFmt(albuf->OriginalChannels,
324 albuf->OriginalType);
327 if(offset > albuf->OriginalSize || length > albuf->OriginalSize-offset ||
328 (offset%byte_align) != 0 || (length%byte_align) != 0)
330 WriteUnlock(&albuf->lock);
331 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
334 channels = ChannelsFromFmt(albuf->FmtChannels);
335 bytes = BytesFromFmt(albuf->FmtType);
336 /* offset -> byte offset, length -> sample count */
337 offset = offset/byte_align * channels*bytes;
338 length = length/byte_align * albuf->OriginalAlign;
340 ConvertData((char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
341 data, srctype, channels, length, align);
342 WriteUnlock(&albuf->lock);
344 done:
345 ALCcontext_DecRef(context);
349 AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer,
350 ALuint samplerate, ALenum internalformat, ALsizei samples,
351 ALenum channels, ALenum type, const ALvoid *data)
353 ALCdevice *device;
354 ALCcontext *context;
355 ALbuffer *albuf;
356 ALsizei align;
357 ALenum err;
359 context = GetContextRef();
360 if(!context) return;
362 device = context->Device;
363 if((albuf=LookupBuffer(device, buffer)) == NULL)
364 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
365 if(!(samples >= 0 && samplerate != 0))
366 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
367 if(IsValidType(type) == AL_FALSE || IsValidChannels(channels) == AL_FALSE)
368 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
370 align = albuf->UnpackAlign;
371 if(SanitizeAlignment(type, &align) == AL_FALSE)
372 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
373 if((samples%align) != 0)
374 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
376 err = LoadData(albuf, samplerate, internalformat, samples,
377 channels, type, data, align, AL_FALSE);
378 if(err != AL_NO_ERROR)
379 SET_ERROR_AND_GOTO(context, err, done);
381 done:
382 ALCcontext_DecRef(context);
385 AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer,
386 ALsizei offset, ALsizei samples,
387 ALenum channels, ALenum type, const ALvoid *data)
389 ALCdevice *device;
390 ALCcontext *context;
391 ALbuffer *albuf;
392 ALsizei align;
394 context = GetContextRef();
395 if(!context) return;
397 device = context->Device;
398 if((albuf=LookupBuffer(device, buffer)) == NULL)
399 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
400 if(!(samples >= 0 && offset >= 0))
401 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
402 if(IsValidType(type) == AL_FALSE)
403 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
405 WriteLock(&albuf->lock);
406 align = albuf->UnpackAlign;
407 if(SanitizeAlignment(type, &align) == AL_FALSE)
409 WriteUnlock(&albuf->lock);
410 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
412 if(channels != (ALenum)albuf->FmtChannels)
414 WriteUnlock(&albuf->lock);
415 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
417 if(offset > albuf->SampleLen || samples > albuf->SampleLen-offset)
419 WriteUnlock(&albuf->lock);
420 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
422 if((samples%align) != 0)
424 WriteUnlock(&albuf->lock);
425 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
428 /* offset -> byte offset */
429 offset *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType);
430 ConvertData((char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
431 data, type, ChannelsFromFmt(albuf->FmtChannels), samples, align);
432 WriteUnlock(&albuf->lock);
434 done:
435 ALCcontext_DecRef(context);
438 AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer,
439 ALsizei offset, ALsizei samples,
440 ALenum channels, ALenum type, ALvoid *data)
442 ALCdevice *device;
443 ALCcontext *context;
444 ALbuffer *albuf;
445 ALsizei align;
447 context = GetContextRef();
448 if(!context) return;
450 device = context->Device;
451 if((albuf=LookupBuffer(device, buffer)) == NULL)
452 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
453 if(!(samples >= 0 && offset >= 0))
454 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
455 if(IsValidType(type) == AL_FALSE)
456 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
458 ReadLock(&albuf->lock);
459 align = albuf->PackAlign;
460 if(SanitizeAlignment(type, &align) == AL_FALSE)
462 ReadUnlock(&albuf->lock);
463 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
465 if(channels != (ALenum)albuf->FmtChannels)
467 ReadUnlock(&albuf->lock);
468 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
470 if(offset > albuf->SampleLen || samples > albuf->SampleLen-offset)
472 ReadUnlock(&albuf->lock);
473 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
475 if((samples%align) != 0)
477 ReadUnlock(&albuf->lock);
478 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
481 /* offset -> byte offset */
482 offset *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType);
483 ConvertData(data, type, (char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
484 ChannelsFromFmt(albuf->FmtChannels), samples, align);
485 ReadUnlock(&albuf->lock);
487 done:
488 ALCcontext_DecRef(context);
491 AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format)
493 enum FmtChannels dstchannels;
494 enum FmtType dsttype;
495 ALCcontext *context;
496 ALboolean ret;
498 context = GetContextRef();
499 if(!context) return AL_FALSE;
501 ret = DecomposeFormat(format, &dstchannels, &dsttype);
503 ALCcontext_DecRef(context);
505 return ret;
509 AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(value))
511 ALCdevice *device;
512 ALCcontext *context;
514 context = GetContextRef();
515 if(!context) return;
517 device = context->Device;
518 if(LookupBuffer(device, buffer) == NULL)
519 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
521 switch(param)
523 default:
524 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
527 done:
528 ALCcontext_DecRef(context);
532 AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(value1), ALfloat UNUSED(value2), ALfloat UNUSED(value3))
534 ALCdevice *device;
535 ALCcontext *context;
537 context = GetContextRef();
538 if(!context) return;
540 device = context->Device;
541 if(LookupBuffer(device, buffer) == NULL)
542 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
544 switch(param)
546 default:
547 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
550 done:
551 ALCcontext_DecRef(context);
555 AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values)
557 ALCdevice *device;
558 ALCcontext *context;
560 context = GetContextRef();
561 if(!context) return;
563 device = context->Device;
564 if(LookupBuffer(device, buffer) == NULL)
565 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
567 if(!(values))
568 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
569 switch(param)
571 default:
572 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
575 done:
576 ALCcontext_DecRef(context);
580 AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value)
582 ALCdevice *device;
583 ALCcontext *context;
584 ALbuffer *albuf;
586 context = GetContextRef();
587 if(!context) return;
589 device = context->Device;
590 if((albuf=LookupBuffer(device, buffer)) == NULL)
591 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
593 switch(param)
595 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
596 if(!(value >= 0))
597 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
598 ExchangeInt(&albuf->UnpackAlign, value);
599 break;
601 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
602 if(!(value >= 0))
603 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
604 ExchangeInt(&albuf->PackAlign, value);
605 break;
607 default:
608 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
611 done:
612 ALCcontext_DecRef(context);
616 AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(value1), ALint UNUSED(value2), ALint UNUSED(value3))
618 ALCdevice *device;
619 ALCcontext *context;
621 context = GetContextRef();
622 if(!context) return;
624 device = context->Device;
625 if(LookupBuffer(device, buffer) == NULL)
626 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
628 switch(param)
630 default:
631 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
634 done:
635 ALCcontext_DecRef(context);
639 AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values)
641 ALCdevice *device;
642 ALCcontext *context;
643 ALbuffer *albuf;
645 if(values)
647 switch(param)
649 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
650 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
651 alBufferi(buffer, param, values[0]);
652 return;
656 context = GetContextRef();
657 if(!context) return;
659 device = context->Device;
660 if((albuf=LookupBuffer(device, buffer)) == NULL)
661 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
663 if(!(values))
664 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
665 switch(param)
667 case AL_LOOP_POINTS_SOFT:
668 WriteLock(&albuf->lock);
669 if(ReadRef(&albuf->ref) != 0)
671 WriteUnlock(&albuf->lock);
672 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
674 if(values[0] >= values[1] || values[0] < 0 ||
675 values[1] > albuf->SampleLen)
677 WriteUnlock(&albuf->lock);
678 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
681 albuf->LoopStart = values[0];
682 albuf->LoopEnd = values[1];
683 WriteUnlock(&albuf->lock);
684 break;
686 default:
687 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
690 done:
691 ALCcontext_DecRef(context);
695 AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value)
697 ALCdevice *device;
698 ALCcontext *context;
699 ALbuffer *albuf;
701 context = GetContextRef();
702 if(!context) return;
704 device = context->Device;
705 if((albuf=LookupBuffer(device, buffer)) == NULL)
706 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
708 if(!(value))
709 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
710 switch(param)
712 case AL_SEC_LENGTH_SOFT:
713 ReadLock(&albuf->lock);
714 if(albuf->SampleLen != 0)
715 *value = albuf->SampleLen / (ALfloat)albuf->Frequency;
716 else
717 *value = 0.0f;
718 ReadUnlock(&albuf->lock);
719 break;
721 default:
722 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
725 done:
726 ALCcontext_DecRef(context);
730 AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
732 ALCdevice *device;
733 ALCcontext *context;
735 context = GetContextRef();
736 if(!context) return;
738 device = context->Device;
739 if(LookupBuffer(device, buffer) == NULL)
740 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
742 if(!(value1 && value2 && value3))
743 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
744 switch(param)
746 default:
747 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
750 done:
751 ALCcontext_DecRef(context);
755 AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values)
757 ALCdevice *device;
758 ALCcontext *context;
760 switch(param)
762 case AL_SEC_LENGTH_SOFT:
763 alGetBufferf(buffer, param, values);
764 return;
767 context = GetContextRef();
768 if(!context) return;
770 device = context->Device;
771 if(LookupBuffer(device, buffer) == NULL)
772 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
774 if(!(values))
775 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
776 switch(param)
778 default:
779 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
782 done:
783 ALCcontext_DecRef(context);
787 AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value)
789 ALCdevice *device;
790 ALCcontext *context;
791 ALbuffer *albuf;
793 context = GetContextRef();
794 if(!context) return;
796 device = context->Device;
797 if((albuf=LookupBuffer(device, buffer)) == NULL)
798 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
800 if(!(value))
801 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
802 switch(param)
804 case AL_FREQUENCY:
805 *value = albuf->Frequency;
806 break;
808 case AL_BITS:
809 *value = BytesFromFmt(albuf->FmtType) * 8;
810 break;
812 case AL_CHANNELS:
813 *value = ChannelsFromFmt(albuf->FmtChannels);
814 break;
816 case AL_SIZE:
817 ReadLock(&albuf->lock);
818 *value = albuf->SampleLen * FrameSizeFromFmt(albuf->FmtChannels,
819 albuf->FmtType);
820 ReadUnlock(&albuf->lock);
821 break;
823 case AL_INTERNAL_FORMAT_SOFT:
824 *value = albuf->Format;
825 break;
827 case AL_BYTE_LENGTH_SOFT:
828 *value = albuf->OriginalSize;
829 break;
831 case AL_SAMPLE_LENGTH_SOFT:
832 *value = albuf->SampleLen;
833 break;
835 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
836 *value = albuf->UnpackAlign;
837 break;
839 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
840 *value = albuf->PackAlign;
841 break;
843 default:
844 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
847 done:
848 ALCcontext_DecRef(context);
852 AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3)
854 ALCdevice *device;
855 ALCcontext *context;
857 context = GetContextRef();
858 if(!context) return;
860 device = context->Device;
861 if(LookupBuffer(device, buffer) == NULL)
862 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
864 if(!(value1 && value2 && value3))
865 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
866 switch(param)
868 default:
869 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
872 done:
873 ALCcontext_DecRef(context);
877 AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values)
879 ALCdevice *device;
880 ALCcontext *context;
881 ALbuffer *albuf;
883 switch(param)
885 case AL_FREQUENCY:
886 case AL_BITS:
887 case AL_CHANNELS:
888 case AL_SIZE:
889 case AL_INTERNAL_FORMAT_SOFT:
890 case AL_BYTE_LENGTH_SOFT:
891 case AL_SAMPLE_LENGTH_SOFT:
892 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
893 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
894 alGetBufferi(buffer, param, values);
895 return;
898 context = GetContextRef();
899 if(!context) return;
901 device = context->Device;
902 if((albuf=LookupBuffer(device, buffer)) == NULL)
903 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
905 if(!(values))
906 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
907 switch(param)
909 case AL_LOOP_POINTS_SOFT:
910 ReadLock(&albuf->lock);
911 values[0] = albuf->LoopStart;
912 values[1] = albuf->LoopEnd;
913 ReadUnlock(&albuf->lock);
914 break;
916 default:
917 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
920 done:
921 ALCcontext_DecRef(context);
926 * LoadData
928 * Loads the specified data into the buffer, using the specified formats.
929 * Currently, the new format must have the same channel configuration as the
930 * original format.
932 ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc)
934 ALuint NewChannels, NewBytes;
935 enum FmtChannels DstChannels;
936 enum FmtType DstType;
937 ALuint64 newsize;
938 ALvoid *temp;
940 if(DecomposeFormat(NewFormat, &DstChannels, &DstType) == AL_FALSE ||
941 (long)SrcChannels != (long)DstChannels)
942 return AL_INVALID_ENUM;
944 NewChannels = ChannelsFromFmt(DstChannels);
945 NewBytes = BytesFromFmt(DstType);
947 newsize = frames;
948 newsize *= NewBytes;
949 newsize *= NewChannels;
950 if(newsize > INT_MAX)
951 return AL_OUT_OF_MEMORY;
953 WriteLock(&ALBuf->lock);
954 if(ReadRef(&ALBuf->ref) != 0)
956 WriteUnlock(&ALBuf->lock);
957 return AL_INVALID_OPERATION;
960 temp = realloc(ALBuf->data, (size_t)newsize);
961 if(!temp && newsize)
963 WriteUnlock(&ALBuf->lock);
964 return AL_OUT_OF_MEMORY;
966 ALBuf->data = temp;
968 if(data != NULL)
969 ConvertData(ALBuf->data, (enum UserFmtType)DstType, data, SrcType, NewChannels, frames, align);
971 if(storesrc)
973 ALBuf->OriginalChannels = SrcChannels;
974 ALBuf->OriginalType = SrcType;
975 if(SrcType == UserFmtIMA4)
977 ALsizei byte_align = ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels);
978 ALBuf->OriginalSize = frames / align * byte_align;
979 ALBuf->OriginalAlign = align;
981 else if(SrcType == UserFmtMSADPCM)
983 ALsizei byte_align = ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels);
984 ALBuf->OriginalSize = frames / align * byte_align;
985 ALBuf->OriginalAlign = align;
987 else
989 ALBuf->OriginalSize = frames * FrameSizeFromUserFmt(SrcChannels, SrcType);
990 ALBuf->OriginalAlign = 1;
993 else
995 ALBuf->OriginalChannels = (enum UserFmtChannels)DstChannels;
996 ALBuf->OriginalType = (enum UserFmtType)DstType;
997 ALBuf->OriginalSize = frames * NewBytes * NewChannels;
998 ALBuf->OriginalAlign = 1;
1001 ALBuf->Frequency = freq;
1002 ALBuf->FmtChannels = DstChannels;
1003 ALBuf->FmtType = DstType;
1004 ALBuf->Format = NewFormat;
1006 ALBuf->SampleLen = frames;
1007 ALBuf->LoopStart = 0;
1008 ALBuf->LoopEnd = ALBuf->SampleLen;
1010 WriteUnlock(&ALBuf->lock);
1011 return AL_NO_ERROR;
1015 ALuint BytesFromUserFmt(enum UserFmtType type)
1017 switch(type)
1019 case UserFmtByte: return sizeof(ALbyte);
1020 case UserFmtUByte: return sizeof(ALubyte);
1021 case UserFmtShort: return sizeof(ALshort);
1022 case UserFmtUShort: return sizeof(ALushort);
1023 case UserFmtInt: return sizeof(ALint);
1024 case UserFmtUInt: return sizeof(ALuint);
1025 case UserFmtFloat: return sizeof(ALfloat);
1026 case UserFmtDouble: return sizeof(ALdouble);
1027 case UserFmtByte3: return sizeof(ALbyte[3]);
1028 case UserFmtUByte3: return sizeof(ALubyte[3]);
1029 case UserFmtMulaw: return sizeof(ALubyte);
1030 case UserFmtAlaw: return sizeof(ALubyte);
1031 case UserFmtIMA4: break; /* not handled here */
1032 case UserFmtMSADPCM: break; /* not handled here */
1034 return 0;
1036 ALuint ChannelsFromUserFmt(enum UserFmtChannels chans)
1038 switch(chans)
1040 case UserFmtMono: return 1;
1041 case UserFmtStereo: return 2;
1042 case UserFmtRear: return 2;
1043 case UserFmtQuad: return 4;
1044 case UserFmtX51: return 6;
1045 case UserFmtX61: return 7;
1046 case UserFmtX71: return 8;
1048 return 0;
1050 static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
1051 enum UserFmtType *type)
1053 static const struct {
1054 ALenum format;
1055 enum UserFmtChannels channels;
1056 enum UserFmtType type;
1057 } list[] = {
1058 { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte },
1059 { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort },
1060 { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat },
1061 { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble },
1062 { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 },
1063 { AL_FORMAT_MONO_MSADPCM_SOFT, UserFmtMono, UserFmtMSADPCM },
1064 { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw },
1065 { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw },
1067 { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte },
1068 { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort },
1069 { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat },
1070 { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble },
1071 { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 },
1072 { AL_FORMAT_STEREO_MSADPCM_SOFT, UserFmtStereo, UserFmtMSADPCM },
1073 { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw },
1074 { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw },
1076 { AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte },
1077 { AL_FORMAT_REAR16, UserFmtRear, UserFmtShort },
1078 { AL_FORMAT_REAR32, UserFmtRear, UserFmtFloat },
1079 { AL_FORMAT_REAR_MULAW, UserFmtRear, UserFmtMulaw },
1081 { AL_FORMAT_QUAD8_LOKI, UserFmtQuad, UserFmtUByte },
1082 { AL_FORMAT_QUAD16_LOKI, UserFmtQuad, UserFmtShort },
1084 { AL_FORMAT_QUAD8, UserFmtQuad, UserFmtUByte },
1085 { AL_FORMAT_QUAD16, UserFmtQuad, UserFmtShort },
1086 { AL_FORMAT_QUAD32, UserFmtQuad, UserFmtFloat },
1087 { AL_FORMAT_QUAD_MULAW, UserFmtQuad, UserFmtMulaw },
1089 { AL_FORMAT_51CHN8, UserFmtX51, UserFmtUByte },
1090 { AL_FORMAT_51CHN16, UserFmtX51, UserFmtShort },
1091 { AL_FORMAT_51CHN32, UserFmtX51, UserFmtFloat },
1092 { AL_FORMAT_51CHN_MULAW, UserFmtX51, UserFmtMulaw },
1094 { AL_FORMAT_61CHN8, UserFmtX61, UserFmtUByte },
1095 { AL_FORMAT_61CHN16, UserFmtX61, UserFmtShort },
1096 { AL_FORMAT_61CHN32, UserFmtX61, UserFmtFloat },
1097 { AL_FORMAT_61CHN_MULAW, UserFmtX61, UserFmtMulaw },
1099 { AL_FORMAT_71CHN8, UserFmtX71, UserFmtUByte },
1100 { AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort },
1101 { AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat },
1102 { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw },
1104 ALuint i;
1106 for(i = 0;i < COUNTOF(list);i++)
1108 if(list[i].format == format)
1110 *chans = list[i].channels;
1111 *type = list[i].type;
1112 return AL_TRUE;
1116 return AL_FALSE;
1119 ALuint BytesFromFmt(enum FmtType type)
1121 switch(type)
1123 case FmtByte: return sizeof(ALbyte);
1124 case FmtShort: return sizeof(ALshort);
1125 case FmtFloat: return sizeof(ALfloat);
1127 return 0;
1129 ALuint ChannelsFromFmt(enum FmtChannels chans)
1131 switch(chans)
1133 case FmtMono: return 1;
1134 case FmtStereo: return 2;
1135 case FmtRear: return 2;
1136 case FmtQuad: return 4;
1137 case FmtX51: return 6;
1138 case FmtX61: return 7;
1139 case FmtX71: return 8;
1141 return 0;
1143 static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type)
1145 static const struct {
1146 ALenum format;
1147 enum FmtChannels channels;
1148 enum FmtType type;
1149 } list[] = {
1150 { AL_MONO8_SOFT, FmtMono, FmtByte },
1151 { AL_MONO16_SOFT, FmtMono, FmtShort },
1152 { AL_MONO32F_SOFT, FmtMono, FmtFloat },
1154 { AL_STEREO8_SOFT, FmtStereo, FmtByte },
1155 { AL_STEREO16_SOFT, FmtStereo, FmtShort },
1156 { AL_STEREO32F_SOFT, FmtStereo, FmtFloat },
1158 { AL_REAR8_SOFT, FmtRear, FmtByte },
1159 { AL_REAR16_SOFT, FmtRear, FmtShort },
1160 { AL_REAR32F_SOFT, FmtRear, FmtFloat },
1162 { AL_FORMAT_QUAD8_LOKI, FmtQuad, FmtByte },
1163 { AL_FORMAT_QUAD16_LOKI, FmtQuad, FmtShort },
1165 { AL_QUAD8_SOFT, FmtQuad, FmtByte },
1166 { AL_QUAD16_SOFT, FmtQuad, FmtShort },
1167 { AL_QUAD32F_SOFT, FmtQuad, FmtFloat },
1169 { AL_5POINT1_8_SOFT, FmtX51, FmtByte },
1170 { AL_5POINT1_16_SOFT, FmtX51, FmtShort },
1171 { AL_5POINT1_32F_SOFT, FmtX51, FmtFloat },
1173 { AL_6POINT1_8_SOFT, FmtX61, FmtByte },
1174 { AL_6POINT1_16_SOFT, FmtX61, FmtShort },
1175 { AL_6POINT1_32F_SOFT, FmtX61, FmtFloat },
1177 { AL_7POINT1_8_SOFT, FmtX71, FmtByte },
1178 { AL_7POINT1_16_SOFT, FmtX71, FmtShort },
1179 { AL_7POINT1_32F_SOFT, FmtX71, FmtFloat },
1181 ALuint i;
1183 for(i = 0;i < COUNTOF(list);i++)
1185 if(list[i].format == format)
1187 *chans = list[i].channels;
1188 *type = list[i].type;
1189 return AL_TRUE;
1193 return AL_FALSE;
1196 static ALboolean SanitizeAlignment(enum UserFmtType type, ALsizei *align)
1198 if(*align < 0)
1199 return AL_FALSE;
1201 if(*align == 0)
1203 if(type == UserFmtIMA4)
1205 /* Here is where things vary:
1206 * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
1207 * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
1209 *align = 65;
1211 else if(type == UserFmtMSADPCM)
1212 *align = 64;
1213 else
1214 *align = 1;
1215 return AL_TRUE;
1218 if(type == UserFmtIMA4)
1220 /* IMA4 block alignment must be a multiple of 8, plus 1. */
1221 return ((*align)&7) == 1;
1223 if(type == UserFmtMSADPCM)
1225 /* MSADPCM block alignment must be a multiple of 2. */
1226 /* FIXME: Too strict? Might only require align*channels to be a
1227 * multiple of 2. */
1228 return ((*align)&1) == 0;
1231 return AL_TRUE;
1235 static ALboolean IsValidType(ALenum type)
1237 switch(type)
1239 case AL_BYTE_SOFT:
1240 case AL_UNSIGNED_BYTE_SOFT:
1241 case AL_SHORT_SOFT:
1242 case AL_UNSIGNED_SHORT_SOFT:
1243 case AL_INT_SOFT:
1244 case AL_UNSIGNED_INT_SOFT:
1245 case AL_FLOAT_SOFT:
1246 case AL_DOUBLE_SOFT:
1247 case AL_BYTE3_SOFT:
1248 case AL_UNSIGNED_BYTE3_SOFT:
1249 return AL_TRUE;
1251 return AL_FALSE;
1254 static ALboolean IsValidChannels(ALenum channels)
1256 switch(channels)
1258 case AL_MONO_SOFT:
1259 case AL_STEREO_SOFT:
1260 case AL_REAR_SOFT:
1261 case AL_QUAD_SOFT:
1262 case AL_5POINT1_SOFT:
1263 case AL_6POINT1_SOFT:
1264 case AL_7POINT1_SOFT:
1265 return AL_TRUE;
1267 return AL_FALSE;
1271 ALbuffer *NewBuffer(ALCcontext *context)
1273 ALCdevice *device = context->Device;
1274 ALbuffer *buffer;
1275 ALenum err;
1277 buffer = calloc(1, sizeof(ALbuffer));
1278 if(!buffer)
1279 SET_ERROR_AND_RETURN_VALUE(context, AL_OUT_OF_MEMORY, NULL);
1280 RWLockInit(&buffer->lock);
1282 err = NewThunkEntry(&buffer->id);
1283 if(err == AL_NO_ERROR)
1284 err = InsertUIntMapEntry(&device->BufferMap, buffer->id, buffer);
1285 if(err != AL_NO_ERROR)
1287 FreeThunkEntry(buffer->id);
1288 memset(buffer, 0, sizeof(ALbuffer));
1289 free(buffer);
1291 SET_ERROR_AND_RETURN_VALUE(context, err, NULL);
1294 return buffer;
1297 void DeleteBuffer(ALCdevice *device, ALuint bufid)
1299 ALbuffer *buffer;
1301 if((buffer=RemoveBuffer(device, bufid)) == NULL)
1302 return;
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);