buffer.cpp 55 KB

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