Ensure that LoopEnd > LoopStart
[openal-soft.git] / OpenAL32 / alBuffer.c
blobc7cfc7606f9816f765bbbaac653b0653c44cce6f
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 ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels chans, enum UserFmtType type, const ALvoid *data, ALsizei align, ALboolean storesrc);
45 static ALboolean IsValidType(ALenum type);
46 static ALboolean IsValidChannels(ALenum channels);
47 static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type);
48 static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type);
49 static ALboolean SanitizeAlignment(enum UserFmtType type, ALsizei *align);
52 AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers)
54 ALCdevice *device;
55 ALCcontext *context;
56 ALsizei cur = 0;
57 ALenum err;
59 context = GetContextRef();
60 if(!context) return;
62 if(!(n >= 0))
63 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
65 device = context->Device;
66 for(cur = 0;cur < n;cur++)
68 ALbuffer *buffer = calloc(1, sizeof(ALbuffer));
69 if(!buffer)
71 alDeleteBuffers(cur, buffers);
72 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
74 RWLockInit(&buffer->lock);
76 err = NewThunkEntry(&buffer->id);
77 if(err == AL_NO_ERROR)
78 err = InsertUIntMapEntry(&device->BufferMap, buffer->id, buffer);
79 if(err != AL_NO_ERROR)
81 FreeThunkEntry(buffer->id);
82 memset(buffer, 0, sizeof(ALbuffer));
83 free(buffer);
85 alDeleteBuffers(cur, buffers);
86 SET_ERROR_AND_GOTO(context, err, done);
89 buffers[cur] = buffer->id;
92 done:
93 ALCcontext_DecRef(context);
96 AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers)
98 ALCdevice *device;
99 ALCcontext *context;
100 ALbuffer *ALBuf;
101 ALsizei i;
103 context = GetContextRef();
104 if(!context) return;
106 if(!(n >= 0))
107 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
109 device = context->Device;
110 for(i = 0;i < n;i++)
112 if(!buffers[i])
113 continue;
115 /* Check for valid Buffer ID */
116 if((ALBuf=LookupBuffer(device, buffers[i])) == NULL)
117 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
118 if(ReadRef(&ALBuf->ref) != 0)
119 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
122 for(i = 0;i < n;i++)
124 if((ALBuf=RemoveBuffer(device, buffers[i])) == NULL)
125 continue;
126 FreeThunkEntry(ALBuf->id);
128 free(ALBuf->data);
130 memset(ALBuf, 0, sizeof(*ALBuf));
131 free(ALBuf);
134 done:
135 ALCcontext_DecRef(context);
138 AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer)
140 ALCcontext *context;
141 ALboolean ret;
143 context = GetContextRef();
144 if(!context) return AL_FALSE;
146 ret = ((!buffer || LookupBuffer(context->Device, buffer)) ?
147 AL_TRUE : AL_FALSE);
149 ALCcontext_DecRef(context);
151 return ret;
155 AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq)
157 enum UserFmtChannels srcchannels;
158 enum UserFmtType srctype;
159 ALCdevice *device;
160 ALCcontext *context;
161 ALbuffer *albuf;
162 ALenum newformat = AL_NONE;
163 ALuint framesize;
164 ALsizei align;
165 ALenum err;
167 context = GetContextRef();
168 if(!context) return;
170 device = context->Device;
171 if((albuf=LookupBuffer(device, buffer)) == NULL)
172 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
173 if(!(size >= 0 && freq > 0))
174 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
175 if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
176 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
178 align = albuf->UnpackAlign;
179 if(SanitizeAlignment(srctype, &align) == AL_FALSE)
180 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
181 switch(srctype)
183 case UserFmtByte:
184 case UserFmtUByte:
185 case UserFmtShort:
186 case UserFmtUShort:
187 case UserFmtFloat:
188 framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
189 if((size%framesize) != 0)
190 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
192 err = LoadData(albuf, freq, format, 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 UserFmtInt:
199 case UserFmtUInt:
200 case UserFmtByte3:
201 case UserFmtUByte3:
202 case UserFmtDouble:
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_MONO_FLOAT32; break;
210 case UserFmtStereo: newformat = AL_FORMAT_STEREO_FLOAT32; break;
211 case UserFmtRear: newformat = AL_FORMAT_REAR32; break;
212 case UserFmtQuad: newformat = AL_FORMAT_QUAD32; break;
213 case UserFmtX51: newformat = AL_FORMAT_51CHN32; break;
214 case UserFmtX61: newformat = AL_FORMAT_61CHN32; break;
215 case UserFmtX71: newformat = AL_FORMAT_71CHN32; 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 UserFmtMulaw:
224 case UserFmtAlaw:
225 framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
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 UserFmtIMA4:
246 framesize = (align-1)/2 + 4;
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;
267 case UserFmtMSADPCM:
268 framesize = (align-2)/2 + 7;
269 framesize *= ChannelsFromUserFmt(srcchannels);
270 if((size%framesize) != 0)
271 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
273 switch(srcchannels)
275 case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
276 case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
277 case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
278 case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
279 case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
280 case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
281 case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
283 err = LoadData(albuf, freq, newformat, size/framesize*align,
284 srcchannels, srctype, data, align, AL_TRUE);
285 if(err != AL_NO_ERROR)
286 SET_ERROR_AND_GOTO(context, err, done);
287 break;
290 done:
291 ALCcontext_DecRef(context);
294 AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length)
296 enum UserFmtChannels srcchannels;
297 enum UserFmtType srctype;
298 ALCdevice *device;
299 ALCcontext *context;
300 ALbuffer *albuf;
301 ALuint byte_align;
302 ALuint channels;
303 ALuint bytes;
304 ALsizei align;
306 context = GetContextRef();
307 if(!context) return;
309 device = context->Device;
310 if((albuf=LookupBuffer(device, buffer)) == NULL)
311 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
312 if(!(length >= 0 && offset >= 0))
313 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
314 if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
315 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
317 WriteLock(&albuf->lock);
318 align = albuf->UnpackAlign;
319 if(SanitizeAlignment(srctype, &align) == AL_FALSE)
321 WriteUnlock(&albuf->lock);
322 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
324 if(srcchannels != albuf->OriginalChannels || srctype != albuf->OriginalType)
326 WriteUnlock(&albuf->lock);
327 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
329 if(align != albuf->OriginalAlign)
331 WriteUnlock(&albuf->lock);
332 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
335 if(albuf->OriginalType == UserFmtIMA4)
337 byte_align = (albuf->OriginalAlign-1)/2 + 4;
338 byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels);
340 else if(albuf->OriginalType == UserFmtMSADPCM)
342 byte_align = (albuf->OriginalAlign-2)/2 + 7;
343 byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels);
345 else
347 byte_align = albuf->OriginalAlign;
348 byte_align *= FrameSizeFromUserFmt(albuf->OriginalChannels,
349 albuf->OriginalType);
352 if(offset > albuf->OriginalSize || length > albuf->OriginalSize-offset ||
353 (offset%byte_align) != 0 || (length%byte_align) != 0)
355 WriteUnlock(&albuf->lock);
356 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
359 channels = ChannelsFromFmt(albuf->FmtChannels);
360 bytes = BytesFromFmt(albuf->FmtType);
361 /* offset -> byte offset, length -> sample count */
362 offset = offset/byte_align * channels*bytes;
363 length = length/byte_align * albuf->OriginalAlign;
365 ConvertData((char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
366 data, srctype, channels, length, align);
367 WriteUnlock(&albuf->lock);
369 done:
370 ALCcontext_DecRef(context);
374 AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer,
375 ALuint samplerate, ALenum internalformat, ALsizei samples,
376 ALenum channels, ALenum type, const ALvoid *data)
378 ALCdevice *device;
379 ALCcontext *context;
380 ALbuffer *albuf;
381 ALsizei align;
382 ALenum err;
384 context = GetContextRef();
385 if(!context) return;
387 device = context->Device;
388 if((albuf=LookupBuffer(device, buffer)) == NULL)
389 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
390 if(!(samples >= 0 && samplerate != 0))
391 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
392 if(IsValidType(type) == AL_FALSE || IsValidChannels(channels) == AL_FALSE)
393 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
395 align = albuf->UnpackAlign;
396 if(SanitizeAlignment(type, &align) == AL_FALSE)
397 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
398 if((samples%align) != 0)
399 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
401 err = LoadData(albuf, samplerate, internalformat, samples,
402 channels, type, data, align, AL_FALSE);
403 if(err != AL_NO_ERROR)
404 SET_ERROR_AND_GOTO(context, err, done);
406 done:
407 ALCcontext_DecRef(context);
410 AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer,
411 ALsizei offset, ALsizei samples,
412 ALenum channels, ALenum type, const ALvoid *data)
414 ALCdevice *device;
415 ALCcontext *context;
416 ALbuffer *albuf;
417 ALsizei align;
419 context = GetContextRef();
420 if(!context) return;
422 device = context->Device;
423 if((albuf=LookupBuffer(device, buffer)) == NULL)
424 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
425 if(!(samples >= 0 && offset >= 0))
426 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
427 if(IsValidType(type) == AL_FALSE)
428 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
430 WriteLock(&albuf->lock);
431 align = albuf->UnpackAlign;
432 if(SanitizeAlignment(type, &align) == AL_FALSE)
434 WriteUnlock(&albuf->lock);
435 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
437 if(channels != (ALenum)albuf->FmtChannels)
439 WriteUnlock(&albuf->lock);
440 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
442 if(offset > albuf->SampleLen || samples > albuf->SampleLen-offset)
444 WriteUnlock(&albuf->lock);
445 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
447 if((samples%align) != 0)
449 WriteUnlock(&albuf->lock);
450 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
453 /* offset -> byte offset */
454 offset *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType);
455 ConvertData((char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
456 data, type, ChannelsFromFmt(albuf->FmtChannels), samples, align);
457 WriteUnlock(&albuf->lock);
459 done:
460 ALCcontext_DecRef(context);
463 AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer,
464 ALsizei offset, ALsizei samples,
465 ALenum channels, ALenum type, ALvoid *data)
467 ALCdevice *device;
468 ALCcontext *context;
469 ALbuffer *albuf;
470 ALsizei align;
472 context = GetContextRef();
473 if(!context) return;
475 device = context->Device;
476 if((albuf=LookupBuffer(device, buffer)) == NULL)
477 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
478 if(!(samples >= 0 && offset >= 0))
479 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
480 if(IsValidType(type) == AL_FALSE)
481 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
483 ReadLock(&albuf->lock);
484 align = albuf->PackAlign;
485 if(SanitizeAlignment(type, &align) == AL_FALSE)
487 ReadUnlock(&albuf->lock);
488 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
490 if(channels != (ALenum)albuf->FmtChannels)
492 ReadUnlock(&albuf->lock);
493 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
495 if(offset > albuf->SampleLen || samples > albuf->SampleLen-offset)
497 ReadUnlock(&albuf->lock);
498 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
500 if((samples%align) != 0)
502 ReadUnlock(&albuf->lock);
503 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
506 /* offset -> byte offset */
507 offset *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType);
508 ConvertData(data, type, (char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
509 ChannelsFromFmt(albuf->FmtChannels), samples, align);
510 ReadUnlock(&albuf->lock);
512 done:
513 ALCcontext_DecRef(context);
516 AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format)
518 enum FmtChannels dstchannels;
519 enum FmtType dsttype;
520 ALCcontext *context;
521 ALboolean ret;
523 context = GetContextRef();
524 if(!context) return AL_FALSE;
526 ret = DecomposeFormat(format, &dstchannels, &dsttype);
528 ALCcontext_DecRef(context);
530 return ret;
534 AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(value))
536 ALCdevice *device;
537 ALCcontext *context;
539 context = GetContextRef();
540 if(!context) return;
542 device = context->Device;
543 if(LookupBuffer(device, buffer) == NULL)
544 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
546 switch(param)
548 default:
549 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
552 done:
553 ALCcontext_DecRef(context);
557 AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(value1), ALfloat UNUSED(value2), ALfloat UNUSED(value3))
559 ALCdevice *device;
560 ALCcontext *context;
562 context = GetContextRef();
563 if(!context) return;
565 device = context->Device;
566 if(LookupBuffer(device, buffer) == NULL)
567 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, 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 alBufferfv(ALuint buffer, ALenum param, const ALfloat *values)
582 ALCdevice *device;
583 ALCcontext *context;
585 context = GetContextRef();
586 if(!context) return;
588 device = context->Device;
589 if(LookupBuffer(device, buffer) == NULL)
590 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
592 if(!(values))
593 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
594 switch(param)
596 default:
597 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
600 done:
601 ALCcontext_DecRef(context);
605 AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value)
607 ALCdevice *device;
608 ALCcontext *context;
609 ALbuffer *albuf;
611 context = GetContextRef();
612 if(!context) return;
614 device = context->Device;
615 if((albuf=LookupBuffer(device, buffer)) == NULL)
616 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
618 switch(param)
620 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
621 if(!(value >= 0))
622 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
623 ExchangeInt(&albuf->UnpackAlign, value);
624 break;
626 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
627 if(!(value >= 0))
628 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
629 ExchangeInt(&albuf->PackAlign, value);
630 break;
632 default:
633 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
636 done:
637 ALCcontext_DecRef(context);
641 AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(value1), ALint UNUSED(value2), ALint UNUSED(value3))
643 ALCdevice *device;
644 ALCcontext *context;
646 context = GetContextRef();
647 if(!context) return;
649 device = context->Device;
650 if(LookupBuffer(device, buffer) == NULL)
651 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
653 switch(param)
655 default:
656 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
659 done:
660 ALCcontext_DecRef(context);
664 AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values)
666 ALCdevice *device;
667 ALCcontext *context;
668 ALbuffer *albuf;
670 if(values)
672 switch(param)
674 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
675 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
676 alBufferi(buffer, param, values[0]);
677 return;
681 context = GetContextRef();
682 if(!context) return;
684 device = context->Device;
685 if((albuf=LookupBuffer(device, buffer)) == NULL)
686 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
688 if(!(values))
689 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
690 switch(param)
692 case AL_LOOP_POINTS_SOFT:
693 WriteLock(&albuf->lock);
694 if(ReadRef(&albuf->ref) != 0)
696 WriteUnlock(&albuf->lock);
697 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
699 if(values[0] >= values[1] || values[0] < 0 ||
700 values[1] > albuf->SampleLen)
702 WriteUnlock(&albuf->lock);
703 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
706 albuf->LoopStart = values[0];
707 albuf->LoopEnd = values[1];
708 WriteUnlock(&albuf->lock);
709 break;
711 default:
712 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
715 done:
716 ALCcontext_DecRef(context);
720 AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value)
722 ALCdevice *device;
723 ALCcontext *context;
724 ALbuffer *albuf;
726 context = GetContextRef();
727 if(!context) return;
729 device = context->Device;
730 if((albuf=LookupBuffer(device, buffer)) == NULL)
731 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
733 if(!(value))
734 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
735 switch(param)
737 case AL_SEC_LENGTH_SOFT:
738 ReadLock(&albuf->lock);
739 if(albuf->SampleLen != 0)
740 *value = albuf->SampleLen / (ALfloat)albuf->Frequency;
741 else
742 *value = 0.0f;
743 ReadUnlock(&albuf->lock);
744 break;
746 default:
747 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
750 done:
751 ALCcontext_DecRef(context);
755 AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
757 ALCdevice *device;
758 ALCcontext *context;
760 context = GetContextRef();
761 if(!context) return;
763 device = context->Device;
764 if(LookupBuffer(device, buffer) == NULL)
765 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
767 if(!(value1 && value2 && value3))
768 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
769 switch(param)
771 default:
772 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
775 done:
776 ALCcontext_DecRef(context);
780 AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values)
782 ALCdevice *device;
783 ALCcontext *context;
785 switch(param)
787 case AL_SEC_LENGTH_SOFT:
788 alGetBufferf(buffer, param, values);
789 return;
792 context = GetContextRef();
793 if(!context) return;
795 device = context->Device;
796 if(LookupBuffer(device, buffer) == NULL)
797 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
799 if(!(values))
800 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
801 switch(param)
803 default:
804 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
807 done:
808 ALCcontext_DecRef(context);
812 AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value)
814 ALCdevice *device;
815 ALCcontext *context;
816 ALbuffer *albuf;
818 context = GetContextRef();
819 if(!context) return;
821 device = context->Device;
822 if((albuf=LookupBuffer(device, buffer)) == NULL)
823 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
825 if(!(value))
826 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
827 switch(param)
829 case AL_FREQUENCY:
830 *value = albuf->Frequency;
831 break;
833 case AL_BITS:
834 *value = BytesFromFmt(albuf->FmtType) * 8;
835 break;
837 case AL_CHANNELS:
838 *value = ChannelsFromFmt(albuf->FmtChannels);
839 break;
841 case AL_SIZE:
842 ReadLock(&albuf->lock);
843 *value = albuf->SampleLen * FrameSizeFromFmt(albuf->FmtChannels,
844 albuf->FmtType);
845 ReadUnlock(&albuf->lock);
846 break;
848 case AL_INTERNAL_FORMAT_SOFT:
849 *value = albuf->Format;
850 break;
852 case AL_BYTE_LENGTH_SOFT:
853 *value = albuf->OriginalSize;
854 break;
856 case AL_SAMPLE_LENGTH_SOFT:
857 *value = albuf->SampleLen;
858 break;
860 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
861 *value = albuf->UnpackAlign;
862 break;
864 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
865 *value = albuf->PackAlign;
866 break;
868 default:
869 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
872 done:
873 ALCcontext_DecRef(context);
877 AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3)
879 ALCdevice *device;
880 ALCcontext *context;
882 context = GetContextRef();
883 if(!context) return;
885 device = context->Device;
886 if(LookupBuffer(device, buffer) == NULL)
887 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
889 if(!(value1 && value2 && value3))
890 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
891 switch(param)
893 default:
894 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
897 done:
898 ALCcontext_DecRef(context);
902 AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values)
904 ALCdevice *device;
905 ALCcontext *context;
906 ALbuffer *albuf;
908 switch(param)
910 case AL_FREQUENCY:
911 case AL_BITS:
912 case AL_CHANNELS:
913 case AL_SIZE:
914 case AL_INTERNAL_FORMAT_SOFT:
915 case AL_BYTE_LENGTH_SOFT:
916 case AL_SAMPLE_LENGTH_SOFT:
917 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
918 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
919 alGetBufferi(buffer, param, values);
920 return;
923 context = GetContextRef();
924 if(!context) return;
926 device = context->Device;
927 if((albuf=LookupBuffer(device, buffer)) == NULL)
928 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
930 if(!(values))
931 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
932 switch(param)
934 case AL_LOOP_POINTS_SOFT:
935 ReadLock(&albuf->lock);
936 values[0] = albuf->LoopStart;
937 values[1] = albuf->LoopEnd;
938 ReadUnlock(&albuf->lock);
939 break;
941 default:
942 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
945 done:
946 ALCcontext_DecRef(context);
951 * LoadData
953 * Loads the specified data into the buffer, using the specified formats.
954 * Currently, the new format must have the same channel configuration as the
955 * original format.
957 static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc)
959 ALuint NewChannels, NewBytes;
960 enum FmtChannels DstChannels;
961 enum FmtType DstType;
962 ALuint64 newsize;
963 ALvoid *temp;
965 if(DecomposeFormat(NewFormat, &DstChannels, &DstType) == AL_FALSE ||
966 (long)SrcChannels != (long)DstChannels)
967 return AL_INVALID_ENUM;
969 NewChannels = ChannelsFromFmt(DstChannels);
970 NewBytes = BytesFromFmt(DstType);
972 newsize = frames;
973 newsize *= NewBytes;
974 newsize *= NewChannels;
975 if(newsize > INT_MAX)
976 return AL_OUT_OF_MEMORY;
978 WriteLock(&ALBuf->lock);
979 if(ReadRef(&ALBuf->ref) != 0)
981 WriteUnlock(&ALBuf->lock);
982 return AL_INVALID_OPERATION;
985 temp = realloc(ALBuf->data, (size_t)newsize);
986 if(!temp && newsize)
988 WriteUnlock(&ALBuf->lock);
989 return AL_OUT_OF_MEMORY;
991 ALBuf->data = temp;
993 if(data != NULL)
994 ConvertData(ALBuf->data, (enum UserFmtType)DstType, data, SrcType, NewChannels, frames, align);
996 if(storesrc)
998 ALBuf->OriginalChannels = SrcChannels;
999 ALBuf->OriginalType = SrcType;
1000 if(SrcType == UserFmtIMA4)
1002 ALsizei byte_align = ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels);
1003 ALBuf->OriginalSize = frames / align * byte_align;
1004 ALBuf->OriginalAlign = align;
1006 else if(SrcType == UserFmtMSADPCM)
1008 ALsizei byte_align = ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels);
1009 ALBuf->OriginalSize = frames / align * byte_align;
1010 ALBuf->OriginalAlign = align;
1012 else
1014 ALBuf->OriginalSize = frames * FrameSizeFromUserFmt(SrcChannels, SrcType);
1015 ALBuf->OriginalAlign = 1;
1018 else
1020 ALBuf->OriginalChannels = (enum UserFmtChannels)DstChannels;
1021 ALBuf->OriginalType = (enum UserFmtType)DstType;
1022 ALBuf->OriginalSize = frames * NewBytes * NewChannels;
1023 ALBuf->OriginalAlign = 1;
1026 ALBuf->Frequency = freq;
1027 ALBuf->FmtChannels = DstChannels;
1028 ALBuf->FmtType = DstType;
1029 ALBuf->Format = NewFormat;
1031 ALBuf->SampleLen = frames;
1032 ALBuf->LoopStart = 0;
1033 ALBuf->LoopEnd = ALBuf->SampleLen;
1035 WriteUnlock(&ALBuf->lock);
1036 return AL_NO_ERROR;
1040 ALuint BytesFromUserFmt(enum UserFmtType type)
1042 switch(type)
1044 case UserFmtByte: return sizeof(ALbyte);
1045 case UserFmtUByte: return sizeof(ALubyte);
1046 case UserFmtShort: return sizeof(ALshort);
1047 case UserFmtUShort: return sizeof(ALushort);
1048 case UserFmtInt: return sizeof(ALint);
1049 case UserFmtUInt: return sizeof(ALuint);
1050 case UserFmtFloat: return sizeof(ALfloat);
1051 case UserFmtDouble: return sizeof(ALdouble);
1052 case UserFmtByte3: return sizeof(ALbyte[3]);
1053 case UserFmtUByte3: return sizeof(ALubyte[3]);
1054 case UserFmtMulaw: return sizeof(ALubyte);
1055 case UserFmtAlaw: return sizeof(ALubyte);
1056 case UserFmtIMA4: break; /* not handled here */
1057 case UserFmtMSADPCM: break; /* not handled here */
1059 return 0;
1061 ALuint ChannelsFromUserFmt(enum UserFmtChannels chans)
1063 switch(chans)
1065 case UserFmtMono: return 1;
1066 case UserFmtStereo: return 2;
1067 case UserFmtRear: return 2;
1068 case UserFmtQuad: return 4;
1069 case UserFmtX51: return 6;
1070 case UserFmtX61: return 7;
1071 case UserFmtX71: return 8;
1073 return 0;
1075 static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
1076 enum UserFmtType *type)
1078 static const struct {
1079 ALenum format;
1080 enum UserFmtChannels channels;
1081 enum UserFmtType type;
1082 } list[] = {
1083 { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte },
1084 { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort },
1085 { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat },
1086 { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble },
1087 { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 },
1088 { AL_FORMAT_MONO_MSADPCM_SOFT, UserFmtMono, UserFmtMSADPCM },
1089 { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw },
1090 { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw },
1092 { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte },
1093 { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort },
1094 { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat },
1095 { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble },
1096 { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 },
1097 { AL_FORMAT_STEREO_MSADPCM_SOFT, UserFmtStereo, UserFmtMSADPCM },
1098 { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw },
1099 { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw },
1101 { AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte },
1102 { AL_FORMAT_REAR16, UserFmtRear, UserFmtShort },
1103 { AL_FORMAT_REAR32, UserFmtRear, UserFmtFloat },
1104 { AL_FORMAT_REAR_MULAW, UserFmtRear, UserFmtMulaw },
1106 { AL_FORMAT_QUAD8_LOKI, UserFmtQuad, UserFmtUByte },
1107 { AL_FORMAT_QUAD16_LOKI, UserFmtQuad, UserFmtShort },
1109 { AL_FORMAT_QUAD8, UserFmtQuad, UserFmtUByte },
1110 { AL_FORMAT_QUAD16, UserFmtQuad, UserFmtShort },
1111 { AL_FORMAT_QUAD32, UserFmtQuad, UserFmtFloat },
1112 { AL_FORMAT_QUAD_MULAW, UserFmtQuad, UserFmtMulaw },
1114 { AL_FORMAT_51CHN8, UserFmtX51, UserFmtUByte },
1115 { AL_FORMAT_51CHN16, UserFmtX51, UserFmtShort },
1116 { AL_FORMAT_51CHN32, UserFmtX51, UserFmtFloat },
1117 { AL_FORMAT_51CHN_MULAW, UserFmtX51, UserFmtMulaw },
1119 { AL_FORMAT_61CHN8, UserFmtX61, UserFmtUByte },
1120 { AL_FORMAT_61CHN16, UserFmtX61, UserFmtShort },
1121 { AL_FORMAT_61CHN32, UserFmtX61, UserFmtFloat },
1122 { AL_FORMAT_61CHN_MULAW, UserFmtX61, UserFmtMulaw },
1124 { AL_FORMAT_71CHN8, UserFmtX71, UserFmtUByte },
1125 { AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort },
1126 { AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat },
1127 { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw },
1129 ALuint i;
1131 for(i = 0;i < COUNTOF(list);i++)
1133 if(list[i].format == format)
1135 *chans = list[i].channels;
1136 *type = list[i].type;
1137 return AL_TRUE;
1141 return AL_FALSE;
1144 ALuint BytesFromFmt(enum FmtType type)
1146 switch(type)
1148 case FmtByte: return sizeof(ALbyte);
1149 case FmtShort: return sizeof(ALshort);
1150 case FmtFloat: return sizeof(ALfloat);
1152 return 0;
1154 ALuint ChannelsFromFmt(enum FmtChannels chans)
1156 switch(chans)
1158 case FmtMono: return 1;
1159 case FmtStereo: return 2;
1160 case FmtRear: return 2;
1161 case FmtQuad: return 4;
1162 case FmtX51: return 6;
1163 case FmtX61: return 7;
1164 case FmtX71: return 8;
1166 return 0;
1168 static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type)
1170 static const struct {
1171 ALenum format;
1172 enum FmtChannels channels;
1173 enum FmtType type;
1174 } list[] = {
1175 { AL_MONO8_SOFT, FmtMono, FmtByte },
1176 { AL_MONO16_SOFT, FmtMono, FmtShort },
1177 { AL_MONO32F_SOFT, FmtMono, FmtFloat },
1179 { AL_STEREO8_SOFT, FmtStereo, FmtByte },
1180 { AL_STEREO16_SOFT, FmtStereo, FmtShort },
1181 { AL_STEREO32F_SOFT, FmtStereo, FmtFloat },
1183 { AL_REAR8_SOFT, FmtRear, FmtByte },
1184 { AL_REAR16_SOFT, FmtRear, FmtShort },
1185 { AL_REAR32F_SOFT, FmtRear, FmtFloat },
1187 { AL_FORMAT_QUAD8_LOKI, FmtQuad, FmtByte },
1188 { AL_FORMAT_QUAD16_LOKI, FmtQuad, FmtShort },
1190 { AL_QUAD8_SOFT, FmtQuad, FmtByte },
1191 { AL_QUAD16_SOFT, FmtQuad, FmtShort },
1192 { AL_QUAD32F_SOFT, FmtQuad, FmtFloat },
1194 { AL_5POINT1_8_SOFT, FmtX51, FmtByte },
1195 { AL_5POINT1_16_SOFT, FmtX51, FmtShort },
1196 { AL_5POINT1_32F_SOFT, FmtX51, FmtFloat },
1198 { AL_6POINT1_8_SOFT, FmtX61, FmtByte },
1199 { AL_6POINT1_16_SOFT, FmtX61, FmtShort },
1200 { AL_6POINT1_32F_SOFT, FmtX61, FmtFloat },
1202 { AL_7POINT1_8_SOFT, FmtX71, FmtByte },
1203 { AL_7POINT1_16_SOFT, FmtX71, FmtShort },
1204 { AL_7POINT1_32F_SOFT, FmtX71, FmtFloat },
1206 ALuint i;
1208 for(i = 0;i < COUNTOF(list);i++)
1210 if(list[i].format == format)
1212 *chans = list[i].channels;
1213 *type = list[i].type;
1214 return AL_TRUE;
1218 return AL_FALSE;
1221 static ALboolean SanitizeAlignment(enum UserFmtType type, ALsizei *align)
1223 if(*align < 0)
1224 return AL_FALSE;
1226 if(*align == 0)
1228 if(type == UserFmtIMA4)
1230 /* Here is where things vary:
1231 * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
1232 * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
1234 *align = 65;
1236 else if(type == UserFmtMSADPCM)
1237 *align = 64;
1238 else
1239 *align = 1;
1240 return AL_TRUE;
1243 if(type == UserFmtIMA4)
1245 /* IMA4 block alignment must be a multiple of 8, plus 1. */
1246 return ((*align)&7) == 1;
1248 if(type == UserFmtMSADPCM)
1250 /* MSADPCM block alignment must be a multiple of 2. */
1251 /* FIXME: Too strict? Might only require align*channels to be a
1252 * multiple of 2. */
1253 return ((*align)&1) == 0;
1256 return AL_TRUE;
1260 static ALboolean IsValidType(ALenum type)
1262 switch(type)
1264 case AL_BYTE_SOFT:
1265 case AL_UNSIGNED_BYTE_SOFT:
1266 case AL_SHORT_SOFT:
1267 case AL_UNSIGNED_SHORT_SOFT:
1268 case AL_INT_SOFT:
1269 case AL_UNSIGNED_INT_SOFT:
1270 case AL_FLOAT_SOFT:
1271 case AL_DOUBLE_SOFT:
1272 case AL_BYTE3_SOFT:
1273 case AL_UNSIGNED_BYTE3_SOFT:
1274 return AL_TRUE;
1276 return AL_FALSE;
1279 static ALboolean IsValidChannels(ALenum channels)
1281 switch(channels)
1283 case AL_MONO_SOFT:
1284 case AL_STEREO_SOFT:
1285 case AL_REAR_SOFT:
1286 case AL_QUAD_SOFT:
1287 case AL_5POINT1_SOFT:
1288 case AL_6POINT1_SOFT:
1289 case AL_7POINT1_SOFT:
1290 return AL_TRUE;
1292 return AL_FALSE;
1297 * ReleaseALBuffers()
1299 * INTERNAL: Called to destroy any buffers that still exist on the device
1301 ALvoid ReleaseALBuffers(ALCdevice *device)
1303 ALsizei i;
1304 for(i = 0;i < device->BufferMap.size;i++)
1306 ALbuffer *temp = device->BufferMap.array[i].value;
1307 device->BufferMap.array[i].value = NULL;
1309 free(temp->data);
1311 FreeThunkEntry(temp->id);
1312 memset(temp, 0, sizeof(ALbuffer));
1313 free(temp);