2007-11-13 18:02:18 -08: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 14:11:03 +02:00
|
|
|
* Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2007-11-13 18:02:18 -08:00
|
|
|
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
|
|
|
*/
|
|
|
|
|
2008-01-16 14:09:04 -08:00
|
|
|
#include "config.h"
|
|
|
|
|
2019-07-29 17:54:07 -07:00
|
|
|
#include "buffer.h"
|
2010-05-24 17:08:12 -07:00
|
|
|
|
2019-07-28 11:28:36 -07:00
|
|
|
#include <algorithm>
|
2018-10-31 12:01:07 -07:00
|
|
|
#include <array>
|
2019-07-28 11:28:36 -07:00
|
|
|
#include <atomic>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstdint>
|
2019-07-28 21:29:59 -07:00
|
|
|
#include <cstdlib>
|
2019-07-28 11:28:36 -07:00
|
|
|
#include <cstring>
|
|
|
|
#include <iterator>
|
2018-11-07 21:47:46 -08:00
|
|
|
#include <limits>
|
2019-07-28 11:28:36 -07:00
|
|
|
#include <memory>
|
|
|
|
#include <mutex>
|
|
|
|
#include <new>
|
2019-09-11 12:28:33 -07:00
|
|
|
#include <numeric>
|
2021-04-27 23:03:24 -07:00
|
|
|
#include <stdexcept>
|
2019-07-28 11:28:36 -07:00
|
|
|
#include <utility>
|
2018-10-31 10:37:16 -07:00
|
|
|
|
2019-07-28 11:28:36 -07:00
|
|
|
#include "AL/al.h"
|
|
|
|
#include "AL/alc.h"
|
|
|
|
#include "AL/alext.h"
|
|
|
|
|
2021-01-22 04:58:42 -08:00
|
|
|
#include "albit.h"
|
2019-07-28 11:28:36 -07:00
|
|
|
#include "albyte.h"
|
2021-04-27 18:31:20 -07:00
|
|
|
#include "alc/context.h"
|
2021-04-27 16:40:22 -07:00
|
|
|
#include "alc/device.h"
|
2021-04-27 16:04:54 -07:00
|
|
|
#include "alc/inprogext.h"
|
2019-07-28 11:28:36 -07:00
|
|
|
#include "almalloc.h"
|
|
|
|
#include "alnumeric.h"
|
2019-06-30 16:57:10 -07:00
|
|
|
#include "aloptional.h"
|
2019-07-28 11:28:36 -07:00
|
|
|
#include "atomic.h"
|
2020-12-21 18:00:43 -08:00
|
|
|
#include "core/except.h"
|
2021-03-31 09:37:30 -07:00
|
|
|
#include "core/logging.h"
|
2021-04-27 08:26:42 -07:00
|
|
|
#include "core/voice.h"
|
2019-07-28 11:28:36 -07:00
|
|
|
#include "opthelpers.h"
|
2007-11-13 18:02:18 -08:00
|
|
|
|
|
|
|
|
2018-11-07 21:47:46 -08:00
|
|
|
namespace {
|
2007-12-28 20:25:18 -08:00
|
|
|
|
2020-03-28 16:29:57 -07:00
|
|
|
constexpr int MaxAdpcmChannels{2};
|
|
|
|
|
2019-07-28 17:22:00 -07:00
|
|
|
/* IMA ADPCM Stepsize table */
|
|
|
|
constexpr int IMAStep_size[89] = {
|
|
|
|
7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19,
|
|
|
|
21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55,
|
|
|
|
60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157,
|
|
|
|
173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449,
|
|
|
|
494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282,
|
|
|
|
1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660,
|
|
|
|
4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,10442,
|
|
|
|
11487,12635,13899,15289,16818,18500,20350,22358,24633,27086,29794,
|
|
|
|
32767
|
|
|
|
};
|
|
|
|
|
|
|
|
/* IMA4 ADPCM Codeword decode table */
|
|
|
|
constexpr int IMA4Codeword[16] = {
|
|
|
|
1, 3, 5, 7, 9, 11, 13, 15,
|
|
|
|
-1,-3,-5,-7,-9,-11,-13,-15,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* IMA4 ADPCM Step index adjust decode table */
|
|
|
|
constexpr int IMA4Index_adjust[16] = {
|
|
|
|
-1,-1,-1,-1, 2, 4, 6, 8,
|
|
|
|
-1,-1,-1,-1, 2, 4, 6, 8
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/* MSADPCM Adaption table */
|
|
|
|
constexpr int MSADPCMAdaption[16] = {
|
|
|
|
230, 230, 230, 230, 307, 409, 512, 614,
|
|
|
|
768, 614, 512, 409, 307, 230, 230, 230
|
|
|
|
};
|
|
|
|
|
|
|
|
/* MSADPCM Adaption Coefficient tables */
|
|
|
|
constexpr int MSADPCMAdaptionCoeff[7][2] = {
|
|
|
|
{ 256, 0 },
|
|
|
|
{ 512, -256 },
|
|
|
|
{ 0, 0 },
|
|
|
|
{ 192, 64 },
|
|
|
|
{ 240, 0 },
|
|
|
|
{ 460, -208 },
|
|
|
|
{ 392, -232 }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2020-04-08 10:15:43 -07:00
|
|
|
void DecodeIMA4Block(int16_t *dst, const al::byte *src, size_t numchans, size_t align)
|
2019-07-28 17:22:00 -07:00
|
|
|
{
|
2020-04-08 10:15:43 -07:00
|
|
|
int sample[MaxAdpcmChannels]{};
|
|
|
|
int index[MaxAdpcmChannels]{};
|
2020-03-28 16:29:57 -07:00
|
|
|
ALuint code[MaxAdpcmChannels]{};
|
2019-07-28 17:22:00 -07:00
|
|
|
|
2019-09-11 14:33:26 -07:00
|
|
|
for(size_t c{0};c < numchans;c++)
|
2019-07-28 17:22:00 -07:00
|
|
|
{
|
|
|
|
sample[c] = al::to_integer<int>(src[0]) | (al::to_integer<int>(src[1])<<8);
|
|
|
|
sample[c] = (sample[c]^0x8000) - 32768;
|
|
|
|
src += 2;
|
|
|
|
index[c] = al::to_integer<int>(src[0]) | (al::to_integer<int>(src[1])<<8);
|
|
|
|
index[c] = clampi((index[c]^0x8000) - 32768, 0, 88);
|
|
|
|
src += 2;
|
|
|
|
|
2020-04-23 04:57:04 -07:00
|
|
|
*(dst++) = static_cast<int16_t>(sample[c]);
|
2019-07-28 17:22:00 -07:00
|
|
|
}
|
|
|
|
|
2019-09-11 14:33:26 -07:00
|
|
|
for(size_t i{1};i < align;i++)
|
2019-07-28 17:22:00 -07:00
|
|
|
{
|
|
|
|
if((i&7) == 1)
|
|
|
|
{
|
2019-09-11 14:33:26 -07:00
|
|
|
for(size_t c{0};c < numchans;c++)
|
2019-07-28 17:22:00 -07:00
|
|
|
{
|
|
|
|
code[c] = al::to_integer<ALuint>(src[0]) | (al::to_integer<ALuint>(src[1])<< 8) |
|
|
|
|
(al::to_integer<ALuint>(src[2])<<16) | (al::to_integer<ALuint>(src[3])<<24);
|
|
|
|
src += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-11 14:33:26 -07:00
|
|
|
for(size_t c{0};c < numchans;c++)
|
2019-07-28 17:22:00 -07:00
|
|
|
{
|
|
|
|
const ALuint nibble{code[c]&0xf};
|
|
|
|
code[c] >>= 4;
|
|
|
|
|
|
|
|
sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8;
|
|
|
|
sample[c] = clampi(sample[c], -32768, 32767);
|
|
|
|
|
|
|
|
index[c] += IMA4Index_adjust[nibble];
|
|
|
|
index[c] = clampi(index[c], 0, 88);
|
|
|
|
|
2020-04-23 04:57:04 -07:00
|
|
|
*(dst++) = static_cast<int16_t>(sample[c]);
|
2019-07-28 17:22:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-08 10:15:43 -07:00
|
|
|
void DecodeMSADPCMBlock(int16_t *dst, const al::byte *src, size_t numchans, size_t align)
|
2019-07-28 17:22:00 -07:00
|
|
|
{
|
2020-04-23 04:57:04 -07:00
|
|
|
uint8_t blockpred[MaxAdpcmChannels]{};
|
2020-04-08 10:15:43 -07:00
|
|
|
int delta[MaxAdpcmChannels]{};
|
|
|
|
int16_t samples[MaxAdpcmChannels][2]{};
|
2019-07-28 17:22:00 -07:00
|
|
|
|
2019-09-11 14:33:26 -07:00
|
|
|
for(size_t c{0};c < numchans;c++)
|
2019-07-28 17:22:00 -07:00
|
|
|
{
|
2019-09-11 14:33:26 -07:00
|
|
|
blockpred[c] = std::min<ALubyte>(al::to_integer<ALubyte>(src[0]), 6);
|
2019-07-28 17:22:00 -07:00
|
|
|
++src;
|
|
|
|
}
|
2019-09-11 14:33:26 -07:00
|
|
|
for(size_t c{0};c < numchans;c++)
|
2019-07-28 17:22:00 -07:00
|
|
|
{
|
|
|
|
delta[c] = al::to_integer<int>(src[0]) | (al::to_integer<int>(src[1])<<8);
|
|
|
|
delta[c] = (delta[c]^0x8000) - 32768;
|
|
|
|
src += 2;
|
|
|
|
}
|
2019-09-11 14:33:26 -07:00
|
|
|
for(size_t c{0};c < numchans;c++)
|
2019-07-28 17:22:00 -07:00
|
|
|
{
|
2019-09-11 14:33:26 -07:00
|
|
|
samples[c][0] = static_cast<ALshort>(al::to_integer<int>(src[0]) |
|
|
|
|
(al::to_integer<int>(src[1])<<8));
|
2019-07-28 17:22:00 -07:00
|
|
|
src += 2;
|
|
|
|
}
|
2019-09-11 14:33:26 -07:00
|
|
|
for(size_t c{0};c < numchans;c++)
|
2019-07-28 17:22:00 -07:00
|
|
|
{
|
2019-09-11 14:33:26 -07:00
|
|
|
samples[c][1] = static_cast<ALshort>(al::to_integer<int>(src[0]) |
|
|
|
|
(al::to_integer<int>(src[1])<<8));
|
2019-07-28 17:22:00 -07:00
|
|
|
src += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Second sample is written first. */
|
2019-09-11 14:33:26 -07:00
|
|
|
for(size_t c{0};c < numchans;c++)
|
2019-07-28 17:22:00 -07:00
|
|
|
*(dst++) = samples[c][1];
|
2019-09-11 14:33:26 -07:00
|
|
|
for(size_t c{0};c < numchans;c++)
|
2019-07-28 17:22:00 -07:00
|
|
|
*(dst++) = samples[c][0];
|
|
|
|
|
|
|
|
int num{0};
|
2019-09-11 14:33:26 -07:00
|
|
|
for(size_t i{2};i < align;i++)
|
2019-07-28 17:22:00 -07:00
|
|
|
{
|
2019-09-11 14:33:26 -07:00
|
|
|
for(size_t c{0};c < numchans;c++)
|
2019-07-28 17:22:00 -07:00
|
|
|
{
|
|
|
|
/* Read the nibble (first is in the upper bits). */
|
|
|
|
al::byte nibble;
|
|
|
|
if(!(num++ & 1))
|
|
|
|
nibble = *src >> 4;
|
|
|
|
else
|
|
|
|
nibble = *(src++) & 0x0f;
|
|
|
|
|
2020-04-08 10:15:43 -07:00
|
|
|
int pred{(samples[c][0]*MSADPCMAdaptionCoeff[blockpred[c]][0] +
|
2019-07-28 17:22:00 -07:00
|
|
|
samples[c][1]*MSADPCMAdaptionCoeff[blockpred[c]][1]) / 256};
|
|
|
|
pred += (al::to_integer<int>(nibble^0x08) - 0x08) * delta[c];
|
|
|
|
pred = clampi(pred, -32768, 32767);
|
|
|
|
|
|
|
|
samples[c][1] = samples[c][0];
|
2020-04-08 10:15:43 -07:00
|
|
|
samples[c][0] = static_cast<int16_t>(pred);
|
2019-07-28 17:22:00 -07:00
|
|
|
|
|
|
|
delta[c] = (MSADPCMAdaption[al::to_integer<ALubyte>(nibble)] * delta[c]) / 256;
|
|
|
|
delta[c] = maxi(16, delta[c]);
|
|
|
|
|
2020-04-08 10:15:43 -07:00
|
|
|
*(dst++) = static_cast<int16_t>(pred);
|
2019-07-28 17:22:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-23 04:57:04 -07:00
|
|
|
void Convert_int16_ima4(int16_t *dst, const al::byte *src, size_t numchans, size_t len,
|
2019-09-11 14:33:26 -07:00
|
|
|
size_t align)
|
2019-07-28 17:22:00 -07:00
|
|
|
{
|
2020-03-28 16:29:57 -07:00
|
|
|
assert(numchans <= MaxAdpcmChannels);
|
2019-09-11 14:33:26 -07:00
|
|
|
const size_t byte_align{((align-1)/2 + 4) * numchans};
|
2019-07-28 17:22:00 -07:00
|
|
|
|
|
|
|
len /= align;
|
|
|
|
while(len--)
|
|
|
|
{
|
|
|
|
DecodeIMA4Block(dst, src, numchans, align);
|
|
|
|
src += byte_align;
|
|
|
|
dst += align*numchans;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-23 04:57:04 -07:00
|
|
|
void Convert_int16_msadpcm(int16_t *dst, const al::byte *src, size_t numchans, size_t len,
|
2019-09-11 14:33:26 -07:00
|
|
|
size_t align)
|
2019-07-28 17:22:00 -07:00
|
|
|
{
|
2020-03-28 16:29:57 -07:00
|
|
|
assert(numchans <= MaxAdpcmChannels);
|
2019-09-11 14:33:26 -07:00
|
|
|
const size_t byte_align{((align-2)/2 + 7) * numchans};
|
2019-07-28 17:22:00 -07:00
|
|
|
|
|
|
|
len /= align;
|
|
|
|
while(len--)
|
|
|
|
{
|
|
|
|
DecodeMSADPCMBlock(dst, src, numchans, align);
|
|
|
|
src += byte_align;
|
|
|
|
dst += align*numchans;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-04-03 21:43:57 -07:00
|
|
|
ALuint BytesFromUserFmt(UserFmtType type) noexcept
|
2019-09-11 14:33:26 -07:00
|
|
|
{
|
|
|
|
switch(type)
|
|
|
|
{
|
2020-04-23 04:57:04 -07:00
|
|
|
case UserFmtUByte: return sizeof(uint8_t);
|
|
|
|
case UserFmtShort: return sizeof(int16_t);
|
|
|
|
case UserFmtFloat: return sizeof(float);
|
|
|
|
case UserFmtDouble: return sizeof(double);
|
|
|
|
case UserFmtMulaw: return sizeof(uint8_t);
|
|
|
|
case UserFmtAlaw: return sizeof(uint8_t);
|
2019-09-11 14:33:26 -07:00
|
|
|
case UserFmtIMA4: break; /* not handled here */
|
|
|
|
case UserFmtMSADPCM: break; /* not handled here */
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2020-04-03 21:43:57 -07:00
|
|
|
ALuint ChannelsFromUserFmt(UserFmtChannels chans, ALuint ambiorder) noexcept
|
2019-09-11 14:33:26 -07:00
|
|
|
{
|
|
|
|
switch(chans)
|
|
|
|
{
|
|
|
|
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;
|
2020-04-03 21:43:57 -07:00
|
|
|
case UserFmtBFormat2D: return (ambiorder*2) + 1;
|
|
|
|
case UserFmtBFormat3D: return (ambiorder+1) * (ambiorder+1);
|
2021-03-31 05:37:56 -07:00
|
|
|
case UserFmtUHJ2: return 2;
|
2021-03-31 10:03:31 -07:00
|
|
|
case UserFmtUHJ3: return 3;
|
2021-03-31 20:46:03 -07:00
|
|
|
case UserFmtUHJ4: return 4;
|
2019-09-11 14:33:26 -07:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-11-20 04:27:10 -08:00
|
|
|
al::optional<AmbiLayout> AmbiLayoutFromEnum(ALenum layout)
|
|
|
|
{
|
|
|
|
switch(layout)
|
|
|
|
{
|
|
|
|
case AL_FUMA_SOFT: return al::make_optional(AmbiLayout::FuMa);
|
|
|
|
case AL_ACN_SOFT: return al::make_optional(AmbiLayout::ACN);
|
|
|
|
}
|
|
|
|
return al::nullopt;
|
|
|
|
}
|
|
|
|
ALenum EnumFromAmbiLayout(AmbiLayout layout)
|
|
|
|
{
|
|
|
|
switch(layout)
|
|
|
|
{
|
|
|
|
case AmbiLayout::FuMa: return AL_FUMA_SOFT;
|
|
|
|
case AmbiLayout::ACN: return AL_ACN_SOFT;
|
|
|
|
}
|
|
|
|
throw std::runtime_error{"Invalid AmbiLayout: "+std::to_string(int(layout))};
|
|
|
|
}
|
|
|
|
|
|
|
|
al::optional<AmbiScaling> AmbiScalingFromEnum(ALenum scale)
|
|
|
|
{
|
|
|
|
switch(scale)
|
|
|
|
{
|
|
|
|
case AL_FUMA_SOFT: return al::make_optional(AmbiScaling::FuMa);
|
|
|
|
case AL_SN3D_SOFT: return al::make_optional(AmbiScaling::SN3D);
|
|
|
|
case AL_N3D_SOFT: return al::make_optional(AmbiScaling::N3D);
|
|
|
|
}
|
|
|
|
return al::nullopt;
|
|
|
|
}
|
|
|
|
ALenum EnumFromAmbiScaling(AmbiScaling scale)
|
|
|
|
{
|
|
|
|
switch(scale)
|
|
|
|
{
|
|
|
|
case AmbiScaling::FuMa: return AL_FUMA_SOFT;
|
|
|
|
case AmbiScaling::SN3D: return AL_SN3D_SOFT;
|
2021-07-13 06:33:54 -07:00
|
|
|
case AmbiScaling::N3D: return AL_N3D_SOFT;
|
2021-07-13 06:31:13 -07:00
|
|
|
case AmbiScaling::UHJ: break;
|
2020-11-20 04:27:10 -08:00
|
|
|
}
|
|
|
|
throw std::runtime_error{"Invalid AmbiScaling: "+std::to_string(int(scale))};
|
|
|
|
}
|
|
|
|
|
2021-07-17 10:08:38 -07:00
|
|
|
al::optional<FmtChannels> FmtFromUserFmt(UserFmtChannels chans)
|
|
|
|
{
|
|
|
|
switch(chans)
|
|
|
|
{
|
|
|
|
case UserFmtMono: return al::make_optional(FmtMono);
|
|
|
|
case UserFmtStereo: return al::make_optional(FmtStereo);
|
|
|
|
case UserFmtRear: return al::make_optional(FmtRear);
|
|
|
|
case UserFmtQuad: return al::make_optional(FmtQuad);
|
|
|
|
case UserFmtX51: return al::make_optional(FmtX51);
|
|
|
|
case UserFmtX61: return al::make_optional(FmtX61);
|
|
|
|
case UserFmtX71: return al::make_optional(FmtX71);
|
|
|
|
case UserFmtBFormat2D: return al::make_optional(FmtBFormat2D);
|
|
|
|
case UserFmtBFormat3D: return al::make_optional(FmtBFormat3D);
|
|
|
|
case UserFmtUHJ2: return al::make_optional(FmtUHJ2);
|
|
|
|
case UserFmtUHJ3: return al::make_optional(FmtUHJ3);
|
|
|
|
case UserFmtUHJ4: return al::make_optional(FmtUHJ4);
|
|
|
|
}
|
|
|
|
return al::nullopt;
|
|
|
|
}
|
|
|
|
al::optional<FmtType> FmtFromUserFmt(UserFmtType type)
|
|
|
|
{
|
|
|
|
switch(type)
|
|
|
|
{
|
|
|
|
case UserFmtUByte: return al::make_optional(FmtUByte);
|
|
|
|
case UserFmtShort: return al::make_optional(FmtShort);
|
|
|
|
case UserFmtFloat: return al::make_optional(FmtFloat);
|
|
|
|
case UserFmtDouble: return al::make_optional(FmtDouble);
|
|
|
|
case UserFmtMulaw: return al::make_optional(FmtMulaw);
|
|
|
|
case UserFmtAlaw: return al::make_optional(FmtAlaw);
|
|
|
|
/* ADPCM not handled here. */
|
|
|
|
case UserFmtIMA4: break;
|
|
|
|
case UserFmtMSADPCM: break;
|
|
|
|
}
|
|
|
|
return al::nullopt;
|
|
|
|
}
|
|
|
|
|
2019-09-11 14:33:26 -07:00
|
|
|
|
2018-11-07 21:47:46 -08:00
|
|
|
constexpr ALbitfieldSOFT INVALID_STORAGE_MASK{~unsigned(AL_MAP_READ_BIT_SOFT |
|
|
|
|
AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT)};
|
|
|
|
constexpr ALbitfieldSOFT MAP_READ_WRITE_FLAGS{AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT};
|
|
|
|
constexpr ALbitfieldSOFT INVALID_MAP_FLAGS{~unsigned(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT |
|
|
|
|
AL_MAP_PERSISTENT_BIT_SOFT)};
|
|
|
|
|
|
|
|
|
2019-09-11 12:28:33 -07:00
|
|
|
bool EnsureBuffers(ALCdevice *device, size_t needed)
|
2018-11-07 21:47:46 -08:00
|
|
|
{
|
2019-09-11 12:28:33 -07:00
|
|
|
size_t count{std::accumulate(device->BufferList.cbegin(), device->BufferList.cend(), size_t{0},
|
|
|
|
[](size_t cur, const BufferSubList &sublist) noexcept -> size_t
|
2021-01-22 04:58:42 -08:00
|
|
|
{ return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })};
|
2018-11-18 22:31:51 -08:00
|
|
|
|
2019-09-11 12:28:33 -07:00
|
|
|
while(needed > count)
|
2018-11-07 21:47:46 -08:00
|
|
|
{
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(device->BufferList.size() >= 1<<25)
|
2019-09-11 12:28:33 -07:00
|
|
|
return false;
|
|
|
|
|
2018-11-18 22:31:51 -08:00
|
|
|
device->BufferList.emplace_back();
|
2019-09-11 12:28:33 -07:00
|
|
|
auto sublist = device->BufferList.end() - 1;
|
2019-01-07 04:06:40 -08:00
|
|
|
sublist->FreeMask = ~0_u64;
|
2019-09-11 12:28:33 -07:00
|
|
|
sublist->Buffers = static_cast<ALbuffer*>(al_calloc(alignof(ALbuffer), sizeof(ALbuffer)*64));
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!sublist->Buffers)
|
2018-11-07 21:47:46 -08:00
|
|
|
{
|
2018-11-18 22:31:51 -08:00
|
|
|
device->BufferList.pop_back();
|
2019-09-11 12:28:33 -07:00
|
|
|
return false;
|
2018-11-07 21:47:46 -08:00
|
|
|
}
|
2019-09-11 12:28:33 -07:00
|
|
|
count += 64;
|
2018-11-07 21:47:46 -08:00
|
|
|
}
|
2019-09-11 12:28:33 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ALbuffer *AllocBuffer(ALCdevice *device)
|
|
|
|
{
|
|
|
|
auto sublist = std::find_if(device->BufferList.begin(), device->BufferList.end(),
|
|
|
|
[](const BufferSubList &entry) noexcept -> bool
|
|
|
|
{ return entry.FreeMask != 0; }
|
|
|
|
);
|
|
|
|
|
|
|
|
auto lidx = static_cast<ALuint>(std::distance(device->BufferList.begin(), sublist));
|
2021-01-22 04:58:42 -08:00
|
|
|
auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask));
|
2018-11-07 21:47:46 -08:00
|
|
|
|
2019-09-01 18:07:16 -07:00
|
|
|
ALbuffer *buffer{::new (sublist->Buffers + slidx) ALbuffer{}};
|
|
|
|
|
2018-11-07 21:47:46 -08:00
|
|
|
/* Add 1 to avoid buffer ID 0. */
|
|
|
|
buffer->id = ((lidx<<6) | slidx) + 1;
|
|
|
|
|
2019-01-07 04:06:40 -08:00
|
|
|
sublist->FreeMask &= ~(1_u64 << slidx);
|
2018-11-07 21:47:46 -08:00
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreeBuffer(ALCdevice *device, ALbuffer *buffer)
|
|
|
|
{
|
2019-09-11 12:28:33 -07:00
|
|
|
const ALuint id{buffer->id - 1};
|
|
|
|
const size_t lidx{id >> 6};
|
|
|
|
const ALuint slidx{id & 0x3f};
|
2018-11-07 21:47:46 -08:00
|
|
|
|
2019-06-05 17:25:08 -07:00
|
|
|
al::destroy_at(buffer);
|
2018-11-07 21:47:46 -08:00
|
|
|
|
2019-01-07 04:06:40 -08:00
|
|
|
device->BufferList[lidx].FreeMask |= 1_u64 << slidx;
|
2018-11-07 21:47:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id)
|
2018-01-27 01:51:01 -08:00
|
|
|
{
|
2019-09-11 12:28:33 -07:00
|
|
|
const size_t lidx{(id-1) >> 6};
|
|
|
|
const ALuint slidx{(id-1) & 0x3f};
|
2018-01-27 01:51:01 -08:00
|
|
|
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(lidx >= device->BufferList.size())
|
2018-10-31 10:37:16 -07:00
|
|
|
return nullptr;
|
2018-11-18 22:31:51 -08:00
|
|
|
BufferSubList &sublist = device->BufferList[lidx];
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(sublist.FreeMask & (1_u64 << slidx))
|
2018-10-31 10:37:16 -07:00
|
|
|
return nullptr;
|
2018-11-18 22:31:51 -08:00
|
|
|
return sublist.Buffers + slidx;
|
2018-01-27 01:51:01 -08:00
|
|
|
}
|
2018-01-26 21:11:12 -08:00
|
|
|
|
2018-11-07 21:47:46 -08:00
|
|
|
|
2019-09-11 14:33:26 -07:00
|
|
|
ALuint SanitizeAlignment(UserFmtType type, ALuint align)
|
2018-11-07 21:47:46 -08:00
|
|
|
{
|
|
|
|
if(align == 0)
|
|
|
|
{
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
return 65;
|
|
|
|
}
|
|
|
|
if(type == UserFmtMSADPCM)
|
|
|
|
return 64;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(type == UserFmtIMA4)
|
|
|
|
{
|
|
|
|
/* IMA4 block alignment must be a multiple of 8, plus 1. */
|
2019-09-11 14:33:26 -07:00
|
|
|
if((align&7) == 1) return static_cast<ALuint>(align);
|
2018-11-07 21:47:46 -08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if(type == UserFmtMSADPCM)
|
|
|
|
{
|
|
|
|
/* MSADPCM block alignment must be a multiple of 2. */
|
2019-09-11 14:33:26 -07:00
|
|
|
if((align&1) == 0) return static_cast<ALuint>(align);
|
2018-11-07 21:47:46 -08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-11 14:33:26 -07:00
|
|
|
return static_cast<ALuint>(align);
|
2018-11-07 21:47:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const ALchar *NameFromUserFmtType(UserFmtType type)
|
|
|
|
{
|
|
|
|
switch(type)
|
|
|
|
{
|
2020-04-28 07:56:36 -07:00
|
|
|
case UserFmtUByte: return "UInt8";
|
|
|
|
case UserFmtShort: return "Int16";
|
2018-11-07 21:47:46 -08:00
|
|
|
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>";
|
|
|
|
}
|
|
|
|
|
2019-09-11 14:33:26 -07:00
|
|
|
/** Loads the specified data into the buffer, using the specified format. */
|
|
|
|
void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size,
|
|
|
|
UserFmtChannels SrcChannels, UserFmtType SrcType, const al::byte *SrcData,
|
|
|
|
ALbitfieldSOFT access)
|
2018-11-07 21:47:46 -08:00
|
|
|
{
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)
|
2018-11-07 21:47:46 -08:00
|
|
|
SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u",
|
|
|
|
ALBuf->id);
|
|
|
|
|
|
|
|
/* Currently no channel configurations need to be converted. */
|
2021-07-17 10:08:38 -07:00
|
|
|
auto DstChannels = FmtFromUserFmt(SrcChannels);
|
|
|
|
if UNLIKELY(!DstChannels)
|
2019-01-08 19:42:44 +01:00
|
|
|
SETERR_RETURN(context, AL_INVALID_ENUM, , "Invalid format");
|
2018-11-07 21:47:46 -08:00
|
|
|
|
2021-07-17 10:08:38 -07:00
|
|
|
/* IMA4 and MSADPCM convert to 16-bit short.
|
|
|
|
*
|
|
|
|
* TODO: Currently we can only map samples when they're not converted. To
|
2018-11-07 21:47:46 -08:00
|
|
|
* allow it would need some kind of double-buffering to hold onto a copy of
|
|
|
|
* the original data.
|
|
|
|
*/
|
|
|
|
if((access&MAP_READ_WRITE_FLAGS))
|
|
|
|
{
|
2021-07-17 10:08:38 -07:00
|
|
|
if UNLIKELY(SrcType == UserFmtIMA4 || SrcType == UserFmtMSADPCM)
|
2019-08-04 11:59:14 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "%s samples cannot be mapped",
|
|
|
|
NameFromUserFmtType(SrcType));
|
2018-11-07 21:47:46 -08:00
|
|
|
}
|
2021-07-17 10:08:38 -07:00
|
|
|
auto DstType = (SrcType == UserFmtIMA4 || SrcType == UserFmtMSADPCM)
|
|
|
|
? al::make_optional(FmtShort) : FmtFromUserFmt(SrcType);
|
|
|
|
if UNLIKELY(!DstType)
|
|
|
|
SETERR_RETURN(context, AL_INVALID_ENUM, , "Invalid format");
|
2018-11-07 21:47:46 -08:00
|
|
|
|
2019-09-11 14:33:26 -07:00
|
|
|
const ALuint unpackalign{ALBuf->UnpackAlign};
|
|
|
|
const ALuint align{SanitizeAlignment(SrcType, unpackalign)};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(align < 1)
|
2019-09-11 14:33:26 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %u for %s samples",
|
2019-08-04 11:59:14 -07:00
|
|
|
unpackalign, NameFromUserFmtType(SrcType));
|
2018-11-07 21:47:46 -08:00
|
|
|
|
2021-07-17 10:08:38 -07:00
|
|
|
const ALuint ambiorder{(*DstChannels == FmtBFormat2D || *DstChannels == FmtBFormat3D) ?
|
2021-03-31 20:46:03 -07:00
|
|
|
ALBuf->UnpackAmbiOrder :
|
2021-07-17 10:08:38 -07:00
|
|
|
((*DstChannels == FmtUHJ2 || *DstChannels == FmtUHJ3 || *DstChannels == FmtUHJ4) ? 1 :
|
2021-03-31 20:46:03 -07:00
|
|
|
0)};
|
2020-04-04 01:52:29 -07:00
|
|
|
|
2018-11-07 21:47:46 -08:00
|
|
|
if((access&AL_PRESERVE_DATA_BIT_SOFT))
|
|
|
|
{
|
|
|
|
/* Can only preserve data with the same format and alignment. */
|
2020-11-21 00:54:25 -08:00
|
|
|
if UNLIKELY(ALBuf->mChannels != DstChannels || ALBuf->OriginalType != SrcType)
|
2018-11-07 21:47:46 -08:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format");
|
2019-09-21 16:47:33 -07:00
|
|
|
if UNLIKELY(ALBuf->OriginalAlign != align)
|
2018-11-07 21:47:46 -08:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment");
|
2020-11-21 00:54:25 -08:00
|
|
|
if(ALBuf->mAmbiOrder != ambiorder)
|
2020-04-04 01:52:29 -07:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched order");
|
2018-11-07 21:47:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert the input/source size in bytes to sample frames using the unpack
|
|
|
|
* block alignment.
|
|
|
|
*/
|
2020-04-04 01:52:29 -07:00
|
|
|
const ALuint SrcByteAlign{ChannelsFromUserFmt(SrcChannels, ambiorder) *
|
|
|
|
((SrcType == UserFmtIMA4) ? (align-1)/2 + 4 :
|
|
|
|
(SrcType == UserFmtMSADPCM) ? (align-2)/2 + 7 :
|
|
|
|
(align * BytesFromUserFmt(SrcType)))};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY((size%SrcByteAlign) != 0)
|
2018-11-07 21:47:46 -08:00
|
|
|
SETERR_RETURN(context, AL_INVALID_VALUE,,
|
|
|
|
"Data size %d is not a multiple of frame size %d (%d unpack alignment)",
|
|
|
|
size, SrcByteAlign, align);
|
|
|
|
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(size/SrcByteAlign > std::numeric_limits<ALsizei>::max()/align)
|
2018-11-07 21:47:46 -08:00
|
|
|
SETERR_RETURN(context, AL_OUT_OF_MEMORY,,
|
|
|
|
"Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align);
|
2019-09-11 14:33:26 -07:00
|
|
|
const ALuint frames{size / SrcByteAlign * align};
|
2018-11-07 21:47:46 -08:00
|
|
|
|
|
|
|
/* Convert the sample frames to the number of bytes needed for internal
|
|
|
|
* storage.
|
|
|
|
*/
|
2021-07-17 10:08:38 -07:00
|
|
|
ALuint NumChannels{ChannelsFromFmt(*DstChannels, ambiorder)};
|
|
|
|
ALuint FrameSize{NumChannels * BytesFromFmt(*DstType)};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(frames > std::numeric_limits<size_t>::max()/FrameSize)
|
2018-11-07 21:47:46 -08:00
|
|
|
SETERR_RETURN(context, AL_OUT_OF_MEMORY,,
|
|
|
|
"Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize);
|
2019-05-24 06:25:18 -07:00
|
|
|
size_t newsize{static_cast<size_t>(frames) * FrameSize};
|
2018-11-07 21:47:46 -08: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.
|
|
|
|
*/
|
2019-05-24 06:25:18 -07:00
|
|
|
newsize = RoundUp(newsize, 16);
|
2020-11-21 00:54:25 -08:00
|
|
|
if(newsize != ALBuf->mData.size())
|
2018-11-07 21:47:46 -08:00
|
|
|
{
|
2019-05-24 13:32:20 -07:00
|
|
|
auto newdata = al::vector<al::byte,16>(newsize, al::byte{});
|
2018-11-07 21:47:46 -08:00
|
|
|
if((access&AL_PRESERVE_DATA_BIT_SOFT))
|
|
|
|
{
|
2020-11-21 00:54:25 -08:00
|
|
|
const size_t tocopy{minz(newdata.size(), ALBuf->mData.size())};
|
|
|
|
std::copy_n(ALBuf->mData.begin(), tocopy, newdata.begin());
|
2018-11-07 21:47:46 -08:00
|
|
|
}
|
2020-11-21 00:54:25 -08:00
|
|
|
newdata.swap(ALBuf->mData);
|
2018-11-07 21:47:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if(SrcType == UserFmtIMA4)
|
|
|
|
{
|
2021-07-17 10:08:38 -07:00
|
|
|
assert(*DstType == FmtShort);
|
2020-11-21 00:54:25 -08:00
|
|
|
if(SrcData != nullptr && !ALBuf->mData.empty())
|
|
|
|
Convert_int16_ima4(reinterpret_cast<int16_t*>(ALBuf->mData.data()), SrcData,
|
2020-04-23 04:57:04 -07:00
|
|
|
NumChannels, frames, align);
|
2018-11-07 21:47:46 -08:00
|
|
|
ALBuf->OriginalAlign = align;
|
|
|
|
}
|
|
|
|
else if(SrcType == UserFmtMSADPCM)
|
|
|
|
{
|
2021-07-17 10:08:38 -07:00
|
|
|
assert(*DstType == FmtShort);
|
2020-11-21 00:54:25 -08:00
|
|
|
if(SrcData != nullptr && !ALBuf->mData.empty())
|
|
|
|
Convert_int16_msadpcm(reinterpret_cast<int16_t*>(ALBuf->mData.data()), SrcData,
|
2020-04-23 04:57:04 -07:00
|
|
|
NumChannels, frames, align);
|
2018-11-07 21:47:46 -08:00
|
|
|
ALBuf->OriginalAlign = align;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-07-17 10:08:38 -07:00
|
|
|
assert(DstType.has_value());
|
2020-11-21 00:54:25 -08:00
|
|
|
if(SrcData != nullptr && !ALBuf->mData.empty())
|
|
|
|
std::copy_n(SrcData, frames*FrameSize, ALBuf->mData.begin());
|
2018-11-07 21:47:46 -08:00
|
|
|
ALBuf->OriginalAlign = 1;
|
|
|
|
}
|
|
|
|
ALBuf->OriginalSize = size;
|
|
|
|
ALBuf->OriginalType = SrcType;
|
|
|
|
|
|
|
|
ALBuf->Access = access;
|
|
|
|
|
2020-11-21 00:54:25 -08:00
|
|
|
ALBuf->mSampleRate = static_cast<ALuint>(freq);
|
2021-07-17 10:08:38 -07:00
|
|
|
ALBuf->mChannels = *DstChannels;
|
|
|
|
ALBuf->mType = *DstType;
|
2020-11-21 00:54:25 -08:00
|
|
|
ALBuf->mAmbiOrder = ambiorder;
|
2020-02-17 00:22:51 -08:00
|
|
|
|
2020-11-21 00:54:25 -08:00
|
|
|
ALBuf->mCallback = nullptr;
|
|
|
|
ALBuf->mUserData = nullptr;
|
|
|
|
|
|
|
|
ALBuf->mSampleLen = frames;
|
|
|
|
ALBuf->mLoopStart = 0;
|
|
|
|
ALBuf->mLoopEnd = ALBuf->mSampleLen;
|
2018-11-07 21:47:46 -08:00
|
|
|
}
|
|
|
|
|
2020-02-17 00:22:51 -08:00
|
|
|
/** Prepares the buffer to use the specified callback, using the specified format. */
|
|
|
|
void PrepareCallback(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq,
|
|
|
|
UserFmtChannels SrcChannels, UserFmtType SrcType, LPALBUFFERCALLBACKTYPESOFT callback,
|
|
|
|
void *userptr)
|
|
|
|
{
|
|
|
|
if UNLIKELY(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)
|
|
|
|
SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying callback for in-use buffer %u",
|
|
|
|
ALBuf->id);
|
|
|
|
|
|
|
|
/* Currently no channel configurations need to be converted. */
|
2021-07-17 10:08:38 -07:00
|
|
|
auto DstChannels = FmtFromUserFmt(SrcChannels);
|
|
|
|
if UNLIKELY(!DstChannels)
|
2020-02-17 00:22:51 -08:00
|
|
|
SETERR_RETURN(context, AL_INVALID_ENUM,, "Invalid format");
|
|
|
|
|
|
|
|
/* IMA4 and MSADPCM convert to 16-bit short. Not supported with callbacks. */
|
2021-07-17 10:08:38 -07:00
|
|
|
auto DstType = FmtFromUserFmt(SrcType);
|
|
|
|
if UNLIKELY(!DstType)
|
2020-02-17 00:22:51 -08:00
|
|
|
SETERR_RETURN(context, AL_INVALID_ENUM,, "Unsupported callback format");
|
|
|
|
|
2021-07-17 10:08:38 -07:00
|
|
|
const ALuint ambiorder{(*DstChannels == FmtBFormat2D || *DstChannels == FmtBFormat3D) ?
|
2021-03-31 20:46:03 -07:00
|
|
|
ALBuf->UnpackAmbiOrder :
|
2021-07-17 10:08:38 -07:00
|
|
|
((*DstChannels == FmtUHJ2 || *DstChannels == FmtUHJ3 || *DstChannels == FmtUHJ4) ? 1 :
|
2021-03-31 20:46:03 -07:00
|
|
|
0)};
|
2020-04-04 01:52:29 -07:00
|
|
|
|
2021-03-31 09:37:30 -07:00
|
|
|
constexpr uint line_size{BufferLineSize + MaxPostVoiceLoad};
|
2021-07-17 10:08:38 -07:00
|
|
|
al::vector<al::byte,16>(FrameSizeFromFmt(*DstChannels, *DstType, ambiorder) *
|
2021-03-31 09:37:30 -07:00
|
|
|
size_t{line_size}).swap(ALBuf->mData);
|
2020-02-17 00:22:51 -08:00
|
|
|
|
2020-11-21 00:54:25 -08:00
|
|
|
ALBuf->mCallback = callback;
|
|
|
|
ALBuf->mUserData = userptr;
|
2020-02-17 00:22:51 -08:00
|
|
|
|
|
|
|
ALBuf->OriginalType = SrcType;
|
|
|
|
ALBuf->OriginalSize = 0;
|
|
|
|
ALBuf->OriginalAlign = 1;
|
|
|
|
ALBuf->Access = 0;
|
|
|
|
|
2020-11-21 00:54:25 -08:00
|
|
|
ALBuf->mSampleRate = static_cast<ALuint>(freq);
|
2021-07-17 10:08:38 -07:00
|
|
|
ALBuf->mChannels = *DstChannels;
|
|
|
|
ALBuf->mType = *DstType;
|
2020-11-21 00:54:25 -08:00
|
|
|
ALBuf->mAmbiOrder = ambiorder;
|
|
|
|
|
|
|
|
ALBuf->mSampleLen = 0;
|
|
|
|
ALBuf->mLoopStart = 0;
|
|
|
|
ALBuf->mLoopEnd = ALBuf->mSampleLen;
|
2020-02-17 00:22:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-30 16:57:10 -07:00
|
|
|
struct DecompResult { UserFmtChannels channels; UserFmtType type; };
|
|
|
|
al::optional<DecompResult> DecomposeUserFormat(ALenum format)
|
2018-11-07 21:47:46 -08:00
|
|
|
{
|
|
|
|
struct FormatMap {
|
|
|
|
ALenum format;
|
|
|
|
UserFmtChannels channels;
|
|
|
|
UserFmtType type;
|
|
|
|
};
|
2021-03-31 20:46:03 -07:00
|
|
|
static const std::array<FormatMap,55> UserFmtList{{
|
2018-11-07 21:47:46 -08: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 },
|
|
|
|
|
|
|
|
{ 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 },
|
|
|
|
|
|
|
|
{ AL_FORMAT_BFORMAT2D_8, UserFmtBFormat2D, UserFmtUByte },
|
|
|
|
{ AL_FORMAT_BFORMAT2D_16, UserFmtBFormat2D, UserFmtShort },
|
|
|
|
{ AL_FORMAT_BFORMAT2D_FLOAT32, UserFmtBFormat2D, UserFmtFloat },
|
|
|
|
{ AL_FORMAT_BFORMAT2D_MULAW, UserFmtBFormat2D, UserFmtMulaw },
|
|
|
|
|
|
|
|
{ AL_FORMAT_BFORMAT3D_8, UserFmtBFormat3D, UserFmtUByte },
|
|
|
|
{ AL_FORMAT_BFORMAT3D_16, UserFmtBFormat3D, UserFmtShort },
|
|
|
|
{ AL_FORMAT_BFORMAT3D_FLOAT32, UserFmtBFormat3D, UserFmtFloat },
|
|
|
|
{ AL_FORMAT_BFORMAT3D_MULAW, UserFmtBFormat3D, UserFmtMulaw },
|
2021-03-31 05:37:56 -07:00
|
|
|
|
2021-03-31 20:46:03 -07:00
|
|
|
{ AL_FORMAT_UHJ2CHN8_SOFT, UserFmtUHJ2, UserFmtUByte },
|
|
|
|
{ AL_FORMAT_UHJ2CHN16_SOFT, UserFmtUHJ2, UserFmtShort },
|
|
|
|
{ AL_FORMAT_UHJ2CHN_FLOAT32_SOFT, UserFmtUHJ2, UserFmtFloat },
|
2021-03-31 10:03:31 -07:00
|
|
|
|
2021-03-31 20:46:03 -07:00
|
|
|
{ AL_FORMAT_UHJ3CHN8_SOFT, UserFmtUHJ3, UserFmtUByte },
|
|
|
|
{ AL_FORMAT_UHJ3CHN16_SOFT, UserFmtUHJ3, UserFmtShort },
|
|
|
|
{ AL_FORMAT_UHJ3CHN_FLOAT32_SOFT, UserFmtUHJ3, UserFmtFloat },
|
|
|
|
|
|
|
|
{ AL_FORMAT_UHJ4CHN8_SOFT, UserFmtUHJ4, UserFmtUByte },
|
|
|
|
{ AL_FORMAT_UHJ4CHN16_SOFT, UserFmtUHJ4, UserFmtShort },
|
|
|
|
{ AL_FORMAT_UHJ4CHN_FLOAT32_SOFT, UserFmtUHJ4, UserFmtFloat },
|
2018-11-07 21:47:46 -08:00
|
|
|
}};
|
|
|
|
|
2018-11-08 14:09:13 -08:00
|
|
|
for(const auto &fmt : UserFmtList)
|
2018-11-07 21:47:46 -08:00
|
|
|
{
|
|
|
|
if(fmt.format == format)
|
2019-09-11 14:33:26 -07:00
|
|
|
return al::make_optional<DecompResult>({fmt.channels, fmt.type});
|
2018-11-07 21:47:46 -08:00
|
|
|
}
|
2019-06-30 16:57:10 -07:00
|
|
|
return al::nullopt;
|
2018-11-07 21:47:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
2018-01-20 11:49:01 -08:00
|
|
|
|
2020-04-28 14:48:12 -07:00
|
|
|
AL_API void AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(n < 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "Generating %d buffers", n);
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(n <= 0) return;
|
2013-10-06 18:01:01 -07:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2019-09-11 14:33:26 -07:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2019-09-11 12:28:33 -07:00
|
|
|
if(!EnsureBuffers(device, static_cast<ALuint>(n)))
|
|
|
|
{
|
|
|
|
context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d buffer%s", n, (n==1)?"":"s");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-08-04 11:59:14 -07:00
|
|
|
if LIKELY(n == 1)
|
2018-10-31 10:37:16 -07:00
|
|
|
{
|
|
|
|
/* Special handling for the easy and normal case. */
|
2019-09-11 12:28:33 -07:00
|
|
|
ALbuffer *buffer{AllocBuffer(device)};
|
|
|
|
buffers[0] = buffer->id;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2019-08-04 11:59:14 -07:00
|
|
|
else
|
2018-10-31 10:37:16 -07:00
|
|
|
{
|
|
|
|
/* Store the allocated buffer IDs in a separate local list, to avoid
|
|
|
|
* modifying the user storage in case of failure.
|
|
|
|
*/
|
2018-11-24 16:58:49 -08:00
|
|
|
al::vector<ALuint> ids;
|
2019-09-11 12:28:33 -07:00
|
|
|
ids.reserve(static_cast<ALuint>(n));
|
2018-10-31 10:37:16 -07:00
|
|
|
do {
|
2019-09-11 12:28:33 -07:00
|
|
|
ALbuffer *buffer{AllocBuffer(device)};
|
2018-10-31 10:37:16 -07:00
|
|
|
ids.emplace_back(buffer->id);
|
|
|
|
} while(--n);
|
|
|
|
std::copy(ids.begin(), ids.end(), buffers);
|
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2020-04-28 14:48:12 -07:00
|
|
|
AL_API void AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(n < 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "Deleting %d buffers", n);
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(n <= 0) return;
|
2012-04-24 00:17:05 -07:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2013-10-06 18:01:01 -07:00
|
|
|
|
2018-10-31 10:37:16 -07:00
|
|
|
/* First try to find any buffers that are invalid or in-use. */
|
2019-09-12 17:10:33 -07:00
|
|
|
auto validate_buffer = [device, &context](const ALuint bid) -> bool
|
|
|
|
{
|
|
|
|
if(!bid) return true;
|
|
|
|
ALbuffer *ALBuf{LookupBuffer(device, bid)};
|
|
|
|
if UNLIKELY(!ALBuf)
|
2018-01-26 00:13:03 -08:00
|
|
|
{
|
2019-09-12 17:10:33 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", bid);
|
2018-10-31 10:37:16 -07:00
|
|
|
return false;
|
2018-01-26 00:13:03 -08:00
|
|
|
}
|
2019-09-12 17:10:33 -07:00
|
|
|
if UNLIKELY(ReadRef(ALBuf->ref) != 0)
|
|
|
|
{
|
|
|
|
context->setError(AL_INVALID_OPERATION, "Deleting in-use buffer %u", bid);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
const ALuint *buffers_end = buffers + n;
|
|
|
|
auto invbuf = std::find_if_not(buffers, buffers_end, validate_buffer);
|
|
|
|
if UNLIKELY(invbuf != buffers_end) return;
|
|
|
|
|
|
|
|
/* All good. Delete non-0 buffer IDs. */
|
|
|
|
auto delete_buffer = [device](const ALuint bid) -> void
|
2014-06-30 00:10:40 -07:00
|
|
|
{
|
2019-09-12 17:10:33 -07:00
|
|
|
ALbuffer *buffer{bid ? LookupBuffer(device, bid) : nullptr};
|
|
|
|
if(buffer) FreeBuffer(device, buffer);
|
|
|
|
};
|
|
|
|
std::for_each(buffers, buffers_end, delete_buffer);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2010-05-19 11:06:13 -07:00
|
|
|
AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if LIKELY(context)
|
2018-10-31 10:37:16 -07:00
|
|
|
{
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2018-10-31 10:37:16 -07:00
|
|
|
if(!buffer || LookupBuffer(device, buffer))
|
|
|
|
return AL_TRUE;
|
|
|
|
}
|
|
|
|
return AL_FALSE;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-24 00:17:05 -07:00
|
|
|
|
2020-04-28 14:48:12 -07:00
|
|
|
AL_API void AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2018-01-23 14:33:30 -08:00
|
|
|
{ alBufferStorageSOFT(buffer, format, data, size, freq, 0); }
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2018-01-23 14:33:30 -08:00
|
|
|
|
|
|
|
AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2018-10-31 10:37:16 -07:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2018-10-31 10:37:16 -07:00
|
|
|
|
2018-10-31 13:00:08 -07:00
|
|
|
ALbuffer *albuf = LookupBuffer(device, buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!albuf)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY(size < 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "Negative storage size %d", size);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY(freq < 1)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "Invalid sample rate %d", freq);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY((flags&INVALID_STORAGE_MASK) != 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "Invalid storage flags 0x%x",
|
|
|
|
flags&INVALID_STORAGE_MASK);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE,
|
|
|
|
"Declaring persistently mapped storage without read or write access");
|
2018-01-26 00:13:03 -08:00
|
|
|
else
|
2018-11-08 14:09:13 -08:00
|
|
|
{
|
2019-06-30 16:57:10 -07:00
|
|
|
auto usrfmt = DecomposeUserFormat(format);
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!usrfmt)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid format 0x%04x", format);
|
2018-11-08 14:09:13 -08:00
|
|
|
else
|
2019-09-11 14:33:26 -07:00
|
|
|
LoadData(context.get(), albuf, freq, static_cast<ALuint>(size), usrfmt->channels,
|
|
|
|
usrfmt->type, static_cast<const al::byte*>(data), flags);
|
2018-11-08 14:09:13 -08:00
|
|
|
}
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-01-20 11:49:01 -08:00
|
|
|
AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2018-01-20 11:49:01 -08:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return nullptr;
|
2018-01-20 11:49:01 -08:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2018-01-20 11:49:01 -08:00
|
|
|
|
2018-10-31 13:00:08 -07:00
|
|
|
ALbuffer *albuf = LookupBuffer(device, buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!albuf)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY((access&INVALID_MAP_FLAGS) != 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "Invalid map flags 0x%x", access&INVALID_MAP_FLAGS);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY(!(access&MAP_READ_WRITE_FLAGS))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "Mapping buffer %u without read or write access",
|
|
|
|
buffer);
|
2018-01-26 00:13:03 -08:00
|
|
|
else
|
|
|
|
{
|
2018-02-02 22:24:33 -08:00
|
|
|
ALbitfieldSOFT unavailable = (albuf->Access^access) & access;
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(ReadRef(albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_OPERATION,
|
|
|
|
"Mapping in-use buffer %u without persistent mapping", buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY(albuf->MappedAccess != 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_OPERATION, "Mapping already-mapped buffer %u", buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY((unavailable&AL_MAP_READ_BIT_SOFT))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE,
|
|
|
|
"Mapping buffer %u for reading without read access", buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY((unavailable&AL_MAP_WRITE_BIT_SOFT))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE,
|
|
|
|
"Mapping buffer %u for writing without write access", buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY((unavailable&AL_MAP_PERSISTENT_BIT_SOFT))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE,
|
|
|
|
"Mapping buffer %u persistently without persistent access", buffer);
|
2019-09-11 14:33:26 -07:00
|
|
|
else if UNLIKELY(offset < 0 || length <= 0
|
|
|
|
|| static_cast<ALuint>(offset) >= albuf->OriginalSize
|
|
|
|
|| static_cast<ALuint>(length) > albuf->OriginalSize - static_cast<ALuint>(offset))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u",
|
|
|
|
offset, length, buffer);
|
2018-01-26 00:13:03 -08:00
|
|
|
else
|
|
|
|
{
|
2020-11-21 00:54:25 -08:00
|
|
|
void *retval{albuf->mData.data() + offset};
|
2018-01-26 00:13:03 -08:00
|
|
|
albuf->MappedAccess = access;
|
|
|
|
albuf->MappedOffset = offset;
|
|
|
|
albuf->MappedSize = length;
|
2018-10-31 10:37:16 -07:00
|
|
|
return retval;
|
2018-01-26 00:13:03 -08:00
|
|
|
}
|
|
|
|
}
|
2018-01-20 11:49:01 -08:00
|
|
|
|
2018-10-31 10:37:16 -07:00
|
|
|
return nullptr;
|
2018-01-20 11:49:01 -08:00
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2018-01-20 11:49:01 -08:00
|
|
|
|
|
|
|
AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2018-01-20 11:49:01 -08:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2018-01-20 11:49:01 -08:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2018-01-20 11:49:01 -08:00
|
|
|
|
2018-10-31 13:00:08 -07:00
|
|
|
ALbuffer *albuf = LookupBuffer(device, buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!albuf)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY(albuf->MappedAccess == 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer);
|
2018-01-20 11:49:01 -08:00
|
|
|
else
|
2018-01-23 10:51:23 -08:00
|
|
|
{
|
2018-02-02 22:24:33 -08:00
|
|
|
albuf->MappedAccess = 0;
|
|
|
|
albuf->MappedOffset = 0;
|
|
|
|
albuf->MappedSize = 0;
|
2018-01-23 10:51:23 -08:00
|
|
|
}
|
2018-01-20 11:49:01 -08:00
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2018-01-20 11:49:01 -08:00
|
|
|
|
2018-01-23 10:38:27 -08:00
|
|
|
AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2018-01-23 10:38:27 -08:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2018-01-23 10:38:27 -08:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2018-01-23 10:38:27 -08:00
|
|
|
|
2018-10-31 13:00:08 -07:00
|
|
|
ALbuffer *albuf = LookupBuffer(device, buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!albuf)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_OPERATION, "Flushing buffer %u while not mapped for writing",
|
|
|
|
buffer);
|
2019-09-11 14:33:26 -07:00
|
|
|
else if UNLIKELY(offset < albuf->MappedOffset || length <= 0
|
|
|
|
|| offset >= albuf->MappedOffset+albuf->MappedSize
|
|
|
|
|| length > albuf->MappedOffset+albuf->MappedSize-offset)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u", offset,
|
|
|
|
length, buffer);
|
2018-01-23 10:38:27 -08:00
|
|
|
else
|
|
|
|
{
|
2018-02-02 22:24:33 -08:00
|
|
|
/* 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...
|
|
|
|
*/
|
2018-11-19 05:04:17 -08:00
|
|
|
std::atomic_thread_fence(std::memory_order_seq_cst);
|
2018-01-23 10:38:27 -08:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2018-01-23 10:38:27 -08:00
|
|
|
|
2020-04-28 14:48:12 -07:00
|
|
|
AL_API void AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2008-11-11 05:57:32 -08:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2018-10-31 10:37:16 -07:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2018-10-31 10:37:16 -07:00
|
|
|
|
2018-10-31 13:00:08 -07:00
|
|
|
ALbuffer *albuf = LookupBuffer(device, buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!albuf)
|
2018-11-08 14:09:13 -08:00
|
|
|
{
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2018-11-08 14:09:13 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-30 16:57:10 -07:00
|
|
|
auto usrfmt = DecomposeUserFormat(format);
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!usrfmt)
|
2018-11-08 14:09:13 -08:00
|
|
|
{
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid format 0x%04x", format);
|
2018-11-08 14:09:13 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-09-11 14:33:26 -07:00
|
|
|
ALuint unpack_align{albuf->UnpackAlign};
|
|
|
|
ALuint align{SanitizeAlignment(usrfmt->type, unpack_align)};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(align < 1)
|
2019-09-11 14:33:26 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "Invalid unpack alignment %u", unpack_align);
|
2020-11-21 00:54:25 -08:00
|
|
|
else if UNLIKELY(long{usrfmt->channels} != long{albuf->mChannels}
|
2019-09-11 14:33:26 -07:00
|
|
|
|| usrfmt->type != albuf->OriginalType)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_ENUM, "Unpacking data with mismatched format");
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY(align != albuf->OriginalAlign)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE,
|
|
|
|
"Unpacking data with alignment %u does not match original alignment %u", align,
|
|
|
|
albuf->OriginalAlign);
|
2020-11-21 00:54:25 -08:00
|
|
|
else if UNLIKELY(albuf->isBFormat() && albuf->UnpackAmbiOrder != albuf->mAmbiOrder)
|
2020-04-04 01:52:29 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "Unpacking data with mismatched ambisonic order");
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY(albuf->MappedAccess != 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", buffer);
|
2018-01-21 23:35:28 -08:00
|
|
|
else
|
|
|
|
{
|
2020-01-18 13:23:59 -08:00
|
|
|
ALuint num_chans{albuf->channelsFromFmt()};
|
|
|
|
ALuint frame_size{num_chans * albuf->bytesFromFmt()};
|
2019-09-11 14:33:26 -07:00
|
|
|
ALuint byte_align{
|
2018-11-08 14:09:13 -08:00
|
|
|
(albuf->OriginalType == UserFmtIMA4) ? ((align-1)/2 + 4) * num_chans :
|
|
|
|
(albuf->OriginalType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * num_chans :
|
|
|
|
(align * frame_size)
|
|
|
|
};
|
|
|
|
|
2019-09-11 14:33:26 -07:00
|
|
|
if UNLIKELY(offset < 0 || length < 0 || static_cast<ALuint>(offset) > albuf->OriginalSize
|
|
|
|
|| static_cast<ALuint>(length) > albuf->OriginalSize-static_cast<ALuint>(offset))
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u",
|
|
|
|
offset, length, buffer);
|
2019-09-11 14:33:26 -07:00
|
|
|
else if UNLIKELY((static_cast<ALuint>(offset)%byte_align) != 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE,
|
2018-11-08 14:09:13 -08:00
|
|
|
"Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)",
|
|
|
|
offset, byte_align, align);
|
2019-09-11 14:33:26 -07:00
|
|
|
else if UNLIKELY((static_cast<ALuint>(length)%byte_align) != 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE,
|
2018-11-08 14:09:13 -08:00
|
|
|
"Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)",
|
|
|
|
length, byte_align, align);
|
2018-01-26 00:13:03 -08:00
|
|
|
else
|
|
|
|
{
|
2018-11-08 14:09:13 -08:00
|
|
|
/* offset -> byte offset, length -> sample count */
|
2019-09-11 14:33:26 -07:00
|
|
|
size_t byteoff{static_cast<ALuint>(offset)/byte_align * align * frame_size};
|
|
|
|
size_t samplen{static_cast<ALuint>(length)/byte_align * align};
|
2018-11-08 14:09:13 -08:00
|
|
|
|
2020-11-21 00:54:25 -08:00
|
|
|
void *dst = albuf->mData.data() + byteoff;
|
|
|
|
if(usrfmt->type == UserFmtIMA4 && albuf->mType == FmtShort)
|
2020-04-23 04:57:04 -07:00
|
|
|
Convert_int16_ima4(static_cast<int16_t*>(dst), static_cast<const al::byte*>(data),
|
|
|
|
num_chans, samplen, align);
|
2020-11-21 00:54:25 -08:00
|
|
|
else if(usrfmt->type == UserFmtMSADPCM && albuf->mType == FmtShort)
|
2020-04-23 04:57:04 -07:00
|
|
|
Convert_int16_msadpcm(static_cast<int16_t*>(dst),
|
2019-09-11 14:33:26 -07:00
|
|
|
static_cast<const al::byte*>(data), num_chans, samplen, align);
|
2018-01-26 00:13:03 -08:00
|
|
|
else
|
|
|
|
{
|
2020-11-21 00:54:25 -08:00
|
|
|
assert(long{usrfmt->type} == long{albuf->mType});
|
2019-09-11 14:33:26 -07:00
|
|
|
memcpy(dst, data, size_t{samplen} * frame_size);
|
2018-01-26 00:13:03 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-11-11 05:57:32 -08:00
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2008-11-11 05:57:32 -08:00
|
|
|
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2019-07-28 17:15:34 -07:00
|
|
|
AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint /*buffer*/, ALuint /*samplerate*/,
|
|
|
|
ALenum /*internalformat*/, ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/,
|
|
|
|
const ALvoid* /*data*/)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2011-03-16 11:29:22 -07:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2013-10-06 18:01:01 -07:00
|
|
|
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported");
|
2011-03-16 11:29:22 -07:00
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2011-03-16 11:29:22 -07:00
|
|
|
|
2019-07-28 17:15:34 -07:00
|
|
|
AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/,
|
|
|
|
ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, const ALvoid* /*data*/)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2011-03-16 12:13:17 -07:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2013-10-06 18:01:01 -07:00
|
|
|
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported");
|
2011-03-16 12:13:17 -07:00
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2011-03-16 12:13:17 -07:00
|
|
|
|
2019-07-28 17:15:34 -07:00
|
|
|
AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/,
|
|
|
|
ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, ALvoid* /*data*/)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2011-03-16 12:56:39 -07:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2011-03-16 12:56:39 -07:00
|
|
|
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported");
|
2011-03-16 12:56:39 -07:00
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2011-03-16 12:56:39 -07:00
|
|
|
|
2019-07-28 17:15:34 -07:00
|
|
|
AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum /*format*/)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2011-03-16 13:57:00 -07:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return AL_FALSE;
|
2011-03-16 13:57:00 -07:00
|
|
|
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported");
|
2018-01-21 17:19:57 -08:00
|
|
|
return AL_FALSE;
|
2011-03-16 13:57:00 -07:00
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2011-03-16 13:57:00 -07:00
|
|
|
|
2011-03-16 11:29:22 -07:00
|
|
|
|
2019-07-28 17:15:34 -07:00
|
|
|
AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat /*value*/)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2018-01-26 00:13:03 -08:00
|
|
|
else switch(param)
|
2013-10-07 07:06:01 -07:00
|
|
|
{
|
|
|
|
default:
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2019-07-28 17:15:34 -07:00
|
|
|
AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param,
|
|
|
|
ALfloat /*value1*/, ALfloat /*value2*/, ALfloat /*value3*/)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2018-01-26 00:13:03 -08:00
|
|
|
else switch(param)
|
2013-10-07 07:06:01 -07:00
|
|
|
{
|
|
|
|
default:
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-24 00:17:05 -07:00
|
|
|
AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY(!values)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-01-26 00:13:03 -08:00
|
|
|
else switch(param)
|
2013-10-07 07:06:01 -07:00
|
|
|
{
|
|
|
|
default:
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08: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 05:16:45 -08:00
|
|
|
AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-10-31 13:00:08 -07:00
|
|
|
ALbuffer *albuf = LookupBuffer(device, buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!albuf)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2018-01-26 00:13:03 -08:00
|
|
|
else switch(param)
|
2013-10-07 07:06:01 -07: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 05:16:45 -08:00
|
|
|
case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(value < 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "Invalid unpack block alignment %d", value);
|
2018-01-26 00:13:03 -08:00
|
|
|
else
|
2019-09-11 14:33:26 -07:00
|
|
|
albuf->UnpackAlign = static_cast<ALuint>(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 05:16:45 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AL_PACK_BLOCK_ALIGNMENT_SOFT:
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(value < 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "Invalid pack block alignment %d", value);
|
2018-01-26 00:13:03 -08:00
|
|
|
else
|
2019-09-11 14:33:26 -07:00
|
|
|
albuf->PackAlign = static_cast<ALuint>(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 05:16:45 -08:00
|
|
|
break;
|
|
|
|
|
2019-12-02 11:39:30 -08:00
|
|
|
case AL_AMBISONIC_LAYOUT_SOFT:
|
|
|
|
if UNLIKELY(ReadRef(albuf->ref) != 0)
|
|
|
|
context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's ambisonic layout",
|
|
|
|
buffer);
|
|
|
|
else if UNLIKELY(value != AL_FUMA_SOFT && value != AL_ACN_SOFT)
|
|
|
|
context->setError(AL_INVALID_VALUE, "Invalid unpack ambisonic layout %04x", value);
|
|
|
|
else
|
2020-11-21 00:54:25 -08:00
|
|
|
albuf->mAmbiLayout = AmbiLayoutFromEnum(value).value();
|
2019-12-02 11:39:30 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AL_AMBISONIC_SCALING_SOFT:
|
|
|
|
if UNLIKELY(ReadRef(albuf->ref) != 0)
|
|
|
|
context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's ambisonic scaling",
|
|
|
|
buffer);
|
|
|
|
else if UNLIKELY(value != AL_FUMA_SOFT && value != AL_SN3D_SOFT && value != AL_N3D_SOFT)
|
|
|
|
context->setError(AL_INVALID_VALUE, "Invalid unpack ambisonic scaling %04x", value);
|
|
|
|
else
|
2020-11-21 00:54:25 -08:00
|
|
|
albuf->mAmbiScaling = AmbiScalingFromEnum(value).value();
|
2019-12-02 11:39:30 -08:00
|
|
|
break;
|
|
|
|
|
2020-04-04 03:10:01 -07:00
|
|
|
case AL_UNPACK_AMBISONIC_ORDER_SOFT:
|
|
|
|
if UNLIKELY(value < 1 || value > 14)
|
|
|
|
context->setError(AL_INVALID_VALUE, "Invalid unpack ambisonic order %d", value);
|
|
|
|
else
|
|
|
|
albuf->UnpackAmbiOrder = static_cast<ALuint>(value);
|
|
|
|
break;
|
|
|
|
|
2013-10-07 07:06:01 -07:00
|
|
|
default:
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2019-07-28 17:15:34 -07:00
|
|
|
AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param,
|
|
|
|
ALint /*value1*/, ALint /*value2*/, ALint /*value3*/)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2018-01-26 00:13:03 -08:00
|
|
|
else switch(param)
|
2013-10-07 07:06:01 -07:00
|
|
|
{
|
|
|
|
default:
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-24 00:17:05 -07:00
|
|
|
AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08: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 05:16:45 -08:00
|
|
|
if(values)
|
|
|
|
{
|
|
|
|
switch(param)
|
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
|
|
|
|
case AL_PACK_BLOCK_ALIGNMENT_SOFT:
|
2019-12-02 11:39:30 -08:00
|
|
|
case AL_AMBISONIC_LAYOUT_SOFT:
|
|
|
|
case AL_AMBISONIC_SCALING_SOFT:
|
2020-04-04 03:10:01 -07:00
|
|
|
case AL_UNPACK_AMBISONIC_ORDER_SOFT:
|
2018-10-31 10:37:16 -07:00
|
|
|
alBufferi(buffer, param, values[0]);
|
|
|
|
return;
|
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 05:16:45 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2018-10-31 10:37:16 -07:00
|
|
|
|
2018-10-31 13:00:08 -07:00
|
|
|
ALbuffer *albuf = LookupBuffer(device, buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!albuf)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY(!values)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-01-26 00:13:03 -08:00
|
|
|
else switch(param)
|
2013-10-07 07:06:01 -07:00
|
|
|
{
|
|
|
|
case AL_LOOP_POINTS_SOFT:
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(ReadRef(albuf->ref) != 0)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points",
|
|
|
|
buffer);
|
2019-09-11 14:33:26 -07:00
|
|
|
else if UNLIKELY(values[0] < 0 || values[0] >= values[1]
|
2020-11-21 00:54:25 -08:00
|
|
|
|| static_cast<ALuint>(values[1]) > albuf->mSampleLen)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "Invalid loop point range %d -> %d on buffer %u",
|
|
|
|
values[0], values[1], buffer);
|
2018-01-26 00:13:03 -08:00
|
|
|
else
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2020-11-21 00:54:25 -08:00
|
|
|
albuf->mLoopStart = static_cast<ALuint>(values[0]);
|
|
|
|
albuf->mLoopEnd = static_cast<ALuint>(values[1]);
|
2013-10-07 07:06:01 -07:00
|
|
|
}
|
|
|
|
break;
|
2010-05-13 02:03:48 -07:00
|
|
|
|
2013-10-07 07:06:01 -07:00
|
|
|
default:
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", param);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
|
|
|
|
2020-04-28 14:48:12 -07:00
|
|
|
AL_API void AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2018-10-31 13:00:08 -07:00
|
|
|
ALbuffer *albuf = LookupBuffer(device, buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!albuf)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY(!value)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-01-26 00:13:03 -08:00
|
|
|
else switch(param)
|
2013-10-07 07:06:01 -07:00
|
|
|
{
|
|
|
|
default:
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-24 00:17:05 -07:00
|
|
|
AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY(!value1 || !value2 || !value3)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-01-26 00:13:03 -08:00
|
|
|
else switch(param)
|
2013-10-07 07:06:01 -07:00
|
|
|
{
|
|
|
|
default:
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2012-04-24 00:17:05 -07:00
|
|
|
AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2012-04-24 00:17:05 -07: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 06:19:55 -07:00
|
|
|
{
|
2012-01-10 00:41:05 -08:00
|
|
|
case AL_SEC_LENGTH_SOFT:
|
2012-04-24 00:17:05 -07: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 06:19:55 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2018-10-31 10:37:16 -07:00
|
|
|
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY(!values)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-01-26 00:13:03 -08:00
|
|
|
else switch(param)
|
2013-10-07 07:06:01 -07:00
|
|
|
{
|
|
|
|
default:
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
|
|
|
|
|
2020-04-28 14:48:12 -07:00
|
|
|
AL_API void AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2018-10-31 10:37:16 -07:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2018-10-31 13:00:08 -07:00
|
|
|
ALbuffer *albuf = LookupBuffer(device, buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!albuf)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY(!value)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-01-26 00:13:03 -08:00
|
|
|
else switch(param)
|
2013-10-07 07:06:01 -07:00
|
|
|
{
|
|
|
|
case AL_FREQUENCY:
|
2020-11-21 00:54:25 -08:00
|
|
|
*value = static_cast<ALint>(albuf->mSampleRate);
|
2013-10-07 07:06:01 -07:00
|
|
|
break;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 07:06:01 -07:00
|
|
|
case AL_BITS:
|
2020-01-18 13:23:59 -08:00
|
|
|
*value = static_cast<ALint>(albuf->bytesFromFmt() * 8);
|
2013-10-07 07:06:01 -07:00
|
|
|
break;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 07:06:01 -07:00
|
|
|
case AL_CHANNELS:
|
2020-01-18 13:23:59 -08:00
|
|
|
*value = static_cast<ALint>(albuf->channelsFromFmt());
|
2013-10-07 07:06:01 -07:00
|
|
|
break;
|
2007-11-13 18:02:18 -08:00
|
|
|
|
2013-10-07 07:06:01 -07:00
|
|
|
case AL_SIZE:
|
2020-11-21 00:54:25 -08:00
|
|
|
*value = static_cast<ALint>(albuf->mSampleLen * albuf->frameSizeFromFmt());
|
2013-10-07 07:06:01 -07:00
|
|
|
break;
|
2007-11-13 18:02:18 -08: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 05:16:45 -08:00
|
|
|
case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
|
2019-09-11 14:33:26 -07:00
|
|
|
*value = static_cast<ALint>(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 05:16:45 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AL_PACK_BLOCK_ALIGNMENT_SOFT:
|
2019-09-11 14:33:26 -07:00
|
|
|
*value = static_cast<ALint>(albuf->PackAlign);
|
2018-11-07 21:47:46 -08:00
|
|
|
break;
|
|
|
|
|
2019-12-02 11:39:30 -08:00
|
|
|
case AL_AMBISONIC_LAYOUT_SOFT:
|
2020-11-21 00:54:25 -08:00
|
|
|
*value = EnumFromAmbiLayout(albuf->mAmbiLayout);
|
2019-12-02 11:39:30 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AL_AMBISONIC_SCALING_SOFT:
|
2020-11-21 00:54:25 -08:00
|
|
|
*value = EnumFromAmbiScaling(albuf->mAmbiScaling);
|
2019-12-02 11:39:30 -08:00
|
|
|
break;
|
|
|
|
|
2020-04-04 03:10:01 -07:00
|
|
|
case AL_UNPACK_AMBISONIC_ORDER_SOFT:
|
|
|
|
*value = static_cast<int>(albuf->UnpackAmbiOrder);
|
|
|
|
break;
|
|
|
|
|
2018-11-07 21:47:46 -08:00
|
|
|
default:
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param);
|
2018-01-21 23:35:28 -08:00
|
|
|
}
|
2018-11-07 21:47:46 -08:00
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2018-11-07 21:47:46 -08:00
|
|
|
|
|
|
|
AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2018-11-07 21:47:46 -08:00
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2018-11-07 21:47:46 -08:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY(!value1 || !value2 || !value3)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-11-07 21:47:46 -08:00
|
|
|
else switch(param)
|
2018-01-21 23:35:28 -08:00
|
|
|
{
|
2018-11-07 21:47:46 -08:00
|
|
|
default:
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param);
|
2010-11-27 20:33:37 -08:00
|
|
|
}
|
2018-11-07 21:47:46 -08:00
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2018-11-07 21:47:46 -08:00
|
|
|
|
|
|
|
AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values)
|
2019-04-10 17:33:21 -07:00
|
|
|
START_API_FUNC
|
2018-11-07 21:47:46 -08:00
|
|
|
{
|
|
|
|
switch(param)
|
2011-03-16 12:24:53 -07:00
|
|
|
{
|
2018-11-07 21:47:46 -08:00
|
|
|
case AL_FREQUENCY:
|
|
|
|
case AL_BITS:
|
|
|
|
case AL_CHANNELS:
|
|
|
|
case AL_SIZE:
|
|
|
|
case AL_INTERNAL_FORMAT_SOFT:
|
|
|
|
case AL_BYTE_LENGTH_SOFT:
|
|
|
|
case AL_SAMPLE_LENGTH_SOFT:
|
|
|
|
case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
|
|
|
|
case AL_PACK_BLOCK_ALIGNMENT_SOFT:
|
2019-12-02 11:39:30 -08:00
|
|
|
case AL_AMBISONIC_LAYOUT_SOFT:
|
|
|
|
case AL_AMBISONIC_SCALING_SOFT:
|
2020-04-04 03:10:01 -07:00
|
|
|
case AL_UNPACK_AMBISONIC_ORDER_SOFT:
|
2018-11-07 21:47:46 -08:00
|
|
|
alGetBufferi(buffer, param, values);
|
|
|
|
return;
|
2011-03-16 12:24:53 -07:00
|
|
|
}
|
2012-01-25 19:32:10 -08:00
|
|
|
|
2018-11-07 21:47:46 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!context) return;
|
2010-11-27 20:33:37 -08:00
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2018-11-26 22:06:53 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
2018-11-07 21:47:46 -08:00
|
|
|
ALbuffer *albuf = LookupBuffer(device, buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
if UNLIKELY(!albuf)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
2019-08-04 11:59:14 -07:00
|
|
|
else if UNLIKELY(!values)
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
2018-11-07 21:47:46 -08:00
|
|
|
else switch(param)
|
|
|
|
{
|
|
|
|
case AL_LOOP_POINTS_SOFT:
|
2020-11-21 00:54:25 -08:00
|
|
|
values[0] = static_cast<ALint>(albuf->mLoopStart);
|
|
|
|
values[1] = static_cast<ALint>(albuf->mLoopEnd);
|
2018-11-07 21:47:46 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2019-07-30 21:32:05 -07:00
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", param);
|
2018-11-07 21:47:46 -08:00
|
|
|
}
|
2010-11-27 20:33:37 -08:00
|
|
|
}
|
2019-04-10 17:33:21 -07:00
|
|
|
END_API_FUNC
|
2010-11-27 20:33:37 -08:00
|
|
|
|
|
|
|
|
2020-02-17 00:22:51 -08:00
|
|
|
AL_API void AL_APIENTRY alBufferCallbackSOFT(ALuint buffer, ALenum format, ALsizei freq,
|
|
|
|
LPALBUFFERCALLBACKTYPESOFT callback, ALvoid *userptr, ALbitfieldSOFT flags)
|
2020-02-16 23:49:29 -08:00
|
|
|
START_API_FUNC
|
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if UNLIKELY(!context) return;
|
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2020-02-17 00:22:51 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
|
|
|
|
|
|
|
ALbuffer *albuf = LookupBuffer(device, buffer);
|
|
|
|
if UNLIKELY(!albuf)
|
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else if UNLIKELY(freq < 1)
|
|
|
|
context->setError(AL_INVALID_VALUE, "Invalid sample rate %d", freq);
|
|
|
|
else if UNLIKELY(callback == nullptr)
|
|
|
|
context->setError(AL_INVALID_VALUE, "NULL callback");
|
|
|
|
else if UNLIKELY(flags != 0)
|
|
|
|
context->setError(AL_INVALID_VALUE, "Invalid callback flags 0x%x", flags);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto usrfmt = DecomposeUserFormat(format);
|
|
|
|
if UNLIKELY(!usrfmt)
|
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid format 0x%04x", format);
|
|
|
|
else
|
|
|
|
PrepareCallback(context.get(), albuf, freq, usrfmt->channels, usrfmt->type, callback,
|
|
|
|
userptr);
|
|
|
|
}
|
2020-02-16 23:49:29 -08:00
|
|
|
}
|
|
|
|
END_API_FUNC
|
|
|
|
|
2020-02-17 00:22:51 -08:00
|
|
|
AL_API void AL_APIENTRY alGetBufferPtrSOFT(ALuint buffer, ALenum param, ALvoid **value)
|
2020-02-16 23:49:29 -08:00
|
|
|
START_API_FUNC
|
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if UNLIKELY(!context) return;
|
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2020-02-17 00:22:51 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
|
|
|
ALbuffer *albuf = LookupBuffer(device, buffer);
|
|
|
|
if UNLIKELY(!albuf)
|
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else if UNLIKELY(!value)
|
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
|
|
|
else switch(param)
|
|
|
|
{
|
|
|
|
case AL_BUFFER_CALLBACK_FUNCTION_SOFT:
|
2020-11-21 00:54:25 -08:00
|
|
|
*value = reinterpret_cast<void*>(albuf->mCallback);
|
2020-02-17 00:22:51 -08:00
|
|
|
break;
|
|
|
|
case AL_BUFFER_CALLBACK_USER_PARAM_SOFT:
|
2020-11-21 00:54:25 -08:00
|
|
|
*value = albuf->mUserData;
|
2020-02-17 00:22:51 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid buffer pointer property 0x%04x", param);
|
|
|
|
}
|
2020-02-16 23:49:29 -08:00
|
|
|
}
|
|
|
|
END_API_FUNC
|
|
|
|
|
2020-02-17 00:22:51 -08:00
|
|
|
AL_API void AL_APIENTRY alGetBuffer3PtrSOFT(ALuint buffer, ALenum param, ALvoid **value1, ALvoid **value2, ALvoid **value3)
|
2020-02-16 23:49:29 -08:00
|
|
|
START_API_FUNC
|
|
|
|
{
|
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if UNLIKELY(!context) return;
|
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2020-02-17 00:22:51 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
|
|
|
if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
|
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else if UNLIKELY(!value1 || !value2 || !value3)
|
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
|
|
|
else switch(param)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid buffer 3-pointer property 0x%04x", param);
|
|
|
|
}
|
2020-02-16 23:49:29 -08:00
|
|
|
}
|
|
|
|
END_API_FUNC
|
|
|
|
|
2020-02-17 00:22:51 -08:00
|
|
|
AL_API void AL_APIENTRY alGetBufferPtrvSOFT(ALuint buffer, ALenum param, ALvoid **values)
|
2020-02-16 23:49:29 -08:00
|
|
|
START_API_FUNC
|
|
|
|
{
|
2020-02-17 00:22:51 -08:00
|
|
|
switch(param)
|
|
|
|
{
|
|
|
|
case AL_BUFFER_CALLBACK_FUNCTION_SOFT:
|
|
|
|
case AL_BUFFER_CALLBACK_USER_PARAM_SOFT:
|
|
|
|
alGetBufferPtrSOFT(buffer, param, values);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-02-16 23:49:29 -08:00
|
|
|
ContextRef context{GetContextRef()};
|
|
|
|
if UNLIKELY(!context) return;
|
|
|
|
|
2021-04-24 08:28:13 -07:00
|
|
|
ALCdevice *device{context->mALDevice.get()};
|
2020-02-17 00:22:51 -08:00
|
|
|
std::lock_guard<std::mutex> _{device->BufferLock};
|
|
|
|
if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
|
|
|
|
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
|
|
|
|
else if UNLIKELY(!values)
|
|
|
|
context->setError(AL_INVALID_VALUE, "NULL pointer");
|
|
|
|
else switch(param)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
context->setError(AL_INVALID_ENUM, "Invalid buffer pointer-vector property 0x%04x", param);
|
|
|
|
}
|
2020-02-16 23:49:29 -08:00
|
|
|
}
|
|
|
|
END_API_FUNC
|
|
|
|
|
|
|
|
|
2018-11-25 15:30:32 -08:00
|
|
|
BufferSubList::~BufferSubList()
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2019-02-11 12:16:58 -08:00
|
|
|
uint64_t usemask{~FreeMask};
|
2018-11-25 15:30:32 -08:00
|
|
|
while(usemask)
|
2007-11-13 18:02:18 -08:00
|
|
|
{
|
2021-01-22 04:58:42 -08:00
|
|
|
const int idx{al::countr_zero(usemask)};
|
2019-06-05 17:25:08 -07:00
|
|
|
al::destroy_at(Buffers+idx);
|
2019-01-07 04:06:40 -08:00
|
|
|
usemask &= ~(1_u64 << idx);
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|
2018-11-25 15:30:32 -08:00
|
|
|
FreeMask = ~usemask;
|
|
|
|
al_free(Buffers);
|
|
|
|
Buffers = nullptr;
|
2007-11-13 18:02:18 -08:00
|
|
|
}
|