🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1862 lines
61 KiB

  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 1999-2007 by authors.
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public
  15. * License along with this library; if not, write to the
  16. * Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. * Or go to http://www.gnu.org/copyleft/lgpl.html
  19. */
  20. #include "config.h"
  21. #include "buffer.h"
  22. #include <algorithm>
  23. #include <array>
  24. #include <atomic>
  25. #include <cassert>
  26. #include <cstdint>
  27. #include <cstdlib>
  28. #include <cstring>
  29. #include <iterator>
  30. #include <limits>
  31. #include <memory>
  32. #include <mutex>
  33. #include <new>
  34. #include <numeric>
  35. #include <stdexcept>
  36. #include <utility>
  37. #include "AL/al.h"
  38. #include "AL/alc.h"
  39. #include "AL/alext.h"
  40. #include "albit.h"
  41. #include "albyte.h"
  42. #include "alc/context.h"
  43. #include "alc/device.h"
  44. #include "alc/inprogext.h"
  45. #include "almalloc.h"
  46. #include "alnumeric.h"
  47. #include "aloptional.h"
  48. #include "atomic.h"
  49. #include "core/except.h"
  50. #include "core/logging.h"
  51. #include "core/voice.h"
  52. #include "opthelpers.h"
  53. #ifdef ALSOFT_EAX
  54. #include "eax_globals.h"
  55. #include "eax_x_ram.h"
  56. #endif // ALSOFT_EAX
  57. namespace {
  58. constexpr int MaxAdpcmChannels{2};
  59. /* IMA ADPCM Stepsize table */
  60. constexpr int IMAStep_size[89] = {
  61. 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19,
  62. 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55,
  63. 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157,
  64. 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449,
  65. 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282,
  66. 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660,
  67. 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,10442,
  68. 11487,12635,13899,15289,16818,18500,20350,22358,24633,27086,29794,
  69. 32767
  70. };
  71. /* IMA4 ADPCM Codeword decode table */
  72. constexpr int IMA4Codeword[16] = {
  73. 1, 3, 5, 7, 9, 11, 13, 15,
  74. -1,-3,-5,-7,-9,-11,-13,-15,
  75. };
  76. /* IMA4 ADPCM Step index adjust decode table */
  77. constexpr int IMA4Index_adjust[16] = {
  78. -1,-1,-1,-1, 2, 4, 6, 8,
  79. -1,-1,-1,-1, 2, 4, 6, 8
  80. };
  81. /* MSADPCM Adaption table */
  82. constexpr int MSADPCMAdaption[16] = {
  83. 230, 230, 230, 230, 307, 409, 512, 614,
  84. 768, 614, 512, 409, 307, 230, 230, 230
  85. };
  86. /* MSADPCM Adaption Coefficient tables */
  87. constexpr int MSADPCMAdaptionCoeff[7][2] = {
  88. { 256, 0 },
  89. { 512, -256 },
  90. { 0, 0 },
  91. { 192, 64 },
  92. { 240, 0 },
  93. { 460, -208 },
  94. { 392, -232 }
  95. };
  96. void DecodeIMA4Block(int16_t *dst, const al::byte *src, size_t numchans, size_t align)
  97. {
  98. int sample[MaxAdpcmChannels]{};
  99. int index[MaxAdpcmChannels]{};
  100. ALuint code[MaxAdpcmChannels]{};
  101. for(size_t c{0};c < numchans;c++)
  102. {
  103. sample[c] = src[0] | (src[1]<<8);
  104. sample[c] = (sample[c]^0x8000) - 32768;
  105. src += 2;
  106. index[c] = src[0] | (src[1]<<8);
  107. index[c] = clampi((index[c]^0x8000) - 32768, 0, 88);
  108. src += 2;
  109. *(dst++) = static_cast<int16_t>(sample[c]);
  110. }
  111. for(size_t i{1};i < align;i++)
  112. {
  113. if((i&7) == 1)
  114. {
  115. for(size_t c{0};c < numchans;c++)
  116. {
  117. code[c] = ALuint{src[0]} | (ALuint{src[1]}<< 8) | (ALuint{src[2]}<<16)
  118. | (ALuint{src[3]}<<24);
  119. src += 4;
  120. }
  121. }
  122. for(size_t c{0};c < numchans;c++)
  123. {
  124. const ALuint nibble{code[c]&0xf};
  125. code[c] >>= 4;
  126. sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8;
  127. sample[c] = clampi(sample[c], -32768, 32767);
  128. index[c] += IMA4Index_adjust[nibble];
  129. index[c] = clampi(index[c], 0, 88);
  130. *(dst++) = static_cast<int16_t>(sample[c]);
  131. }
  132. }
  133. }
  134. void DecodeMSADPCMBlock(int16_t *dst, const al::byte *src, size_t numchans, size_t align)
  135. {
  136. uint8_t blockpred[MaxAdpcmChannels]{};
  137. int delta[MaxAdpcmChannels]{};
  138. int16_t samples[MaxAdpcmChannels][2]{};
  139. for(size_t c{0};c < numchans;c++)
  140. {
  141. blockpred[c] = std::min<ALubyte>(src[0], 6);
  142. ++src;
  143. }
  144. for(size_t c{0};c < numchans;c++)
  145. {
  146. delta[c] = src[0] | (src[1]<<8);
  147. delta[c] = (delta[c]^0x8000) - 32768;
  148. src += 2;
  149. }
  150. for(size_t c{0};c < numchans;c++)
  151. {
  152. samples[c][0] = static_cast<ALshort>(src[0] | (src[1]<<8));
  153. src += 2;
  154. }
  155. for(size_t c{0};c < numchans;c++)
  156. {
  157. samples[c][1] = static_cast<ALshort>(src[0] | (src[1]<<8));
  158. src += 2;
  159. }
  160. /* Second sample is written first. */
  161. for(size_t c{0};c < numchans;c++)
  162. *(dst++) = samples[c][1];
  163. for(size_t c{0};c < numchans;c++)
  164. *(dst++) = samples[c][0];
  165. int num{0};
  166. for(size_t i{2};i < align;i++)
  167. {
  168. for(size_t c{0};c < numchans;c++)
  169. {
  170. /* Read the nibble (first is in the upper bits). */
  171. al::byte nibble;
  172. if(!(num++ & 1))
  173. nibble = *src >> 4;
  174. else
  175. nibble = *(src++) & 0x0f;
  176. int pred{(samples[c][0]*MSADPCMAdaptionCoeff[blockpred[c]][0] +
  177. samples[c][1]*MSADPCMAdaptionCoeff[blockpred[c]][1]) / 256};
  178. pred += ((nibble^0x08) - 0x08) * delta[c];
  179. pred = clampi(pred, -32768, 32767);
  180. samples[c][1] = samples[c][0];
  181. samples[c][0] = static_cast<int16_t>(pred);
  182. delta[c] = (MSADPCMAdaption[nibble] * delta[c]) / 256;
  183. delta[c] = maxi(16, delta[c]);
  184. *(dst++) = static_cast<int16_t>(pred);
  185. }
  186. }
  187. }
  188. void Convert_int16_ima4(int16_t *dst, const al::byte *src, size_t numchans, size_t len,
  189. size_t align)
  190. {
  191. assert(numchans <= MaxAdpcmChannels);
  192. const size_t byte_align{((align-1)/2 + 4) * numchans};
  193. len /= align;
  194. while(len--)
  195. {
  196. DecodeIMA4Block(dst, src, numchans, align);
  197. src += byte_align;
  198. dst += align*numchans;
  199. }
  200. }
  201. void Convert_int16_msadpcm(int16_t *dst, const al::byte *src, size_t numchans, size_t len,
  202. size_t align)
  203. {
  204. assert(numchans <= MaxAdpcmChannels);
  205. const size_t byte_align{((align-2)/2 + 7) * numchans};
  206. len /= align;
  207. while(len--)
  208. {
  209. DecodeMSADPCMBlock(dst, src, numchans, align);
  210. src += byte_align;
  211. dst += align*numchans;
  212. }
  213. }
  214. ALuint BytesFromUserFmt(UserFmtType type) noexcept
  215. {
  216. switch(type)
  217. {
  218. case UserFmtUByte: return sizeof(uint8_t);
  219. case UserFmtShort: return sizeof(int16_t);
  220. case UserFmtFloat: return sizeof(float);
  221. case UserFmtDouble: return sizeof(double);
  222. case UserFmtMulaw: return sizeof(uint8_t);
  223. case UserFmtAlaw: return sizeof(uint8_t);
  224. case UserFmtIMA4: break; /* not handled here */
  225. case UserFmtMSADPCM: break; /* not handled here */
  226. }
  227. return 0;
  228. }
  229. ALuint ChannelsFromUserFmt(UserFmtChannels chans, ALuint ambiorder) noexcept
  230. {
  231. switch(chans)
  232. {
  233. case UserFmtMono: return 1;
  234. case UserFmtStereo: return 2;
  235. case UserFmtRear: return 2;
  236. case UserFmtQuad: return 4;
  237. case UserFmtX51: return 6;
  238. case UserFmtX61: return 7;
  239. case UserFmtX71: return 8;
  240. case UserFmtBFormat2D: return (ambiorder*2) + 1;
  241. case UserFmtBFormat3D: return (ambiorder+1) * (ambiorder+1);
  242. case UserFmtUHJ2: return 2;
  243. case UserFmtUHJ3: return 3;
  244. case UserFmtUHJ4: return 4;
  245. }
  246. return 0;
  247. }
  248. al::optional<AmbiLayout> AmbiLayoutFromEnum(ALenum layout)
  249. {
  250. switch(layout)
  251. {
  252. case AL_FUMA_SOFT: return al::make_optional(AmbiLayout::FuMa);
  253. case AL_ACN_SOFT: return al::make_optional(AmbiLayout::ACN);
  254. }
  255. return al::nullopt;
  256. }
  257. ALenum EnumFromAmbiLayout(AmbiLayout layout)
  258. {
  259. switch(layout)
  260. {
  261. case AmbiLayout::FuMa: return AL_FUMA_SOFT;
  262. case AmbiLayout::ACN: return AL_ACN_SOFT;
  263. }
  264. throw std::runtime_error{"Invalid AmbiLayout: "+std::to_string(int(layout))};
  265. }
  266. al::optional<AmbiScaling> AmbiScalingFromEnum(ALenum scale)
  267. {
  268. switch(scale)
  269. {
  270. case AL_FUMA_SOFT: return al::make_optional(AmbiScaling::FuMa);
  271. case AL_SN3D_SOFT: return al::make_optional(AmbiScaling::SN3D);
  272. case AL_N3D_SOFT: return al::make_optional(AmbiScaling::N3D);
  273. }
  274. return al::nullopt;
  275. }
  276. ALenum EnumFromAmbiScaling(AmbiScaling scale)
  277. {
  278. switch(scale)
  279. {
  280. case AmbiScaling::FuMa: return AL_FUMA_SOFT;
  281. case AmbiScaling::SN3D: return AL_SN3D_SOFT;
  282. case AmbiScaling::N3D: return AL_N3D_SOFT;
  283. case AmbiScaling::UHJ: break;
  284. }
  285. throw std::runtime_error{"Invalid AmbiScaling: "+std::to_string(int(scale))};
  286. }
  287. al::optional<FmtChannels> FmtFromUserFmt(UserFmtChannels chans)
  288. {
  289. switch(chans)
  290. {
  291. case UserFmtMono: return al::make_optional(FmtMono);
  292. case UserFmtStereo: return al::make_optional(FmtStereo);
  293. case UserFmtRear: return al::make_optional(FmtRear);
  294. case UserFmtQuad: return al::make_optional(FmtQuad);
  295. case UserFmtX51: return al::make_optional(FmtX51);
  296. case UserFmtX61: return al::make_optional(FmtX61);
  297. case UserFmtX71: return al::make_optional(FmtX71);
  298. case UserFmtBFormat2D: return al::make_optional(FmtBFormat2D);
  299. case UserFmtBFormat3D: return al::make_optional(FmtBFormat3D);
  300. case UserFmtUHJ2: return al::make_optional(FmtUHJ2);
  301. case UserFmtUHJ3: return al::make_optional(FmtUHJ3);
  302. case UserFmtUHJ4: return al::make_optional(FmtUHJ4);
  303. }
  304. return al::nullopt;
  305. }
  306. al::optional<FmtType> FmtFromUserFmt(UserFmtType type)
  307. {
  308. switch(type)
  309. {
  310. case UserFmtUByte: return al::make_optional(FmtUByte);
  311. case UserFmtShort: return al::make_optional(FmtShort);
  312. case UserFmtFloat: return al::make_optional(FmtFloat);
  313. case UserFmtDouble: return al::make_optional(FmtDouble);
  314. case UserFmtMulaw: return al::make_optional(FmtMulaw);
  315. case UserFmtAlaw: return al::make_optional(FmtAlaw);
  316. /* ADPCM not handled here. */
  317. case UserFmtIMA4: break;
  318. case UserFmtMSADPCM: break;
  319. }
  320. return al::nullopt;
  321. }
  322. #ifdef ALSOFT_EAX
  323. bool eax_x_ram_check_availability(const ALCdevice &device, const ALbuffer &buffer,
  324. const ALuint newsize) noexcept
  325. {
  326. ALuint freemem{device.eax_x_ram_free_size};
  327. /* If the buffer is currently in "hardware", add its memory to the free
  328. * pool since it'll be "replaced".
  329. */
  330. if(buffer.eax_x_ram_is_hardware)
  331. freemem += buffer.OriginalSize;
  332. return freemem >= newsize;
  333. }
  334. void eax_x_ram_apply(ALCdevice &device, ALbuffer &buffer) noexcept
  335. {
  336. if(buffer.eax_x_ram_is_hardware)
  337. return;
  338. if(device.eax_x_ram_free_size >= buffer.OriginalSize)
  339. {
  340. device.eax_x_ram_free_size -= buffer.OriginalSize;
  341. buffer.eax_x_ram_is_hardware = true;
  342. }
  343. }
  344. void eax_x_ram_clear(ALCdevice& al_device, ALbuffer& al_buffer)
  345. {
  346. if(al_buffer.eax_x_ram_is_hardware)
  347. al_device.eax_x_ram_free_size += al_buffer.OriginalSize;
  348. al_buffer.eax_x_ram_is_hardware = false;
  349. }
  350. #endif // ALSOFT_EAX
  351. constexpr ALbitfieldSOFT INVALID_STORAGE_MASK{~unsigned(AL_MAP_READ_BIT_SOFT |
  352. AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT)};
  353. constexpr ALbitfieldSOFT MAP_READ_WRITE_FLAGS{AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT};
  354. constexpr ALbitfieldSOFT INVALID_MAP_FLAGS{~unsigned(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT |
  355. AL_MAP_PERSISTENT_BIT_SOFT)};
  356. bool EnsureBuffers(ALCdevice *device, size_t needed)
  357. {
  358. size_t count{std::accumulate(device->BufferList.cbegin(), device->BufferList.cend(), size_t{0},
  359. [](size_t cur, const BufferSubList &sublist) noexcept -> size_t
  360. { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })};
  361. while(needed > count)
  362. {
  363. if UNLIKELY(device->BufferList.size() >= 1<<25)
  364. return false;
  365. device->BufferList.emplace_back();
  366. auto sublist = device->BufferList.end() - 1;
  367. sublist->FreeMask = ~0_u64;
  368. sublist->Buffers = static_cast<ALbuffer*>(al_calloc(alignof(ALbuffer), sizeof(ALbuffer)*64));
  369. if UNLIKELY(!sublist->Buffers)
  370. {
  371. device->BufferList.pop_back();
  372. return false;
  373. }
  374. count += 64;
  375. }
  376. return true;
  377. }
  378. ALbuffer *AllocBuffer(ALCdevice *device)
  379. {
  380. auto sublist = std::find_if(device->BufferList.begin(), device->BufferList.end(),
  381. [](const BufferSubList &entry) noexcept -> bool
  382. { return entry.FreeMask != 0; });
  383. auto lidx = static_cast<ALuint>(std::distance(device->BufferList.begin(), sublist));
  384. auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask));
  385. ASSUME(slidx < 64);
  386. ALbuffer *buffer{al::construct_at(sublist->Buffers + slidx)};
  387. /* Add 1 to avoid buffer ID 0. */
  388. buffer->id = ((lidx<<6) | slidx) + 1;
  389. sublist->FreeMask &= ~(1_u64 << slidx);
  390. return buffer;
  391. }
  392. void FreeBuffer(ALCdevice *device, ALbuffer *buffer)
  393. {
  394. #ifdef ALSOFT_EAX
  395. eax_x_ram_clear(*device, *buffer);
  396. #endif // ALSOFT_EAX
  397. const ALuint id{buffer->id - 1};
  398. const size_t lidx{id >> 6};
  399. const ALuint slidx{id & 0x3f};
  400. al::destroy_at(buffer);
  401. device->BufferList[lidx].FreeMask |= 1_u64 << slidx;
  402. }
  403. inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id)
  404. {
  405. const size_t lidx{(id-1) >> 6};
  406. const ALuint slidx{(id-1) & 0x3f};
  407. if UNLIKELY(lidx >= device->BufferList.size())
  408. return nullptr;
  409. BufferSubList &sublist = device->BufferList[lidx];
  410. if UNLIKELY(sublist.FreeMask & (1_u64 << slidx))
  411. return nullptr;
  412. return sublist.Buffers + slidx;
  413. }
  414. ALuint SanitizeAlignment(UserFmtType type, ALuint align)
  415. {
  416. if(align == 0)
  417. {
  418. if(type == UserFmtIMA4)
  419. {
  420. /* Here is where things vary:
  421. * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
  422. * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
  423. */
  424. return 65;
  425. }
  426. if(type == UserFmtMSADPCM)
  427. return 64;
  428. return 1;
  429. }
  430. if(type == UserFmtIMA4)
  431. {
  432. /* IMA4 block alignment must be a multiple of 8, plus 1. */
  433. if((align&7) == 1) return static_cast<ALuint>(align);
  434. return 0;
  435. }
  436. if(type == UserFmtMSADPCM)
  437. {
  438. /* MSADPCM block alignment must be a multiple of 2. */
  439. if((align&1) == 0) return static_cast<ALuint>(align);
  440. return 0;
  441. }
  442. return static_cast<ALuint>(align);
  443. }
  444. const ALchar *NameFromUserFmtType(UserFmtType type)
  445. {
  446. switch(type)
  447. {
  448. case UserFmtUByte: return "UInt8";
  449. case UserFmtShort: return "Int16";
  450. case UserFmtFloat: return "Float32";
  451. case UserFmtDouble: return "Float64";
  452. case UserFmtMulaw: return "muLaw";
  453. case UserFmtAlaw: return "aLaw";
  454. case UserFmtIMA4: return "IMA4 ADPCM";
  455. case UserFmtMSADPCM: return "MSADPCM";
  456. }
  457. return "<internal type error>";
  458. }
  459. /** Loads the specified data into the buffer, using the specified format. */
  460. void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size,
  461. UserFmtChannels SrcChannels, UserFmtType SrcType, const al::byte *SrcData,
  462. ALbitfieldSOFT access)
  463. {
  464. if UNLIKELY(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)
  465. SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u",
  466. ALBuf->id);
  467. /* Currently no channel configurations need to be converted. */
  468. auto DstChannels = FmtFromUserFmt(SrcChannels);
  469. if UNLIKELY(!DstChannels)
  470. SETERR_RETURN(context, AL_INVALID_ENUM, , "Invalid format");
  471. /* IMA4 and MSADPCM convert to 16-bit short.
  472. *
  473. * TODO: Currently we can only map samples when they're not converted. To
  474. * allow it would need some kind of double-buffering to hold onto a copy of
  475. * the original data.
  476. */
  477. if((access&MAP_READ_WRITE_FLAGS))
  478. {
  479. if UNLIKELY(SrcType == UserFmtIMA4 || SrcType == UserFmtMSADPCM)
  480. SETERR_RETURN(context, AL_INVALID_VALUE,, "%s samples cannot be mapped",
  481. NameFromUserFmtType(SrcType));
  482. }
  483. auto DstType = (SrcType == UserFmtIMA4 || SrcType == UserFmtMSADPCM)
  484. ? al::make_optional(FmtShort) : FmtFromUserFmt(SrcType);
  485. if UNLIKELY(!DstType)
  486. SETERR_RETURN(context, AL_INVALID_ENUM, , "Invalid format");
  487. const ALuint unpackalign{ALBuf->UnpackAlign};
  488. const ALuint align{SanitizeAlignment(SrcType, unpackalign)};
  489. if UNLIKELY(align < 1)
  490. SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %u for %s samples",
  491. unpackalign, NameFromUserFmtType(SrcType));
  492. const ALuint ambiorder{IsBFormat(*DstChannels) ? ALBuf->UnpackAmbiOrder :
  493. (IsUHJ(*DstChannels) ? 1 : 0)};
  494. if((access&AL_PRESERVE_DATA_BIT_SOFT))
  495. {
  496. /* Can only preserve data with the same format and alignment. */
  497. if UNLIKELY(ALBuf->mChannels != *DstChannels || ALBuf->OriginalType != SrcType)
  498. SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format");
  499. if UNLIKELY(ALBuf->OriginalAlign != align)
  500. SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment");
  501. if(ALBuf->mAmbiOrder != ambiorder)
  502. SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched order");
  503. }
  504. /* Convert the input/source size in bytes to sample frames using the unpack
  505. * block alignment.
  506. */
  507. const ALuint SrcByteAlign{ChannelsFromUserFmt(SrcChannels, ambiorder) *
  508. ((SrcType == UserFmtIMA4) ? (align-1)/2 + 4 :
  509. (SrcType == UserFmtMSADPCM) ? (align-2)/2 + 7 :
  510. (align * BytesFromUserFmt(SrcType)))};
  511. if UNLIKELY((size%SrcByteAlign) != 0)
  512. SETERR_RETURN(context, AL_INVALID_VALUE,,
  513. "Data size %d is not a multiple of frame size %d (%d unpack alignment)",
  514. size, SrcByteAlign, align);
  515. if UNLIKELY(size/SrcByteAlign > std::numeric_limits<ALsizei>::max()/align)
  516. SETERR_RETURN(context, AL_OUT_OF_MEMORY,,
  517. "Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align);
  518. const ALuint frames{size / SrcByteAlign * align};
  519. /* Convert the sample frames to the number of bytes needed for internal
  520. * storage.
  521. */
  522. ALuint NumChannels{ChannelsFromFmt(*DstChannels, ambiorder)};
  523. ALuint FrameSize{NumChannels * BytesFromFmt(*DstType)};
  524. if UNLIKELY(frames > std::numeric_limits<size_t>::max()/FrameSize)
  525. SETERR_RETURN(context, AL_OUT_OF_MEMORY,,
  526. "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize);
  527. size_t newsize{static_cast<size_t>(frames) * FrameSize};
  528. #ifdef ALSOFT_EAX
  529. if(ALBuf->eax_x_ram_mode == AL_STORAGE_HARDWARE)
  530. {
  531. ALCdevice &device = *context->mALDevice;
  532. if(!eax_x_ram_check_availability(device, *ALBuf, size))
  533. SETERR_RETURN(context, AL_OUT_OF_MEMORY,,
  534. "Out of X-RAM memory (avail: %u, needed: %u)", device.eax_x_ram_free_size, size);
  535. }
  536. #endif
  537. /* Round up to the next 16-byte multiple. This could reallocate only when
  538. * increasing or the new size is less than half the current, but then the
  539. * buffer's AL_SIZE would not be very reliable for accounting buffer memory
  540. * usage, and reporting the real size could cause problems for apps that
  541. * use AL_SIZE to try to get the buffer's play length.
  542. */
  543. newsize = RoundUp(newsize, 16);
  544. if(newsize != ALBuf->mData.size())
  545. {
  546. auto newdata = al::vector<al::byte,16>(newsize, al::byte{});
  547. if((access&AL_PRESERVE_DATA_BIT_SOFT))
  548. {
  549. const size_t tocopy{minz(newdata.size(), ALBuf->mData.size())};
  550. std::copy_n(ALBuf->mData.begin(), tocopy, newdata.begin());
  551. }
  552. newdata.swap(ALBuf->mData);
  553. }
  554. if(SrcType == UserFmtIMA4)
  555. {
  556. assert(*DstType == FmtShort);
  557. if(SrcData != nullptr && !ALBuf->mData.empty())
  558. Convert_int16_ima4(reinterpret_cast<int16_t*>(ALBuf->mData.data()), SrcData,
  559. NumChannels, frames, align);
  560. ALBuf->OriginalAlign = align;
  561. }
  562. else if(SrcType == UserFmtMSADPCM)
  563. {
  564. assert(*DstType == FmtShort);
  565. if(SrcData != nullptr && !ALBuf->mData.empty())
  566. Convert_int16_msadpcm(reinterpret_cast<int16_t*>(ALBuf->mData.data()), SrcData,
  567. NumChannels, frames, align);
  568. ALBuf->OriginalAlign = align;
  569. }
  570. else
  571. {
  572. assert(DstType.has_value());
  573. if(SrcData != nullptr && !ALBuf->mData.empty())
  574. std::copy_n(SrcData, frames*FrameSize, ALBuf->mData.begin());
  575. ALBuf->OriginalAlign = 1;
  576. }
  577. ALBuf->OriginalSize = size;
  578. ALBuf->OriginalType = SrcType;
  579. ALBuf->Access = access;
  580. ALBuf->mSampleRate = static_cast<ALuint>(freq);
  581. ALBuf->mChannels = *DstChannels;
  582. ALBuf->mType = *DstType;
  583. ALBuf->mAmbiOrder = ambiorder;
  584. ALBuf->mCallback = nullptr;
  585. ALBuf->mUserData = nullptr;
  586. ALBuf->mSampleLen = frames;
  587. ALBuf->mLoopStart = 0;
  588. ALBuf->mLoopEnd = ALBuf->mSampleLen;
  589. #ifdef ALSOFT_EAX
  590. if(eax_g_is_enabled && ALBuf->eax_x_ram_mode != AL_STORAGE_ACCESSIBLE)
  591. eax_x_ram_apply(*context->mALDevice, *ALBuf);
  592. #endif
  593. }
  594. /** Prepares the buffer to use the specified callback, using the specified format. */
  595. void PrepareCallback(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq,
  596. UserFmtChannels SrcChannels, UserFmtType SrcType, ALBUFFERCALLBACKTYPESOFT callback,
  597. void *userptr)
  598. {
  599. if UNLIKELY(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)
  600. SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying callback for in-use buffer %u",
  601. ALBuf->id);
  602. /* Currently no channel configurations need to be converted. */
  603. auto DstChannels = FmtFromUserFmt(SrcChannels);
  604. if UNLIKELY(!DstChannels)
  605. SETERR_RETURN(context, AL_INVALID_ENUM,, "Invalid format");
  606. /* IMA4 and MSADPCM convert to 16-bit short. Not supported with callbacks. */
  607. auto DstType = FmtFromUserFmt(SrcType);
  608. if UNLIKELY(!DstType)
  609. SETERR_RETURN(context, AL_INVALID_ENUM,, "Unsupported callback format");
  610. const ALuint ambiorder{IsBFormat(*DstChannels) ? ALBuf->UnpackAmbiOrder :
  611. (IsUHJ(*DstChannels) ? 1 : 0)};
  612. static constexpr uint line_size{BufferLineSize + MaxPostVoiceLoad};
  613. al::vector<al::byte,16>(FrameSizeFromFmt(*DstChannels, *DstType, ambiorder) *
  614. size_t{line_size}).swap(ALBuf->mData);
  615. #ifdef ALSOFT_EAX
  616. eax_x_ram_clear(*context->mALDevice, *ALBuf);
  617. #endif
  618. ALBuf->mCallback = callback;
  619. ALBuf->mUserData = userptr;
  620. ALBuf->OriginalType = SrcType;
  621. ALBuf->OriginalSize = 0;
  622. ALBuf->OriginalAlign = 1;
  623. ALBuf->Access = 0;
  624. ALBuf->mSampleRate = static_cast<ALuint>(freq);
  625. ALBuf->mChannels = *DstChannels;
  626. ALBuf->mType = *DstType;
  627. ALBuf->mAmbiOrder = ambiorder;
  628. ALBuf->mSampleLen = 0;
  629. ALBuf->mLoopStart = 0;
  630. ALBuf->mLoopEnd = ALBuf->mSampleLen;
  631. }
  632. struct DecompResult { UserFmtChannels channels; UserFmtType type; };
  633. al::optional<DecompResult> DecomposeUserFormat(ALenum format)
  634. {
  635. struct FormatMap {
  636. ALenum format;
  637. UserFmtChannels channels;
  638. UserFmtType type;
  639. };
  640. static const std::array<FormatMap,55> UserFmtList{{
  641. { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte },
  642. { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort },
  643. { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat },
  644. { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble },
  645. { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 },
  646. { AL_FORMAT_MONO_MSADPCM_SOFT, UserFmtMono, UserFmtMSADPCM },
  647. { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw },
  648. { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw },
  649. { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte },
  650. { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort },
  651. { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat },
  652. { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble },
  653. { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 },
  654. { AL_FORMAT_STEREO_MSADPCM_SOFT, UserFmtStereo, UserFmtMSADPCM },
  655. { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw },
  656. { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw },
  657. { AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte },
  658. { AL_FORMAT_REAR16, UserFmtRear, UserFmtShort },
  659. { AL_FORMAT_REAR32, UserFmtRear, UserFmtFloat },
  660. { AL_FORMAT_REAR_MULAW, UserFmtRear, UserFmtMulaw },
  661. { AL_FORMAT_QUAD8_LOKI, UserFmtQuad, UserFmtUByte },
  662. { AL_FORMAT_QUAD16_LOKI, UserFmtQuad, UserFmtShort },
  663. { AL_FORMAT_QUAD8, UserFmtQuad, UserFmtUByte },
  664. { AL_FORMAT_QUAD16, UserFmtQuad, UserFmtShort },
  665. { AL_FORMAT_QUAD32, UserFmtQuad, UserFmtFloat },
  666. { AL_FORMAT_QUAD_MULAW, UserFmtQuad, UserFmtMulaw },
  667. { AL_FORMAT_51CHN8, UserFmtX51, UserFmtUByte },
  668. { AL_FORMAT_51CHN16, UserFmtX51, UserFmtShort },
  669. { AL_FORMAT_51CHN32, UserFmtX51, UserFmtFloat },
  670. { AL_FORMAT_51CHN_MULAW, UserFmtX51, UserFmtMulaw },
  671. { AL_FORMAT_61CHN8, UserFmtX61, UserFmtUByte },
  672. { AL_FORMAT_61CHN16, UserFmtX61, UserFmtShort },
  673. { AL_FORMAT_61CHN32, UserFmtX61, UserFmtFloat },
  674. { AL_FORMAT_61CHN_MULAW, UserFmtX61, UserFmtMulaw },
  675. { AL_FORMAT_71CHN8, UserFmtX71, UserFmtUByte },
  676. { AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort },
  677. { AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat },
  678. { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw },
  679. { AL_FORMAT_BFORMAT2D_8, UserFmtBFormat2D, UserFmtUByte },
  680. { AL_FORMAT_BFORMAT2D_16, UserFmtBFormat2D, UserFmtShort },
  681. { AL_FORMAT_BFORMAT2D_FLOAT32, UserFmtBFormat2D, UserFmtFloat },
  682. { AL_FORMAT_BFORMAT2D_MULAW, UserFmtBFormat2D, UserFmtMulaw },
  683. { AL_FORMAT_BFORMAT3D_8, UserFmtBFormat3D, UserFmtUByte },
  684. { AL_FORMAT_BFORMAT3D_16, UserFmtBFormat3D, UserFmtShort },
  685. { AL_FORMAT_BFORMAT3D_FLOAT32, UserFmtBFormat3D, UserFmtFloat },
  686. { AL_FORMAT_BFORMAT3D_MULAW, UserFmtBFormat3D, UserFmtMulaw },
  687. { AL_FORMAT_UHJ2CHN8_SOFT, UserFmtUHJ2, UserFmtUByte },
  688. { AL_FORMAT_UHJ2CHN16_SOFT, UserFmtUHJ2, UserFmtShort },
  689. { AL_FORMAT_UHJ2CHN_FLOAT32_SOFT, UserFmtUHJ2, UserFmtFloat },
  690. { AL_FORMAT_UHJ3CHN8_SOFT, UserFmtUHJ3, UserFmtUByte },
  691. { AL_FORMAT_UHJ3CHN16_SOFT, UserFmtUHJ3, UserFmtShort },
  692. { AL_FORMAT_UHJ3CHN_FLOAT32_SOFT, UserFmtUHJ3, UserFmtFloat },
  693. { AL_FORMAT_UHJ4CHN8_SOFT, UserFmtUHJ4, UserFmtUByte },
  694. { AL_FORMAT_UHJ4CHN16_SOFT, UserFmtUHJ4, UserFmtShort },
  695. { AL_FORMAT_UHJ4CHN_FLOAT32_SOFT, UserFmtUHJ4, UserFmtFloat },
  696. }};
  697. for(const auto &fmt : UserFmtList)
  698. {
  699. if(fmt.format == format)
  700. return al::make_optional<DecompResult>({fmt.channels, fmt.type});
  701. }
  702. return al::nullopt;
  703. }
  704. } // namespace
  705. AL_API void AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers)
  706. START_API_FUNC
  707. {
  708. ContextRef context{GetContextRef()};
  709. if UNLIKELY(!context) return;
  710. if UNLIKELY(n < 0)
  711. context->setError(AL_INVALID_VALUE, "Generating %d buffers", n);
  712. if UNLIKELY(n <= 0) return;
  713. ALCdevice *device{context->mALDevice.get()};
  714. std::lock_guard<std::mutex> _{device->BufferLock};
  715. if(!EnsureBuffers(device, static_cast<ALuint>(n)))
  716. {
  717. context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d buffer%s", n, (n==1)?"":"s");
  718. return;
  719. }
  720. if LIKELY(n == 1)
  721. {
  722. /* Special handling for the easy and normal case. */
  723. ALbuffer *buffer{AllocBuffer(device)};
  724. buffers[0] = buffer->id;
  725. }
  726. else
  727. {
  728. /* Store the allocated buffer IDs in a separate local list, to avoid
  729. * modifying the user storage in case of failure.
  730. */
  731. al::vector<ALuint> ids;
  732. ids.reserve(static_cast<ALuint>(n));
  733. do {
  734. ALbuffer *buffer{AllocBuffer(device)};
  735. ids.emplace_back(buffer->id);
  736. } while(--n);
  737. std::copy(ids.begin(), ids.end(), buffers);
  738. }
  739. }
  740. END_API_FUNC
  741. AL_API void AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers)
  742. START_API_FUNC
  743. {
  744. ContextRef context{GetContextRef()};
  745. if UNLIKELY(!context) return;
  746. if UNLIKELY(n < 0)
  747. context->setError(AL_INVALID_VALUE, "Deleting %d buffers", n);
  748. if UNLIKELY(n <= 0) return;
  749. ALCdevice *device{context->mALDevice.get()};
  750. std::lock_guard<std::mutex> _{device->BufferLock};
  751. /* First try to find any buffers that are invalid or in-use. */
  752. auto validate_buffer = [device, &context](const ALuint bid) -> bool
  753. {
  754. if(!bid) return true;
  755. ALbuffer *ALBuf{LookupBuffer(device, bid)};
  756. if UNLIKELY(!ALBuf)
  757. {
  758. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", bid);
  759. return false;
  760. }
  761. if UNLIKELY(ReadRef(ALBuf->ref) != 0)
  762. {
  763. context->setError(AL_INVALID_OPERATION, "Deleting in-use buffer %u", bid);
  764. return false;
  765. }
  766. return true;
  767. };
  768. const ALuint *buffers_end = buffers + n;
  769. auto invbuf = std::find_if_not(buffers, buffers_end, validate_buffer);
  770. if UNLIKELY(invbuf != buffers_end) return;
  771. /* All good. Delete non-0 buffer IDs. */
  772. auto delete_buffer = [device](const ALuint bid) -> void
  773. {
  774. ALbuffer *buffer{bid ? LookupBuffer(device, bid) : nullptr};
  775. if(buffer) FreeBuffer(device, buffer);
  776. };
  777. std::for_each(buffers, buffers_end, delete_buffer);
  778. }
  779. END_API_FUNC
  780. AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer)
  781. START_API_FUNC
  782. {
  783. ContextRef context{GetContextRef()};
  784. if LIKELY(context)
  785. {
  786. ALCdevice *device{context->mALDevice.get()};
  787. std::lock_guard<std::mutex> _{device->BufferLock};
  788. if(!buffer || LookupBuffer(device, buffer))
  789. return AL_TRUE;
  790. }
  791. return AL_FALSE;
  792. }
  793. END_API_FUNC
  794. AL_API void AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq)
  795. START_API_FUNC
  796. { alBufferStorageSOFT(buffer, format, data, size, freq, 0); }
  797. END_API_FUNC
  798. AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags)
  799. START_API_FUNC
  800. {
  801. ContextRef context{GetContextRef()};
  802. if UNLIKELY(!context) return;
  803. ALCdevice *device{context->mALDevice.get()};
  804. std::lock_guard<std::mutex> _{device->BufferLock};
  805. ALbuffer *albuf = LookupBuffer(device, buffer);
  806. if UNLIKELY(!albuf)
  807. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  808. else if UNLIKELY(size < 0)
  809. context->setError(AL_INVALID_VALUE, "Negative storage size %d", size);
  810. else if UNLIKELY(freq < 1)
  811. context->setError(AL_INVALID_VALUE, "Invalid sample rate %d", freq);
  812. else if UNLIKELY((flags&INVALID_STORAGE_MASK) != 0)
  813. context->setError(AL_INVALID_VALUE, "Invalid storage flags 0x%x",
  814. flags&INVALID_STORAGE_MASK);
  815. else if UNLIKELY((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS))
  816. context->setError(AL_INVALID_VALUE,
  817. "Declaring persistently mapped storage without read or write access");
  818. else
  819. {
  820. auto usrfmt = DecomposeUserFormat(format);
  821. if UNLIKELY(!usrfmt)
  822. context->setError(AL_INVALID_ENUM, "Invalid format 0x%04x", format);
  823. else
  824. {
  825. LoadData(context.get(), albuf, freq, static_cast<ALuint>(size), usrfmt->channels,
  826. usrfmt->type, static_cast<const al::byte*>(data), flags);
  827. }
  828. }
  829. }
  830. END_API_FUNC
  831. AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access)
  832. START_API_FUNC
  833. {
  834. ContextRef context{GetContextRef()};
  835. if UNLIKELY(!context) return nullptr;
  836. ALCdevice *device{context->mALDevice.get()};
  837. std::lock_guard<std::mutex> _{device->BufferLock};
  838. ALbuffer *albuf = LookupBuffer(device, buffer);
  839. if UNLIKELY(!albuf)
  840. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  841. else if UNLIKELY((access&INVALID_MAP_FLAGS) != 0)
  842. context->setError(AL_INVALID_VALUE, "Invalid map flags 0x%x", access&INVALID_MAP_FLAGS);
  843. else if UNLIKELY(!(access&MAP_READ_WRITE_FLAGS))
  844. context->setError(AL_INVALID_VALUE, "Mapping buffer %u without read or write access",
  845. buffer);
  846. else
  847. {
  848. ALbitfieldSOFT unavailable = (albuf->Access^access) & access;
  849. if UNLIKELY(ReadRef(albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT))
  850. context->setError(AL_INVALID_OPERATION,
  851. "Mapping in-use buffer %u without persistent mapping", buffer);
  852. else if UNLIKELY(albuf->MappedAccess != 0)
  853. context->setError(AL_INVALID_OPERATION, "Mapping already-mapped buffer %u", buffer);
  854. else if UNLIKELY((unavailable&AL_MAP_READ_BIT_SOFT))
  855. context->setError(AL_INVALID_VALUE,
  856. "Mapping buffer %u for reading without read access", buffer);
  857. else if UNLIKELY((unavailable&AL_MAP_WRITE_BIT_SOFT))
  858. context->setError(AL_INVALID_VALUE,
  859. "Mapping buffer %u for writing without write access", buffer);
  860. else if UNLIKELY((unavailable&AL_MAP_PERSISTENT_BIT_SOFT))
  861. context->setError(AL_INVALID_VALUE,
  862. "Mapping buffer %u persistently without persistent access", buffer);
  863. else if UNLIKELY(offset < 0 || length <= 0
  864. || static_cast<ALuint>(offset) >= albuf->OriginalSize
  865. || static_cast<ALuint>(length) > albuf->OriginalSize - static_cast<ALuint>(offset))
  866. context->setError(AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u",
  867. offset, length, buffer);
  868. else
  869. {
  870. void *retval{albuf->mData.data() + offset};
  871. albuf->MappedAccess = access;
  872. albuf->MappedOffset = offset;
  873. albuf->MappedSize = length;
  874. return retval;
  875. }
  876. }
  877. return nullptr;
  878. }
  879. END_API_FUNC
  880. AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer)
  881. START_API_FUNC
  882. {
  883. ContextRef context{GetContextRef()};
  884. if UNLIKELY(!context) return;
  885. ALCdevice *device{context->mALDevice.get()};
  886. std::lock_guard<std::mutex> _{device->BufferLock};
  887. ALbuffer *albuf = LookupBuffer(device, buffer);
  888. if UNLIKELY(!albuf)
  889. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  890. else if UNLIKELY(albuf->MappedAccess == 0)
  891. context->setError(AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer);
  892. else
  893. {
  894. albuf->MappedAccess = 0;
  895. albuf->MappedOffset = 0;
  896. albuf->MappedSize = 0;
  897. }
  898. }
  899. END_API_FUNC
  900. AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length)
  901. START_API_FUNC
  902. {
  903. ContextRef context{GetContextRef()};
  904. if UNLIKELY(!context) return;
  905. ALCdevice *device{context->mALDevice.get()};
  906. std::lock_guard<std::mutex> _{device->BufferLock};
  907. ALbuffer *albuf = LookupBuffer(device, buffer);
  908. if UNLIKELY(!albuf)
  909. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  910. else if UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT))
  911. context->setError(AL_INVALID_OPERATION, "Flushing buffer %u while not mapped for writing",
  912. buffer);
  913. else if UNLIKELY(offset < albuf->MappedOffset || length <= 0
  914. || offset >= albuf->MappedOffset+albuf->MappedSize
  915. || length > albuf->MappedOffset+albuf->MappedSize-offset)
  916. context->setError(AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u", offset,
  917. length, buffer);
  918. else
  919. {
  920. /* FIXME: Need to use some method of double-buffering for the mixer and
  921. * app to hold separate memory, which can be safely transfered
  922. * asynchronously. Currently we just say the app shouldn't write where
  923. * OpenAL's reading, and hope for the best...
  924. */
  925. std::atomic_thread_fence(std::memory_order_seq_cst);
  926. }
  927. }
  928. END_API_FUNC
  929. AL_API void AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length)
  930. START_API_FUNC
  931. {
  932. ContextRef context{GetContextRef()};
  933. if UNLIKELY(!context) return;
  934. ALCdevice *device{context->mALDevice.get()};
  935. std::lock_guard<std::mutex> _{device->BufferLock};
  936. ALbuffer *albuf = LookupBuffer(device, buffer);
  937. if UNLIKELY(!albuf)
  938. {
  939. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  940. return;
  941. }
  942. auto usrfmt = DecomposeUserFormat(format);
  943. if UNLIKELY(!usrfmt)
  944. {
  945. context->setError(AL_INVALID_ENUM, "Invalid format 0x%04x", format);
  946. return;
  947. }
  948. ALuint unpack_align{albuf->UnpackAlign};
  949. ALuint align{SanitizeAlignment(usrfmt->type, unpack_align)};
  950. if UNLIKELY(align < 1)
  951. context->setError(AL_INVALID_VALUE, "Invalid unpack alignment %u", unpack_align);
  952. else if UNLIKELY(long{usrfmt->channels} != long{albuf->mChannels}
  953. || usrfmt->type != albuf->OriginalType)
  954. context->setError(AL_INVALID_ENUM, "Unpacking data with mismatched format");
  955. else if UNLIKELY(align != albuf->OriginalAlign)
  956. context->setError(AL_INVALID_VALUE,
  957. "Unpacking data with alignment %u does not match original alignment %u", align,
  958. albuf->OriginalAlign);
  959. else if UNLIKELY(albuf->isBFormat() && albuf->UnpackAmbiOrder != albuf->mAmbiOrder)
  960. context->setError(AL_INVALID_VALUE, "Unpacking data with mismatched ambisonic order");
  961. else if UNLIKELY(albuf->MappedAccess != 0)
  962. context->setError(AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", buffer);
  963. else
  964. {
  965. ALuint num_chans{albuf->channelsFromFmt()};
  966. ALuint frame_size{num_chans * albuf->bytesFromFmt()};
  967. ALuint byte_align{
  968. (albuf->OriginalType == UserFmtIMA4) ? ((align-1)/2 + 4) * num_chans :
  969. (albuf->OriginalType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * num_chans :
  970. (align * frame_size)
  971. };
  972. if UNLIKELY(offset < 0 || length < 0 || static_cast<ALuint>(offset) > albuf->OriginalSize
  973. || static_cast<ALuint>(length) > albuf->OriginalSize-static_cast<ALuint>(offset))
  974. context->setError(AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u",
  975. offset, length, buffer);
  976. else if UNLIKELY((static_cast<ALuint>(offset)%byte_align) != 0)
  977. context->setError(AL_INVALID_VALUE,
  978. "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)",
  979. offset, byte_align, align);
  980. else if UNLIKELY((static_cast<ALuint>(length)%byte_align) != 0)
  981. context->setError(AL_INVALID_VALUE,
  982. "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)",
  983. length, byte_align, align);
  984. else
  985. {
  986. /* offset -> byte offset, length -> sample count */
  987. size_t byteoff{static_cast<ALuint>(offset)/byte_align * align * frame_size};
  988. size_t samplen{static_cast<ALuint>(length)/byte_align * align};
  989. void *dst = albuf->mData.data() + byteoff;
  990. if(usrfmt->type == UserFmtIMA4 && albuf->mType == FmtShort)
  991. Convert_int16_ima4(static_cast<int16_t*>(dst), static_cast<const al::byte*>(data),
  992. num_chans, samplen, align);
  993. else if(usrfmt->type == UserFmtMSADPCM && albuf->mType == FmtShort)
  994. Convert_int16_msadpcm(static_cast<int16_t*>(dst),
  995. static_cast<const al::byte*>(data), num_chans, samplen, align);
  996. else
  997. {
  998. assert(long{usrfmt->type} == long{albuf->mType});
  999. memcpy(dst, data, size_t{samplen} * frame_size);
  1000. }
  1001. }
  1002. }
  1003. }
  1004. END_API_FUNC
  1005. AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint /*buffer*/, ALuint /*samplerate*/,
  1006. ALenum /*internalformat*/, ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/,
  1007. const ALvoid* /*data*/)
  1008. START_API_FUNC
  1009. {
  1010. ContextRef context{GetContextRef()};
  1011. if UNLIKELY(!context) return;
  1012. context->setError(AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported");
  1013. }
  1014. END_API_FUNC
  1015. AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/,
  1016. ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, const ALvoid* /*data*/)
  1017. START_API_FUNC
  1018. {
  1019. ContextRef context{GetContextRef()};
  1020. if UNLIKELY(!context) return;
  1021. context->setError(AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported");
  1022. }
  1023. END_API_FUNC
  1024. AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/,
  1025. ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, ALvoid* /*data*/)
  1026. START_API_FUNC
  1027. {
  1028. ContextRef context{GetContextRef()};
  1029. if UNLIKELY(!context) return;
  1030. context->setError(AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported");
  1031. }
  1032. END_API_FUNC
  1033. AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum /*format*/)
  1034. START_API_FUNC
  1035. {
  1036. ContextRef context{GetContextRef()};
  1037. if UNLIKELY(!context) return AL_FALSE;
  1038. context->setError(AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported");
  1039. return AL_FALSE;
  1040. }
  1041. END_API_FUNC
  1042. AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat /*value*/)
  1043. START_API_FUNC
  1044. {
  1045. ContextRef context{GetContextRef()};
  1046. if UNLIKELY(!context) return;
  1047. ALCdevice *device{context->mALDevice.get()};
  1048. std::lock_guard<std::mutex> _{device->BufferLock};
  1049. if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
  1050. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  1051. else switch(param)
  1052. {
  1053. default:
  1054. context->setError(AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param);
  1055. }
  1056. }
  1057. END_API_FUNC
  1058. AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param,
  1059. ALfloat /*value1*/, ALfloat /*value2*/, ALfloat /*value3*/)
  1060. START_API_FUNC
  1061. {
  1062. ContextRef context{GetContextRef()};
  1063. if UNLIKELY(!context) return;
  1064. ALCdevice *device{context->mALDevice.get()};
  1065. std::lock_guard<std::mutex> _{device->BufferLock};
  1066. if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
  1067. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  1068. else switch(param)
  1069. {
  1070. default:
  1071. context->setError(AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param);
  1072. }
  1073. }
  1074. END_API_FUNC
  1075. AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values)
  1076. START_API_FUNC
  1077. {
  1078. ContextRef context{GetContextRef()};
  1079. if UNLIKELY(!context) return;
  1080. ALCdevice *device{context->mALDevice.get()};
  1081. std::lock_guard<std::mutex> _{device->BufferLock};
  1082. if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
  1083. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  1084. else if UNLIKELY(!values)
  1085. context->setError(AL_INVALID_VALUE, "NULL pointer");
  1086. else switch(param)
  1087. {
  1088. default:
  1089. context->setError(AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param);
  1090. }
  1091. }
  1092. END_API_FUNC
  1093. AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value)
  1094. START_API_FUNC
  1095. {
  1096. ContextRef context{GetContextRef()};
  1097. if UNLIKELY(!context) return;
  1098. ALCdevice *device{context->mALDevice.get()};
  1099. std::lock_guard<std::mutex> _{device->BufferLock};
  1100. ALbuffer *albuf = LookupBuffer(device, buffer);
  1101. if UNLIKELY(!albuf)
  1102. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  1103. else switch(param)
  1104. {
  1105. case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
  1106. if UNLIKELY(value < 0)
  1107. context->setError(AL_INVALID_VALUE, "Invalid unpack block alignment %d", value);
  1108. else
  1109. albuf->UnpackAlign = static_cast<ALuint>(value);
  1110. break;
  1111. case AL_PACK_BLOCK_ALIGNMENT_SOFT:
  1112. if UNLIKELY(value < 0)
  1113. context->setError(AL_INVALID_VALUE, "Invalid pack block alignment %d", value);
  1114. else
  1115. albuf->PackAlign = static_cast<ALuint>(value);
  1116. break;
  1117. case AL_AMBISONIC_LAYOUT_SOFT:
  1118. if UNLIKELY(ReadRef(albuf->ref) != 0)
  1119. context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's ambisonic layout",
  1120. buffer);
  1121. else if UNLIKELY(value != AL_FUMA_SOFT && value != AL_ACN_SOFT)
  1122. context->setError(AL_INVALID_VALUE, "Invalid unpack ambisonic layout %04x", value);
  1123. else
  1124. albuf->mAmbiLayout = AmbiLayoutFromEnum(value).value();
  1125. break;
  1126. case AL_AMBISONIC_SCALING_SOFT:
  1127. if UNLIKELY(ReadRef(albuf->ref) != 0)
  1128. context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's ambisonic scaling",
  1129. buffer);
  1130. else if UNLIKELY(value != AL_FUMA_SOFT && value != AL_SN3D_SOFT && value != AL_N3D_SOFT)
  1131. context->setError(AL_INVALID_VALUE, "Invalid unpack ambisonic scaling %04x", value);
  1132. else
  1133. albuf->mAmbiScaling = AmbiScalingFromEnum(value).value();
  1134. break;
  1135. case AL_UNPACK_AMBISONIC_ORDER_SOFT:
  1136. if UNLIKELY(value < 1 || value > 14)
  1137. context->setError(AL_INVALID_VALUE, "Invalid unpack ambisonic order %d", value);
  1138. else
  1139. albuf->UnpackAmbiOrder = static_cast<ALuint>(value);
  1140. break;
  1141. default:
  1142. context->setError(AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param);
  1143. }
  1144. }
  1145. END_API_FUNC
  1146. AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param,
  1147. ALint /*value1*/, ALint /*value2*/, ALint /*value3*/)
  1148. START_API_FUNC
  1149. {
  1150. ContextRef context{GetContextRef()};
  1151. if UNLIKELY(!context) return;
  1152. ALCdevice *device{context->mALDevice.get()};
  1153. std::lock_guard<std::mutex> _{device->BufferLock};
  1154. if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
  1155. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  1156. else switch(param)
  1157. {
  1158. default:
  1159. context->setError(AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param);
  1160. }
  1161. }
  1162. END_API_FUNC
  1163. AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values)
  1164. START_API_FUNC
  1165. {
  1166. if(values)
  1167. {
  1168. switch(param)
  1169. {
  1170. case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
  1171. case AL_PACK_BLOCK_ALIGNMENT_SOFT:
  1172. case AL_AMBISONIC_LAYOUT_SOFT:
  1173. case AL_AMBISONIC_SCALING_SOFT:
  1174. case AL_UNPACK_AMBISONIC_ORDER_SOFT:
  1175. alBufferi(buffer, param, values[0]);
  1176. return;
  1177. }
  1178. }
  1179. ContextRef context{GetContextRef()};
  1180. if UNLIKELY(!context) return;
  1181. ALCdevice *device{context->mALDevice.get()};
  1182. std::lock_guard<std::mutex> _{device->BufferLock};
  1183. ALbuffer *albuf = LookupBuffer(device, buffer);
  1184. if UNLIKELY(!albuf)
  1185. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  1186. else if UNLIKELY(!values)
  1187. context->setError(AL_INVALID_VALUE, "NULL pointer");
  1188. else switch(param)
  1189. {
  1190. case AL_LOOP_POINTS_SOFT:
  1191. if UNLIKELY(ReadRef(albuf->ref) != 0)
  1192. context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points",
  1193. buffer);
  1194. else if UNLIKELY(values[0] < 0 || values[0] >= values[1]
  1195. || static_cast<ALuint>(values[1]) > albuf->mSampleLen)
  1196. context->setError(AL_INVALID_VALUE, "Invalid loop point range %d -> %d on buffer %u",
  1197. values[0], values[1], buffer);
  1198. else
  1199. {
  1200. albuf->mLoopStart = static_cast<ALuint>(values[0]);
  1201. albuf->mLoopEnd = static_cast<ALuint>(values[1]);
  1202. }
  1203. break;
  1204. default:
  1205. context->setError(AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", param);
  1206. }
  1207. }
  1208. END_API_FUNC
  1209. AL_API void AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value)
  1210. START_API_FUNC
  1211. {
  1212. ContextRef context{GetContextRef()};
  1213. if UNLIKELY(!context) return;
  1214. ALCdevice *device{context->mALDevice.get()};
  1215. std::lock_guard<std::mutex> _{device->BufferLock};
  1216. ALbuffer *albuf = LookupBuffer(device, buffer);
  1217. if UNLIKELY(!albuf)
  1218. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  1219. else if UNLIKELY(!value)
  1220. context->setError(AL_INVALID_VALUE, "NULL pointer");
  1221. else switch(param)
  1222. {
  1223. default:
  1224. context->setError(AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param);
  1225. }
  1226. }
  1227. END_API_FUNC
  1228. AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
  1229. START_API_FUNC
  1230. {
  1231. ContextRef context{GetContextRef()};
  1232. if UNLIKELY(!context) return;
  1233. ALCdevice *device{context->mALDevice.get()};
  1234. std::lock_guard<std::mutex> _{device->BufferLock};
  1235. if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
  1236. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  1237. else if UNLIKELY(!value1 || !value2 || !value3)
  1238. context->setError(AL_INVALID_VALUE, "NULL pointer");
  1239. else switch(param)
  1240. {
  1241. default:
  1242. context->setError(AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param);
  1243. }
  1244. }
  1245. END_API_FUNC
  1246. AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values)
  1247. START_API_FUNC
  1248. {
  1249. switch(param)
  1250. {
  1251. case AL_SEC_LENGTH_SOFT:
  1252. alGetBufferf(buffer, param, values);
  1253. return;
  1254. }
  1255. ContextRef context{GetContextRef()};
  1256. if UNLIKELY(!context) return;
  1257. ALCdevice *device{context->mALDevice.get()};
  1258. std::lock_guard<std::mutex> _{device->BufferLock};
  1259. if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
  1260. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  1261. else if UNLIKELY(!values)
  1262. context->setError(AL_INVALID_VALUE, "NULL pointer");
  1263. else switch(param)
  1264. {
  1265. default:
  1266. context->setError(AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param);
  1267. }
  1268. }
  1269. END_API_FUNC
  1270. AL_API void AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value)
  1271. START_API_FUNC
  1272. {
  1273. ContextRef context{GetContextRef()};
  1274. if UNLIKELY(!context) return;
  1275. ALCdevice *device{context->mALDevice.get()};
  1276. std::lock_guard<std::mutex> _{device->BufferLock};
  1277. ALbuffer *albuf = LookupBuffer(device, buffer);
  1278. if UNLIKELY(!albuf)
  1279. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  1280. else if UNLIKELY(!value)
  1281. context->setError(AL_INVALID_VALUE, "NULL pointer");
  1282. else switch(param)
  1283. {
  1284. case AL_FREQUENCY:
  1285. *value = static_cast<ALint>(albuf->mSampleRate);
  1286. break;
  1287. case AL_BITS:
  1288. *value = static_cast<ALint>(albuf->bytesFromFmt() * 8);
  1289. break;
  1290. case AL_CHANNELS:
  1291. *value = static_cast<ALint>(albuf->channelsFromFmt());
  1292. break;
  1293. case AL_SIZE:
  1294. *value = static_cast<ALint>(albuf->mSampleLen * albuf->frameSizeFromFmt());
  1295. break;
  1296. case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
  1297. *value = static_cast<ALint>(albuf->UnpackAlign);
  1298. break;
  1299. case AL_PACK_BLOCK_ALIGNMENT_SOFT:
  1300. *value = static_cast<ALint>(albuf->PackAlign);
  1301. break;
  1302. case AL_AMBISONIC_LAYOUT_SOFT:
  1303. *value = EnumFromAmbiLayout(albuf->mAmbiLayout);
  1304. break;
  1305. case AL_AMBISONIC_SCALING_SOFT:
  1306. *value = EnumFromAmbiScaling(albuf->mAmbiScaling);
  1307. break;
  1308. case AL_UNPACK_AMBISONIC_ORDER_SOFT:
  1309. *value = static_cast<int>(albuf->UnpackAmbiOrder);
  1310. break;
  1311. default:
  1312. context->setError(AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param);
  1313. }
  1314. }
  1315. END_API_FUNC
  1316. AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3)
  1317. START_API_FUNC
  1318. {
  1319. ContextRef context{GetContextRef()};
  1320. if UNLIKELY(!context) return;
  1321. ALCdevice *device{context->mALDevice.get()};
  1322. std::lock_guard<std::mutex> _{device->BufferLock};
  1323. if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
  1324. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  1325. else if UNLIKELY(!value1 || !value2 || !value3)
  1326. context->setError(AL_INVALID_VALUE, "NULL pointer");
  1327. else switch(param)
  1328. {
  1329. default:
  1330. context->setError(AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param);
  1331. }
  1332. }
  1333. END_API_FUNC
  1334. AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values)
  1335. START_API_FUNC
  1336. {
  1337. switch(param)
  1338. {
  1339. case AL_FREQUENCY:
  1340. case AL_BITS:
  1341. case AL_CHANNELS:
  1342. case AL_SIZE:
  1343. case AL_INTERNAL_FORMAT_SOFT:
  1344. case AL_BYTE_LENGTH_SOFT:
  1345. case AL_SAMPLE_LENGTH_SOFT:
  1346. case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
  1347. case AL_PACK_BLOCK_ALIGNMENT_SOFT:
  1348. case AL_AMBISONIC_LAYOUT_SOFT:
  1349. case AL_AMBISONIC_SCALING_SOFT:
  1350. case AL_UNPACK_AMBISONIC_ORDER_SOFT:
  1351. alGetBufferi(buffer, param, values);
  1352. return;
  1353. }
  1354. ContextRef context{GetContextRef()};
  1355. if UNLIKELY(!context) return;
  1356. ALCdevice *device{context->mALDevice.get()};
  1357. std::lock_guard<std::mutex> _{device->BufferLock};
  1358. ALbuffer *albuf = LookupBuffer(device, buffer);
  1359. if UNLIKELY(!albuf)
  1360. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  1361. else if UNLIKELY(!values)
  1362. context->setError(AL_INVALID_VALUE, "NULL pointer");
  1363. else switch(param)
  1364. {
  1365. case AL_LOOP_POINTS_SOFT:
  1366. values[0] = static_cast<ALint>(albuf->mLoopStart);
  1367. values[1] = static_cast<ALint>(albuf->mLoopEnd);
  1368. break;
  1369. default:
  1370. context->setError(AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", param);
  1371. }
  1372. }
  1373. END_API_FUNC
  1374. AL_API void AL_APIENTRY alBufferCallbackSOFT(ALuint buffer, ALenum format, ALsizei freq,
  1375. ALBUFFERCALLBACKTYPESOFT callback, ALvoid *userptr)
  1376. START_API_FUNC
  1377. {
  1378. ContextRef context{GetContextRef()};
  1379. if UNLIKELY(!context) return;
  1380. ALCdevice *device{context->mALDevice.get()};
  1381. std::lock_guard<std::mutex> _{device->BufferLock};
  1382. ALbuffer *albuf = LookupBuffer(device, buffer);
  1383. if UNLIKELY(!albuf)
  1384. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  1385. else if UNLIKELY(freq < 1)
  1386. context->setError(AL_INVALID_VALUE, "Invalid sample rate %d", freq);
  1387. else if UNLIKELY(callback == nullptr)
  1388. context->setError(AL_INVALID_VALUE, "NULL callback");
  1389. else
  1390. {
  1391. auto usrfmt = DecomposeUserFormat(format);
  1392. if UNLIKELY(!usrfmt)
  1393. context->setError(AL_INVALID_ENUM, "Invalid format 0x%04x", format);
  1394. else
  1395. PrepareCallback(context.get(), albuf, freq, usrfmt->channels, usrfmt->type, callback,
  1396. userptr);
  1397. }
  1398. }
  1399. END_API_FUNC
  1400. AL_API void AL_APIENTRY alGetBufferPtrSOFT(ALuint buffer, ALenum param, ALvoid **value)
  1401. START_API_FUNC
  1402. {
  1403. ContextRef context{GetContextRef()};
  1404. if UNLIKELY(!context) return;
  1405. ALCdevice *device{context->mALDevice.get()};
  1406. std::lock_guard<std::mutex> _{device->BufferLock};
  1407. ALbuffer *albuf = LookupBuffer(device, buffer);
  1408. if UNLIKELY(!albuf)
  1409. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  1410. else if UNLIKELY(!value)
  1411. context->setError(AL_INVALID_VALUE, "NULL pointer");
  1412. else switch(param)
  1413. {
  1414. case AL_BUFFER_CALLBACK_FUNCTION_SOFT:
  1415. *value = reinterpret_cast<void*>(albuf->mCallback);
  1416. break;
  1417. case AL_BUFFER_CALLBACK_USER_PARAM_SOFT:
  1418. *value = albuf->mUserData;
  1419. break;
  1420. default:
  1421. context->setError(AL_INVALID_ENUM, "Invalid buffer pointer property 0x%04x", param);
  1422. }
  1423. }
  1424. END_API_FUNC
  1425. AL_API void AL_APIENTRY alGetBuffer3PtrSOFT(ALuint buffer, ALenum param, ALvoid **value1, ALvoid **value2, ALvoid **value3)
  1426. START_API_FUNC
  1427. {
  1428. ContextRef context{GetContextRef()};
  1429. if UNLIKELY(!context) return;
  1430. ALCdevice *device{context->mALDevice.get()};
  1431. std::lock_guard<std::mutex> _{device->BufferLock};
  1432. if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
  1433. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  1434. else if UNLIKELY(!value1 || !value2 || !value3)
  1435. context->setError(AL_INVALID_VALUE, "NULL pointer");
  1436. else switch(param)
  1437. {
  1438. default:
  1439. context->setError(AL_INVALID_ENUM, "Invalid buffer 3-pointer property 0x%04x", param);
  1440. }
  1441. }
  1442. END_API_FUNC
  1443. AL_API void AL_APIENTRY alGetBufferPtrvSOFT(ALuint buffer, ALenum param, ALvoid **values)
  1444. START_API_FUNC
  1445. {
  1446. switch(param)
  1447. {
  1448. case AL_BUFFER_CALLBACK_FUNCTION_SOFT:
  1449. case AL_BUFFER_CALLBACK_USER_PARAM_SOFT:
  1450. alGetBufferPtrSOFT(buffer, param, values);
  1451. return;
  1452. }
  1453. ContextRef context{GetContextRef()};
  1454. if UNLIKELY(!context) return;
  1455. ALCdevice *device{context->mALDevice.get()};
  1456. std::lock_guard<std::mutex> _{device->BufferLock};
  1457. if UNLIKELY(LookupBuffer(device, buffer) == nullptr)
  1458. context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer);
  1459. else if UNLIKELY(!values)
  1460. context->setError(AL_INVALID_VALUE, "NULL pointer");
  1461. else switch(param)
  1462. {
  1463. default:
  1464. context->setError(AL_INVALID_ENUM, "Invalid buffer pointer-vector property 0x%04x", param);
  1465. }
  1466. }
  1467. END_API_FUNC
  1468. BufferSubList::~BufferSubList()
  1469. {
  1470. uint64_t usemask{~FreeMask};
  1471. while(usemask)
  1472. {
  1473. const int idx{al::countr_zero(usemask)};
  1474. al::destroy_at(Buffers+idx);
  1475. usemask &= ~(1_u64 << idx);
  1476. }
  1477. FreeMask = ~usemask;
  1478. al_free(Buffers);
  1479. Buffers = nullptr;
  1480. }
  1481. #ifdef ALSOFT_EAX
  1482. FORCE_ALIGN ALboolean AL_APIENTRY EAXSetBufferMode(ALsizei n, const ALuint* buffers, ALint value)
  1483. START_API_FUNC
  1484. {
  1485. #define EAX_PREFIX "[EAXSetBufferMode] "
  1486. const auto context = ContextRef{GetContextRef()};
  1487. if(!context)
  1488. {
  1489. ERR(EAX_PREFIX "%s\n", "No current context.");
  1490. return ALC_FALSE;
  1491. }
  1492. if(!eax_g_is_enabled)
  1493. {
  1494. context->setError(AL_INVALID_OPERATION, EAX_PREFIX "%s", "EAX not enabled.");
  1495. return ALC_FALSE;
  1496. }
  1497. switch(value)
  1498. {
  1499. case AL_STORAGE_AUTOMATIC:
  1500. case AL_STORAGE_HARDWARE:
  1501. case AL_STORAGE_ACCESSIBLE:
  1502. break;
  1503. default:
  1504. context->setError(AL_INVALID_ENUM, EAX_PREFIX "Unsupported X-RAM mode 0x%x", value);
  1505. return ALC_FALSE;
  1506. }
  1507. if(n == 0)
  1508. return ALC_TRUE;
  1509. if(n < 0)
  1510. {
  1511. context->setError(AL_INVALID_VALUE, EAX_PREFIX "Buffer count %d out of range", n);
  1512. return ALC_FALSE;
  1513. }
  1514. if(!buffers)
  1515. {
  1516. context->setError(AL_INVALID_VALUE, EAX_PREFIX "%s", "Null AL buffers");
  1517. return ALC_FALSE;
  1518. }
  1519. auto device = context->mALDevice.get();
  1520. std::lock_guard<std::mutex> device_lock{device->BufferLock};
  1521. size_t total_needed{0};
  1522. // Validate the buffers.
  1523. //
  1524. for(auto i = 0;i < n;++i)
  1525. {
  1526. const auto buffer = buffers[i];
  1527. if(buffer == AL_NONE)
  1528. continue;
  1529. const auto al_buffer = LookupBuffer(device, buffer);
  1530. if (!al_buffer)
  1531. {
  1532. ERR(EAX_PREFIX "Invalid buffer ID %u.\n", buffer);
  1533. return ALC_FALSE;
  1534. }
  1535. /* TODO: Is the store location allowed to change for in-use buffers, or
  1536. * only when not set/queued on a source?
  1537. */
  1538. if(value == AL_STORAGE_HARDWARE && !al_buffer->eax_x_ram_is_hardware)
  1539. {
  1540. /* FIXME: This doesn't account for duplicate buffers. When the same
  1541. * buffer ID is specified multiple times in the provided list, it
  1542. * counts each instance as more memory that needs to fit in X-RAM.
  1543. */
  1544. if(unlikely(std::numeric_limits<size_t>::max()-al_buffer->OriginalSize < total_needed))
  1545. {
  1546. context->setError(AL_OUT_OF_MEMORY, EAX_PREFIX "Buffer size overflow (%u + %zu)\n",
  1547. al_buffer->OriginalSize, total_needed);
  1548. return ALC_FALSE;
  1549. }
  1550. total_needed += al_buffer->OriginalSize;
  1551. }
  1552. }
  1553. if(total_needed > device->eax_x_ram_free_size)
  1554. {
  1555. context->setError(AL_INVALID_ENUM, EAX_PREFIX "Out of X-RAM memory (need: %zu, avail: %u)",
  1556. total_needed, device->eax_x_ram_free_size);
  1557. return ALC_FALSE;
  1558. }
  1559. // Update the mode.
  1560. //
  1561. for(auto i = 0;i < n;++i)
  1562. {
  1563. const auto buffer = buffers[i];
  1564. if(buffer == AL_NONE)
  1565. continue;
  1566. const auto al_buffer = LookupBuffer(device, buffer);
  1567. assert(al_buffer);
  1568. if(value != AL_STORAGE_ACCESSIBLE)
  1569. eax_x_ram_apply(*device, *al_buffer);
  1570. else
  1571. eax_x_ram_clear(*device, *al_buffer);
  1572. al_buffer->eax_x_ram_mode = value;
  1573. }
  1574. return AL_TRUE;
  1575. #undef EAX_PREFIX
  1576. }
  1577. END_API_FUNC
  1578. FORCE_ALIGN ALenum AL_APIENTRY EAXGetBufferMode(ALuint buffer, ALint* pReserved)
  1579. START_API_FUNC
  1580. {
  1581. #define EAX_PREFIX "[EAXGetBufferMode] "
  1582. const auto context = ContextRef{GetContextRef()};
  1583. if(!context)
  1584. {
  1585. ERR(EAX_PREFIX "%s\n", "No current context.");
  1586. return AL_NONE;
  1587. }
  1588. if(!eax_g_is_enabled)
  1589. {
  1590. context->setError(AL_INVALID_OPERATION, EAX_PREFIX "%s", "EAX not enabled.");
  1591. return AL_NONE;
  1592. }
  1593. if(pReserved)
  1594. {
  1595. context->setError(AL_INVALID_VALUE, EAX_PREFIX "%s", "Non-null reserved parameter");
  1596. return AL_NONE;
  1597. }
  1598. auto device = context->mALDevice.get();
  1599. std::lock_guard<std::mutex> device_lock{device->BufferLock};
  1600. const auto al_buffer = LookupBuffer(device, buffer);
  1601. if(!al_buffer)
  1602. {
  1603. context->setError(AL_INVALID_NAME, EAX_PREFIX "Invalid buffer ID %u", buffer);
  1604. return AL_NONE;
  1605. }
  1606. return al_buffer->eax_x_ram_mode;
  1607. #undef EAX_PREFIX
  1608. }
  1609. END_API_FUNC
  1610. #endif // ALSOFT_EAX