Move atomic method definitions to a separate common source
[openal-soft.git] / OpenAL32 / alBuffer.c
blob2d36898755cda0bf2edea453b74dac7f91184365
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(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 ALuint framesize;
162 ALenum newformat;
163 ALbuffer *albuf;
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 newformat = AL_FORMAT_MONO_FLOAT32;
208 switch(srcchannels)
210 case UserFmtMono: newformat = AL_FORMAT_MONO_FLOAT32; break;
211 case UserFmtStereo: newformat = AL_FORMAT_STEREO_FLOAT32; break;
212 case UserFmtRear: newformat = AL_FORMAT_REAR32; break;
213 case UserFmtQuad: newformat = AL_FORMAT_QUAD32; break;
214 case UserFmtX51: newformat = AL_FORMAT_51CHN32; break;
215 case UserFmtX61: newformat = AL_FORMAT_61CHN32; break;
216 case UserFmtX71: newformat = AL_FORMAT_71CHN32; break;
218 err = LoadData(albuf, freq, newformat, size/framesize*align,
219 srcchannels, srctype, data, align, AL_TRUE);
220 if(err != AL_NO_ERROR)
221 SET_ERROR_AND_GOTO(context, err, done);
222 break;
224 case UserFmtMulaw:
225 case UserFmtAlaw:
226 framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
227 if((size%framesize) != 0)
228 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
230 newformat = AL_FORMAT_MONO16;
231 switch(srcchannels)
233 case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
234 case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
235 case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
236 case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
237 case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
238 case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
239 case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
241 err = LoadData(albuf, freq, newformat, size/framesize*align,
242 srcchannels, srctype, data, align, AL_TRUE);
243 if(err != AL_NO_ERROR)
244 SET_ERROR_AND_GOTO(context, err, done);
245 break;
247 case UserFmtIMA4:
248 framesize = (align-1)/2 + 4;
249 framesize *= ChannelsFromUserFmt(srcchannels);
250 if((size%framesize) != 0)
251 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
253 newformat = AL_FORMAT_MONO16;
254 switch(srcchannels)
256 case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
257 case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
258 case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
259 case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
260 case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
261 case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
262 case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
264 err = LoadData(albuf, freq, newformat, size/framesize*align,
265 srcchannels, srctype, data, align, AL_TRUE);
266 if(err != AL_NO_ERROR)
267 SET_ERROR_AND_GOTO(context, err, done);
268 break;
270 case UserFmtMSADPCM:
271 framesize = (align-2)/2 + 7;
272 framesize *= ChannelsFromUserFmt(srcchannels);
273 if((size%framesize) != 0)
274 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
276 newformat = AL_FORMAT_MONO16;
277 switch(srcchannels)
279 case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
280 case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
281 case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
282 case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
283 case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
284 case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
285 case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
287 err = LoadData(albuf, freq, newformat, size/framesize*align,
288 srcchannels, srctype, data, align, AL_TRUE);
289 if(err != AL_NO_ERROR)
290 SET_ERROR_AND_GOTO(context, err, done);
291 break;
294 done:
295 ALCcontext_DecRef(context);
298 AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length)
300 enum UserFmtChannels srcchannels;
301 enum UserFmtType srctype;
302 ALCdevice *device;
303 ALCcontext *context;
304 ALbuffer *albuf;
305 ALuint byte_align;
306 ALuint channels;
307 ALuint bytes;
308 ALsizei align;
310 context = GetContextRef();
311 if(!context) return;
313 device = context->Device;
314 if((albuf=LookupBuffer(device, buffer)) == NULL)
315 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
316 if(!(length >= 0 && offset >= 0))
317 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
318 if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
319 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
321 WriteLock(&albuf->lock);
322 align = albuf->UnpackAlign;
323 if(SanitizeAlignment(srctype, &align) == AL_FALSE)
325 WriteUnlock(&albuf->lock);
326 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
328 if(srcchannels != albuf->OriginalChannels || srctype != albuf->OriginalType)
330 WriteUnlock(&albuf->lock);
331 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
333 if(align != albuf->OriginalAlign)
335 WriteUnlock(&albuf->lock);
336 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
339 if(albuf->OriginalType == UserFmtIMA4)
341 byte_align = (albuf->OriginalAlign-1)/2 + 4;
342 byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels);
344 else if(albuf->OriginalType == UserFmtMSADPCM)
346 byte_align = (albuf->OriginalAlign-2)/2 + 7;
347 byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels);
349 else
351 byte_align = albuf->OriginalAlign;
352 byte_align *= FrameSizeFromUserFmt(albuf->OriginalChannels,
353 albuf->OriginalType);
356 if(offset > albuf->OriginalSize || length > albuf->OriginalSize-offset ||
357 (offset%byte_align) != 0 || (length%byte_align) != 0)
359 WriteUnlock(&albuf->lock);
360 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
363 channels = ChannelsFromFmt(albuf->FmtChannels);
364 bytes = BytesFromFmt(albuf->FmtType);
365 /* offset -> byte offset, length -> sample count */
366 offset = offset/byte_align * channels*bytes;
367 length = length/byte_align * albuf->OriginalAlign;
369 ConvertData((char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
370 data, srctype, channels, length, align);
371 WriteUnlock(&albuf->lock);
373 done:
374 ALCcontext_DecRef(context);
378 AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer,
379 ALuint samplerate, ALenum internalformat, ALsizei samples,
380 ALenum channels, ALenum type, const ALvoid *data)
382 ALCdevice *device;
383 ALCcontext *context;
384 ALbuffer *albuf;
385 ALsizei align;
386 ALenum err;
388 context = GetContextRef();
389 if(!context) return;
391 device = context->Device;
392 if((albuf=LookupBuffer(device, buffer)) == NULL)
393 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
394 if(!(samples >= 0 && samplerate != 0))
395 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
396 if(IsValidType(type) == AL_FALSE || IsValidChannels(channels) == AL_FALSE)
397 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
399 align = albuf->UnpackAlign;
400 if(SanitizeAlignment(type, &align) == AL_FALSE)
401 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
402 if((samples%align) != 0)
403 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
405 err = LoadData(albuf, samplerate, internalformat, samples,
406 channels, type, data, align, AL_FALSE);
407 if(err != AL_NO_ERROR)
408 SET_ERROR_AND_GOTO(context, err, done);
410 done:
411 ALCcontext_DecRef(context);
414 AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer,
415 ALsizei offset, ALsizei samples,
416 ALenum channels, ALenum type, const ALvoid *data)
418 ALCdevice *device;
419 ALCcontext *context;
420 ALbuffer *albuf;
421 ALsizei align;
423 context = GetContextRef();
424 if(!context) return;
426 device = context->Device;
427 if((albuf=LookupBuffer(device, buffer)) == NULL)
428 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
429 if(!(samples >= 0 && offset >= 0))
430 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
431 if(IsValidType(type) == AL_FALSE)
432 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
434 WriteLock(&albuf->lock);
435 align = albuf->UnpackAlign;
436 if(SanitizeAlignment(type, &align) == AL_FALSE)
438 WriteUnlock(&albuf->lock);
439 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
441 if(channels != (ALenum)albuf->FmtChannels)
443 WriteUnlock(&albuf->lock);
444 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
446 if(offset > albuf->SampleLen || samples > albuf->SampleLen-offset)
448 WriteUnlock(&albuf->lock);
449 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
451 if((samples%align) != 0)
453 WriteUnlock(&albuf->lock);
454 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
457 /* offset -> byte offset */
458 offset *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType);
459 ConvertData((char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
460 data, type, ChannelsFromFmt(albuf->FmtChannels), samples, align);
461 WriteUnlock(&albuf->lock);
463 done:
464 ALCcontext_DecRef(context);
467 AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer,
468 ALsizei offset, ALsizei samples,
469 ALenum channels, ALenum type, ALvoid *data)
471 ALCdevice *device;
472 ALCcontext *context;
473 ALbuffer *albuf;
474 ALsizei align;
476 context = GetContextRef();
477 if(!context) return;
479 device = context->Device;
480 if((albuf=LookupBuffer(device, buffer)) == NULL)
481 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
482 if(!(samples >= 0 && offset >= 0))
483 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
484 if(IsValidType(type) == AL_FALSE)
485 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
487 ReadLock(&albuf->lock);
488 align = albuf->PackAlign;
489 if(SanitizeAlignment(type, &align) == AL_FALSE)
491 ReadUnlock(&albuf->lock);
492 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
494 if(channels != (ALenum)albuf->FmtChannels)
496 ReadUnlock(&albuf->lock);
497 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
499 if(offset > albuf->SampleLen || samples > albuf->SampleLen-offset)
501 ReadUnlock(&albuf->lock);
502 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
504 if((samples%align) != 0)
506 ReadUnlock(&albuf->lock);
507 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
510 /* offset -> byte offset */
511 offset *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType);
512 ConvertData(data, type, (char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
513 ChannelsFromFmt(albuf->FmtChannels), samples, align);
514 ReadUnlock(&albuf->lock);
516 done:
517 ALCcontext_DecRef(context);
520 AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format)
522 enum FmtChannels dstchannels;
523 enum FmtType dsttype;
524 ALCcontext *context;
525 ALboolean ret;
527 context = GetContextRef();
528 if(!context) return AL_FALSE;
530 ret = DecomposeFormat(format, &dstchannels, &dsttype);
532 ALCcontext_DecRef(context);
534 return ret;
538 AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(value))
540 ALCdevice *device;
541 ALCcontext *context;
543 context = GetContextRef();
544 if(!context) return;
546 device = context->Device;
547 if(LookupBuffer(device, buffer) == NULL)
548 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
550 switch(param)
552 default:
553 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
556 done:
557 ALCcontext_DecRef(context);
561 AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(value1), ALfloat UNUSED(value2), ALfloat UNUSED(value3))
563 ALCdevice *device;
564 ALCcontext *context;
566 context = GetContextRef();
567 if(!context) return;
569 device = context->Device;
570 if(LookupBuffer(device, buffer) == NULL)
571 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
573 switch(param)
575 default:
576 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
579 done:
580 ALCcontext_DecRef(context);
584 AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values)
586 ALCdevice *device;
587 ALCcontext *context;
589 context = GetContextRef();
590 if(!context) return;
592 device = context->Device;
593 if(LookupBuffer(device, buffer) == NULL)
594 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
596 if(!(values))
597 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
598 switch(param)
600 default:
601 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
604 done:
605 ALCcontext_DecRef(context);
609 AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value)
611 ALCdevice *device;
612 ALCcontext *context;
613 ALbuffer *albuf;
615 context = GetContextRef();
616 if(!context) return;
618 device = context->Device;
619 if((albuf=LookupBuffer(device, buffer)) == NULL)
620 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
622 switch(param)
624 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
625 if(!(value >= 0))
626 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
627 ExchangeInt(&albuf->UnpackAlign, value);
628 break;
630 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
631 if(!(value >= 0))
632 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
633 ExchangeInt(&albuf->PackAlign, value);
634 break;
636 default:
637 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
640 done:
641 ALCcontext_DecRef(context);
645 AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(value1), ALint UNUSED(value2), ALint UNUSED(value3))
647 ALCdevice *device;
648 ALCcontext *context;
650 context = GetContextRef();
651 if(!context) return;
653 device = context->Device;
654 if(LookupBuffer(device, buffer) == NULL)
655 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
657 switch(param)
659 default:
660 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
663 done:
664 ALCcontext_DecRef(context);
668 AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values)
670 ALCdevice *device;
671 ALCcontext *context;
672 ALbuffer *albuf;
674 if(values)
676 switch(param)
678 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
679 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
680 alBufferi(buffer, param, values[0]);
681 return;
685 context = GetContextRef();
686 if(!context) return;
688 device = context->Device;
689 if((albuf=LookupBuffer(device, buffer)) == NULL)
690 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
692 if(!(values))
693 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
694 switch(param)
696 case AL_LOOP_POINTS_SOFT:
697 WriteLock(&albuf->lock);
698 if(albuf->ref != 0)
700 WriteUnlock(&albuf->lock);
701 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
703 if(values[0] >= values[1] || values[0] < 0 ||
704 values[1] > albuf->SampleLen)
706 WriteUnlock(&albuf->lock);
707 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
710 albuf->LoopStart = values[0];
711 albuf->LoopEnd = values[1];
712 WriteUnlock(&albuf->lock);
713 break;
715 default:
716 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
719 done:
720 ALCcontext_DecRef(context);
724 AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value)
726 ALCdevice *device;
727 ALCcontext *context;
728 ALbuffer *albuf;
730 context = GetContextRef();
731 if(!context) return;
733 device = context->Device;
734 if((albuf=LookupBuffer(device, buffer)) == NULL)
735 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
737 if(!(value))
738 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
739 switch(param)
741 case AL_SEC_LENGTH_SOFT:
742 ReadLock(&albuf->lock);
743 if(albuf->SampleLen != 0)
744 *value = albuf->SampleLen / (ALfloat)albuf->Frequency;
745 else
746 *value = 0.0f;
747 ReadUnlock(&albuf->lock);
748 break;
750 default:
751 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
754 done:
755 ALCcontext_DecRef(context);
759 AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
761 ALCdevice *device;
762 ALCcontext *context;
764 context = GetContextRef();
765 if(!context) return;
767 device = context->Device;
768 if(LookupBuffer(device, buffer) == NULL)
769 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
771 if(!(value1 && value2 && value3))
772 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
773 switch(param)
775 default:
776 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
779 done:
780 ALCcontext_DecRef(context);
784 AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values)
786 ALCdevice *device;
787 ALCcontext *context;
789 switch(param)
791 case AL_SEC_LENGTH_SOFT:
792 alGetBufferf(buffer, param, values);
793 return;
796 context = GetContextRef();
797 if(!context) return;
799 device = context->Device;
800 if(LookupBuffer(device, buffer) == NULL)
801 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
803 if(!(values))
804 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
805 switch(param)
807 default:
808 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
811 done:
812 ALCcontext_DecRef(context);
816 AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value)
818 ALCdevice *device;
819 ALCcontext *context;
820 ALbuffer *albuf;
822 context = GetContextRef();
823 if(!context) return;
825 device = context->Device;
826 if((albuf=LookupBuffer(device, buffer)) == NULL)
827 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
829 if(!(value))
830 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
831 switch(param)
833 case AL_FREQUENCY:
834 *value = albuf->Frequency;
835 break;
837 case AL_BITS:
838 *value = BytesFromFmt(albuf->FmtType) * 8;
839 break;
841 case AL_CHANNELS:
842 *value = ChannelsFromFmt(albuf->FmtChannels);
843 break;
845 case AL_SIZE:
846 ReadLock(&albuf->lock);
847 *value = albuf->SampleLen * FrameSizeFromFmt(albuf->FmtChannels,
848 albuf->FmtType);
849 ReadUnlock(&albuf->lock);
850 break;
852 case AL_INTERNAL_FORMAT_SOFT:
853 *value = albuf->Format;
854 break;
856 case AL_BYTE_LENGTH_SOFT:
857 *value = albuf->OriginalSize;
858 break;
860 case AL_SAMPLE_LENGTH_SOFT:
861 *value = albuf->SampleLen;
862 break;
864 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
865 *value = albuf->UnpackAlign;
866 break;
868 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
869 *value = albuf->PackAlign;
870 break;
872 default:
873 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
876 done:
877 ALCcontext_DecRef(context);
881 AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3)
883 ALCdevice *device;
884 ALCcontext *context;
886 context = GetContextRef();
887 if(!context) return;
889 device = context->Device;
890 if(LookupBuffer(device, buffer) == NULL)
891 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
893 if(!(value1 && value2 && value3))
894 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
895 switch(param)
897 default:
898 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
901 done:
902 ALCcontext_DecRef(context);
906 AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values)
908 ALCdevice *device;
909 ALCcontext *context;
910 ALbuffer *albuf;
912 switch(param)
914 case AL_FREQUENCY:
915 case AL_BITS:
916 case AL_CHANNELS:
917 case AL_SIZE:
918 case AL_INTERNAL_FORMAT_SOFT:
919 case AL_BYTE_LENGTH_SOFT:
920 case AL_SAMPLE_LENGTH_SOFT:
921 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
922 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
923 alGetBufferi(buffer, param, values);
924 return;
927 context = GetContextRef();
928 if(!context) return;
930 device = context->Device;
931 if((albuf=LookupBuffer(device, buffer)) == NULL)
932 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
934 if(!(values))
935 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
936 switch(param)
938 case AL_LOOP_POINTS_SOFT:
939 ReadLock(&albuf->lock);
940 values[0] = albuf->LoopStart;
941 values[1] = albuf->LoopEnd;
942 ReadUnlock(&albuf->lock);
943 break;
945 default:
946 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
949 done:
950 ALCcontext_DecRef(context);
955 * LoadData
957 * Loads the specified data into the buffer, using the specified formats.
958 * Currently, the new format must have the same channel configuration as the
959 * original format.
961 static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc)
963 ALuint NewChannels, NewBytes;
964 enum FmtChannels DstChannels;
965 enum FmtType DstType;
966 ALuint64 newsize;
967 ALvoid *temp;
969 if(DecomposeFormat(NewFormat, &DstChannels, &DstType) == AL_FALSE ||
970 (long)SrcChannels != (long)DstChannels)
971 return AL_INVALID_ENUM;
973 NewChannels = ChannelsFromFmt(DstChannels);
974 NewBytes = BytesFromFmt(DstType);
976 newsize = frames;
977 newsize *= NewBytes;
978 newsize *= NewChannels;
979 if(newsize > INT_MAX)
980 return AL_OUT_OF_MEMORY;
982 WriteLock(&ALBuf->lock);
983 if(ALBuf->ref != 0)
985 WriteUnlock(&ALBuf->lock);
986 return AL_INVALID_OPERATION;
989 temp = realloc(ALBuf->data, (size_t)newsize);
990 if(!temp && newsize)
992 WriteUnlock(&ALBuf->lock);
993 return AL_OUT_OF_MEMORY;
995 ALBuf->data = temp;
997 if(data != NULL)
998 ConvertData(ALBuf->data, (enum UserFmtType)DstType, data, SrcType, NewChannels, frames, align);
1000 if(storesrc)
1002 ALBuf->OriginalChannels = SrcChannels;
1003 ALBuf->OriginalType = SrcType;
1004 if(SrcType == UserFmtIMA4)
1006 ALsizei byte_align = ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels);
1007 ALBuf->OriginalSize = frames / align * byte_align;
1008 ALBuf->OriginalAlign = align;
1010 else if(SrcType == UserFmtMSADPCM)
1012 ALsizei byte_align = ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels);
1013 ALBuf->OriginalSize = frames / align * byte_align;
1014 ALBuf->OriginalAlign = align;
1016 else
1018 ALBuf->OriginalSize = frames * FrameSizeFromUserFmt(SrcChannels, SrcType);
1019 ALBuf->OriginalAlign = 1;
1022 else
1024 ALBuf->OriginalChannels = (enum UserFmtChannels)DstChannels;
1025 ALBuf->OriginalType = (enum UserFmtType)DstType;
1026 ALBuf->OriginalSize = frames * NewBytes * NewChannels;
1027 ALBuf->OriginalAlign = 1;
1030 ALBuf->Frequency = freq;
1031 ALBuf->FmtChannels = DstChannels;
1032 ALBuf->FmtType = DstType;
1033 ALBuf->Format = NewFormat;
1035 ALBuf->SampleLen = frames;
1036 ALBuf->LoopStart = 0;
1037 ALBuf->LoopEnd = ALBuf->SampleLen;
1039 WriteUnlock(&ALBuf->lock);
1040 return AL_NO_ERROR;
1044 ALuint BytesFromUserFmt(enum UserFmtType type)
1046 switch(type)
1048 case UserFmtByte: return sizeof(ALbyte);
1049 case UserFmtUByte: return sizeof(ALubyte);
1050 case UserFmtShort: return sizeof(ALshort);
1051 case UserFmtUShort: return sizeof(ALushort);
1052 case UserFmtInt: return sizeof(ALint);
1053 case UserFmtUInt: return sizeof(ALuint);
1054 case UserFmtFloat: return sizeof(ALfloat);
1055 case UserFmtDouble: return sizeof(ALdouble);
1056 case UserFmtByte3: return sizeof(ALbyte[3]);
1057 case UserFmtUByte3: return sizeof(ALubyte[3]);
1058 case UserFmtMulaw: return sizeof(ALubyte);
1059 case UserFmtAlaw: return sizeof(ALubyte);
1060 case UserFmtIMA4: break; /* not handled here */
1061 case UserFmtMSADPCM: break; /* not handled here */
1063 return 0;
1065 ALuint ChannelsFromUserFmt(enum UserFmtChannels chans)
1067 switch(chans)
1069 case UserFmtMono: return 1;
1070 case UserFmtStereo: return 2;
1071 case UserFmtRear: return 2;
1072 case UserFmtQuad: return 4;
1073 case UserFmtX51: return 6;
1074 case UserFmtX61: return 7;
1075 case UserFmtX71: return 8;
1077 return 0;
1079 static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
1080 enum UserFmtType *type)
1082 static const struct {
1083 ALenum format;
1084 enum UserFmtChannels channels;
1085 enum UserFmtType type;
1086 } list[] = {
1087 { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte },
1088 { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort },
1089 { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat },
1090 { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble },
1091 { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 },
1092 { AL_FORMAT_MONO_MSADPCM_SOFT, UserFmtMono, UserFmtMSADPCM },
1093 { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw },
1094 { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw },
1096 { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte },
1097 { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort },
1098 { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat },
1099 { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble },
1100 { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 },
1101 { AL_FORMAT_STEREO_MSADPCM_SOFT, UserFmtStereo, UserFmtMSADPCM },
1102 { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw },
1103 { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw },
1105 { AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte },
1106 { AL_FORMAT_REAR16, UserFmtRear, UserFmtShort },
1107 { AL_FORMAT_REAR32, UserFmtRear, UserFmtFloat },
1108 { AL_FORMAT_REAR_MULAW, UserFmtRear, UserFmtMulaw },
1110 { AL_FORMAT_QUAD8_LOKI, UserFmtQuad, UserFmtUByte },
1111 { AL_FORMAT_QUAD16_LOKI, UserFmtQuad, UserFmtShort },
1113 { AL_FORMAT_QUAD8, UserFmtQuad, UserFmtUByte },
1114 { AL_FORMAT_QUAD16, UserFmtQuad, UserFmtShort },
1115 { AL_FORMAT_QUAD32, UserFmtQuad, UserFmtFloat },
1116 { AL_FORMAT_QUAD_MULAW, UserFmtQuad, UserFmtMulaw },
1118 { AL_FORMAT_51CHN8, UserFmtX51, UserFmtUByte },
1119 { AL_FORMAT_51CHN16, UserFmtX51, UserFmtShort },
1120 { AL_FORMAT_51CHN32, UserFmtX51, UserFmtFloat },
1121 { AL_FORMAT_51CHN_MULAW, UserFmtX51, UserFmtMulaw },
1123 { AL_FORMAT_61CHN8, UserFmtX61, UserFmtUByte },
1124 { AL_FORMAT_61CHN16, UserFmtX61, UserFmtShort },
1125 { AL_FORMAT_61CHN32, UserFmtX61, UserFmtFloat },
1126 { AL_FORMAT_61CHN_MULAW, UserFmtX61, UserFmtMulaw },
1128 { AL_FORMAT_71CHN8, UserFmtX71, UserFmtUByte },
1129 { AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort },
1130 { AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat },
1131 { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw },
1133 ALuint i;
1135 for(i = 0;i < COUNTOF(list);i++)
1137 if(list[i].format == format)
1139 *chans = list[i].channels;
1140 *type = list[i].type;
1141 return AL_TRUE;
1145 return AL_FALSE;
1148 ALuint BytesFromFmt(enum FmtType type)
1150 switch(type)
1152 case FmtByte: return sizeof(ALbyte);
1153 case FmtShort: return sizeof(ALshort);
1154 case FmtFloat: return sizeof(ALfloat);
1156 return 0;
1158 ALuint ChannelsFromFmt(enum FmtChannels chans)
1160 switch(chans)
1162 case FmtMono: return 1;
1163 case FmtStereo: return 2;
1164 case FmtRear: return 2;
1165 case FmtQuad: return 4;
1166 case FmtX51: return 6;
1167 case FmtX61: return 7;
1168 case FmtX71: return 8;
1170 return 0;
1172 static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type)
1174 static const struct {
1175 ALenum format;
1176 enum FmtChannels channels;
1177 enum FmtType type;
1178 } list[] = {
1179 { AL_MONO8_SOFT, FmtMono, FmtByte },
1180 { AL_MONO16_SOFT, FmtMono, FmtShort },
1181 { AL_MONO32F_SOFT, FmtMono, FmtFloat },
1183 { AL_STEREO8_SOFT, FmtStereo, FmtByte },
1184 { AL_STEREO16_SOFT, FmtStereo, FmtShort },
1185 { AL_STEREO32F_SOFT, FmtStereo, FmtFloat },
1187 { AL_REAR8_SOFT, FmtRear, FmtByte },
1188 { AL_REAR16_SOFT, FmtRear, FmtShort },
1189 { AL_REAR32F_SOFT, FmtRear, FmtFloat },
1191 { AL_FORMAT_QUAD8_LOKI, FmtQuad, FmtByte },
1192 { AL_FORMAT_QUAD16_LOKI, FmtQuad, FmtShort },
1194 { AL_QUAD8_SOFT, FmtQuad, FmtByte },
1195 { AL_QUAD16_SOFT, FmtQuad, FmtShort },
1196 { AL_QUAD32F_SOFT, FmtQuad, FmtFloat },
1198 { AL_5POINT1_8_SOFT, FmtX51, FmtByte },
1199 { AL_5POINT1_16_SOFT, FmtX51, FmtShort },
1200 { AL_5POINT1_32F_SOFT, FmtX51, FmtFloat },
1202 { AL_6POINT1_8_SOFT, FmtX61, FmtByte },
1203 { AL_6POINT1_16_SOFT, FmtX61, FmtShort },
1204 { AL_6POINT1_32F_SOFT, FmtX61, FmtFloat },
1206 { AL_7POINT1_8_SOFT, FmtX71, FmtByte },
1207 { AL_7POINT1_16_SOFT, FmtX71, FmtShort },
1208 { AL_7POINT1_32F_SOFT, FmtX71, FmtFloat },
1210 ALuint i;
1212 for(i = 0;i < COUNTOF(list);i++)
1214 if(list[i].format == format)
1216 *chans = list[i].channels;
1217 *type = list[i].type;
1218 return AL_TRUE;
1222 return AL_FALSE;
1225 static ALboolean SanitizeAlignment(enum UserFmtType type, ALsizei *align)
1227 if(*align < 0)
1228 return AL_FALSE;
1230 if(*align == 0)
1232 if(type == UserFmtIMA4)
1234 /* Here is where things vary:
1235 * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
1236 * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
1238 *align = 65;
1240 else if(type == UserFmtMSADPCM)
1241 *align = 64;
1242 else
1243 *align = 1;
1244 return AL_TRUE;
1247 if(type == UserFmtIMA4)
1249 /* IMA4 block alignment must be a multiple of 8, plus 1. */
1250 return ((*align)&7) == 1;
1252 if(type == UserFmtMSADPCM)
1254 /* MSADPCM block alignment must be a multiple of 2. */
1255 /* FIXME: Too strict? Might only require align*channels to be a
1256 * multiple of 2. */
1257 return ((*align)&1) == 0;
1260 return AL_TRUE;
1264 static ALboolean IsValidType(ALenum type)
1266 switch(type)
1268 case AL_BYTE_SOFT:
1269 case AL_UNSIGNED_BYTE_SOFT:
1270 case AL_SHORT_SOFT:
1271 case AL_UNSIGNED_SHORT_SOFT:
1272 case AL_INT_SOFT:
1273 case AL_UNSIGNED_INT_SOFT:
1274 case AL_FLOAT_SOFT:
1275 case AL_DOUBLE_SOFT:
1276 case AL_BYTE3_SOFT:
1277 case AL_UNSIGNED_BYTE3_SOFT:
1278 return AL_TRUE;
1280 return AL_FALSE;
1283 static ALboolean IsValidChannels(ALenum channels)
1285 switch(channels)
1287 case AL_MONO_SOFT:
1288 case AL_STEREO_SOFT:
1289 case AL_REAR_SOFT:
1290 case AL_QUAD_SOFT:
1291 case AL_5POINT1_SOFT:
1292 case AL_6POINT1_SOFT:
1293 case AL_7POINT1_SOFT:
1294 return AL_TRUE;
1296 return AL_FALSE;
1301 * ReleaseALBuffers()
1303 * INTERNAL: Called to destroy any buffers that still exist on the device
1305 ALvoid ReleaseALBuffers(ALCdevice *device)
1307 ALsizei i;
1308 for(i = 0;i < device->BufferMap.size;i++)
1310 ALbuffer *temp = device->BufferMap.array[i].value;
1311 device->BufferMap.array[i].value = NULL;
1313 free(temp->data);
1315 FreeThunkEntry(temp->id);
1316 memset(temp, 0, sizeof(ALbuffer));
1317 free(temp);