Check the current directory first for data files
[openal-soft.git] / OpenAL32 / alBuffer.c
blobd03f30a49b9cc2da4338cf37ec71d41ac3b1ff36
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 ALCcontext *context;
54 ALsizei cur = 0;
56 context = GetContextRef();
57 if(!context) return;
59 if(!(n >= 0))
60 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
62 for(cur = 0;cur < n;cur++)
64 ALbuffer *buffer = NewBuffer(context);
65 if(!buffer)
67 alDeleteBuffers(cur, buffers);
68 break;
71 buffers[cur] = buffer->id;
74 done:
75 ALCcontext_DecRef(context);
78 AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers)
80 ALCdevice *device;
81 ALCcontext *context;
82 ALbuffer *ALBuf;
83 ALsizei i;
85 context = GetContextRef();
86 if(!context) return;
88 if(!(n >= 0))
89 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
91 device = context->Device;
92 for(i = 0;i < n;i++)
94 if(!buffers[i])
95 continue;
97 /* Check for valid Buffer ID */
98 if((ALBuf=LookupBuffer(device, buffers[i])) == NULL)
99 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
100 if(ReadRef(&ALBuf->ref) != 0)
101 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
104 for(i = 0;i < n;i++)
106 if((ALBuf=LookupBuffer(device, buffers[i])) != NULL)
107 DeleteBuffer(device, ALBuf);
110 done:
111 ALCcontext_DecRef(context);
114 AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer)
116 ALCcontext *context;
117 ALboolean ret;
119 context = GetContextRef();
120 if(!context) return AL_FALSE;
122 ret = ((!buffer || LookupBuffer(context->Device, buffer)) ?
123 AL_TRUE : AL_FALSE);
125 ALCcontext_DecRef(context);
127 return ret;
131 AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq)
133 enum UserFmtChannels srcchannels;
134 enum UserFmtType srctype;
135 ALCdevice *device;
136 ALCcontext *context;
137 ALbuffer *albuf;
138 ALenum newformat = AL_NONE;
139 ALuint framesize;
140 ALsizei align;
141 ALenum err;
143 context = GetContextRef();
144 if(!context) return;
146 device = context->Device;
147 if((albuf=LookupBuffer(device, buffer)) == NULL)
148 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
149 if(!(size >= 0 && freq > 0))
150 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
151 if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
152 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
154 align = albuf->UnpackAlign;
155 if(SanitizeAlignment(srctype, &align) == AL_FALSE)
156 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
157 switch(srctype)
159 case UserFmtByte:
160 case UserFmtUByte:
161 case UserFmtShort:
162 case UserFmtUShort:
163 case UserFmtFloat:
164 framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
165 if((size%framesize) != 0)
166 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
168 err = LoadData(albuf, freq, format, size/framesize*align,
169 srcchannels, srctype, data, align, AL_TRUE);
170 if(err != AL_NO_ERROR)
171 SET_ERROR_AND_GOTO(context, err, done);
172 break;
174 case UserFmtInt:
175 case UserFmtUInt:
176 case UserFmtByte3:
177 case UserFmtUByte3:
178 case UserFmtDouble:
179 framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
180 if((size%framesize) != 0)
181 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
183 switch(srcchannels)
185 case UserFmtMono: newformat = AL_FORMAT_MONO_FLOAT32; break;
186 case UserFmtStereo: newformat = AL_FORMAT_STEREO_FLOAT32; break;
187 case UserFmtRear: newformat = AL_FORMAT_REAR32; break;
188 case UserFmtQuad: newformat = AL_FORMAT_QUAD32; break;
189 case UserFmtX51: newformat = AL_FORMAT_51CHN32; break;
190 case UserFmtX61: newformat = AL_FORMAT_61CHN32; break;
191 case UserFmtX71: newformat = AL_FORMAT_71CHN32; break;
193 err = LoadData(albuf, freq, newformat, size/framesize*align,
194 srcchannels, srctype, data, align, AL_TRUE);
195 if(err != AL_NO_ERROR)
196 SET_ERROR_AND_GOTO(context, err, done);
197 break;
199 case UserFmtMulaw:
200 case UserFmtAlaw:
201 framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
202 if((size%framesize) != 0)
203 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
205 switch(srcchannels)
207 case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
208 case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
209 case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
210 case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
211 case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
212 case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
213 case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
215 err = LoadData(albuf, freq, newformat, size/framesize*align,
216 srcchannels, srctype, data, align, AL_TRUE);
217 if(err != AL_NO_ERROR)
218 SET_ERROR_AND_GOTO(context, err, done);
219 break;
221 case UserFmtIMA4:
222 framesize = (align-1)/2 + 4;
223 framesize *= ChannelsFromUserFmt(srcchannels);
224 if((size%framesize) != 0)
225 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
227 switch(srcchannels)
229 case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
230 case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
231 case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
232 case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
233 case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
234 case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
235 case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
237 err = LoadData(albuf, freq, newformat, size/framesize*align,
238 srcchannels, srctype, data, align, AL_TRUE);
239 if(err != AL_NO_ERROR)
240 SET_ERROR_AND_GOTO(context, err, done);
241 break;
243 case UserFmtMSADPCM:
244 framesize = (align-2)/2 + 7;
245 framesize *= ChannelsFromUserFmt(srcchannels);
246 if((size%framesize) != 0)
247 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
249 switch(srcchannels)
251 case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
252 case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
253 case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
254 case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
255 case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
256 case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
257 case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
259 err = LoadData(albuf, freq, newformat, size/framesize*align,
260 srcchannels, srctype, data, align, AL_TRUE);
261 if(err != AL_NO_ERROR)
262 SET_ERROR_AND_GOTO(context, err, done);
263 break;
266 done:
267 ALCcontext_DecRef(context);
270 AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length)
272 enum UserFmtChannels srcchannels;
273 enum UserFmtType srctype;
274 ALCdevice *device;
275 ALCcontext *context;
276 ALbuffer *albuf;
277 ALuint byte_align;
278 ALuint channels;
279 ALuint bytes;
280 ALsizei align;
282 context = GetContextRef();
283 if(!context) return;
285 device = context->Device;
286 if((albuf=LookupBuffer(device, buffer)) == NULL)
287 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
288 if(!(length >= 0 && offset >= 0))
289 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
290 if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
291 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
293 WriteLock(&albuf->lock);
294 align = albuf->UnpackAlign;
295 if(SanitizeAlignment(srctype, &align) == AL_FALSE)
297 WriteUnlock(&albuf->lock);
298 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
300 if(srcchannels != albuf->OriginalChannels || srctype != albuf->OriginalType)
302 WriteUnlock(&albuf->lock);
303 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
305 if(align != albuf->OriginalAlign)
307 WriteUnlock(&albuf->lock);
308 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
311 if(albuf->OriginalType == UserFmtIMA4)
313 byte_align = (albuf->OriginalAlign-1)/2 + 4;
314 byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels);
316 else if(albuf->OriginalType == UserFmtMSADPCM)
318 byte_align = (albuf->OriginalAlign-2)/2 + 7;
319 byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels);
321 else
323 byte_align = albuf->OriginalAlign;
324 byte_align *= FrameSizeFromUserFmt(albuf->OriginalChannels,
325 albuf->OriginalType);
328 if(offset > albuf->OriginalSize || length > albuf->OriginalSize-offset ||
329 (offset%byte_align) != 0 || (length%byte_align) != 0)
331 WriteUnlock(&albuf->lock);
332 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
335 channels = ChannelsFromFmt(albuf->FmtChannels);
336 bytes = BytesFromFmt(albuf->FmtType);
337 /* offset -> byte offset, length -> sample count */
338 offset = offset/byte_align * channels*bytes;
339 length = length/byte_align * albuf->OriginalAlign;
341 ConvertData((char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
342 data, srctype, channels, length, align);
343 WriteUnlock(&albuf->lock);
345 done:
346 ALCcontext_DecRef(context);
350 AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer,
351 ALuint samplerate, ALenum internalformat, ALsizei samples,
352 ALenum channels, ALenum type, const ALvoid *data)
354 ALCdevice *device;
355 ALCcontext *context;
356 ALbuffer *albuf;
357 ALsizei align;
358 ALenum err;
360 context = GetContextRef();
361 if(!context) return;
363 device = context->Device;
364 if((albuf=LookupBuffer(device, buffer)) == NULL)
365 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
366 if(!(samples >= 0 && samplerate != 0))
367 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
368 if(IsValidType(type) == AL_FALSE || IsValidChannels(channels) == AL_FALSE)
369 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
371 align = albuf->UnpackAlign;
372 if(SanitizeAlignment(type, &align) == AL_FALSE)
373 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
374 if((samples%align) != 0)
375 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
377 err = LoadData(albuf, samplerate, internalformat, samples,
378 channels, type, data, align, AL_FALSE);
379 if(err != AL_NO_ERROR)
380 SET_ERROR_AND_GOTO(context, err, done);
382 done:
383 ALCcontext_DecRef(context);
386 AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer,
387 ALsizei offset, ALsizei samples,
388 ALenum channels, ALenum type, const ALvoid *data)
390 ALCdevice *device;
391 ALCcontext *context;
392 ALbuffer *albuf;
393 ALsizei align;
395 context = GetContextRef();
396 if(!context) return;
398 device = context->Device;
399 if((albuf=LookupBuffer(device, buffer)) == NULL)
400 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
401 if(!(samples >= 0 && offset >= 0))
402 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
403 if(IsValidType(type) == AL_FALSE)
404 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
406 WriteLock(&albuf->lock);
407 align = albuf->UnpackAlign;
408 if(SanitizeAlignment(type, &align) == AL_FALSE)
410 WriteUnlock(&albuf->lock);
411 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
413 if(channels != (ALenum)albuf->FmtChannels)
415 WriteUnlock(&albuf->lock);
416 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
418 if(offset > albuf->SampleLen || samples > albuf->SampleLen-offset)
420 WriteUnlock(&albuf->lock);
421 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
423 if((samples%align) != 0)
425 WriteUnlock(&albuf->lock);
426 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
429 /* offset -> byte offset */
430 offset *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType);
431 ConvertData((char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
432 data, type, ChannelsFromFmt(albuf->FmtChannels), samples, align);
433 WriteUnlock(&albuf->lock);
435 done:
436 ALCcontext_DecRef(context);
439 AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer,
440 ALsizei offset, ALsizei samples,
441 ALenum channels, ALenum type, ALvoid *data)
443 ALCdevice *device;
444 ALCcontext *context;
445 ALbuffer *albuf;
446 ALsizei align;
448 context = GetContextRef();
449 if(!context) return;
451 device = context->Device;
452 if((albuf=LookupBuffer(device, buffer)) == NULL)
453 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
454 if(!(samples >= 0 && offset >= 0))
455 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
456 if(IsValidType(type) == AL_FALSE)
457 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
459 ReadLock(&albuf->lock);
460 align = albuf->PackAlign;
461 if(SanitizeAlignment(type, &align) == AL_FALSE)
463 ReadUnlock(&albuf->lock);
464 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
466 if(channels != (ALenum)albuf->FmtChannels)
468 ReadUnlock(&albuf->lock);
469 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
471 if(offset > albuf->SampleLen || samples > albuf->SampleLen-offset)
473 ReadUnlock(&albuf->lock);
474 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
476 if((samples%align) != 0)
478 ReadUnlock(&albuf->lock);
479 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
482 /* offset -> byte offset */
483 offset *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType);
484 ConvertData(data, type, (char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
485 ChannelsFromFmt(albuf->FmtChannels), samples, align);
486 ReadUnlock(&albuf->lock);
488 done:
489 ALCcontext_DecRef(context);
492 AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format)
494 enum FmtChannels dstchannels;
495 enum FmtType dsttype;
496 ALCcontext *context;
497 ALboolean ret;
499 context = GetContextRef();
500 if(!context) return AL_FALSE;
502 ret = DecomposeFormat(format, &dstchannels, &dsttype);
504 ALCcontext_DecRef(context);
506 return ret;
510 AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(value))
512 ALCdevice *device;
513 ALCcontext *context;
515 context = GetContextRef();
516 if(!context) return;
518 device = context->Device;
519 if(LookupBuffer(device, buffer) == NULL)
520 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
522 switch(param)
524 default:
525 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
528 done:
529 ALCcontext_DecRef(context);
533 AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(value1), ALfloat UNUSED(value2), ALfloat UNUSED(value3))
535 ALCdevice *device;
536 ALCcontext *context;
538 context = GetContextRef();
539 if(!context) return;
541 device = context->Device;
542 if(LookupBuffer(device, buffer) == NULL)
543 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
545 switch(param)
547 default:
548 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
551 done:
552 ALCcontext_DecRef(context);
556 AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values)
558 ALCdevice *device;
559 ALCcontext *context;
561 context = GetContextRef();
562 if(!context) return;
564 device = context->Device;
565 if(LookupBuffer(device, buffer) == NULL)
566 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
568 if(!(values))
569 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
570 switch(param)
572 default:
573 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
576 done:
577 ALCcontext_DecRef(context);
581 AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value)
583 ALCdevice *device;
584 ALCcontext *context;
585 ALbuffer *albuf;
587 context = GetContextRef();
588 if(!context) return;
590 device = context->Device;
591 if((albuf=LookupBuffer(device, buffer)) == NULL)
592 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
594 switch(param)
596 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
597 if(!(value >= 0))
598 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
599 ExchangeInt(&albuf->UnpackAlign, value);
600 break;
602 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
603 if(!(value >= 0))
604 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
605 ExchangeInt(&albuf->PackAlign, value);
606 break;
608 default:
609 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
612 done:
613 ALCcontext_DecRef(context);
617 AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(value1), ALint UNUSED(value2), ALint UNUSED(value3))
619 ALCdevice *device;
620 ALCcontext *context;
622 context = GetContextRef();
623 if(!context) return;
625 device = context->Device;
626 if(LookupBuffer(device, buffer) == NULL)
627 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
629 switch(param)
631 default:
632 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
635 done:
636 ALCcontext_DecRef(context);
640 AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values)
642 ALCdevice *device;
643 ALCcontext *context;
644 ALbuffer *albuf;
646 if(values)
648 switch(param)
650 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
651 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
652 alBufferi(buffer, param, values[0]);
653 return;
657 context = GetContextRef();
658 if(!context) return;
660 device = context->Device;
661 if((albuf=LookupBuffer(device, buffer)) == NULL)
662 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
664 if(!(values))
665 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
666 switch(param)
668 case AL_LOOP_POINTS_SOFT:
669 WriteLock(&albuf->lock);
670 if(ReadRef(&albuf->ref) != 0)
672 WriteUnlock(&albuf->lock);
673 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
675 if(values[0] >= values[1] || values[0] < 0 ||
676 values[1] > albuf->SampleLen)
678 WriteUnlock(&albuf->lock);
679 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
682 albuf->LoopStart = values[0];
683 albuf->LoopEnd = values[1];
684 WriteUnlock(&albuf->lock);
685 break;
687 default:
688 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
691 done:
692 ALCcontext_DecRef(context);
696 AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value)
698 ALCdevice *device;
699 ALCcontext *context;
700 ALbuffer *albuf;
702 context = GetContextRef();
703 if(!context) return;
705 device = context->Device;
706 if((albuf=LookupBuffer(device, buffer)) == NULL)
707 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
709 if(!(value))
710 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
711 switch(param)
713 case AL_SEC_LENGTH_SOFT:
714 ReadLock(&albuf->lock);
715 if(albuf->SampleLen != 0)
716 *value = albuf->SampleLen / (ALfloat)albuf->Frequency;
717 else
718 *value = 0.0f;
719 ReadUnlock(&albuf->lock);
720 break;
722 default:
723 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
726 done:
727 ALCcontext_DecRef(context);
731 AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
733 ALCdevice *device;
734 ALCcontext *context;
736 context = GetContextRef();
737 if(!context) return;
739 device = context->Device;
740 if(LookupBuffer(device, buffer) == NULL)
741 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
743 if(!(value1 && value2 && value3))
744 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
745 switch(param)
747 default:
748 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
751 done:
752 ALCcontext_DecRef(context);
756 AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values)
758 ALCdevice *device;
759 ALCcontext *context;
761 switch(param)
763 case AL_SEC_LENGTH_SOFT:
764 alGetBufferf(buffer, param, values);
765 return;
768 context = GetContextRef();
769 if(!context) return;
771 device = context->Device;
772 if(LookupBuffer(device, buffer) == NULL)
773 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
775 if(!(values))
776 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
777 switch(param)
779 default:
780 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
783 done:
784 ALCcontext_DecRef(context);
788 AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value)
790 ALCdevice *device;
791 ALCcontext *context;
792 ALbuffer *albuf;
794 context = GetContextRef();
795 if(!context) return;
797 device = context->Device;
798 if((albuf=LookupBuffer(device, buffer)) == NULL)
799 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
801 if(!(value))
802 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
803 switch(param)
805 case AL_FREQUENCY:
806 *value = albuf->Frequency;
807 break;
809 case AL_BITS:
810 *value = BytesFromFmt(albuf->FmtType) * 8;
811 break;
813 case AL_CHANNELS:
814 *value = ChannelsFromFmt(albuf->FmtChannels);
815 break;
817 case AL_SIZE:
818 ReadLock(&albuf->lock);
819 *value = albuf->SampleLen * FrameSizeFromFmt(albuf->FmtChannels,
820 albuf->FmtType);
821 ReadUnlock(&albuf->lock);
822 break;
824 case AL_INTERNAL_FORMAT_SOFT:
825 *value = albuf->Format;
826 break;
828 case AL_BYTE_LENGTH_SOFT:
829 *value = albuf->OriginalSize;
830 break;
832 case AL_SAMPLE_LENGTH_SOFT:
833 *value = albuf->SampleLen;
834 break;
836 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
837 *value = albuf->UnpackAlign;
838 break;
840 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
841 *value = albuf->PackAlign;
842 break;
844 default:
845 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
848 done:
849 ALCcontext_DecRef(context);
853 AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3)
855 ALCdevice *device;
856 ALCcontext *context;
858 context = GetContextRef();
859 if(!context) return;
861 device = context->Device;
862 if(LookupBuffer(device, buffer) == NULL)
863 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
865 if(!(value1 && value2 && value3))
866 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
867 switch(param)
869 default:
870 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
873 done:
874 ALCcontext_DecRef(context);
878 AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values)
880 ALCdevice *device;
881 ALCcontext *context;
882 ALbuffer *albuf;
884 switch(param)
886 case AL_FREQUENCY:
887 case AL_BITS:
888 case AL_CHANNELS:
889 case AL_SIZE:
890 case AL_INTERNAL_FORMAT_SOFT:
891 case AL_BYTE_LENGTH_SOFT:
892 case AL_SAMPLE_LENGTH_SOFT:
893 case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
894 case AL_PACK_BLOCK_ALIGNMENT_SOFT:
895 alGetBufferi(buffer, param, values);
896 return;
899 context = GetContextRef();
900 if(!context) return;
902 device = context->Device;
903 if((albuf=LookupBuffer(device, buffer)) == NULL)
904 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
906 if(!(values))
907 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
908 switch(param)
910 case AL_LOOP_POINTS_SOFT:
911 ReadLock(&albuf->lock);
912 values[0] = albuf->LoopStart;
913 values[1] = albuf->LoopEnd;
914 ReadUnlock(&albuf->lock);
915 break;
917 default:
918 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
921 done:
922 ALCcontext_DecRef(context);
927 * LoadData
929 * Loads the specified data into the buffer, using the specified formats.
930 * Currently, the new format must have the same channel configuration as the
931 * original format.
933 ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc)
935 ALuint NewChannels, NewBytes;
936 enum FmtChannels DstChannels;
937 enum FmtType DstType;
938 ALuint64 newsize;
939 ALvoid *temp;
941 if(DecomposeFormat(NewFormat, &DstChannels, &DstType) == AL_FALSE ||
942 (long)SrcChannels != (long)DstChannels)
943 return AL_INVALID_ENUM;
945 NewChannels = ChannelsFromFmt(DstChannels);
946 NewBytes = BytesFromFmt(DstType);
948 newsize = frames;
949 newsize *= NewBytes;
950 newsize *= NewChannels;
951 if(newsize > INT_MAX)
952 return AL_OUT_OF_MEMORY;
954 WriteLock(&ALBuf->lock);
955 if(ReadRef(&ALBuf->ref) != 0)
957 WriteUnlock(&ALBuf->lock);
958 return AL_INVALID_OPERATION;
961 temp = realloc(ALBuf->data, (size_t)newsize);
962 if(!temp && newsize)
964 WriteUnlock(&ALBuf->lock);
965 return AL_OUT_OF_MEMORY;
967 ALBuf->data = temp;
969 if(data != NULL)
970 ConvertData(ALBuf->data, (enum UserFmtType)DstType, data, SrcType, NewChannels, frames, align);
972 if(storesrc)
974 ALBuf->OriginalChannels = SrcChannels;
975 ALBuf->OriginalType = SrcType;
976 if(SrcType == UserFmtIMA4)
978 ALsizei byte_align = ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels);
979 ALBuf->OriginalSize = frames / align * byte_align;
980 ALBuf->OriginalAlign = align;
982 else if(SrcType == UserFmtMSADPCM)
984 ALsizei byte_align = ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels);
985 ALBuf->OriginalSize = frames / align * byte_align;
986 ALBuf->OriginalAlign = align;
988 else
990 ALBuf->OriginalSize = frames * FrameSizeFromUserFmt(SrcChannels, SrcType);
991 ALBuf->OriginalAlign = 1;
994 else
996 ALBuf->OriginalChannels = (enum UserFmtChannels)DstChannels;
997 ALBuf->OriginalType = (enum UserFmtType)DstType;
998 ALBuf->OriginalSize = frames * NewBytes * NewChannels;
999 ALBuf->OriginalAlign = 1;
1002 ALBuf->Frequency = freq;
1003 ALBuf->FmtChannels = DstChannels;
1004 ALBuf->FmtType = DstType;
1005 ALBuf->Format = NewFormat;
1007 ALBuf->SampleLen = frames;
1008 ALBuf->LoopStart = 0;
1009 ALBuf->LoopEnd = ALBuf->SampleLen;
1011 WriteUnlock(&ALBuf->lock);
1012 return AL_NO_ERROR;
1016 ALuint BytesFromUserFmt(enum UserFmtType type)
1018 switch(type)
1020 case UserFmtByte: return sizeof(ALbyte);
1021 case UserFmtUByte: return sizeof(ALubyte);
1022 case UserFmtShort: return sizeof(ALshort);
1023 case UserFmtUShort: return sizeof(ALushort);
1024 case UserFmtInt: return sizeof(ALint);
1025 case UserFmtUInt: return sizeof(ALuint);
1026 case UserFmtFloat: return sizeof(ALfloat);
1027 case UserFmtDouble: return sizeof(ALdouble);
1028 case UserFmtByte3: return sizeof(ALbyte[3]);
1029 case UserFmtUByte3: return sizeof(ALubyte[3]);
1030 case UserFmtMulaw: return sizeof(ALubyte);
1031 case UserFmtAlaw: return sizeof(ALubyte);
1032 case UserFmtIMA4: break; /* not handled here */
1033 case UserFmtMSADPCM: break; /* not handled here */
1035 return 0;
1037 ALuint ChannelsFromUserFmt(enum UserFmtChannels chans)
1039 switch(chans)
1041 case UserFmtMono: return 1;
1042 case UserFmtStereo: return 2;
1043 case UserFmtRear: return 2;
1044 case UserFmtQuad: return 4;
1045 case UserFmtX51: return 6;
1046 case UserFmtX61: return 7;
1047 case UserFmtX71: return 8;
1049 return 0;
1051 static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
1052 enum UserFmtType *type)
1054 static const struct {
1055 ALenum format;
1056 enum UserFmtChannels channels;
1057 enum UserFmtType type;
1058 } list[] = {
1059 { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte },
1060 { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort },
1061 { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat },
1062 { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble },
1063 { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 },
1064 { AL_FORMAT_MONO_MSADPCM_SOFT, UserFmtMono, UserFmtMSADPCM },
1065 { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw },
1066 { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw },
1068 { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte },
1069 { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort },
1070 { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat },
1071 { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble },
1072 { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 },
1073 { AL_FORMAT_STEREO_MSADPCM_SOFT, UserFmtStereo, UserFmtMSADPCM },
1074 { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw },
1075 { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw },
1077 { AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte },
1078 { AL_FORMAT_REAR16, UserFmtRear, UserFmtShort },
1079 { AL_FORMAT_REAR32, UserFmtRear, UserFmtFloat },
1080 { AL_FORMAT_REAR_MULAW, UserFmtRear, UserFmtMulaw },
1082 { AL_FORMAT_QUAD8_LOKI, UserFmtQuad, UserFmtUByte },
1083 { AL_FORMAT_QUAD16_LOKI, UserFmtQuad, UserFmtShort },
1085 { AL_FORMAT_QUAD8, UserFmtQuad, UserFmtUByte },
1086 { AL_FORMAT_QUAD16, UserFmtQuad, UserFmtShort },
1087 { AL_FORMAT_QUAD32, UserFmtQuad, UserFmtFloat },
1088 { AL_FORMAT_QUAD_MULAW, UserFmtQuad, UserFmtMulaw },
1090 { AL_FORMAT_51CHN8, UserFmtX51, UserFmtUByte },
1091 { AL_FORMAT_51CHN16, UserFmtX51, UserFmtShort },
1092 { AL_FORMAT_51CHN32, UserFmtX51, UserFmtFloat },
1093 { AL_FORMAT_51CHN_MULAW, UserFmtX51, UserFmtMulaw },
1095 { AL_FORMAT_61CHN8, UserFmtX61, UserFmtUByte },
1096 { AL_FORMAT_61CHN16, UserFmtX61, UserFmtShort },
1097 { AL_FORMAT_61CHN32, UserFmtX61, UserFmtFloat },
1098 { AL_FORMAT_61CHN_MULAW, UserFmtX61, UserFmtMulaw },
1100 { AL_FORMAT_71CHN8, UserFmtX71, UserFmtUByte },
1101 { AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort },
1102 { AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat },
1103 { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw },
1105 ALuint i;
1107 for(i = 0;i < COUNTOF(list);i++)
1109 if(list[i].format == format)
1111 *chans = list[i].channels;
1112 *type = list[i].type;
1113 return AL_TRUE;
1117 return AL_FALSE;
1120 ALuint BytesFromFmt(enum FmtType type)
1122 switch(type)
1124 case FmtByte: return sizeof(ALbyte);
1125 case FmtShort: return sizeof(ALshort);
1126 case FmtFloat: return sizeof(ALfloat);
1128 return 0;
1130 ALuint ChannelsFromFmt(enum FmtChannels chans)
1132 switch(chans)
1134 case FmtMono: return 1;
1135 case FmtStereo: return 2;
1136 case FmtRear: return 2;
1137 case FmtQuad: return 4;
1138 case FmtX51: return 6;
1139 case FmtX61: return 7;
1140 case FmtX71: return 8;
1142 return 0;
1144 static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type)
1146 static const struct {
1147 ALenum format;
1148 enum FmtChannels channels;
1149 enum FmtType type;
1150 } list[] = {
1151 { AL_MONO8_SOFT, FmtMono, FmtByte },
1152 { AL_MONO16_SOFT, FmtMono, FmtShort },
1153 { AL_MONO32F_SOFT, FmtMono, FmtFloat },
1155 { AL_STEREO8_SOFT, FmtStereo, FmtByte },
1156 { AL_STEREO16_SOFT, FmtStereo, FmtShort },
1157 { AL_STEREO32F_SOFT, FmtStereo, FmtFloat },
1159 { AL_REAR8_SOFT, FmtRear, FmtByte },
1160 { AL_REAR16_SOFT, FmtRear, FmtShort },
1161 { AL_REAR32F_SOFT, FmtRear, FmtFloat },
1163 { AL_FORMAT_QUAD8_LOKI, FmtQuad, FmtByte },
1164 { AL_FORMAT_QUAD16_LOKI, FmtQuad, FmtShort },
1166 { AL_QUAD8_SOFT, FmtQuad, FmtByte },
1167 { AL_QUAD16_SOFT, FmtQuad, FmtShort },
1168 { AL_QUAD32F_SOFT, FmtQuad, FmtFloat },
1170 { AL_5POINT1_8_SOFT, FmtX51, FmtByte },
1171 { AL_5POINT1_16_SOFT, FmtX51, FmtShort },
1172 { AL_5POINT1_32F_SOFT, FmtX51, FmtFloat },
1174 { AL_6POINT1_8_SOFT, FmtX61, FmtByte },
1175 { AL_6POINT1_16_SOFT, FmtX61, FmtShort },
1176 { AL_6POINT1_32F_SOFT, FmtX61, FmtFloat },
1178 { AL_7POINT1_8_SOFT, FmtX71, FmtByte },
1179 { AL_7POINT1_16_SOFT, FmtX71, FmtShort },
1180 { AL_7POINT1_32F_SOFT, FmtX71, FmtFloat },
1182 ALuint i;
1184 for(i = 0;i < COUNTOF(list);i++)
1186 if(list[i].format == format)
1188 *chans = list[i].channels;
1189 *type = list[i].type;
1190 return AL_TRUE;
1194 return AL_FALSE;
1197 static ALboolean SanitizeAlignment(enum UserFmtType type, ALsizei *align)
1199 if(*align < 0)
1200 return AL_FALSE;
1202 if(*align == 0)
1204 if(type == UserFmtIMA4)
1206 /* Here is where things vary:
1207 * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
1208 * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
1210 *align = 65;
1212 else if(type == UserFmtMSADPCM)
1213 *align = 64;
1214 else
1215 *align = 1;
1216 return AL_TRUE;
1219 if(type == UserFmtIMA4)
1221 /* IMA4 block alignment must be a multiple of 8, plus 1. */
1222 return ((*align)&7) == 1;
1224 if(type == UserFmtMSADPCM)
1226 /* MSADPCM block alignment must be a multiple of 2. */
1227 /* FIXME: Too strict? Might only require align*channels to be a
1228 * multiple of 2. */
1229 return ((*align)&1) == 0;
1232 return AL_TRUE;
1236 static ALboolean IsValidType(ALenum type)
1238 switch(type)
1240 case AL_BYTE_SOFT:
1241 case AL_UNSIGNED_BYTE_SOFT:
1242 case AL_SHORT_SOFT:
1243 case AL_UNSIGNED_SHORT_SOFT:
1244 case AL_INT_SOFT:
1245 case AL_UNSIGNED_INT_SOFT:
1246 case AL_FLOAT_SOFT:
1247 case AL_DOUBLE_SOFT:
1248 case AL_BYTE3_SOFT:
1249 case AL_UNSIGNED_BYTE3_SOFT:
1250 return AL_TRUE;
1252 return AL_FALSE;
1255 static ALboolean IsValidChannels(ALenum channels)
1257 switch(channels)
1259 case AL_MONO_SOFT:
1260 case AL_STEREO_SOFT:
1261 case AL_REAR_SOFT:
1262 case AL_QUAD_SOFT:
1263 case AL_5POINT1_SOFT:
1264 case AL_6POINT1_SOFT:
1265 case AL_7POINT1_SOFT:
1266 return AL_TRUE;
1268 return AL_FALSE;
1272 ALbuffer *NewBuffer(ALCcontext *context)
1274 ALCdevice *device = context->Device;
1275 ALbuffer *buffer;
1276 ALenum err;
1278 buffer = calloc(1, sizeof(ALbuffer));
1279 if(!buffer)
1280 SET_ERROR_AND_RETURN_VALUE(context, AL_OUT_OF_MEMORY, NULL);
1281 RWLockInit(&buffer->lock);
1283 err = NewThunkEntry(&buffer->id);
1284 if(err == AL_NO_ERROR)
1285 err = InsertUIntMapEntry(&device->BufferMap, buffer->id, buffer);
1286 if(err != AL_NO_ERROR)
1288 FreeThunkEntry(buffer->id);
1289 memset(buffer, 0, sizeof(ALbuffer));
1290 free(buffer);
1292 SET_ERROR_AND_RETURN_VALUE(context, err, NULL);
1295 return buffer;
1298 void DeleteBuffer(ALCdevice *device, ALbuffer *buffer)
1300 RemoveBuffer(device, buffer->id);
1301 FreeThunkEntry(buffer->id);
1303 free(buffer->data);
1305 memset(buffer, 0, sizeof(*buffer));
1306 free(buffer);
1311 * ReleaseALBuffers()
1313 * INTERNAL: Called to destroy any buffers that still exist on the device
1315 ALvoid ReleaseALBuffers(ALCdevice *device)
1317 ALsizei i;
1318 for(i = 0;i < device->BufferMap.size;i++)
1320 ALbuffer *temp = device->BufferMap.array[i].value;
1321 device->BufferMap.array[i].value = NULL;
1323 free(temp->data);
1325 FreeThunkEntry(temp->id);
1326 memset(temp, 0, sizeof(ALbuffer));
1327 free(temp);