2007-11-14 02:02:18 +00:00
|
|
|
/**
|
|
|
|
* OpenAL cross platform audio library
|
|
|
|
* Copyright (C) 1999-2007 by authors.
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the
|
2014-08-18 12:11:03 +00:00
|
|
|
* Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2007-11-14 02:02:18 +00:00
|
|
|
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
|
|
|
*/
|
|
|
|
|
2008-01-16 22:09:04 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2007-11-14 02:02:18 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
2008-01-06 09:15:44 +00:00
|
|
|
#include <assert.h>
|
2010-05-25 00:08:12 +00:00
|
|
|
#include <limits.h>
|
2014-03-04 04:02:15 +00:00
|
|
|
#ifdef HAVE_MALLOC_H
|
|
|
|
#include <malloc.h>
|
|
|
|
#endif
|
2010-05-25 00:08:12 +00:00
|
|
|
|
2007-11-14 02:02:18 +00:00
|
|
|
#include "alMain.h"
|
2012-09-14 09:14:29 +00:00
|
|
|
#include "alu.h"
|
2007-11-14 02:02:18 +00:00
|
|
|
#include "alError.h"
|
|
|
|
#include "alBuffer.h"
|
2007-12-31 09:09:57 +00:00
|
|
|
#include "alThunk.h"
|
2014-03-06 00:17:47 +00:00
|
|
|
#include "sample_cvt.h"
|
2007-11-14 02:02:18 +00:00
|
|
|
|
|
|
|
|
2016-05-11 06:42:44 +00:00
|
|
|
extern inline void LockBuffersRead(ALCdevice *device);
|
|
|
|
extern inline void UnlockBuffersRead(ALCdevice *device);
|
2018-01-27 05:11:12 +00:00
|
|
|
extern inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id);
|
2017-01-18 15:13:23 +00:00
|
|
|
extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type);
|
|
|
|
extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type);
|
2013-11-04 20:12:31 +00:00
|
|
|
|
2018-01-26 21:34:59 +00:00
|
|
|
static const ALchar *NameFromUserFmtType(enum UserFmtType type);
|
|
|
|
static void LoadData(ALCcontext *context, ALbuffer *buffer, ALuint freq, ALsizei size,
|
2018-01-24 20:45:56 +00:00
|
|
|
enum UserFmtChannels SrcChannels, enum UserFmtType SrcType,
|
2018-01-26 21:34:59 +00:00
|
|
|
const ALvoid *data, ALbitfieldSOFT access);
|
2016-09-06 16:09:25 +00:00
|
|
|
static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type);
|
2018-01-20 05:00:53 +00:00
|
|
|
static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align);
|
2007-12-29 04:25:18 +00:00
|
|
|
|
2018-01-27 05:11:12 +00:00
|
|
|
static inline void LockBuffersWrite(ALCdevice *device)
|
|
|
|
{ LockUIntMapWrite(&device->BufferMap); }
|
|
|
|
static inline void UnlockBuffersWrite(ALCdevice *device)
|
|
|
|
{ UnlockUIntMapWrite(&device->BufferMap); }
|
|
|
|
|
|
|
|
static inline ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id)
|
|
|
|
{ return (ALbuffer*)RemoveUIntMapKeyNoLock(&device->BufferMap, id); }
|
|
|
|
|
2010-11-27 23:33:33 +00:00
|
|
|
|
2018-01-23 22:33:30 +00:00
|
|
|
#define INVALID_STORAGE_MASK ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT)
|
2018-01-23 18:59:51 +00:00
|
|
|
#define MAP_READ_WRITE_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT)
|
2018-01-26 08:13:03 +00:00
|
|
|
#define INVALID_MAP_FLAGS ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT)
|
2018-01-20 19:49:01 +00:00
|
|
|
|
|
|
|
|
2010-05-02 02:59:41 +00:00
|
|
|
AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers)
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2013-10-07 01:01:01 +00:00
|
|
|
ALCcontext *context;
|
|
|
|
ALsizei cur = 0;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 01:01:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 01:01:01 +00:00
|
|
|
if(!(n >= 0))
|
2018-01-26 08:13:03 +00:00
|
|
|
alSetError(context, AL_INVALID_VALUE, "Generating %d buffers", n);
|
|
|
|
else for(cur = 0;cur < n;cur++)
|
2013-10-07 01:01:01 +00:00
|
|
|
{
|
2014-06-29 09:04:05 +00:00
|
|
|
ALbuffer *buffer = NewBuffer(context);
|
2013-10-07 01:01:01 +00:00
|
|
|
if(!buffer)
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2013-10-07 01:01:01 +00:00
|
|
|
alDeleteBuffers(cur, buffers);
|
2014-06-29 09:04:05 +00:00
|
|
|
break;
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
2013-10-07 01:01:01 +00:00
|
|
|
|
|
|
|
buffers[cur] = buffer->id;
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
2013-10-07 01:01:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
2010-09-21 23:54:33 +00:00
|
|
|
AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers)
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2013-10-07 01:01:01 +00:00
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
2007-11-14 02:02:18 +00:00
|
|
|
ALbuffer *ALBuf;
|
|
|
|
ALsizei i;
|
|
|
|
|
2013-10-07 01:01:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2016-05-11 06:42:44 +00:00
|
|
|
device = context->Device;
|
|
|
|
|
|
|
|
LockBuffersWrite(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY(n < 0))
|
|
|
|
{
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "Deleting %d buffers", n);
|
|
|
|
goto done;
|
|
|
|
}
|
2012-04-24 07:17:05 +00:00
|
|
|
|
2013-10-07 01:01:01 +00:00
|
|
|
for(i = 0;i < n;i++)
|
|
|
|
{
|
|
|
|
if(!buffers[i])
|
|
|
|
continue;
|
|
|
|
|
2018-01-26 08:13:03 +00:00
|
|
|
/* Check for valid Buffer ID, and make sure it's not in use. */
|
2013-10-07 01:01:01 +00:00
|
|
|
if((ALBuf=LookupBuffer(device, buffers[i])) == NULL)
|
2018-01-26 08:13:03 +00:00
|
|
|
{
|
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffers[i]);
|
|
|
|
goto done;
|
|
|
|
}
|
2014-05-14 09:47:07 +00:00
|
|
|
if(ReadRef(&ALBuf->ref) != 0)
|
2018-01-26 08:13:03 +00:00
|
|
|
{
|
|
|
|
alSetError(context, AL_INVALID_OPERATION, "Deleting in-use buffer %u", buffers[i]);
|
|
|
|
goto done;
|
|
|
|
}
|
2013-10-07 01:01:01 +00:00
|
|
|
}
|
|
|
|
for(i = 0;i < n;i++)
|
2014-06-30 07:10:40 +00:00
|
|
|
{
|
|
|
|
if((ALBuf=LookupBuffer(device, buffers[i])) != NULL)
|
|
|
|
DeleteBuffer(device, ALBuf);
|
|
|
|
}
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 01:01:01 +00:00
|
|
|
done:
|
2016-05-11 06:42:44 +00:00
|
|
|
UnlockBuffersWrite(device);
|
2013-10-07 01:01:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
2010-05-19 18:06:13 +00:00
|
|
|
AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer)
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2013-10-07 01:01:01 +00:00
|
|
|
ALCcontext *context;
|
|
|
|
ALboolean ret;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 01:01:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return AL_FALSE;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2016-05-11 06:42:44 +00:00
|
|
|
LockBuffersRead(context->Device);
|
2013-10-07 01:01:01 +00:00
|
|
|
ret = ((!buffer || LookupBuffer(context->Device, buffer)) ?
|
|
|
|
AL_TRUE : AL_FALSE);
|
2016-05-11 06:42:44 +00:00
|
|
|
UnlockBuffersRead(context->Device);
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 01:01:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 01:01:01 +00:00
|
|
|
return ret;
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
2012-04-24 07:17:05 +00:00
|
|
|
|
|
|
|
AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq)
|
2018-01-23 22:33:30 +00:00
|
|
|
{ alBufferStorageSOFT(buffer, format, data, size, freq, 0); }
|
|
|
|
|
|
|
|
AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags)
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2016-08-31 11:56:10 +00:00
|
|
|
enum UserFmtChannels srcchannels = UserFmtMono;
|
2018-01-22 02:15:25 +00:00
|
|
|
enum UserFmtType srctype = UserFmtUByte;
|
2013-10-07 01:01:01 +00:00
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
|
|
|
ALbuffer *albuf;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 01:01:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
|
|
|
|
|
|
|
device = context->Device;
|
2016-05-11 06:42:44 +00:00
|
|
|
LockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
|
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else if(UNLIKELY(size < 0))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "Negative storage size %d", size);
|
|
|
|
else if(UNLIKELY(freq < 1))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "Invalid sample rate %d", freq);
|
|
|
|
else if(UNLIKELY((flags&INVALID_STORAGE_MASK) != 0))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "Invalid storage flags 0x%x",
|
|
|
|
flags&INVALID_STORAGE_MASK);
|
|
|
|
else if(UNLIKELY((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS)))
|
|
|
|
alSetError(context, AL_INVALID_VALUE,
|
|
|
|
"Declaring persistently mapped storage without read or write access");
|
|
|
|
else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE))
|
|
|
|
alSetError(context, AL_INVALID_ENUM, "Invalid format 0x%04x", format);
|
|
|
|
else
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2018-01-26 21:34:59 +00:00
|
|
|
WriteLock(&albuf->lock);
|
|
|
|
LoadData(context, albuf, freq, size, srcchannels, srctype, data, flags);
|
|
|
|
WriteUnlock(&albuf->lock);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
2016-05-11 06:42:44 +00:00
|
|
|
UnlockBuffersRead(device);
|
2013-10-07 01:01:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
2018-01-20 19:49:01 +00:00
|
|
|
AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access)
|
|
|
|
{
|
|
|
|
void *retval = NULL;
|
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
|
|
|
ALbuffer *albuf;
|
|
|
|
|
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return retval;
|
|
|
|
|
|
|
|
device = context->Device;
|
|
|
|
LockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
|
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else if(UNLIKELY((access&INVALID_MAP_FLAGS) != 0))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "Invalid map flags 0x%x", access&INVALID_MAP_FLAGS);
|
|
|
|
else if(UNLIKELY(!(access&MAP_READ_WRITE_FLAGS)))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "Mapping buffer %u without read or write access",
|
|
|
|
buffer);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ALbitfieldSOFT unavailable;
|
|
|
|
WriteLock(&albuf->lock);
|
|
|
|
unavailable = (albuf->Access^access) & access;
|
|
|
|
if(UNLIKELY(ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT)))
|
|
|
|
alSetError(context, AL_INVALID_OPERATION,
|
|
|
|
"Mapping in-use buffer %u without persistent mapping", buffer);
|
|
|
|
else if(UNLIKELY(albuf->MappedAccess != 0))
|
|
|
|
alSetError(context, AL_INVALID_OPERATION, "Mapping already-mapped buffer %u", buffer);
|
|
|
|
else if(UNLIKELY((unavailable&AL_MAP_READ_BIT_SOFT)))
|
|
|
|
alSetError(context, AL_INVALID_VALUE,
|
|
|
|
"Mapping buffer %u for reading without read access", buffer);
|
|
|
|
else if(UNLIKELY((unavailable&AL_MAP_WRITE_BIT_SOFT)))
|
|
|
|
alSetError(context, AL_INVALID_VALUE,
|
|
|
|
"Mapping buffer %u for writing without write access", buffer);
|
|
|
|
else if(UNLIKELY((unavailable&AL_MAP_PERSISTENT_BIT_SOFT)))
|
|
|
|
alSetError(context, AL_INVALID_VALUE,
|
|
|
|
"Mapping buffer %u persistently without persistent access", buffer);
|
|
|
|
else if(UNLIKELY(offset < 0 || offset >= albuf->OriginalSize ||
|
|
|
|
length <= 0 || length > albuf->OriginalSize - offset))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u",
|
|
|
|
offset, length, buffer);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
retval = (ALbyte*)albuf->data + offset;
|
|
|
|
albuf->MappedAccess = access;
|
|
|
|
albuf->MappedOffset = offset;
|
|
|
|
albuf->MappedSize = length;
|
|
|
|
}
|
2018-01-20 19:49:01 +00:00
|
|
|
|
2018-01-26 08:13:03 +00:00
|
|
|
WriteUnlock(&albuf->lock);
|
|
|
|
}
|
2018-01-20 19:49:01 +00:00
|
|
|
UnlockBuffersRead(device);
|
|
|
|
|
2018-01-26 08:13:03 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2018-01-20 19:49:01 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer)
|
|
|
|
{
|
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
|
|
|
ALbuffer *albuf;
|
|
|
|
|
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
|
|
|
|
|
|
|
device = context->Device;
|
|
|
|
LockBuffersRead(device);
|
|
|
|
if((albuf=LookupBuffer(device, buffer)) == NULL)
|
2018-01-26 08:13:03 +00:00
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2018-01-20 19:49:01 +00:00
|
|
|
else
|
2018-01-23 18:51:23 +00:00
|
|
|
{
|
2018-01-26 08:13:03 +00:00
|
|
|
WriteLock(&albuf->lock);
|
|
|
|
if(albuf->MappedAccess == 0)
|
|
|
|
alSetError(context, AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
albuf->MappedAccess = 0;
|
|
|
|
albuf->MappedOffset = 0;
|
|
|
|
albuf->MappedSize = 0;
|
|
|
|
}
|
|
|
|
WriteUnlock(&albuf->lock);
|
2018-01-23 18:51:23 +00:00
|
|
|
}
|
2018-01-20 19:49:01 +00:00
|
|
|
UnlockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
|
2018-01-20 19:49:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
|
|
|
}
|
|
|
|
|
2018-01-23 18:38:27 +00:00
|
|
|
AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length)
|
|
|
|
{
|
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
|
|
|
ALbuffer *albuf;
|
|
|
|
|
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
|
|
|
|
|
|
|
device = context->Device;
|
|
|
|
LockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
|
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2018-01-23 18:38:27 +00:00
|
|
|
else
|
|
|
|
{
|
2018-01-26 08:13:03 +00:00
|
|
|
WriteLock(&albuf->lock);
|
|
|
|
if(UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT)))
|
|
|
|
alSetError(context, AL_INVALID_OPERATION,
|
|
|
|
"Flushing buffer %u while not mapped for writing", buffer);
|
|
|
|
else if(UNLIKELY(offset < albuf->MappedOffset ||
|
|
|
|
offset >= albuf->MappedOffset+albuf->MappedSize ||
|
|
|
|
length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u",
|
|
|
|
offset, length, buffer);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* FIXME: Need to use some method of double-buffering for the mixer
|
|
|
|
* and app to hold separate memory, which can be safely transfered
|
|
|
|
* asynchronously. Currently we just say the app shouldn't write
|
|
|
|
* where OpenAL's reading, and hope for the best...
|
|
|
|
*/
|
|
|
|
ATOMIC_THREAD_FENCE(almemory_order_seq_cst);
|
|
|
|
}
|
|
|
|
WriteUnlock(&albuf->lock);
|
2018-01-23 18:38:27 +00:00
|
|
|
}
|
|
|
|
UnlockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
|
2018-01-23 18:38:27 +00:00
|
|
|
ALCcontext_DecRef(context);
|
|
|
|
}
|
|
|
|
|
2012-04-24 07:17:05 +00:00
|
|
|
AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length)
|
2008-11-11 13:57:32 +00:00
|
|
|
{
|
2016-08-31 11:56:10 +00:00
|
|
|
enum UserFmtChannels srcchannels = UserFmtMono;
|
2018-01-22 02:15:25 +00:00
|
|
|
enum UserFmtType srctype = UserFmtUByte;
|
2013-10-07 01:01:01 +00:00
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
|
|
|
ALbuffer *albuf;
|
|
|
|
|
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
|
|
|
|
|
|
|
device = context->Device;
|
2016-05-11 06:42:44 +00:00
|
|
|
LockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
|
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE))
|
|
|
|
alSetError(context, AL_INVALID_ENUM, "Invalid format 0x%04x", format);
|
2018-01-22 07:35:28 +00:00
|
|
|
else
|
|
|
|
{
|
2018-01-26 08:13:03 +00:00
|
|
|
ALsizei unpack_align, align;
|
|
|
|
ALsizei byte_align;
|
|
|
|
ALsizei frame_size;
|
|
|
|
ALsizei num_chans;
|
|
|
|
void *dst;
|
2018-01-23 00:17:45 +00:00
|
|
|
|
2018-01-26 08:13:03 +00:00
|
|
|
WriteLock(&albuf->lock);
|
|
|
|
unpack_align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign);
|
|
|
|
align = SanitizeAlignment(srctype, unpack_align);
|
|
|
|
if(UNLIKELY(align < 1))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align);
|
|
|
|
else if(UNLIKELY((long)srcchannels != (long)albuf->FmtChannels ||
|
|
|
|
srctype != albuf->OriginalType))
|
|
|
|
alSetError(context, AL_INVALID_ENUM, "Unpacking data with mismatched format");
|
|
|
|
else if(UNLIKELY(align != albuf->OriginalAlign))
|
|
|
|
alSetError(context, AL_INVALID_VALUE,
|
|
|
|
"Unpacking data with alignment %u does not match original alignment %u",
|
|
|
|
align, albuf->OriginalAlign);
|
|
|
|
else if(UNLIKELY(albuf->MappedAccess != 0))
|
|
|
|
alSetError(context, AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u",
|
|
|
|
buffer);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
num_chans = ChannelsFromFmt(albuf->FmtChannels);
|
|
|
|
frame_size = num_chans * BytesFromFmt(albuf->FmtType);
|
|
|
|
if(albuf->OriginalType == UserFmtIMA4)
|
|
|
|
byte_align = ((align-1)/2 + 4) * num_chans;
|
|
|
|
else if(albuf->OriginalType == UserFmtMSADPCM)
|
|
|
|
byte_align = ((align-2)/2 + 7) * num_chans;
|
|
|
|
else
|
|
|
|
byte_align = align * frame_size;
|
|
|
|
|
|
|
|
if(UNLIKELY(offset < 0 || length < 0 || offset > albuf->OriginalSize ||
|
|
|
|
length > albuf->OriginalSize-offset))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u",
|
|
|
|
offset, length, buffer);
|
|
|
|
else if(UNLIKELY((offset%byte_align) != 0))
|
|
|
|
alSetError(context, AL_INVALID_VALUE,
|
|
|
|
"Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)",
|
|
|
|
offset, byte_align, align);
|
|
|
|
else if(UNLIKELY((length%byte_align) != 0))
|
|
|
|
alSetError(context, AL_INVALID_VALUE,
|
|
|
|
"Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)",
|
|
|
|
length, byte_align, align);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* offset -> byte offset, length -> sample count */
|
|
|
|
offset = offset/byte_align * align * frame_size;
|
|
|
|
length = length/byte_align * align;
|
|
|
|
|
|
|
|
dst = (ALbyte*)albuf->data + offset;
|
|
|
|
if(srctype == UserFmtIMA4 && albuf->FmtType == FmtShort)
|
|
|
|
Convert_ALshort_ALima4(dst, data, num_chans, length, align);
|
|
|
|
else if(srctype == UserFmtMSADPCM && albuf->FmtType == FmtShort)
|
|
|
|
Convert_ALshort_ALmsadpcm(dst, data, num_chans, length, align);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert((long)srctype == (long)albuf->FmtType);
|
|
|
|
memcpy(dst, data, length*frame_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-11-11 13:57:32 +00:00
|
|
|
|
2018-01-26 08:13:03 +00:00
|
|
|
WriteUnlock(&albuf->lock);
|
|
|
|
}
|
2016-05-11 06:42:44 +00:00
|
|
|
UnlockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
|
2013-10-07 01:01:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2008-11-11 13:57:32 +00:00
|
|
|
}
|
|
|
|
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2018-01-22 01:19:57 +00:00
|
|
|
AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint UNUSED(buffer),
|
|
|
|
ALuint UNUSED(samplerate), ALenum UNUSED(internalformat), ALsizei UNUSED(samples),
|
|
|
|
ALenum UNUSED(channels), ALenum UNUSED(type), const ALvoid *UNUSED(data))
|
2011-03-16 18:29:22 +00:00
|
|
|
{
|
2013-10-07 01:01:01 +00:00
|
|
|
ALCcontext *context;
|
2011-03-16 18:29:22 +00:00
|
|
|
|
2013-10-07 01:01:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2011-03-16 18:29:22 +00:00
|
|
|
|
2018-01-25 23:59:59 +00:00
|
|
|
alSetError(context, AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported");
|
2013-10-07 01:01:01 +00:00
|
|
|
|
|
|
|
ALCcontext_DecRef(context);
|
2011-03-16 18:29:22 +00:00
|
|
|
}
|
|
|
|
|
2018-01-22 01:19:57 +00:00
|
|
|
AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint UNUSED(buffer),
|
|
|
|
ALsizei UNUSED(offset), ALsizei UNUSED(samples),
|
|
|
|
ALenum UNUSED(channels), ALenum UNUSED(type), const ALvoid *UNUSED(data))
|
2011-03-16 19:13:17 +00:00
|
|
|
{
|
2013-10-07 01:01:01 +00:00
|
|
|
ALCcontext *context;
|
|
|
|
|
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
|
|
|
|
2018-01-25 23:59:59 +00:00
|
|
|
alSetError(context, AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported");
|
2013-10-07 01:01:01 +00:00
|
|
|
|
|
|
|
ALCcontext_DecRef(context);
|
2011-03-16 19:13:17 +00:00
|
|
|
}
|
|
|
|
|
2018-01-22 01:19:57 +00:00
|
|
|
AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint UNUSED(buffer),
|
|
|
|
ALsizei UNUSED(offset), ALsizei UNUSED(samples),
|
|
|
|
ALenum UNUSED(channels), ALenum UNUSED(type), ALvoid *UNUSED(data))
|
2011-03-16 19:56:39 +00:00
|
|
|
{
|
2013-10-07 01:01:01 +00:00
|
|
|
ALCcontext *context;
|
|
|
|
|
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
|
|
|
|
2018-01-25 23:59:59 +00:00
|
|
|
alSetError(context, AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported");
|
2011-03-16 19:56:39 +00:00
|
|
|
|
2013-10-07 01:01:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2011-03-16 19:56:39 +00:00
|
|
|
}
|
|
|
|
|
2018-01-22 01:19:57 +00:00
|
|
|
AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum UNUSED(format))
|
2011-03-16 20:57:00 +00:00
|
|
|
{
|
2013-10-07 01:01:01 +00:00
|
|
|
ALCcontext *context;
|
2011-03-16 20:57:00 +00:00
|
|
|
|
2013-10-07 01:01:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return AL_FALSE;
|
2011-03-16 20:57:00 +00:00
|
|
|
|
2018-01-25 23:59:59 +00:00
|
|
|
alSetError(context, AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported");
|
2011-03-16 20:57:00 +00:00
|
|
|
|
2013-10-07 01:01:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2018-01-22 01:19:57 +00:00
|
|
|
return AL_FALSE;
|
2011-03-16 20:57:00 +00:00
|
|
|
}
|
|
|
|
|
2011-03-16 18:29:22 +00:00
|
|
|
|
2013-10-07 14:44:09 +00:00
|
|
|
AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(value))
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
device = context->Device;
|
2016-05-11 06:42:44 +00:00
|
|
|
LockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
|
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else switch(param)
|
2013-10-07 14:06:01 +00:00
|
|
|
{
|
|
|
|
default:
|
2018-01-25 23:59:59 +00:00
|
|
|
alSetError(context, AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
2016-05-11 06:42:44 +00:00
|
|
|
UnlockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-07 14:44:09 +00:00
|
|
|
AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(value1), ALfloat UNUSED(value2), ALfloat UNUSED(value3))
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
device = context->Device;
|
2016-05-11 06:42:44 +00:00
|
|
|
LockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
|
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else switch(param)
|
2013-10-07 14:06:01 +00:00
|
|
|
{
|
|
|
|
default:
|
2018-01-25 23:59:59 +00:00
|
|
|
alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
2016-05-11 06:42:44 +00:00
|
|
|
UnlockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-24 07:17:05 +00:00
|
|
|
AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values)
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
device = context->Device;
|
2016-05-11 06:42:44 +00:00
|
|
|
LockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
|
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else if(UNLIKELY(!values))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
|
|
|
|
else switch(param)
|
2013-10-07 14:06:01 +00:00
|
|
|
{
|
|
|
|
default:
|
2018-01-25 23:59:59 +00:00
|
|
|
alSetError(context, AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
2016-05-11 06:42:44 +00:00
|
|
|
UnlockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
Add an extension to alter the block alignment for buffer unpack/pack ops
This is for unpacking (reading, e.g. alBufferData) and packing (writing, e.g.
alGetBufferSamplesSOFT) operations. The alignments are specified in sample
frames, with 0 meaning the default (65 for IMA4, 1 otherwise). IMA4 alignment
must be a multiple of 8, plus 1 (e.g. alignment = n*8 + 1), otherwise an error
will occur during (un)packing. Chenging the block alignment does not affect
already-loaded sample data, only future unpack/pack operations... so for
example, this is perfectly valid:
// Load mono IMA4 data with a block alignment of 1024 bytes, or 2041 sample
// frames.
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 2041);
alBufferData(buffer, AL_FORMAT_MONO_IMA4, data, data_len, srate);
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 0);
2014-03-04 13:16:45 +00:00
|
|
|
AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value)
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
Add an extension to alter the block alignment for buffer unpack/pack ops
This is for unpacking (reading, e.g. alBufferData) and packing (writing, e.g.
alGetBufferSamplesSOFT) operations. The alignments are specified in sample
frames, with 0 meaning the default (65 for IMA4, 1 otherwise). IMA4 alignment
must be a multiple of 8, plus 1 (e.g. alignment = n*8 + 1), otherwise an error
will occur during (un)packing. Chenging the block alignment does not affect
already-loaded sample data, only future unpack/pack operations... so for
example, this is perfectly valid:
// Load mono IMA4 data with a block alignment of 1024 bytes, or 2041 sample
// frames.
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 2041);
alBufferData(buffer, AL_FORMAT_MONO_IMA4, data, data_len, srate);
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 0);
2014-03-04 13:16:45 +00:00
|
|
|
ALbuffer *albuf;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
device = context->Device;
|
2016-05-11 06:42:44 +00:00
|
|
|
LockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
|
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else switch(param)
|
2013-10-07 14:06:01 +00:00
|
|
|
{
|
Add an extension to alter the block alignment for buffer unpack/pack ops
This is for unpacking (reading, e.g. alBufferData) and packing (writing, e.g.
alGetBufferSamplesSOFT) operations. The alignments are specified in sample
frames, with 0 meaning the default (65 for IMA4, 1 otherwise). IMA4 alignment
must be a multiple of 8, plus 1 (e.g. alignment = n*8 + 1), otherwise an error
will occur during (un)packing. Chenging the block alignment does not affect
already-loaded sample data, only future unpack/pack operations... so for
example, this is perfectly valid:
// Load mono IMA4 data with a block alignment of 1024 bytes, or 2041 sample
// frames.
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 2041);
alBufferData(buffer, AL_FORMAT_MONO_IMA4, data, data_len, srate);
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 0);
2014-03-04 13:16:45 +00:00
|
|
|
case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY(value < 0))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "Invalid unpack block alignment %d", value);
|
|
|
|
else
|
|
|
|
ATOMIC_STORE_SEQ(&albuf->UnpackAlign, value);
|
Add an extension to alter the block alignment for buffer unpack/pack ops
This is for unpacking (reading, e.g. alBufferData) and packing (writing, e.g.
alGetBufferSamplesSOFT) operations. The alignments are specified in sample
frames, with 0 meaning the default (65 for IMA4, 1 otherwise). IMA4 alignment
must be a multiple of 8, plus 1 (e.g. alignment = n*8 + 1), otherwise an error
will occur during (un)packing. Chenging the block alignment does not affect
already-loaded sample data, only future unpack/pack operations... so for
example, this is perfectly valid:
// Load mono IMA4 data with a block alignment of 1024 bytes, or 2041 sample
// frames.
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 2041);
alBufferData(buffer, AL_FORMAT_MONO_IMA4, data, data_len, srate);
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 0);
2014-03-04 13:16:45 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AL_PACK_BLOCK_ALIGNMENT_SOFT:
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY(value < 0))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "Invalid pack block alignment %d", value);
|
|
|
|
else
|
|
|
|
ATOMIC_STORE_SEQ(&albuf->PackAlign, value);
|
Add an extension to alter the block alignment for buffer unpack/pack ops
This is for unpacking (reading, e.g. alBufferData) and packing (writing, e.g.
alGetBufferSamplesSOFT) operations. The alignments are specified in sample
frames, with 0 meaning the default (65 for IMA4, 1 otherwise). IMA4 alignment
must be a multiple of 8, plus 1 (e.g. alignment = n*8 + 1), otherwise an error
will occur during (un)packing. Chenging the block alignment does not affect
already-loaded sample data, only future unpack/pack operations... so for
example, this is perfectly valid:
// Load mono IMA4 data with a block alignment of 1024 bytes, or 2041 sample
// frames.
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 2041);
alBufferData(buffer, AL_FORMAT_MONO_IMA4, data, data_len, srate);
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 0);
2014-03-04 13:16:45 +00:00
|
|
|
break;
|
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
default:
|
2018-01-25 23:59:59 +00:00
|
|
|
alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
2016-05-11 06:42:44 +00:00
|
|
|
UnlockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-07 14:44:09 +00:00
|
|
|
AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(value1), ALint UNUSED(value2), ALint UNUSED(value3))
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
device = context->Device;
|
2018-01-26 08:13:03 +00:00
|
|
|
LockBuffersRead(device);
|
|
|
|
if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
|
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else switch(param)
|
2013-10-07 14:06:01 +00:00
|
|
|
{
|
|
|
|
default:
|
2018-01-25 23:59:59 +00:00
|
|
|
alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
2018-01-26 08:13:03 +00:00
|
|
|
UnlockBuffersRead(device);
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-24 07:17:05 +00:00
|
|
|
AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values)
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
|
|
|
ALbuffer *albuf;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
Add an extension to alter the block alignment for buffer unpack/pack ops
This is for unpacking (reading, e.g. alBufferData) and packing (writing, e.g.
alGetBufferSamplesSOFT) operations. The alignments are specified in sample
frames, with 0 meaning the default (65 for IMA4, 1 otherwise). IMA4 alignment
must be a multiple of 8, plus 1 (e.g. alignment = n*8 + 1), otherwise an error
will occur during (un)packing. Chenging the block alignment does not affect
already-loaded sample data, only future unpack/pack operations... so for
example, this is perfectly valid:
// Load mono IMA4 data with a block alignment of 1024 bytes, or 2041 sample
// frames.
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 2041);
alBufferData(buffer, AL_FORMAT_MONO_IMA4, data, data_len, srate);
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 0);
2014-03-04 13:16:45 +00:00
|
|
|
if(values)
|
|
|
|
{
|
|
|
|
switch(param)
|
|
|
|
{
|
|
|
|
case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
|
|
|
|
case AL_PACK_BLOCK_ALIGNMENT_SOFT:
|
|
|
|
alBufferi(buffer, param, values[0]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
device = context->Device;
|
2016-05-11 06:42:44 +00:00
|
|
|
LockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
|
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else if(UNLIKELY(!values))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
|
|
|
|
else switch(param)
|
2013-10-07 14:06:01 +00:00
|
|
|
{
|
|
|
|
case AL_LOOP_POINTS_SOFT:
|
|
|
|
WriteLock(&albuf->lock);
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY(ReadRef(&albuf->ref) != 0))
|
|
|
|
alSetError(context, AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points",
|
|
|
|
buffer);
|
|
|
|
else if(UNLIKELY(values[0] >= values[1] || values[0] < 0 || values[1] > albuf->SampleLen))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "Invalid loop point range %d -> %d o buffer %u",
|
|
|
|
values[0], values[1], buffer);
|
|
|
|
else
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2018-01-26 08:13:03 +00:00
|
|
|
albuf->LoopStart = values[0];
|
|
|
|
albuf->LoopEnd = values[1];
|
2013-10-07 14:06:01 +00:00
|
|
|
}
|
|
|
|
WriteUnlock(&albuf->lock);
|
|
|
|
break;
|
2010-05-13 09:03:48 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
default:
|
2018-01-25 23:59:59 +00:00
|
|
|
alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x",
|
|
|
|
param);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
2016-05-11 06:42:44 +00:00
|
|
|
UnlockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-24 07:17:05 +00:00
|
|
|
AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value)
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
|
|
|
ALbuffer *albuf;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
device = context->Device;
|
2016-05-11 06:42:44 +00:00
|
|
|
LockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
|
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else if(UNLIKELY(!value))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
|
|
|
|
else switch(param)
|
2013-10-07 14:06:01 +00:00
|
|
|
{
|
|
|
|
default:
|
2018-01-25 23:59:59 +00:00
|
|
|
alSetError(context, AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
2016-05-11 06:42:44 +00:00
|
|
|
UnlockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-24 07:17:05 +00:00
|
|
|
AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
device = context->Device;
|
2016-05-11 06:42:44 +00:00
|
|
|
LockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
|
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else if(UNLIKELY(!value1 || !value2 || !value3))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
|
|
|
|
else switch(param)
|
2013-10-07 14:06:01 +00:00
|
|
|
{
|
|
|
|
default:
|
2018-01-25 23:59:59 +00:00
|
|
|
alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
2016-05-11 06:42:44 +00:00
|
|
|
UnlockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-24 07:17:05 +00:00
|
|
|
AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values)
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2012-04-24 07:17:05 +00:00
|
|
|
switch(param)
|
Add buffer properties to get the internal format, and the length in bytes, samples, and seconds
The provided buffer lengths correspond to the source offsets, in that the byte
length specifies the end of the byte offset (ie, when the buffer is used for a
static source, the offset will range between 0 (inclusive) and the byte length
(exclusive)). Although an application could use the AL_SIZE, AL_CHANNELS,
AL_BITS, and AL_FREQUENCY properties to find the length in samples and seconds,
the byte length cannot be reliably calculated this way.
2011-10-01 13:19:55 +00:00
|
|
|
{
|
2012-01-10 08:41:05 +00:00
|
|
|
case AL_SEC_LENGTH_SOFT:
|
2012-04-24 07:17:05 +00:00
|
|
|
alGetBufferf(buffer, param, values);
|
Add buffer properties to get the internal format, and the length in bytes, samples, and seconds
The provided buffer lengths correspond to the source offsets, in that the byte
length specifies the end of the byte offset (ie, when the buffer is used for a
static source, the offset will range between 0 (inclusive) and the byte length
(exclusive)). Although an application could use the AL_SIZE, AL_CHANNELS,
AL_BITS, and AL_FREQUENCY properties to find the length in samples and seconds,
the byte length cannot be reliably calculated this way.
2011-10-01 13:19:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
device = context->Device;
|
2016-05-11 06:42:44 +00:00
|
|
|
LockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
|
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else if(UNLIKELY(!values))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
|
|
|
|
else switch(param)
|
2013-10-07 14:06:01 +00:00
|
|
|
{
|
|
|
|
default:
|
2018-01-25 23:59:59 +00:00
|
|
|
alSetError(context, AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
2016-05-11 06:42:44 +00:00
|
|
|
UnlockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-24 07:17:05 +00:00
|
|
|
AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value)
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
|
|
|
ALbuffer *albuf;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
device = context->Device;
|
2016-05-11 06:42:44 +00:00
|
|
|
LockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
|
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else if(UNLIKELY(!value))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
|
|
|
|
else switch(param)
|
2013-10-07 14:06:01 +00:00
|
|
|
{
|
|
|
|
case AL_FREQUENCY:
|
|
|
|
*value = albuf->Frequency;
|
|
|
|
break;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
case AL_BITS:
|
|
|
|
*value = BytesFromFmt(albuf->FmtType) * 8;
|
|
|
|
break;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
case AL_CHANNELS:
|
|
|
|
*value = ChannelsFromFmt(albuf->FmtChannels);
|
|
|
|
break;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
case AL_SIZE:
|
|
|
|
ReadLock(&albuf->lock);
|
|
|
|
*value = albuf->SampleLen * FrameSizeFromFmt(albuf->FmtChannels,
|
|
|
|
albuf->FmtType);
|
|
|
|
ReadUnlock(&albuf->lock);
|
|
|
|
break;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
Add an extension to alter the block alignment for buffer unpack/pack ops
This is for unpacking (reading, e.g. alBufferData) and packing (writing, e.g.
alGetBufferSamplesSOFT) operations. The alignments are specified in sample
frames, with 0 meaning the default (65 for IMA4, 1 otherwise). IMA4 alignment
must be a multiple of 8, plus 1 (e.g. alignment = n*8 + 1), otherwise an error
will occur during (un)packing. Chenging the block alignment does not affect
already-loaded sample data, only future unpack/pack operations... so for
example, this is perfectly valid:
// Load mono IMA4 data with a block alignment of 1024 bytes, or 2041 sample
// frames.
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 2041);
alBufferData(buffer, AL_FORMAT_MONO_IMA4, data, data_len, srate);
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 0);
2014-03-04 13:16:45 +00:00
|
|
|
case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
|
2016-12-21 04:49:37 +00:00
|
|
|
*value = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign);
|
Add an extension to alter the block alignment for buffer unpack/pack ops
This is for unpacking (reading, e.g. alBufferData) and packing (writing, e.g.
alGetBufferSamplesSOFT) operations. The alignments are specified in sample
frames, with 0 meaning the default (65 for IMA4, 1 otherwise). IMA4 alignment
must be a multiple of 8, plus 1 (e.g. alignment = n*8 + 1), otherwise an error
will occur during (un)packing. Chenging the block alignment does not affect
already-loaded sample data, only future unpack/pack operations... so for
example, this is perfectly valid:
// Load mono IMA4 data with a block alignment of 1024 bytes, or 2041 sample
// frames.
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 2041);
alBufferData(buffer, AL_FORMAT_MONO_IMA4, data, data_len, srate);
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 0);
2014-03-04 13:16:45 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AL_PACK_BLOCK_ALIGNMENT_SOFT:
|
2016-12-21 04:49:37 +00:00
|
|
|
*value = ATOMIC_LOAD_SEQ(&albuf->PackAlign);
|
Add an extension to alter the block alignment for buffer unpack/pack ops
This is for unpacking (reading, e.g. alBufferData) and packing (writing, e.g.
alGetBufferSamplesSOFT) operations. The alignments are specified in sample
frames, with 0 meaning the default (65 for IMA4, 1 otherwise). IMA4 alignment
must be a multiple of 8, plus 1 (e.g. alignment = n*8 + 1), otherwise an error
will occur during (un)packing. Chenging the block alignment does not affect
already-loaded sample data, only future unpack/pack operations... so for
example, this is perfectly valid:
// Load mono IMA4 data with a block alignment of 1024 bytes, or 2041 sample
// frames.
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 2041);
alBufferData(buffer, AL_FORMAT_MONO_IMA4, data, data_len, srate);
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 0);
2014-03-04 13:16:45 +00:00
|
|
|
break;
|
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
default:
|
2018-01-25 23:59:59 +00:00
|
|
|
alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
2016-05-11 06:42:44 +00:00
|
|
|
UnlockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-24 07:17:05 +00:00
|
|
|
AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3)
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
device = context->Device;
|
2016-05-11 06:42:44 +00:00
|
|
|
LockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY(LookupBuffer(device, buffer) == NULL))
|
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else if(UNLIKELY(!value1 || !value2 || !value3))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
|
|
|
|
else switch(param)
|
2013-10-07 14:06:01 +00:00
|
|
|
{
|
|
|
|
default:
|
2018-01-25 23:59:59 +00:00
|
|
|
alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
2016-05-11 06:42:44 +00:00
|
|
|
UnlockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-24 07:17:05 +00:00
|
|
|
AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values)
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCdevice *device;
|
|
|
|
ALCcontext *context;
|
|
|
|
ALbuffer *albuf;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2012-04-24 07:17:05 +00:00
|
|
|
switch(param)
|
2011-06-16 16:14:41 +00:00
|
|
|
{
|
|
|
|
case AL_FREQUENCY:
|
|
|
|
case AL_BITS:
|
|
|
|
case AL_CHANNELS:
|
|
|
|
case AL_SIZE:
|
2012-01-10 08:41:05 +00:00
|
|
|
case AL_INTERNAL_FORMAT_SOFT:
|
|
|
|
case AL_BYTE_LENGTH_SOFT:
|
|
|
|
case AL_SAMPLE_LENGTH_SOFT:
|
Add an extension to alter the block alignment for buffer unpack/pack ops
This is for unpacking (reading, e.g. alBufferData) and packing (writing, e.g.
alGetBufferSamplesSOFT) operations. The alignments are specified in sample
frames, with 0 meaning the default (65 for IMA4, 1 otherwise). IMA4 alignment
must be a multiple of 8, plus 1 (e.g. alignment = n*8 + 1), otherwise an error
will occur during (un)packing. Chenging the block alignment does not affect
already-loaded sample data, only future unpack/pack operations... so for
example, this is perfectly valid:
// Load mono IMA4 data with a block alignment of 1024 bytes, or 2041 sample
// frames.
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 2041);
alBufferData(buffer, AL_FORMAT_MONO_IMA4, data, data_len, srate);
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 0);
2014-03-04 13:16:45 +00:00
|
|
|
case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
|
|
|
|
case AL_PACK_BLOCK_ALIGNMENT_SOFT:
|
2012-04-24 07:17:05 +00:00
|
|
|
alGetBufferi(buffer, param, values);
|
2011-06-16 16:14:41 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
context = GetContextRef();
|
|
|
|
if(!context) return;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
device = context->Device;
|
2016-05-11 06:42:44 +00:00
|
|
|
LockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL))
|
|
|
|
alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else if(UNLIKELY(!values))
|
|
|
|
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
|
|
|
|
else switch(param)
|
2013-10-07 14:06:01 +00:00
|
|
|
{
|
|
|
|
case AL_LOOP_POINTS_SOFT:
|
|
|
|
ReadLock(&albuf->lock);
|
|
|
|
values[0] = albuf->LoopStart;
|
|
|
|
values[1] = albuf->LoopEnd;
|
|
|
|
ReadUnlock(&albuf->lock);
|
|
|
|
break;
|
2010-05-13 09:03:48 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
default:
|
2018-01-25 23:59:59 +00:00
|
|
|
alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x",
|
|
|
|
param);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
2016-05-11 06:42:44 +00:00
|
|
|
UnlockBuffersRead(device);
|
2018-01-26 08:13:03 +00:00
|
|
|
|
2013-10-07 14:06:01 +00:00
|
|
|
ALCcontext_DecRef(context);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
2007-12-29 04:25:18 +00:00
|
|
|
|
2018-01-26 21:34:59 +00:00
|
|
|
static const ALchar *NameFromUserFmtType(enum UserFmtType type)
|
|
|
|
{
|
|
|
|
switch(type)
|
|
|
|
{
|
|
|
|
case UserFmtUByte: return "Unsigned Byte";
|
|
|
|
case UserFmtShort: return "Signed Short";
|
|
|
|
case UserFmtFloat: return "Float32";
|
|
|
|
case UserFmtDouble: return "Float64";
|
|
|
|
case UserFmtMulaw: return "muLaw";
|
|
|
|
case UserFmtAlaw: return "aLaw";
|
|
|
|
case UserFmtIMA4: return "IMA4 ADPCM";
|
|
|
|
case UserFmtMSADPCM: return "MSADPCM";
|
|
|
|
}
|
|
|
|
return "<internal type error>";
|
|
|
|
}
|
|
|
|
|
2010-11-28 04:33:37 +00:00
|
|
|
/*
|
|
|
|
* LoadData
|
|
|
|
*
|
2018-01-24 20:45:56 +00:00
|
|
|
* Loads the specified data into the buffer, using the specified format.
|
2010-11-28 04:33:37 +00:00
|
|
|
*/
|
2018-01-26 21:34:59 +00:00
|
|
|
static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALbitfieldSOFT access)
|
2010-11-28 04:33:37 +00:00
|
|
|
{
|
2016-08-31 11:56:10 +00:00
|
|
|
enum FmtChannels DstChannels = FmtMono;
|
2018-01-20 04:10:31 +00:00
|
|
|
enum FmtType DstType = FmtUByte;
|
2018-01-22 07:35:28 +00:00
|
|
|
ALsizei NumChannels, FrameSize;
|
2018-01-26 21:34:59 +00:00
|
|
|
ALsizei SrcByteAlign;
|
|
|
|
ALsizei unpackalign;
|
2018-01-22 07:35:28 +00:00
|
|
|
ALsizei newsize;
|
2018-01-26 21:34:59 +00:00
|
|
|
ALsizei frames;
|
|
|
|
ALsizei align;
|
|
|
|
|
|
|
|
if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0))
|
|
|
|
SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u",
|
|
|
|
ALBuf->id);
|
2010-11-28 04:33:37 +00:00
|
|
|
|
2018-01-26 21:34:59 +00:00
|
|
|
/* Currently no channel configurations need to be converted. */
|
2018-01-22 07:35:28 +00:00
|
|
|
switch(SrcChannels)
|
|
|
|
{
|
|
|
|
case UserFmtMono: DstChannels = FmtMono; break;
|
|
|
|
case UserFmtStereo: DstChannels = FmtStereo; break;
|
|
|
|
case UserFmtRear: DstChannels = FmtRear; break;
|
|
|
|
case UserFmtQuad: DstChannels = FmtQuad; break;
|
|
|
|
case UserFmtX51: DstChannels = FmtX51; break;
|
|
|
|
case UserFmtX61: DstChannels = FmtX61; break;
|
|
|
|
case UserFmtX71: DstChannels = FmtX71; break;
|
|
|
|
case UserFmtBFormat2D: DstChannels = FmtBFormat2D; break;
|
|
|
|
case UserFmtBFormat3D: DstChannels = FmtBFormat3D; break;
|
|
|
|
}
|
2018-01-24 20:45:56 +00:00
|
|
|
if(UNLIKELY((long)SrcChannels != (long)DstChannels))
|
2018-01-25 23:59:59 +00:00
|
|
|
SETERR_RETURN(context, AL_INVALID_ENUM,, "Invalid format");
|
2011-03-17 02:39:31 +00:00
|
|
|
|
2018-01-22 07:35:28 +00:00
|
|
|
/* IMA4 and MSADPCM convert to 16-bit short. */
|
|
|
|
switch(SrcType)
|
|
|
|
{
|
|
|
|
case UserFmtUByte: DstType = FmtUByte; break;
|
|
|
|
case UserFmtShort: DstType = FmtShort; break;
|
|
|
|
case UserFmtFloat: DstType = FmtFloat; break;
|
|
|
|
case UserFmtDouble: DstType = FmtDouble; break;
|
|
|
|
case UserFmtAlaw: DstType = FmtAlaw; break;
|
|
|
|
case UserFmtMulaw: DstType = FmtMulaw; break;
|
|
|
|
case UserFmtIMA4: DstType = FmtShort; break;
|
|
|
|
case UserFmtMSADPCM: DstType = FmtShort; break;
|
|
|
|
}
|
|
|
|
|
2018-01-27 00:41:14 +00:00
|
|
|
/* TODO: Currently we can only map samples when they're not converted. To
|
|
|
|
* allow it would need some kind of double-buffering to hold onto a copy of
|
|
|
|
* the original data.
|
2018-01-26 21:34:59 +00:00
|
|
|
*/
|
2018-01-27 00:41:14 +00:00
|
|
|
if((access&MAP_READ_WRITE_FLAGS))
|
2018-01-20 19:49:01 +00:00
|
|
|
{
|
2018-01-24 20:45:56 +00:00
|
|
|
if(UNLIKELY((long)SrcType != (long)DstType))
|
2018-01-27 00:41:14 +00:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "%s samples cannot be mapped",
|
2018-01-26 21:34:59 +00:00
|
|
|
NameFromUserFmtType(SrcType));
|
2018-01-20 19:49:01 +00:00
|
|
|
}
|
|
|
|
|
2018-01-26 21:34:59 +00:00
|
|
|
unpackalign = ATOMIC_LOAD_SEQ(&ALBuf->UnpackAlign);
|
|
|
|
if(UNLIKELY((align=SanitizeAlignment(SrcType, unpackalign)) < 1))
|
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %d for %s samples",
|
|
|
|
unpackalign, NameFromUserFmtType(SrcType));
|
2010-11-30 08:28:02 +00:00
|
|
|
|
2018-01-22 19:34:16 +00:00
|
|
|
if((access&AL_PRESERVE_DATA_BIT_SOFT))
|
|
|
|
{
|
2018-01-22 23:52:53 +00:00
|
|
|
/* Can only preserve data with the same format and alignment. */
|
2018-01-24 20:45:56 +00:00
|
|
|
if(UNLIKELY(ALBuf->FmtChannels != DstChannels || ALBuf->OriginalType != SrcType))
|
2018-01-25 23:59:59 +00:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format");
|
2018-01-24 20:45:56 +00:00
|
|
|
if(UNLIKELY(ALBuf->OriginalAlign != align))
|
2018-01-25 23:59:59 +00:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment");
|
2018-01-22 19:34:16 +00:00
|
|
|
}
|
|
|
|
|
2018-01-26 21:34:59 +00:00
|
|
|
/* Convert the input/source size in bytes to sample frames using the unpack
|
|
|
|
* block alignment.
|
|
|
|
*/
|
|
|
|
if(SrcType == UserFmtIMA4)
|
|
|
|
SrcByteAlign = ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels);
|
|
|
|
else if(SrcType == UserFmtMSADPCM)
|
|
|
|
SrcByteAlign = ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels);
|
|
|
|
else
|
|
|
|
SrcByteAlign = align * FrameSizeFromUserFmt(SrcChannels, SrcType);
|
|
|
|
if(UNLIKELY((size%SrcByteAlign) != 0))
|
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,,
|
|
|
|
"Data size %d is not a multiple of frame size %d (%d unpack alignment)",
|
|
|
|
size, SrcByteAlign, align);
|
|
|
|
|
|
|
|
if(UNLIKELY(size / SrcByteAlign > INT_MAX / align))
|
|
|
|
SETERR_RETURN(context, AL_OUT_OF_MEMORY,,
|
|
|
|
"Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align);
|
|
|
|
frames = size / SrcByteAlign * align;
|
|
|
|
|
|
|
|
/* Convert the sample frames to the number of bytes needed for internal
|
|
|
|
* storage.
|
|
|
|
*/
|
|
|
|
NumChannels = ChannelsFromFmt(DstChannels);
|
|
|
|
FrameSize = NumChannels * BytesFromFmt(DstType);
|
|
|
|
if(UNLIKELY(frames > INT_MAX/FrameSize))
|
|
|
|
SETERR_RETURN(context, AL_OUT_OF_MEMORY,,
|
|
|
|
"Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize);
|
|
|
|
newsize = frames*FrameSize;
|
|
|
|
|
2016-05-21 10:27:51 +00:00
|
|
|
/* Round up to the next 16-byte multiple. This could reallocate only when
|
|
|
|
* increasing or the new size is less than half the current, but then the
|
|
|
|
* buffer's AL_SIZE would not be very reliable for accounting buffer memory
|
|
|
|
* usage, and reporting the real size could cause problems for apps that
|
|
|
|
* use AL_SIZE to try to get the buffer's play length.
|
|
|
|
*/
|
2018-01-26 08:13:03 +00:00
|
|
|
if(LIKELY(newsize <= INT_MAX-15))
|
2018-01-22 07:35:28 +00:00
|
|
|
newsize = (newsize+15) & ~0xf;
|
2016-05-21 10:27:51 +00:00
|
|
|
if(newsize != ALBuf->BytesAlloc)
|
2012-01-26 03:32:10 +00:00
|
|
|
{
|
2018-01-22 23:46:46 +00:00
|
|
|
void *temp = al_malloc(16, (size_t)newsize);
|
2018-01-24 20:45:56 +00:00
|
|
|
if(UNLIKELY(!temp && newsize))
|
2018-01-25 23:59:59 +00:00
|
|
|
SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Failed to allocate %d bytes of storage",
|
|
|
|
newsize);
|
2018-01-22 19:34:16 +00:00
|
|
|
if((access&AL_PRESERVE_DATA_BIT_SOFT))
|
|
|
|
{
|
|
|
|
ALsizei tocopy = mini(newsize, ALBuf->BytesAlloc);
|
|
|
|
if(tocopy > 0) memcpy(temp, ALBuf->data, tocopy);
|
|
|
|
}
|
2016-05-21 10:27:51 +00:00
|
|
|
al_free(ALBuf->data);
|
|
|
|
ALBuf->data = temp;
|
2018-01-22 07:35:28 +00:00
|
|
|
ALBuf->BytesAlloc = newsize;
|
2012-01-26 03:32:10 +00:00
|
|
|
}
|
2010-11-30 08:28:02 +00:00
|
|
|
|
2018-01-22 07:35:28 +00:00
|
|
|
if(SrcType == UserFmtIMA4)
|
2012-01-26 03:32:10 +00:00
|
|
|
{
|
2018-01-22 07:35:28 +00:00
|
|
|
assert(DstType == FmtShort);
|
2018-01-22 08:23:19 +00:00
|
|
|
if(data != NULL && ALBuf->data != NULL)
|
2018-01-22 07:35:28 +00:00
|
|
|
Convert_ALshort_ALima4(ALBuf->data, data, NumChannels, frames, align);
|
2018-01-26 21:34:59 +00:00
|
|
|
ALBuf->OriginalAlign = align;
|
2018-01-22 07:35:28 +00:00
|
|
|
}
|
|
|
|
else if(SrcType == UserFmtMSADPCM)
|
|
|
|
{
|
|
|
|
assert(DstType == FmtShort);
|
2018-01-22 08:23:19 +00:00
|
|
|
if(data != NULL && ALBuf->data != NULL)
|
2018-01-22 07:35:28 +00:00
|
|
|
Convert_ALshort_ALmsadpcm(ALBuf->data, data, NumChannels, frames, align);
|
2018-01-26 21:34:59 +00:00
|
|
|
ALBuf->OriginalAlign = align;
|
2010-11-28 04:33:37 +00:00
|
|
|
}
|
2012-01-26 03:32:10 +00:00
|
|
|
else
|
2011-03-16 19:24:53 +00:00
|
|
|
{
|
2018-01-22 08:23:19 +00:00
|
|
|
assert((long)SrcType == (long)DstType);
|
|
|
|
if(data != NULL && ALBuf->data != NULL)
|
2018-01-22 07:35:28 +00:00
|
|
|
memcpy(ALBuf->data, data, frames*FrameSize);
|
2018-01-26 21:34:59 +00:00
|
|
|
ALBuf->OriginalAlign = 1;
|
2011-03-16 19:24:53 +00:00
|
|
|
}
|
2018-01-26 21:34:59 +00:00
|
|
|
ALBuf->OriginalSize = size;
|
|
|
|
ALBuf->OriginalType = SrcType;
|
2012-01-26 03:32:10 +00:00
|
|
|
|
2010-11-28 21:08:51 +00:00
|
|
|
ALBuf->Frequency = freq;
|
|
|
|
ALBuf->FmtChannels = DstChannels;
|
2010-11-30 08:28:02 +00:00
|
|
|
ALBuf->FmtType = DstType;
|
2018-01-20 19:49:01 +00:00
|
|
|
ALBuf->Access = access;
|
2010-11-28 04:33:37 +00:00
|
|
|
|
2012-01-27 00:49:11 +00:00
|
|
|
ALBuf->SampleLen = frames;
|
2010-11-28 04:33:37 +00:00
|
|
|
ALBuf->LoopStart = 0;
|
2011-10-03 17:07:50 +00:00
|
|
|
ALBuf->LoopEnd = ALBuf->SampleLen;
|
2010-11-28 04:33:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-18 15:13:23 +00:00
|
|
|
ALsizei BytesFromUserFmt(enum UserFmtType type)
|
2010-11-29 23:01:27 +00:00
|
|
|
{
|
|
|
|
switch(type)
|
|
|
|
{
|
2010-12-04 06:33:41 +00:00
|
|
|
case UserFmtUByte: return sizeof(ALubyte);
|
|
|
|
case UserFmtShort: return sizeof(ALshort);
|
|
|
|
case UserFmtFloat: return sizeof(ALfloat);
|
|
|
|
case UserFmtDouble: return sizeof(ALdouble);
|
2011-04-28 04:05:46 +00:00
|
|
|
case UserFmtMulaw: return sizeof(ALubyte);
|
2011-10-01 11:55:03 +00:00
|
|
|
case UserFmtAlaw: return sizeof(ALubyte);
|
2011-04-28 04:05:46 +00:00
|
|
|
case UserFmtIMA4: break; /* not handled here */
|
2014-03-05 06:44:30 +00:00
|
|
|
case UserFmtMSADPCM: break; /* not handled here */
|
2010-11-29 23:01:27 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2017-01-18 15:13:23 +00:00
|
|
|
ALsizei ChannelsFromUserFmt(enum UserFmtChannels chans)
|
2010-11-29 23:01:27 +00:00
|
|
|
{
|
|
|
|
switch(chans)
|
|
|
|
{
|
2010-12-04 06:33:41 +00:00
|
|
|
case UserFmtMono: return 1;
|
|
|
|
case UserFmtStereo: return 2;
|
|
|
|
case UserFmtRear: return 2;
|
|
|
|
case UserFmtQuad: return 4;
|
|
|
|
case UserFmtX51: return 6;
|
|
|
|
case UserFmtX61: return 7;
|
|
|
|
case UserFmtX71: return 8;
|
2014-11-01 00:18:45 +00:00
|
|
|
case UserFmtBFormat2D: return 3;
|
|
|
|
case UserFmtBFormat3D: return 4;
|
2010-11-29 23:01:27 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2011-09-19 02:06:19 +00:00
|
|
|
static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
|
|
|
|
enum UserFmtType *type)
|
2010-11-27 23:33:33 +00:00
|
|
|
{
|
2011-09-19 02:06:19 +00:00
|
|
|
static const struct {
|
|
|
|
ALenum format;
|
|
|
|
enum UserFmtChannels channels;
|
|
|
|
enum UserFmtType type;
|
|
|
|
} list[] = {
|
2014-03-05 06:44:30 +00:00
|
|
|
{ AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte },
|
|
|
|
{ AL_FORMAT_MONO16, UserFmtMono, UserFmtShort },
|
|
|
|
{ AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat },
|
|
|
|
{ AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble },
|
|
|
|
{ AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 },
|
|
|
|
{ AL_FORMAT_MONO_MSADPCM_SOFT, UserFmtMono, UserFmtMSADPCM },
|
|
|
|
{ AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw },
|
|
|
|
{ AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw },
|
|
|
|
|
|
|
|
{ AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte },
|
|
|
|
{ AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort },
|
|
|
|
{ AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat },
|
|
|
|
{ AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble },
|
|
|
|
{ AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 },
|
|
|
|
{ AL_FORMAT_STEREO_MSADPCM_SOFT, UserFmtStereo, UserFmtMSADPCM },
|
|
|
|
{ AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw },
|
|
|
|
{ AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw },
|
2011-09-19 02:06:19 +00:00
|
|
|
|
|
|
|
{ AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte },
|
|
|
|
{ AL_FORMAT_REAR16, UserFmtRear, UserFmtShort },
|
|
|
|
{ AL_FORMAT_REAR32, UserFmtRear, UserFmtFloat },
|
|
|
|
{ AL_FORMAT_REAR_MULAW, UserFmtRear, UserFmtMulaw },
|
|
|
|
|
|
|
|
{ AL_FORMAT_QUAD8_LOKI, UserFmtQuad, UserFmtUByte },
|
|
|
|
{ AL_FORMAT_QUAD16_LOKI, UserFmtQuad, UserFmtShort },
|
|
|
|
|
|
|
|
{ AL_FORMAT_QUAD8, UserFmtQuad, UserFmtUByte },
|
|
|
|
{ AL_FORMAT_QUAD16, UserFmtQuad, UserFmtShort },
|
|
|
|
{ AL_FORMAT_QUAD32, UserFmtQuad, UserFmtFloat },
|
|
|
|
{ AL_FORMAT_QUAD_MULAW, UserFmtQuad, UserFmtMulaw },
|
|
|
|
|
|
|
|
{ AL_FORMAT_51CHN8, UserFmtX51, UserFmtUByte },
|
|
|
|
{ AL_FORMAT_51CHN16, UserFmtX51, UserFmtShort },
|
|
|
|
{ AL_FORMAT_51CHN32, UserFmtX51, UserFmtFloat },
|
|
|
|
{ AL_FORMAT_51CHN_MULAW, UserFmtX51, UserFmtMulaw },
|
|
|
|
|
|
|
|
{ AL_FORMAT_61CHN8, UserFmtX61, UserFmtUByte },
|
|
|
|
{ AL_FORMAT_61CHN16, UserFmtX61, UserFmtShort },
|
|
|
|
{ AL_FORMAT_61CHN32, UserFmtX61, UserFmtFloat },
|
|
|
|
{ AL_FORMAT_61CHN_MULAW, UserFmtX61, UserFmtMulaw },
|
|
|
|
|
|
|
|
{ AL_FORMAT_71CHN8, UserFmtX71, UserFmtUByte },
|
|
|
|
{ AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort },
|
|
|
|
{ AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat },
|
|
|
|
{ AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw },
|
2014-11-01 00:18:45 +00:00
|
|
|
|
|
|
|
{ AL_FORMAT_BFORMAT2D_8, UserFmtBFormat2D, UserFmtUByte },
|
|
|
|
{ AL_FORMAT_BFORMAT2D_16, UserFmtBFormat2D, UserFmtShort },
|
|
|
|
{ AL_FORMAT_BFORMAT2D_FLOAT32, UserFmtBFormat2D, UserFmtFloat },
|
2014-11-01 05:52:30 +00:00
|
|
|
{ AL_FORMAT_BFORMAT2D_MULAW, UserFmtBFormat2D, UserFmtMulaw },
|
2014-11-01 00:18:45 +00:00
|
|
|
|
|
|
|
{ AL_FORMAT_BFORMAT3D_8, UserFmtBFormat3D, UserFmtUByte },
|
|
|
|
{ AL_FORMAT_BFORMAT3D_16, UserFmtBFormat3D, UserFmtShort },
|
|
|
|
{ AL_FORMAT_BFORMAT3D_FLOAT32, UserFmtBFormat3D, UserFmtFloat },
|
2014-11-01 05:52:30 +00:00
|
|
|
{ AL_FORMAT_BFORMAT3D_MULAW, UserFmtBFormat3D, UserFmtMulaw },
|
2011-09-19 02:06:19 +00:00
|
|
|
};
|
|
|
|
ALuint i;
|
|
|
|
|
2012-02-19 20:07:40 +00:00
|
|
|
for(i = 0;i < COUNTOF(list);i++)
|
2010-11-27 23:33:33 +00:00
|
|
|
{
|
2011-09-19 02:06:19 +00:00
|
|
|
if(list[i].format == format)
|
|
|
|
{
|
|
|
|
*chans = list[i].channels;
|
|
|
|
*type = list[i].type;
|
2010-11-30 04:34:33 +00:00
|
|
|
return AL_TRUE;
|
2011-09-19 02:06:19 +00:00
|
|
|
}
|
2010-11-27 23:33:33 +00:00
|
|
|
}
|
2011-09-19 02:06:19 +00:00
|
|
|
|
2010-11-30 04:34:33 +00:00
|
|
|
return AL_FALSE;
|
2010-11-27 23:33:33 +00:00
|
|
|
}
|
|
|
|
|
2017-01-18 15:13:23 +00:00
|
|
|
ALsizei BytesFromFmt(enum FmtType type)
|
2010-11-29 23:01:27 +00:00
|
|
|
{
|
|
|
|
switch(type)
|
|
|
|
{
|
2018-01-20 04:10:31 +00:00
|
|
|
case FmtUByte: return sizeof(ALubyte);
|
2010-11-29 23:01:27 +00:00
|
|
|
case FmtShort: return sizeof(ALshort);
|
|
|
|
case FmtFloat: return sizeof(ALfloat);
|
2018-01-22 02:34:03 +00:00
|
|
|
case FmtDouble: return sizeof(ALdouble);
|
2018-01-17 16:49:49 +00:00
|
|
|
case FmtMulaw: return sizeof(ALubyte);
|
|
|
|
case FmtAlaw: return sizeof(ALubyte);
|
2010-11-29 23:01:27 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2017-01-18 15:13:23 +00:00
|
|
|
ALsizei ChannelsFromFmt(enum FmtChannels chans)
|
2010-11-29 23:01:27 +00:00
|
|
|
{
|
|
|
|
switch(chans)
|
|
|
|
{
|
|
|
|
case FmtMono: return 1;
|
|
|
|
case FmtStereo: return 2;
|
|
|
|
case FmtRear: return 2;
|
|
|
|
case FmtQuad: return 4;
|
|
|
|
case FmtX51: return 6;
|
|
|
|
case FmtX61: return 7;
|
|
|
|
case FmtX71: return 8;
|
2014-11-01 00:18:45 +00:00
|
|
|
case FmtBFormat2D: return 3;
|
|
|
|
case FmtBFormat3D: return 4;
|
2010-11-29 23:01:27 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2010-11-27 23:37:51 +00:00
|
|
|
|
2018-01-20 05:00:53 +00:00
|
|
|
static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align)
|
2014-03-04 12:29:35 +00:00
|
|
|
{
|
2018-01-20 05:00:53 +00:00
|
|
|
if(align < 0)
|
|
|
|
return 0;
|
Add an extension to alter the block alignment for buffer unpack/pack ops
This is for unpacking (reading, e.g. alBufferData) and packing (writing, e.g.
alGetBufferSamplesSOFT) operations. The alignments are specified in sample
frames, with 0 meaning the default (65 for IMA4, 1 otherwise). IMA4 alignment
must be a multiple of 8, plus 1 (e.g. alignment = n*8 + 1), otherwise an error
will occur during (un)packing. Chenging the block alignment does not affect
already-loaded sample data, only future unpack/pack operations... so for
example, this is perfectly valid:
// Load mono IMA4 data with a block alignment of 1024 bytes, or 2041 sample
// frames.
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 2041);
alBufferData(buffer, AL_FORMAT_MONO_IMA4, data, data_len, srate);
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 0);
2014-03-04 13:16:45 +00:00
|
|
|
|
2018-01-20 05:00:53 +00:00
|
|
|
if(align == 0)
|
Add an extension to alter the block alignment for buffer unpack/pack ops
This is for unpacking (reading, e.g. alBufferData) and packing (writing, e.g.
alGetBufferSamplesSOFT) operations. The alignments are specified in sample
frames, with 0 meaning the default (65 for IMA4, 1 otherwise). IMA4 alignment
must be a multiple of 8, plus 1 (e.g. alignment = n*8 + 1), otherwise an error
will occur during (un)packing. Chenging the block alignment does not affect
already-loaded sample data, only future unpack/pack operations... so for
example, this is perfectly valid:
// Load mono IMA4 data with a block alignment of 1024 bytes, or 2041 sample
// frames.
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 2041);
alBufferData(buffer, AL_FORMAT_MONO_IMA4, data, data_len, srate);
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 0);
2014-03-04 13:16:45 +00:00
|
|
|
{
|
|
|
|
if(type == UserFmtIMA4)
|
|
|
|
{
|
|
|
|
/* Here is where things vary:
|
|
|
|
* nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
|
|
|
|
* Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
|
|
|
|
*/
|
2018-01-20 05:00:53 +00:00
|
|
|
return 65;
|
Add an extension to alter the block alignment for buffer unpack/pack ops
This is for unpacking (reading, e.g. alBufferData) and packing (writing, e.g.
alGetBufferSamplesSOFT) operations. The alignments are specified in sample
frames, with 0 meaning the default (65 for IMA4, 1 otherwise). IMA4 alignment
must be a multiple of 8, plus 1 (e.g. alignment = n*8 + 1), otherwise an error
will occur during (un)packing. Chenging the block alignment does not affect
already-loaded sample data, only future unpack/pack operations... so for
example, this is perfectly valid:
// Load mono IMA4 data with a block alignment of 1024 bytes, or 2041 sample
// frames.
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 2041);
alBufferData(buffer, AL_FORMAT_MONO_IMA4, data, data_len, srate);
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 0);
2014-03-04 13:16:45 +00:00
|
|
|
}
|
2018-01-20 05:00:53 +00:00
|
|
|
if(type == UserFmtMSADPCM)
|
|
|
|
return 64;
|
|
|
|
return 1;
|
Add an extension to alter the block alignment for buffer unpack/pack ops
This is for unpacking (reading, e.g. alBufferData) and packing (writing, e.g.
alGetBufferSamplesSOFT) operations. The alignments are specified in sample
frames, with 0 meaning the default (65 for IMA4, 1 otherwise). IMA4 alignment
must be a multiple of 8, plus 1 (e.g. alignment = n*8 + 1), otherwise an error
will occur during (un)packing. Chenging the block alignment does not affect
already-loaded sample data, only future unpack/pack operations... so for
example, this is perfectly valid:
// Load mono IMA4 data with a block alignment of 1024 bytes, or 2041 sample
// frames.
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 2041);
alBufferData(buffer, AL_FORMAT_MONO_IMA4, data, data_len, srate);
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 0);
2014-03-04 13:16:45 +00:00
|
|
|
}
|
|
|
|
|
2014-03-04 12:29:35 +00:00
|
|
|
if(type == UserFmtIMA4)
|
|
|
|
{
|
Add an extension to alter the block alignment for buffer unpack/pack ops
This is for unpacking (reading, e.g. alBufferData) and packing (writing, e.g.
alGetBufferSamplesSOFT) operations. The alignments are specified in sample
frames, with 0 meaning the default (65 for IMA4, 1 otherwise). IMA4 alignment
must be a multiple of 8, plus 1 (e.g. alignment = n*8 + 1), otherwise an error
will occur during (un)packing. Chenging the block alignment does not affect
already-loaded sample data, only future unpack/pack operations... so for
example, this is perfectly valid:
// Load mono IMA4 data with a block alignment of 1024 bytes, or 2041 sample
// frames.
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 2041);
alBufferData(buffer, AL_FORMAT_MONO_IMA4, data, data_len, srate);
alBufferi(buffer, AL_UNPACK_BLOCK_ALIGNMENT_SOFT, 0);
2014-03-04 13:16:45 +00:00
|
|
|
/* IMA4 block alignment must be a multiple of 8, plus 1. */
|
2018-01-20 05:00:53 +00:00
|
|
|
if((align&7) == 1) return align;
|
|
|
|
return 0;
|
2014-03-05 06:44:30 +00:00
|
|
|
}
|
|
|
|
if(type == UserFmtMSADPCM)
|
|
|
|
{
|
2014-03-07 05:42:03 +00:00
|
|
|
/* MSADPCM block alignment must be a multiple of 2. */
|
2018-01-20 05:00:53 +00:00
|
|
|
if((align&1) == 0) return align;
|
|
|
|
return 0;
|
2014-03-04 12:29:35 +00:00
|
|
|
}
|
|
|
|
|
2018-01-20 05:00:53 +00:00
|
|
|
return align;
|
2014-03-04 12:29:35 +00:00
|
|
|
}
|
|
|
|
|
2010-11-27 23:37:51 +00:00
|
|
|
|
2014-06-29 09:04:05 +00:00
|
|
|
ALbuffer *NewBuffer(ALCcontext *context)
|
|
|
|
{
|
|
|
|
ALCdevice *device = context->Device;
|
|
|
|
ALbuffer *buffer;
|
|
|
|
ALenum err;
|
|
|
|
|
2016-05-21 10:27:51 +00:00
|
|
|
buffer = al_calloc(16, sizeof(ALbuffer));
|
2014-06-29 09:04:05 +00:00
|
|
|
if(!buffer)
|
2018-01-25 23:59:59 +00:00
|
|
|
SETERR_RETURN(context, AL_OUT_OF_MEMORY, NULL, "Failed to allocate buffer object");
|
2014-06-29 09:04:05 +00:00
|
|
|
RWLockInit(&buffer->lock);
|
2018-01-20 19:49:01 +00:00
|
|
|
buffer->Access = 0;
|
|
|
|
buffer->MappedAccess = 0;
|
2014-06-29 09:04:05 +00:00
|
|
|
|
|
|
|
err = NewThunkEntry(&buffer->id);
|
|
|
|
if(err == AL_NO_ERROR)
|
|
|
|
err = InsertUIntMapEntry(&device->BufferMap, buffer->id, buffer);
|
|
|
|
if(err != AL_NO_ERROR)
|
|
|
|
{
|
|
|
|
FreeThunkEntry(buffer->id);
|
|
|
|
memset(buffer, 0, sizeof(ALbuffer));
|
2016-05-21 10:27:51 +00:00
|
|
|
al_free(buffer);
|
2014-06-29 09:04:05 +00:00
|
|
|
|
2018-01-25 23:59:59 +00:00
|
|
|
SETERR_RETURN(context, err, NULL, "Failed to set buffer ID");
|
2014-06-29 09:04:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2014-06-30 07:10:40 +00:00
|
|
|
void DeleteBuffer(ALCdevice *device, ALbuffer *buffer)
|
2014-06-29 09:04:05 +00:00
|
|
|
{
|
2014-06-30 07:10:40 +00:00
|
|
|
RemoveBuffer(device, buffer->id);
|
2014-06-29 09:04:05 +00:00
|
|
|
FreeThunkEntry(buffer->id);
|
|
|
|
|
2016-05-21 10:27:51 +00:00
|
|
|
al_free(buffer->data);
|
2014-06-29 09:04:05 +00:00
|
|
|
|
|
|
|
memset(buffer, 0, sizeof(*buffer));
|
2016-05-21 10:27:51 +00:00
|
|
|
al_free(buffer);
|
2014-06-29 09:04:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-11-14 02:02:18 +00:00
|
|
|
/*
|
2010-11-25 20:07:12 +00:00
|
|
|
* ReleaseALBuffers()
|
|
|
|
*
|
2010-12-02 04:34:29 +00:00
|
|
|
* INTERNAL: Called to destroy any buffers that still exist on the device
|
2010-11-25 20:07:12 +00:00
|
|
|
*/
|
2009-08-15 16:14:08 +00:00
|
|
|
ALvoid ReleaseALBuffers(ALCdevice *device)
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2010-05-02 02:59:41 +00:00
|
|
|
ALsizei i;
|
|
|
|
for(i = 0;i < device->BufferMap.size;i++)
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2016-07-05 03:35:32 +00:00
|
|
|
ALbuffer *temp = device->BufferMap.values[i];
|
|
|
|
device->BufferMap.values[i] = NULL;
|
2010-03-21 04:49:02 +00:00
|
|
|
|
2016-05-21 10:27:51 +00:00
|
|
|
al_free(temp->data);
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2012-04-20 05:14:02 +00:00
|
|
|
FreeThunkEntry(temp->id);
|
2010-03-21 04:49:02 +00:00
|
|
|
memset(temp, 0, sizeof(ALbuffer));
|
2016-05-21 10:27:51 +00:00
|
|
|
al_free(temp);
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
}
|