🛠️🐜 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.

3582 lines
121 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 <cstdlib>
  22. #include <climits>
  23. #include <cfloat>
  24. #include <cmath>
  25. #include <thread>
  26. #include <limits>
  27. #include <numeric>
  28. #include <algorithm>
  29. #include <functional>
  30. #include "AL/al.h"
  31. #include "AL/alc.h"
  32. #include "alMain.h"
  33. #include "alcontext.h"
  34. #include "alError.h"
  35. #include "alSource.h"
  36. #include "alBuffer.h"
  37. #include "alFilter.h"
  38. #include "alAuxEffectSlot.h"
  39. #include "ringbuffer.h"
  40. #include "bformatdec.h"
  41. #include "backends/base.h"
  42. #include "threads.h"
  43. #include "alexcpt.h"
  44. #include "almalloc.h"
  45. namespace {
  46. using namespace std::placeholders;
  47. inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context)
  48. {
  49. ALint idx{source->VoiceIdx};
  50. if(idx >= 0 && idx < context->VoiceCount.load(std::memory_order_relaxed))
  51. {
  52. ALuint sid{source->id};
  53. ALvoice *voice{context->Voices[idx]};
  54. if(voice->mSourceID.load(std::memory_order_acquire) == sid)
  55. return voice;
  56. }
  57. source->VoiceIdx = -1;
  58. return nullptr;
  59. }
  60. void UpdateSourceProps(const ALsource *source, ALvoice *voice, ALCcontext *context)
  61. {
  62. /* Get an unused property container, or allocate a new one as needed. */
  63. ALvoiceProps *props{context->FreeVoiceProps.load(std::memory_order_acquire)};
  64. if(!props)
  65. props = new ALvoiceProps{};
  66. else
  67. {
  68. ALvoiceProps *next;
  69. do {
  70. next = props->next.load(std::memory_order_relaxed);
  71. } while(context->FreeVoiceProps.compare_exchange_weak(props, next,
  72. std::memory_order_acq_rel, std::memory_order_acquire) == 0);
  73. }
  74. /* Copy in current property values. */
  75. props->Pitch = source->Pitch;
  76. props->Gain = source->Gain;
  77. props->OuterGain = source->OuterGain;
  78. props->MinGain = source->MinGain;
  79. props->MaxGain = source->MaxGain;
  80. props->InnerAngle = source->InnerAngle;
  81. props->OuterAngle = source->OuterAngle;
  82. props->RefDistance = source->RefDistance;
  83. props->MaxDistance = source->MaxDistance;
  84. props->RolloffFactor = source->RolloffFactor;
  85. props->Position = source->Position;
  86. props->Velocity = source->Velocity;
  87. props->Direction = source->Direction;
  88. props->OrientAt = source->OrientAt;
  89. props->OrientUp = source->OrientUp;
  90. props->HeadRelative = source->HeadRelative;
  91. props->mDistanceModel = source->mDistanceModel;
  92. props->mResampler = source->mResampler;
  93. props->DirectChannels = source->DirectChannels;
  94. props->mSpatializeMode = source->mSpatialize;
  95. props->DryGainHFAuto = source->DryGainHFAuto;
  96. props->WetGainAuto = source->WetGainAuto;
  97. props->WetGainHFAuto = source->WetGainHFAuto;
  98. props->OuterGainHF = source->OuterGainHF;
  99. props->AirAbsorptionFactor = source->AirAbsorptionFactor;
  100. props->RoomRolloffFactor = source->RoomRolloffFactor;
  101. props->DopplerFactor = source->DopplerFactor;
  102. props->StereoPan = source->StereoPan;
  103. props->Radius = source->Radius;
  104. props->Direct.Gain = source->Direct.Gain;
  105. props->Direct.GainHF = source->Direct.GainHF;
  106. props->Direct.HFReference = source->Direct.HFReference;
  107. props->Direct.GainLF = source->Direct.GainLF;
  108. props->Direct.LFReference = source->Direct.LFReference;
  109. auto copy_send = [](const ALsource::SendData &srcsend) noexcept -> ALvoicePropsBase::SendData
  110. {
  111. ALvoicePropsBase::SendData ret;
  112. ret.Slot = srcsend.Slot;
  113. ret.Gain = srcsend.Gain;
  114. ret.GainHF = srcsend.GainHF;
  115. ret.HFReference = srcsend.HFReference;
  116. ret.GainLF = srcsend.GainLF;
  117. ret.LFReference = srcsend.LFReference;
  118. return ret;
  119. };
  120. std::transform(source->Send.cbegin(), source->Send.cend(), props->Send, copy_send);
  121. /* Set the new container for updating internal parameters. */
  122. props = voice->mUpdate.exchange(props, std::memory_order_acq_rel);
  123. if(props)
  124. {
  125. /* If there was an unused update container, put it back in the
  126. * freelist.
  127. */
  128. AtomicReplaceHead(context->FreeVoiceProps, props);
  129. }
  130. }
  131. /* GetSourceSampleOffset
  132. *
  133. * Gets the current read offset for the given Source, in 32.32 fixed-point
  134. * samples. The offset is relative to the start of the queue (not the start of
  135. * the current buffer).
  136. */
  137. int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime)
  138. {
  139. ALCdevice *device{context->Device};
  140. const ALbufferlistitem *Current;
  141. uint64_t readPos;
  142. ALuint refcount;
  143. ALvoice *voice;
  144. do {
  145. Current = nullptr;
  146. readPos = 0;
  147. while(((refcount=device->MixCount.load(std::memory_order_acquire))&1))
  148. std::this_thread::yield();
  149. *clocktime = GetDeviceClockTime(device);
  150. voice = GetSourceVoice(Source, context);
  151. if(voice)
  152. {
  153. Current = voice->mCurrentBuffer.load(std::memory_order_relaxed);
  154. readPos = uint64_t{voice->mPosition.load(std::memory_order_relaxed)} << 32;
  155. readPos |= int64_t{voice->mPositionFrac.load(std::memory_order_relaxed)} <<
  156. (32-FRACTIONBITS);
  157. }
  158. std::atomic_thread_fence(std::memory_order_acquire);
  159. } while(refcount != device->MixCount.load(std::memory_order_relaxed));
  160. if(voice)
  161. {
  162. const ALbufferlistitem *BufferList{Source->queue};
  163. while(BufferList && BufferList != Current)
  164. {
  165. readPos += int64_t{BufferList->max_samples} << 32;
  166. BufferList = BufferList->next.load(std::memory_order_relaxed);
  167. }
  168. readPos = minu64(readPos, 0x7fffffffffffffff_u64);
  169. }
  170. return static_cast<int64_t>(readPos);
  171. }
  172. /* GetSourceSecOffset
  173. *
  174. * Gets the current read offset for the given Source, in seconds. The offset is
  175. * relative to the start of the queue (not the start of the current buffer).
  176. */
  177. ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime)
  178. {
  179. ALCdevice *device{context->Device};
  180. const ALbufferlistitem *Current;
  181. uint64_t readPos;
  182. ALuint refcount;
  183. ALvoice *voice;
  184. do {
  185. Current = nullptr;
  186. readPos = 0;
  187. while(((refcount=device->MixCount.load(std::memory_order_acquire))&1))
  188. std::this_thread::yield();
  189. *clocktime = GetDeviceClockTime(device);
  190. voice = GetSourceVoice(Source, context);
  191. if(voice)
  192. {
  193. Current = voice->mCurrentBuffer.load(std::memory_order_relaxed);
  194. readPos = uint64_t{voice->mPosition.load(std::memory_order_relaxed)} << FRACTIONBITS;
  195. readPos |= voice->mPositionFrac.load(std::memory_order_relaxed);
  196. }
  197. std::atomic_thread_fence(std::memory_order_acquire);
  198. } while(refcount != device->MixCount.load(std::memory_order_relaxed));
  199. ALdouble offset{0.0};
  200. if(voice)
  201. {
  202. const ALbufferlistitem *BufferList{Source->queue};
  203. const ALbuffer *BufferFmt{nullptr};
  204. while(BufferList && BufferList != Current)
  205. {
  206. for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i)
  207. BufferFmt = BufferList->buffers[i];
  208. readPos += int64_t{BufferList->max_samples} << FRACTIONBITS;
  209. BufferList = BufferList->next.load(std::memory_order_relaxed);
  210. }
  211. while(BufferList && !BufferFmt)
  212. {
  213. for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i)
  214. BufferFmt = BufferList->buffers[i];
  215. BufferList = BufferList->next.load(std::memory_order_relaxed);
  216. }
  217. assert(BufferFmt != nullptr);
  218. offset = static_cast<ALdouble>(readPos) / static_cast<ALdouble>FRACTIONONE /
  219. static_cast<ALdouble>(BufferFmt->Frequency);
  220. }
  221. return offset;
  222. }
  223. /* GetSourceOffset
  224. *
  225. * Gets the current read offset for the given Source, in the appropriate format
  226. * (Bytes, Samples or Seconds). The offset is relative to the start of the
  227. * queue (not the start of the current buffer).
  228. */
  229. ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context)
  230. {
  231. ALCdevice *device{context->Device};
  232. const ALbufferlistitem *Current;
  233. ALuint readPos;
  234. ALsizei readPosFrac;
  235. ALuint refcount;
  236. ALvoice *voice;
  237. do {
  238. Current = nullptr;
  239. readPos = readPosFrac = 0;
  240. while(((refcount=device->MixCount.load(std::memory_order_acquire))&1))
  241. std::this_thread::yield();
  242. voice = GetSourceVoice(Source, context);
  243. if(voice)
  244. {
  245. Current = voice->mCurrentBuffer.load(std::memory_order_relaxed);
  246. readPos = voice->mPosition.load(std::memory_order_relaxed);
  247. readPosFrac = voice->mPositionFrac.load(std::memory_order_relaxed);
  248. }
  249. std::atomic_thread_fence(std::memory_order_acquire);
  250. } while(refcount != device->MixCount.load(std::memory_order_relaxed));
  251. ALdouble offset{0.0};
  252. if(voice)
  253. {
  254. const ALbufferlistitem *BufferList{Source->queue};
  255. const ALbuffer *BufferFmt{nullptr};
  256. ALboolean readFin{AL_FALSE};
  257. ALuint totalBufferLen{0u};
  258. while(BufferList)
  259. {
  260. for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i)
  261. BufferFmt = BufferList->buffers[i];
  262. readFin |= (BufferList == Current);
  263. totalBufferLen += BufferList->max_samples;
  264. if(!readFin) readPos += BufferList->max_samples;
  265. BufferList = BufferList->next.load(std::memory_order_relaxed);
  266. }
  267. assert(BufferFmt != nullptr);
  268. if(Source->Looping)
  269. readPos %= totalBufferLen;
  270. else
  271. {
  272. /* Wrap back to 0 */
  273. if(readPos >= totalBufferLen)
  274. readPos = readPosFrac = 0;
  275. }
  276. offset = 0.0;
  277. switch(name)
  278. {
  279. case AL_SEC_OFFSET:
  280. offset = (readPos + static_cast<ALdouble>(readPosFrac)/FRACTIONONE) / BufferFmt->Frequency;
  281. break;
  282. case AL_SAMPLE_OFFSET:
  283. offset = readPos + static_cast<ALdouble>(readPosFrac)/FRACTIONONE;
  284. break;
  285. case AL_BYTE_OFFSET:
  286. if(BufferFmt->OriginalType == UserFmtIMA4)
  287. {
  288. ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
  289. ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->mFmtChannels);
  290. ALuint FrameBlockSize = BufferFmt->OriginalAlign;
  291. /* Round down to nearest ADPCM block */
  292. offset = static_cast<ALdouble>(readPos / FrameBlockSize * BlockSize);
  293. }
  294. else if(BufferFmt->OriginalType == UserFmtMSADPCM)
  295. {
  296. ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
  297. ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->mFmtChannels);
  298. ALuint FrameBlockSize = BufferFmt->OriginalAlign;
  299. /* Round down to nearest ADPCM block */
  300. offset = static_cast<ALdouble>(readPos / FrameBlockSize * BlockSize);
  301. }
  302. else
  303. {
  304. const ALsizei FrameSize{FrameSizeFromFmt(BufferFmt->mFmtChannels,
  305. BufferFmt->mFmtType)};
  306. offset = static_cast<ALdouble>(readPos * FrameSize);
  307. }
  308. break;
  309. }
  310. }
  311. return offset;
  312. }
  313. /* GetSampleOffset
  314. *
  315. * Retrieves the sample offset into the Source's queue (from the Sample, Byte
  316. * or Second offset supplied by the application). This takes into account the
  317. * fact that the buffer format may have been modifed since.
  318. */
  319. ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac)
  320. {
  321. const ALbuffer *BufferFmt{nullptr};
  322. const ALbufferlistitem *BufferList;
  323. /* Find the first valid Buffer in the Queue */
  324. BufferList = Source->queue;
  325. while(BufferList)
  326. {
  327. for(ALsizei i{0};i < BufferList->num_buffers && !BufferFmt;i++)
  328. BufferFmt = BufferList->buffers[i];
  329. if(BufferFmt) break;
  330. BufferList = BufferList->next.load(std::memory_order_relaxed);
  331. }
  332. if(!BufferFmt)
  333. {
  334. Source->OffsetType = AL_NONE;
  335. Source->Offset = 0.0;
  336. return AL_FALSE;
  337. }
  338. ALdouble dbloff, dblfrac;
  339. switch(Source->OffsetType)
  340. {
  341. case AL_BYTE_OFFSET:
  342. /* Determine the ByteOffset (and ensure it is block aligned) */
  343. *offset = static_cast<ALuint>(Source->Offset);
  344. if(BufferFmt->OriginalType == UserFmtIMA4)
  345. {
  346. ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4;
  347. *offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels);
  348. *offset *= BufferFmt->OriginalAlign;
  349. }
  350. else if(BufferFmt->OriginalType == UserFmtMSADPCM)
  351. {
  352. ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7;
  353. *offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels);
  354. *offset *= BufferFmt->OriginalAlign;
  355. }
  356. else
  357. *offset /= FrameSizeFromFmt(BufferFmt->mFmtChannels, BufferFmt->mFmtType);
  358. *frac = 0;
  359. break;
  360. case AL_SAMPLE_OFFSET:
  361. dblfrac = modf(Source->Offset, &dbloff);
  362. *offset = static_cast<ALuint>(mind(dbloff, std::numeric_limits<unsigned int>::max()));
  363. *frac = static_cast<ALsizei>(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0));
  364. break;
  365. case AL_SEC_OFFSET:
  366. dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff);
  367. *offset = static_cast<ALuint>(mind(dbloff, std::numeric_limits<unsigned int>::max()));
  368. *frac = static_cast<ALsizei>(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0));
  369. break;
  370. }
  371. Source->OffsetType = AL_NONE;
  372. Source->Offset = 0.0;
  373. return AL_TRUE;
  374. }
  375. /* ApplyOffset
  376. *
  377. * Apply the stored playback offset to the Source. This function will update
  378. * the number of buffers "played" given the stored offset.
  379. */
  380. ALboolean ApplyOffset(ALsource *Source, ALvoice *voice)
  381. {
  382. /* Get sample frame offset */
  383. ALuint offset{0u};
  384. ALsizei frac{0};
  385. if(!GetSampleOffset(Source, &offset, &frac))
  386. return AL_FALSE;
  387. ALuint totalBufferLen{0u};
  388. ALbufferlistitem *BufferList{Source->queue};
  389. while(BufferList && totalBufferLen <= offset)
  390. {
  391. if(static_cast<ALuint>(BufferList->max_samples) > offset-totalBufferLen)
  392. {
  393. /* Offset is in this buffer */
  394. voice->mPosition.store(offset - totalBufferLen, std::memory_order_relaxed);
  395. voice->mPositionFrac.store(frac, std::memory_order_relaxed);
  396. voice->mCurrentBuffer.store(BufferList, std::memory_order_release);
  397. return AL_TRUE;
  398. }
  399. totalBufferLen += BufferList->max_samples;
  400. BufferList = BufferList->next.load(std::memory_order_relaxed);
  401. }
  402. /* Offset is out of range of the queue */
  403. return AL_FALSE;
  404. }
  405. ALsource *AllocSource(ALCcontext *context)
  406. {
  407. ALCdevice *device{context->Device};
  408. std::lock_guard<std::mutex> _{context->SourceLock};
  409. if(context->NumSources >= device->SourcesMax)
  410. {
  411. alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax);
  412. return nullptr;
  413. }
  414. auto sublist = std::find_if(context->SourceList.begin(), context->SourceList.end(),
  415. [](const SourceSubList &entry) noexcept -> bool
  416. { return entry.FreeMask != 0; }
  417. );
  418. auto lidx = static_cast<ALsizei>(std::distance(context->SourceList.begin(), sublist));
  419. ALsource *source;
  420. ALsizei slidx;
  421. if(LIKELY(sublist != context->SourceList.end()))
  422. {
  423. slidx = CTZ64(sublist->FreeMask);
  424. source = sublist->Sources + slidx;
  425. }
  426. else
  427. {
  428. /* Don't allocate so many list entries that the 32-bit ID could
  429. * overflow...
  430. */
  431. if(UNLIKELY(context->SourceList.size() >= 1<<25))
  432. {
  433. alSetError(context, AL_OUT_OF_MEMORY, "Too many sources allocated");
  434. return nullptr;
  435. }
  436. context->SourceList.emplace_back();
  437. sublist = context->SourceList.end() - 1;
  438. sublist->FreeMask = ~0_u64;
  439. sublist->Sources = static_cast<ALsource*>(al_calloc(16, sizeof(ALsource)*64));
  440. if(UNLIKELY(!sublist->Sources))
  441. {
  442. context->SourceList.pop_back();
  443. alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate source batch");
  444. return nullptr;
  445. }
  446. slidx = 0;
  447. source = sublist->Sources + slidx;
  448. }
  449. source = new (source) ALsource{device->NumAuxSends};
  450. /* Add 1 to avoid source ID 0. */
  451. source->id = ((lidx<<6) | slidx) + 1;
  452. context->NumSources += 1;
  453. sublist->FreeMask &= ~(1_u64 << slidx);
  454. return source;
  455. }
  456. void FreeSource(ALCcontext *context, ALsource *source)
  457. {
  458. ALuint id = source->id - 1;
  459. ALsizei lidx = id >> 6;
  460. ALsizei slidx = id & 0x3f;
  461. ALCdevice *device{context->Device};
  462. BackendUniqueLock backlock{*device->Backend};
  463. if(ALvoice *voice{GetSourceVoice(source, context)})
  464. {
  465. voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed);
  466. voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed);
  467. voice->mSourceID.store(0u, std::memory_order_relaxed);
  468. std::atomic_thread_fence(std::memory_order_release);
  469. /* Don't set the voice to stopping if it was already stopped or
  470. * stopping.
  471. */
  472. ALvoice::State oldvstate{ALvoice::Playing};
  473. voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping,
  474. std::memory_order_acq_rel, std::memory_order_acquire);
  475. }
  476. backlock.unlock();
  477. source->~ALsource();
  478. context->SourceList[lidx].FreeMask |= 1_u64 << slidx;
  479. context->NumSources--;
  480. }
  481. inline ALsource *LookupSource(ALCcontext *context, ALuint id) noexcept
  482. {
  483. ALuint lidx = (id-1) >> 6;
  484. ALsizei slidx = (id-1) & 0x3f;
  485. if(UNLIKELY(lidx >= context->SourceList.size()))
  486. return nullptr;
  487. SourceSubList &sublist{context->SourceList[lidx]};
  488. if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx)))
  489. return nullptr;
  490. return sublist.Sources + slidx;
  491. }
  492. inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) noexcept
  493. {
  494. ALuint lidx = (id-1) >> 6;
  495. ALsizei slidx = (id-1) & 0x3f;
  496. if(UNLIKELY(lidx >= device->BufferList.size()))
  497. return nullptr;
  498. BufferSubList &sublist = device->BufferList[lidx];
  499. if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx)))
  500. return nullptr;
  501. return sublist.Buffers + slidx;
  502. }
  503. inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) noexcept
  504. {
  505. ALuint lidx = (id-1) >> 6;
  506. ALsizei slidx = (id-1) & 0x3f;
  507. if(UNLIKELY(lidx >= device->FilterList.size()))
  508. return nullptr;
  509. FilterSubList &sublist = device->FilterList[lidx];
  510. if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx)))
  511. return nullptr;
  512. return sublist.Filters + slidx;
  513. }
  514. inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept
  515. {
  516. ALuint lidx = (id-1) >> 6;
  517. ALsizei slidx = (id-1) & 0x3f;
  518. if(UNLIKELY(lidx >= context->EffectSlotList.size()))
  519. return nullptr;
  520. EffectSlotSubList &sublist{context->EffectSlotList[lidx]};
  521. if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx)))
  522. return nullptr;
  523. return sublist.EffectSlots + slidx;
  524. }
  525. enum SourceProp : ALenum {
  526. srcPitch = AL_PITCH,
  527. srcGain = AL_GAIN,
  528. srcMinGain = AL_MIN_GAIN,
  529. srcMaxGain = AL_MAX_GAIN,
  530. srcMaxDistance = AL_MAX_DISTANCE,
  531. srcRolloffFactor = AL_ROLLOFF_FACTOR,
  532. srcDopplerFactor = AL_DOPPLER_FACTOR,
  533. srcConeOuterGain = AL_CONE_OUTER_GAIN,
  534. srcSecOffset = AL_SEC_OFFSET,
  535. srcSampleOffset = AL_SAMPLE_OFFSET,
  536. srcByteOffset = AL_BYTE_OFFSET,
  537. srcConeInnerAngle = AL_CONE_INNER_ANGLE,
  538. srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
  539. srcRefDistance = AL_REFERENCE_DISTANCE,
  540. srcPosition = AL_POSITION,
  541. srcVelocity = AL_VELOCITY,
  542. srcDirection = AL_DIRECTION,
  543. srcSourceRelative = AL_SOURCE_RELATIVE,
  544. srcLooping = AL_LOOPING,
  545. srcBuffer = AL_BUFFER,
  546. srcSourceState = AL_SOURCE_STATE,
  547. srcBuffersQueued = AL_BUFFERS_QUEUED,
  548. srcBuffersProcessed = AL_BUFFERS_PROCESSED,
  549. srcSourceType = AL_SOURCE_TYPE,
  550. /* ALC_EXT_EFX */
  551. srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
  552. srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
  553. srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
  554. srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
  555. srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
  556. srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
  557. srcDirectFilter = AL_DIRECT_FILTER,
  558. srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
  559. /* AL_SOFT_direct_channels */
  560. srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
  561. /* AL_EXT_source_distance_model */
  562. srcDistanceModel = AL_DISTANCE_MODEL,
  563. /* AL_SOFT_source_latency */
  564. srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
  565. srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
  566. /* AL_EXT_STEREO_ANGLES */
  567. srcAngles = AL_STEREO_ANGLES,
  568. /* AL_EXT_SOURCE_RADIUS */
  569. srcRadius = AL_SOURCE_RADIUS,
  570. /* AL_EXT_BFORMAT */
  571. srcOrientation = AL_ORIENTATION,
  572. /* AL_SOFT_source_resampler */
  573. srcResampler = AL_SOURCE_RESAMPLER_SOFT,
  574. /* AL_SOFT_source_spatialize */
  575. srcSpatialize = AL_SOURCE_SPATIALIZE_SOFT,
  576. /* ALC_SOFT_device_clock */
  577. srcSampleOffsetClockSOFT = AL_SAMPLE_OFFSET_CLOCK_SOFT,
  578. srcSecOffsetClockSOFT = AL_SEC_OFFSET_CLOCK_SOFT,
  579. };
  580. /**
  581. * Returns if the last known state for the source was playing or paused. Does
  582. * not sync with the mixer voice.
  583. */
  584. inline bool IsPlayingOrPaused(ALsource *source)
  585. { return source->state == AL_PLAYING || source->state == AL_PAUSED; }
  586. /**
  587. * Returns an updated source state using the matching voice's status (or lack
  588. * thereof).
  589. */
  590. inline ALenum GetSourceState(ALsource *source, ALvoice *voice)
  591. {
  592. if(!voice && source->state == AL_PLAYING)
  593. source->state = AL_STOPPED;
  594. return source->state;
  595. }
  596. /**
  597. * Returns if the source should specify an update, given the context's
  598. * deferring state and the source's last known state.
  599. */
  600. inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context)
  601. {
  602. return !context->DeferUpdates.load(std::memory_order_acquire) &&
  603. IsPlayingOrPaused(source);
  604. }
  605. /** Can only be called while the mixer is locked! */
  606. void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state)
  607. {
  608. ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)};
  609. if(!(enabledevt&EventType_SourceStateChange)) return;
  610. /* The mixer may have queued a state change that's not yet been processed,
  611. * and we don't want state change messages to occur out of order, so send
  612. * it through the async queue to ensure proper ordering.
  613. */
  614. RingBuffer *ring{context->AsyncEvents.get()};
  615. auto evt_vec = ring->getWriteVector();
  616. if(evt_vec.first.len < 1) return;
  617. AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_SourceStateChange}};
  618. evt->u.srcstate.id = id;
  619. evt->u.srcstate.state = state;
  620. ring->writeAdvance(1);
  621. context->EventSem.post();
  622. }
  623. ALint FloatValsByProp(ALenum prop)
  624. {
  625. switch(static_cast<SourceProp>(prop))
  626. {
  627. case AL_PITCH:
  628. case AL_GAIN:
  629. case AL_MIN_GAIN:
  630. case AL_MAX_GAIN:
  631. case AL_MAX_DISTANCE:
  632. case AL_ROLLOFF_FACTOR:
  633. case AL_DOPPLER_FACTOR:
  634. case AL_CONE_OUTER_GAIN:
  635. case AL_SEC_OFFSET:
  636. case AL_SAMPLE_OFFSET:
  637. case AL_BYTE_OFFSET:
  638. case AL_CONE_INNER_ANGLE:
  639. case AL_CONE_OUTER_ANGLE:
  640. case AL_REFERENCE_DISTANCE:
  641. case AL_CONE_OUTER_GAINHF:
  642. case AL_AIR_ABSORPTION_FACTOR:
  643. case AL_ROOM_ROLLOFF_FACTOR:
  644. case AL_DIRECT_FILTER_GAINHF_AUTO:
  645. case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
  646. case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
  647. case AL_DIRECT_CHANNELS_SOFT:
  648. case AL_DISTANCE_MODEL:
  649. case AL_SOURCE_RELATIVE:
  650. case AL_LOOPING:
  651. case AL_SOURCE_STATE:
  652. case AL_BUFFERS_QUEUED:
  653. case AL_BUFFERS_PROCESSED:
  654. case AL_SOURCE_TYPE:
  655. case AL_SOURCE_RADIUS:
  656. case AL_SOURCE_RESAMPLER_SOFT:
  657. case AL_SOURCE_SPATIALIZE_SOFT:
  658. return 1;
  659. case AL_STEREO_ANGLES:
  660. return 2;
  661. case AL_POSITION:
  662. case AL_VELOCITY:
  663. case AL_DIRECTION:
  664. return 3;
  665. case AL_ORIENTATION:
  666. return 6;
  667. case AL_SEC_OFFSET_LATENCY_SOFT:
  668. case AL_SEC_OFFSET_CLOCK_SOFT:
  669. break; /* Double only */
  670. case AL_BUFFER:
  671. case AL_DIRECT_FILTER:
  672. case AL_AUXILIARY_SEND_FILTER:
  673. break; /* i/i64 only */
  674. case AL_SAMPLE_OFFSET_LATENCY_SOFT:
  675. case AL_SAMPLE_OFFSET_CLOCK_SOFT:
  676. break; /* i64 only */
  677. }
  678. return 0;
  679. }
  680. ALint DoubleValsByProp(ALenum prop)
  681. {
  682. switch(static_cast<SourceProp>(prop))
  683. {
  684. case AL_PITCH:
  685. case AL_GAIN:
  686. case AL_MIN_GAIN:
  687. case AL_MAX_GAIN:
  688. case AL_MAX_DISTANCE:
  689. case AL_ROLLOFF_FACTOR:
  690. case AL_DOPPLER_FACTOR:
  691. case AL_CONE_OUTER_GAIN:
  692. case AL_SEC_OFFSET:
  693. case AL_SAMPLE_OFFSET:
  694. case AL_BYTE_OFFSET:
  695. case AL_CONE_INNER_ANGLE:
  696. case AL_CONE_OUTER_ANGLE:
  697. case AL_REFERENCE_DISTANCE:
  698. case AL_CONE_OUTER_GAINHF:
  699. case AL_AIR_ABSORPTION_FACTOR:
  700. case AL_ROOM_ROLLOFF_FACTOR:
  701. case AL_DIRECT_FILTER_GAINHF_AUTO:
  702. case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
  703. case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
  704. case AL_DIRECT_CHANNELS_SOFT:
  705. case AL_DISTANCE_MODEL:
  706. case AL_SOURCE_RELATIVE:
  707. case AL_LOOPING:
  708. case AL_SOURCE_STATE:
  709. case AL_BUFFERS_QUEUED:
  710. case AL_BUFFERS_PROCESSED:
  711. case AL_SOURCE_TYPE:
  712. case AL_SOURCE_RADIUS:
  713. case AL_SOURCE_RESAMPLER_SOFT:
  714. case AL_SOURCE_SPATIALIZE_SOFT:
  715. return 1;
  716. case AL_SEC_OFFSET_LATENCY_SOFT:
  717. case AL_SEC_OFFSET_CLOCK_SOFT:
  718. case AL_STEREO_ANGLES:
  719. return 2;
  720. case AL_POSITION:
  721. case AL_VELOCITY:
  722. case AL_DIRECTION:
  723. return 3;
  724. case AL_ORIENTATION:
  725. return 6;
  726. case AL_BUFFER:
  727. case AL_DIRECT_FILTER:
  728. case AL_AUXILIARY_SEND_FILTER:
  729. break; /* i/i64 only */
  730. case AL_SAMPLE_OFFSET_LATENCY_SOFT:
  731. case AL_SAMPLE_OFFSET_CLOCK_SOFT:
  732. break; /* i64 only */
  733. }
  734. return 0;
  735. }
  736. ALint IntValsByProp(ALenum prop)
  737. {
  738. switch(static_cast<SourceProp>(prop))
  739. {
  740. case AL_PITCH:
  741. case AL_GAIN:
  742. case AL_MIN_GAIN:
  743. case AL_MAX_GAIN:
  744. case AL_MAX_DISTANCE:
  745. case AL_ROLLOFF_FACTOR:
  746. case AL_DOPPLER_FACTOR:
  747. case AL_CONE_OUTER_GAIN:
  748. case AL_SEC_OFFSET:
  749. case AL_SAMPLE_OFFSET:
  750. case AL_BYTE_OFFSET:
  751. case AL_CONE_INNER_ANGLE:
  752. case AL_CONE_OUTER_ANGLE:
  753. case AL_REFERENCE_DISTANCE:
  754. case AL_CONE_OUTER_GAINHF:
  755. case AL_AIR_ABSORPTION_FACTOR:
  756. case AL_ROOM_ROLLOFF_FACTOR:
  757. case AL_DIRECT_FILTER_GAINHF_AUTO:
  758. case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
  759. case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
  760. case AL_DIRECT_CHANNELS_SOFT:
  761. case AL_DISTANCE_MODEL:
  762. case AL_SOURCE_RELATIVE:
  763. case AL_LOOPING:
  764. case AL_BUFFER:
  765. case AL_SOURCE_STATE:
  766. case AL_BUFFERS_QUEUED:
  767. case AL_BUFFERS_PROCESSED:
  768. case AL_SOURCE_TYPE:
  769. case AL_DIRECT_FILTER:
  770. case AL_SOURCE_RADIUS:
  771. case AL_SOURCE_RESAMPLER_SOFT:
  772. case AL_SOURCE_SPATIALIZE_SOFT:
  773. return 1;
  774. case AL_POSITION:
  775. case AL_VELOCITY:
  776. case AL_DIRECTION:
  777. case AL_AUXILIARY_SEND_FILTER:
  778. return 3;
  779. case AL_ORIENTATION:
  780. return 6;
  781. case AL_SAMPLE_OFFSET_LATENCY_SOFT:
  782. case AL_SAMPLE_OFFSET_CLOCK_SOFT:
  783. break; /* i64 only */
  784. case AL_SEC_OFFSET_LATENCY_SOFT:
  785. case AL_SEC_OFFSET_CLOCK_SOFT:
  786. break; /* Double only */
  787. case AL_STEREO_ANGLES:
  788. break; /* Float/double only */
  789. }
  790. return 0;
  791. }
  792. ALint Int64ValsByProp(ALenum prop)
  793. {
  794. switch(static_cast<SourceProp>(prop))
  795. {
  796. case AL_PITCH:
  797. case AL_GAIN:
  798. case AL_MIN_GAIN:
  799. case AL_MAX_GAIN:
  800. case AL_MAX_DISTANCE:
  801. case AL_ROLLOFF_FACTOR:
  802. case AL_DOPPLER_FACTOR:
  803. case AL_CONE_OUTER_GAIN:
  804. case AL_SEC_OFFSET:
  805. case AL_SAMPLE_OFFSET:
  806. case AL_BYTE_OFFSET:
  807. case AL_CONE_INNER_ANGLE:
  808. case AL_CONE_OUTER_ANGLE:
  809. case AL_REFERENCE_DISTANCE:
  810. case AL_CONE_OUTER_GAINHF:
  811. case AL_AIR_ABSORPTION_FACTOR:
  812. case AL_ROOM_ROLLOFF_FACTOR:
  813. case AL_DIRECT_FILTER_GAINHF_AUTO:
  814. case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
  815. case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
  816. case AL_DIRECT_CHANNELS_SOFT:
  817. case AL_DISTANCE_MODEL:
  818. case AL_SOURCE_RELATIVE:
  819. case AL_LOOPING:
  820. case AL_BUFFER:
  821. case AL_SOURCE_STATE:
  822. case AL_BUFFERS_QUEUED:
  823. case AL_BUFFERS_PROCESSED:
  824. case AL_SOURCE_TYPE:
  825. case AL_DIRECT_FILTER:
  826. case AL_SOURCE_RADIUS:
  827. case AL_SOURCE_RESAMPLER_SOFT:
  828. case AL_SOURCE_SPATIALIZE_SOFT:
  829. return 1;
  830. case AL_SAMPLE_OFFSET_LATENCY_SOFT:
  831. case AL_SAMPLE_OFFSET_CLOCK_SOFT:
  832. return 2;
  833. case AL_POSITION:
  834. case AL_VELOCITY:
  835. case AL_DIRECTION:
  836. case AL_AUXILIARY_SEND_FILTER:
  837. return 3;
  838. case AL_ORIENTATION:
  839. return 6;
  840. case AL_SEC_OFFSET_LATENCY_SOFT:
  841. case AL_SEC_OFFSET_CLOCK_SOFT:
  842. break; /* Double only */
  843. case AL_STEREO_ANGLES:
  844. break; /* Float/double only */
  845. }
  846. return 0;
  847. }
  848. ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
  849. ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
  850. ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
  851. #define CHECKVAL(x) do { \
  852. if(!(x)) \
  853. { \
  854. alSetError(Context, AL_INVALID_VALUE, "Value out of range"); \
  855. return AL_FALSE; \
  856. } \
  857. } while(0)
  858. void UpdateSourceProps(ALsource *source, ALCcontext *context)
  859. {
  860. ALvoice *voice;
  861. if(SourceShouldUpdate(source, context) && (voice=GetSourceVoice(source, context)) != nullptr)
  862. UpdateSourceProps(source, voice, context);
  863. else
  864. source->PropsClean.clear(std::memory_order_release);
  865. }
  866. ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
  867. {
  868. ALint ival;
  869. switch(prop)
  870. {
  871. case AL_SEC_OFFSET_LATENCY_SOFT:
  872. case AL_SEC_OFFSET_CLOCK_SOFT:
  873. /* Query only */
  874. SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
  875. "Setting read-only source property 0x%04x", prop);
  876. case AL_PITCH:
  877. CHECKVAL(*values >= 0.0f);
  878. Source->Pitch = *values;
  879. UpdateSourceProps(Source, Context);
  880. return AL_TRUE;
  881. case AL_CONE_INNER_ANGLE:
  882. CHECKVAL(*values >= 0.0f && *values <= 360.0f);
  883. Source->InnerAngle = *values;
  884. UpdateSourceProps(Source, Context);
  885. return AL_TRUE;
  886. case AL_CONE_OUTER_ANGLE:
  887. CHECKVAL(*values >= 0.0f && *values <= 360.0f);
  888. Source->OuterAngle = *values;
  889. UpdateSourceProps(Source, Context);
  890. return AL_TRUE;
  891. case AL_GAIN:
  892. CHECKVAL(*values >= 0.0f);
  893. Source->Gain = *values;
  894. UpdateSourceProps(Source, Context);
  895. return AL_TRUE;
  896. case AL_MAX_DISTANCE:
  897. CHECKVAL(*values >= 0.0f);
  898. Source->MaxDistance = *values;
  899. UpdateSourceProps(Source, Context);
  900. return AL_TRUE;
  901. case AL_ROLLOFF_FACTOR:
  902. CHECKVAL(*values >= 0.0f);
  903. Source->RolloffFactor = *values;
  904. UpdateSourceProps(Source, Context);
  905. return AL_TRUE;
  906. case AL_REFERENCE_DISTANCE:
  907. CHECKVAL(*values >= 0.0f);
  908. Source->RefDistance = *values;
  909. UpdateSourceProps(Source, Context);
  910. return AL_TRUE;
  911. case AL_MIN_GAIN:
  912. CHECKVAL(*values >= 0.0f);
  913. Source->MinGain = *values;
  914. UpdateSourceProps(Source, Context);
  915. return AL_TRUE;
  916. case AL_MAX_GAIN:
  917. CHECKVAL(*values >= 0.0f);
  918. Source->MaxGain = *values;
  919. UpdateSourceProps(Source, Context);
  920. return AL_TRUE;
  921. case AL_CONE_OUTER_GAIN:
  922. CHECKVAL(*values >= 0.0f && *values <= 1.0f);
  923. Source->OuterGain = *values;
  924. UpdateSourceProps(Source, Context);
  925. return AL_TRUE;
  926. case AL_CONE_OUTER_GAINHF:
  927. CHECKVAL(*values >= 0.0f && *values <= 1.0f);
  928. Source->OuterGainHF = *values;
  929. UpdateSourceProps(Source, Context);
  930. return AL_TRUE;
  931. case AL_AIR_ABSORPTION_FACTOR:
  932. CHECKVAL(*values >= 0.0f && *values <= 10.0f);
  933. Source->AirAbsorptionFactor = *values;
  934. UpdateSourceProps(Source, Context);
  935. return AL_TRUE;
  936. case AL_ROOM_ROLLOFF_FACTOR:
  937. CHECKVAL(*values >= 0.0f && *values <= 10.0f);
  938. Source->RoomRolloffFactor = *values;
  939. UpdateSourceProps(Source, Context);
  940. return AL_TRUE;
  941. case AL_DOPPLER_FACTOR:
  942. CHECKVAL(*values >= 0.0f && *values <= 1.0f);
  943. Source->DopplerFactor = *values;
  944. UpdateSourceProps(Source, Context);
  945. return AL_TRUE;
  946. case AL_SEC_OFFSET:
  947. case AL_SAMPLE_OFFSET:
  948. case AL_BYTE_OFFSET:
  949. CHECKVAL(*values >= 0.0f);
  950. Source->OffsetType = prop;
  951. Source->Offset = *values;
  952. if(IsPlayingOrPaused(Source))
  953. {
  954. ALCdevice *device{Context->Device};
  955. BackendLockGuard _{*device->Backend};
  956. /* Double-check that the source is still playing while we have
  957. * the lock.
  958. */
  959. if(ALvoice *voice{GetSourceVoice(Source, Context)})
  960. {
  961. if(ApplyOffset(Source, voice) == AL_FALSE)
  962. SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid offset");
  963. }
  964. }
  965. return AL_TRUE;
  966. case AL_SOURCE_RADIUS:
  967. CHECKVAL(*values >= 0.0f && std::isfinite(*values));
  968. Source->Radius = *values;
  969. UpdateSourceProps(Source, Context);
  970. return AL_TRUE;
  971. case AL_STEREO_ANGLES:
  972. CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]));
  973. Source->StereoPan[0] = values[0];
  974. Source->StereoPan[1] = values[1];
  975. UpdateSourceProps(Source, Context);
  976. return AL_TRUE;
  977. case AL_POSITION:
  978. CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]));
  979. Source->Position[0] = values[0];
  980. Source->Position[1] = values[1];
  981. Source->Position[2] = values[2];
  982. UpdateSourceProps(Source, Context);
  983. return AL_TRUE;
  984. case AL_VELOCITY:
  985. CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]));
  986. Source->Velocity[0] = values[0];
  987. Source->Velocity[1] = values[1];
  988. Source->Velocity[2] = values[2];
  989. UpdateSourceProps(Source, Context);
  990. return AL_TRUE;
  991. case AL_DIRECTION:
  992. CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]));
  993. Source->Direction[0] = values[0];
  994. Source->Direction[1] = values[1];
  995. Source->Direction[2] = values[2];
  996. UpdateSourceProps(Source, Context);
  997. return AL_TRUE;
  998. case AL_ORIENTATION:
  999. CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) &&
  1000. std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5]));
  1001. Source->OrientAt[0] = values[0];
  1002. Source->OrientAt[1] = values[1];
  1003. Source->OrientAt[2] = values[2];
  1004. Source->OrientUp[0] = values[3];
  1005. Source->OrientUp[1] = values[4];
  1006. Source->OrientUp[2] = values[5];
  1007. UpdateSourceProps(Source, Context);
  1008. return AL_TRUE;
  1009. case AL_SOURCE_RELATIVE:
  1010. case AL_LOOPING:
  1011. case AL_SOURCE_STATE:
  1012. case AL_SOURCE_TYPE:
  1013. case AL_DISTANCE_MODEL:
  1014. case AL_DIRECT_FILTER_GAINHF_AUTO:
  1015. case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
  1016. case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
  1017. case AL_DIRECT_CHANNELS_SOFT:
  1018. case AL_SOURCE_RESAMPLER_SOFT:
  1019. case AL_SOURCE_SPATIALIZE_SOFT:
  1020. ival = static_cast<ALint>(values[0]);
  1021. return SetSourceiv(Source, Context, prop, &ival);
  1022. case AL_BUFFERS_QUEUED:
  1023. case AL_BUFFERS_PROCESSED:
  1024. ival = static_cast<ALint>(static_cast<ALuint>(values[0]));
  1025. return SetSourceiv(Source, Context, prop, &ival);
  1026. case AL_BUFFER:
  1027. case AL_DIRECT_FILTER:
  1028. case AL_AUXILIARY_SEND_FILTER:
  1029. case AL_SAMPLE_OFFSET_LATENCY_SOFT:
  1030. case AL_SAMPLE_OFFSET_CLOCK_SOFT:
  1031. break;
  1032. }
  1033. ERR("Unexpected property: 0x%04x\n", prop);
  1034. SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source float property 0x%04x", prop);
  1035. }
  1036. ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
  1037. {
  1038. ALCdevice *device{Context->Device};
  1039. ALbuffer *buffer{nullptr};
  1040. ALfilter *filter{nullptr};
  1041. ALeffectslot *slot{nullptr};
  1042. ALbufferlistitem *oldlist{nullptr};
  1043. std::unique_lock<std::mutex> slotlock;
  1044. std::unique_lock<std::mutex> filtlock;
  1045. std::unique_lock<std::mutex> buflock;
  1046. ALfloat fvals[6];
  1047. switch(prop)
  1048. {
  1049. case AL_SOURCE_STATE:
  1050. case AL_SOURCE_TYPE:
  1051. case AL_BUFFERS_QUEUED:
  1052. case AL_BUFFERS_PROCESSED:
  1053. /* Query only */
  1054. SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
  1055. "Setting read-only source property 0x%04x", prop);
  1056. case AL_SOURCE_RELATIVE:
  1057. CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
  1058. Source->HeadRelative = static_cast<ALboolean>(*values);
  1059. UpdateSourceProps(Source, Context);
  1060. return AL_TRUE;
  1061. case AL_LOOPING:
  1062. CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
  1063. Source->Looping = static_cast<ALboolean>(*values);
  1064. if(IsPlayingOrPaused(Source))
  1065. {
  1066. ALvoice *voice{GetSourceVoice(Source, Context)};
  1067. if(voice)
  1068. {
  1069. if(Source->Looping)
  1070. voice->mLoopBuffer.store(Source->queue, std::memory_order_release);
  1071. else
  1072. voice->mLoopBuffer.store(nullptr, std::memory_order_release);
  1073. /* If the source is playing, wait for the current mix to finish
  1074. * to ensure it isn't currently looping back or reaching the
  1075. * end.
  1076. */
  1077. while((device->MixCount.load(std::memory_order_acquire)&1))
  1078. std::this_thread::yield();
  1079. }
  1080. }
  1081. return AL_TRUE;
  1082. case AL_BUFFER:
  1083. buflock = std::unique_lock<std::mutex>{device->BufferLock};
  1084. if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != nullptr))
  1085. SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid buffer ID %u",
  1086. *values);
  1087. if(buffer && buffer->MappedAccess != 0 &&
  1088. !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
  1089. SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
  1090. "Setting non-persistently mapped buffer %u", buffer->id);
  1091. else
  1092. {
  1093. ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context));
  1094. if(state == AL_PLAYING || state == AL_PAUSED)
  1095. SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
  1096. "Setting buffer on playing or paused source %u", Source->id);
  1097. }
  1098. oldlist = Source->queue;
  1099. if(buffer != nullptr)
  1100. {
  1101. /* Add the selected buffer to a one-item queue */
  1102. auto newlist = static_cast<ALbufferlistitem*>(al_calloc(DEF_ALIGN,
  1103. ALbufferlistitem::Sizeof(1u)));
  1104. newlist->next.store(nullptr, std::memory_order_relaxed);
  1105. newlist->max_samples = buffer->SampleLen;
  1106. newlist->num_buffers = 1;
  1107. newlist->buffers[0] = buffer;
  1108. IncrementRef(&buffer->ref);
  1109. /* Source is now Static */
  1110. Source->SourceType = AL_STATIC;
  1111. Source->queue = newlist;
  1112. }
  1113. else
  1114. {
  1115. /* Source is now Undetermined */
  1116. Source->SourceType = AL_UNDETERMINED;
  1117. Source->queue = nullptr;
  1118. }
  1119. buflock.unlock();
  1120. /* Delete all elements in the previous queue */
  1121. while(oldlist != nullptr)
  1122. {
  1123. ALbufferlistitem *temp{oldlist};
  1124. oldlist = temp->next.load(std::memory_order_relaxed);
  1125. for(ALsizei i{0};i < temp->num_buffers;i++)
  1126. {
  1127. if(temp->buffers[i])
  1128. DecrementRef(&temp->buffers[i]->ref);
  1129. }
  1130. al_free(temp);
  1131. }
  1132. return AL_TRUE;
  1133. case AL_SEC_OFFSET:
  1134. case AL_SAMPLE_OFFSET:
  1135. case AL_BYTE_OFFSET:
  1136. CHECKVAL(*values >= 0);
  1137. Source->OffsetType = prop;
  1138. Source->Offset = *values;
  1139. if(IsPlayingOrPaused(Source))
  1140. {
  1141. ALCdevice *device{Context->Device};
  1142. BackendLockGuard _{*device->Backend};
  1143. if(ALvoice *voice{GetSourceVoice(Source, Context)})
  1144. {
  1145. if(ApplyOffset(Source, voice) == AL_FALSE)
  1146. SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE,
  1147. "Invalid source offset");
  1148. }
  1149. }
  1150. return AL_TRUE;
  1151. case AL_DIRECT_FILTER:
  1152. filtlock = std::unique_lock<std::mutex>{device->FilterLock};
  1153. if(!(*values == 0 || (filter=LookupFilter(device, *values)) != nullptr))
  1154. SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u",
  1155. *values);
  1156. if(!filter)
  1157. {
  1158. Source->Direct.Gain = 1.0f;
  1159. Source->Direct.GainHF = 1.0f;
  1160. Source->Direct.HFReference = LOWPASSFREQREF;
  1161. Source->Direct.GainLF = 1.0f;
  1162. Source->Direct.LFReference = HIGHPASSFREQREF;
  1163. }
  1164. else
  1165. {
  1166. Source->Direct.Gain = filter->Gain;
  1167. Source->Direct.GainHF = filter->GainHF;
  1168. Source->Direct.HFReference = filter->HFReference;
  1169. Source->Direct.GainLF = filter->GainLF;
  1170. Source->Direct.LFReference = filter->LFReference;
  1171. }
  1172. filtlock.unlock();
  1173. UpdateSourceProps(Source, Context);
  1174. return AL_TRUE;
  1175. case AL_DIRECT_FILTER_GAINHF_AUTO:
  1176. CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
  1177. Source->DryGainHFAuto = *values;
  1178. UpdateSourceProps(Source, Context);
  1179. return AL_TRUE;
  1180. case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
  1181. CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
  1182. Source->WetGainAuto = *values;
  1183. UpdateSourceProps(Source, Context);
  1184. return AL_TRUE;
  1185. case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
  1186. CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
  1187. Source->WetGainHFAuto = *values;
  1188. UpdateSourceProps(Source, Context);
  1189. return AL_TRUE;
  1190. case AL_DIRECT_CHANNELS_SOFT:
  1191. CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
  1192. Source->DirectChannels = *values;
  1193. UpdateSourceProps(Source, Context);
  1194. return AL_TRUE;
  1195. case AL_DISTANCE_MODEL:
  1196. CHECKVAL(*values == AL_NONE ||
  1197. *values == AL_INVERSE_DISTANCE ||
  1198. *values == AL_INVERSE_DISTANCE_CLAMPED ||
  1199. *values == AL_LINEAR_DISTANCE ||
  1200. *values == AL_LINEAR_DISTANCE_CLAMPED ||
  1201. *values == AL_EXPONENT_DISTANCE ||
  1202. *values == AL_EXPONENT_DISTANCE_CLAMPED);
  1203. Source->mDistanceModel = static_cast<DistanceModel>(*values);
  1204. if(Context->SourceDistanceModel)
  1205. UpdateSourceProps(Source, Context);
  1206. return AL_TRUE;
  1207. case AL_SOURCE_RESAMPLER_SOFT:
  1208. CHECKVAL(*values >= 0 && *values <= ResamplerMax);
  1209. Source->mResampler = static_cast<Resampler>(*values);
  1210. UpdateSourceProps(Source, Context);
  1211. return AL_TRUE;
  1212. case AL_SOURCE_SPATIALIZE_SOFT:
  1213. CHECKVAL(*values >= AL_FALSE && *values <= AL_AUTO_SOFT);
  1214. Source->mSpatialize = static_cast<SpatializeMode>(*values);
  1215. UpdateSourceProps(Source, Context);
  1216. return AL_TRUE;
  1217. case AL_AUXILIARY_SEND_FILTER:
  1218. slotlock = std::unique_lock<std::mutex>{Context->EffectSlotLock};
  1219. if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != nullptr))
  1220. SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u",
  1221. values[0]);
  1222. if(static_cast<ALuint>(values[1]) >= static_cast<ALuint>(device->NumAuxSends))
  1223. SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]);
  1224. filtlock = std::unique_lock<std::mutex>{device->FilterLock};
  1225. if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != nullptr))
  1226. SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u",
  1227. values[2]);
  1228. if(!filter)
  1229. {
  1230. /* Disable filter */
  1231. Source->Send[values[1]].Gain = 1.0f;
  1232. Source->Send[values[1]].GainHF = 1.0f;
  1233. Source->Send[values[1]].HFReference = LOWPASSFREQREF;
  1234. Source->Send[values[1]].GainLF = 1.0f;
  1235. Source->Send[values[1]].LFReference = HIGHPASSFREQREF;
  1236. }
  1237. else
  1238. {
  1239. Source->Send[values[1]].Gain = filter->Gain;
  1240. Source->Send[values[1]].GainHF = filter->GainHF;
  1241. Source->Send[values[1]].HFReference = filter->HFReference;
  1242. Source->Send[values[1]].GainLF = filter->GainLF;
  1243. Source->Send[values[1]].LFReference = filter->LFReference;
  1244. }
  1245. filtlock.unlock();
  1246. if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source))
  1247. {
  1248. /* Add refcount on the new slot, and release the previous slot */
  1249. if(slot) IncrementRef(&slot->ref);
  1250. if(Source->Send[values[1]].Slot)
  1251. DecrementRef(&Source->Send[values[1]].Slot->ref);
  1252. Source->Send[values[1]].Slot = slot;
  1253. /* We must force an update if the auxiliary slot changed on an
  1254. * active source, in case the slot is about to be deleted.
  1255. */
  1256. ALvoice *voice{GetSourceVoice(Source, Context)};
  1257. if(voice) UpdateSourceProps(Source, voice, Context);
  1258. else Source->PropsClean.clear(std::memory_order_release);
  1259. }
  1260. else
  1261. {
  1262. if(slot) IncrementRef(&slot->ref);
  1263. if(Source->Send[values[1]].Slot)
  1264. DecrementRef(&Source->Send[values[1]].Slot->ref);
  1265. Source->Send[values[1]].Slot = slot;
  1266. UpdateSourceProps(Source, Context);
  1267. }
  1268. return AL_TRUE;
  1269. /* 1x float */
  1270. case AL_CONE_INNER_ANGLE:
  1271. case AL_CONE_OUTER_ANGLE:
  1272. case AL_PITCH:
  1273. case AL_GAIN:
  1274. case AL_MIN_GAIN:
  1275. case AL_MAX_GAIN:
  1276. case AL_REFERENCE_DISTANCE:
  1277. case AL_ROLLOFF_FACTOR:
  1278. case AL_CONE_OUTER_GAIN:
  1279. case AL_MAX_DISTANCE:
  1280. case AL_DOPPLER_FACTOR:
  1281. case AL_CONE_OUTER_GAINHF:
  1282. case AL_AIR_ABSORPTION_FACTOR:
  1283. case AL_ROOM_ROLLOFF_FACTOR:
  1284. case AL_SOURCE_RADIUS:
  1285. fvals[0] = static_cast<ALfloat>(*values);
  1286. return SetSourcefv(Source, Context, prop, fvals);
  1287. /* 3x float */
  1288. case AL_POSITION:
  1289. case AL_VELOCITY:
  1290. case AL_DIRECTION:
  1291. fvals[0] = static_cast<ALfloat>(values[0]);
  1292. fvals[1] = static_cast<ALfloat>(values[1]);
  1293. fvals[2] = static_cast<ALfloat>(values[2]);
  1294. return SetSourcefv(Source, Context, prop, fvals);
  1295. /* 6x float */
  1296. case AL_ORIENTATION:
  1297. fvals[0] = static_cast<ALfloat>(values[0]);
  1298. fvals[1] = static_cast<ALfloat>(values[1]);
  1299. fvals[2] = static_cast<ALfloat>(values[2]);
  1300. fvals[3] = static_cast<ALfloat>(values[3]);
  1301. fvals[4] = static_cast<ALfloat>(values[4]);
  1302. fvals[5] = static_cast<ALfloat>(values[5]);
  1303. return SetSourcefv(Source, Context, prop, fvals);
  1304. case AL_SAMPLE_OFFSET_LATENCY_SOFT:
  1305. case AL_SEC_OFFSET_LATENCY_SOFT:
  1306. case AL_SEC_OFFSET_CLOCK_SOFT:
  1307. case AL_SAMPLE_OFFSET_CLOCK_SOFT:
  1308. case AL_STEREO_ANGLES:
  1309. break;
  1310. }
  1311. ERR("Unexpected property: 0x%04x\n", prop);
  1312. SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x",
  1313. prop);
  1314. }
  1315. ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
  1316. {
  1317. ALfloat fvals[6];
  1318. ALint ivals[3];
  1319. switch(prop)
  1320. {
  1321. case AL_SOURCE_TYPE:
  1322. case AL_BUFFERS_QUEUED:
  1323. case AL_BUFFERS_PROCESSED:
  1324. case AL_SOURCE_STATE:
  1325. case AL_SAMPLE_OFFSET_LATENCY_SOFT:
  1326. case AL_SAMPLE_OFFSET_CLOCK_SOFT:
  1327. /* Query only */
  1328. SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE,
  1329. "Setting read-only source property 0x%04x", prop);
  1330. /* 1x int */
  1331. case AL_SOURCE_RELATIVE:
  1332. case AL_LOOPING:
  1333. case AL_SEC_OFFSET:
  1334. case AL_SAMPLE_OFFSET:
  1335. case AL_BYTE_OFFSET:
  1336. case AL_DIRECT_FILTER_GAINHF_AUTO:
  1337. case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
  1338. case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
  1339. case AL_DIRECT_CHANNELS_SOFT:
  1340. case AL_DISTANCE_MODEL:
  1341. case AL_SOURCE_RESAMPLER_SOFT:
  1342. case AL_SOURCE_SPATIALIZE_SOFT:
  1343. CHECKVAL(*values <= INT_MAX && *values >= INT_MIN);
  1344. ivals[0] = static_cast<ALint>(*values);
  1345. return SetSourceiv(Source, Context, prop, ivals);
  1346. /* 1x uint */
  1347. case AL_BUFFER:
  1348. case AL_DIRECT_FILTER:
  1349. CHECKVAL(*values <= UINT_MAX && *values >= 0);
  1350. ivals[0] = static_cast<ALuint>(*values);
  1351. return SetSourceiv(Source, Context, prop, ivals);
  1352. /* 3x uint */
  1353. case AL_AUXILIARY_SEND_FILTER:
  1354. CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 &&
  1355. values[1] <= UINT_MAX && values[1] >= 0 &&
  1356. values[2] <= UINT_MAX && values[2] >= 0);
  1357. ivals[0] = static_cast<ALuint>(values[0]);
  1358. ivals[1] = static_cast<ALuint>(values[1]);
  1359. ivals[2] = static_cast<ALuint>(values[2]);
  1360. return SetSourceiv(Source, Context, prop, ivals);
  1361. /* 1x float */
  1362. case AL_CONE_INNER_ANGLE:
  1363. case AL_CONE_OUTER_ANGLE:
  1364. case AL_PITCH:
  1365. case AL_GAIN:
  1366. case AL_MIN_GAIN:
  1367. case AL_MAX_GAIN:
  1368. case AL_REFERENCE_DISTANCE:
  1369. case AL_ROLLOFF_FACTOR:
  1370. case AL_CONE_OUTER_GAIN:
  1371. case AL_MAX_DISTANCE:
  1372. case AL_DOPPLER_FACTOR:
  1373. case AL_CONE_OUTER_GAINHF:
  1374. case AL_AIR_ABSORPTION_FACTOR:
  1375. case AL_ROOM_ROLLOFF_FACTOR:
  1376. case AL_SOURCE_RADIUS:
  1377. fvals[0] = static_cast<ALfloat>(*values);
  1378. return SetSourcefv(Source, Context, prop, fvals);
  1379. /* 3x float */
  1380. case AL_POSITION:
  1381. case AL_VELOCITY:
  1382. case AL_DIRECTION:
  1383. fvals[0] = static_cast<ALfloat>(values[0]);
  1384. fvals[1] = static_cast<ALfloat>(values[1]);
  1385. fvals[2] = static_cast<ALfloat>(values[2]);
  1386. return SetSourcefv(Source, Context, prop, fvals);
  1387. /* 6x float */
  1388. case AL_ORIENTATION:
  1389. fvals[0] = static_cast<ALfloat>(values[0]);
  1390. fvals[1] = static_cast<ALfloat>(values[1]);
  1391. fvals[2] = static_cast<ALfloat>(values[2]);
  1392. fvals[3] = static_cast<ALfloat>(values[3]);
  1393. fvals[4] = static_cast<ALfloat>(values[4]);
  1394. fvals[5] = static_cast<ALfloat>(values[5]);
  1395. return SetSourcefv(Source, Context, prop, fvals);
  1396. case AL_SEC_OFFSET_LATENCY_SOFT:
  1397. case AL_SEC_OFFSET_CLOCK_SOFT:
  1398. case AL_STEREO_ANGLES:
  1399. break;
  1400. }
  1401. ERR("Unexpected property: 0x%04x\n", prop);
  1402. SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x",
  1403. prop);
  1404. }
  1405. #undef CHECKVAL
  1406. ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
  1407. ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
  1408. ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64SOFT *values);
  1409. ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
  1410. {
  1411. ALCdevice *device{Context->Device};
  1412. ClockLatency clocktime;
  1413. std::chrono::nanoseconds srcclock;
  1414. ALint ivals[3];
  1415. ALboolean err;
  1416. switch(prop)
  1417. {
  1418. case AL_GAIN:
  1419. *values = Source->Gain;
  1420. return AL_TRUE;
  1421. case AL_PITCH:
  1422. *values = Source->Pitch;
  1423. return AL_TRUE;
  1424. case AL_MAX_DISTANCE:
  1425. *values = Source->MaxDistance;
  1426. return AL_TRUE;
  1427. case AL_ROLLOFF_FACTOR:
  1428. *values = Source->RolloffFactor;
  1429. return AL_TRUE;
  1430. case AL_REFERENCE_DISTANCE:
  1431. *values = Source->RefDistance;
  1432. return AL_TRUE;
  1433. case AL_CONE_INNER_ANGLE:
  1434. *values = Source->InnerAngle;
  1435. return AL_TRUE;
  1436. case AL_CONE_OUTER_ANGLE:
  1437. *values = Source->OuterAngle;
  1438. return AL_TRUE;
  1439. case AL_MIN_GAIN:
  1440. *values = Source->MinGain;
  1441. return AL_TRUE;
  1442. case AL_MAX_GAIN:
  1443. *values = Source->MaxGain;
  1444. return AL_TRUE;
  1445. case AL_CONE_OUTER_GAIN:
  1446. *values = Source->OuterGain;
  1447. return AL_TRUE;
  1448. case AL_SEC_OFFSET:
  1449. case AL_SAMPLE_OFFSET:
  1450. case AL_BYTE_OFFSET:
  1451. *values = GetSourceOffset(Source, prop, Context);
  1452. return AL_TRUE;
  1453. case AL_CONE_OUTER_GAINHF:
  1454. *values = Source->OuterGainHF;
  1455. return AL_TRUE;
  1456. case AL_AIR_ABSORPTION_FACTOR:
  1457. *values = Source->AirAbsorptionFactor;
  1458. return AL_TRUE;
  1459. case AL_ROOM_ROLLOFF_FACTOR:
  1460. *values = Source->RoomRolloffFactor;
  1461. return AL_TRUE;
  1462. case AL_DOPPLER_FACTOR:
  1463. *values = Source->DopplerFactor;
  1464. return AL_TRUE;
  1465. case AL_SOURCE_RADIUS:
  1466. *values = Source->Radius;
  1467. return AL_TRUE;
  1468. case AL_STEREO_ANGLES:
  1469. values[0] = Source->StereoPan[0];
  1470. values[1] = Source->StereoPan[1];
  1471. return AL_TRUE;
  1472. case AL_SEC_OFFSET_LATENCY_SOFT:
  1473. /* Get the source offset with the clock time first. Then get the
  1474. * clock time with the device latency. Order is important.
  1475. */
  1476. values[0] = GetSourceSecOffset(Source, Context, &srcclock);
  1477. { std::lock_guard<std::mutex> _{device->StateLock};
  1478. clocktime = GetClockLatency(device);
  1479. }
  1480. if(srcclock == clocktime.ClockTime)
  1481. values[1] = static_cast<ALdouble>(clocktime.Latency.count()) / 1000000000.0;
  1482. else
  1483. {
  1484. /* If the clock time incremented, reduce the latency by that
  1485. * much since it's that much closer to the source offset it got
  1486. * earlier.
  1487. */
  1488. std::chrono::nanoseconds diff = clocktime.ClockTime - srcclock;
  1489. values[1] = static_cast<ALdouble>((clocktime.Latency - std::min(clocktime.Latency, diff)).count()) /
  1490. 1000000000.0;
  1491. }
  1492. return AL_TRUE;
  1493. case AL_SEC_OFFSET_CLOCK_SOFT:
  1494. values[0] = GetSourceSecOffset(Source, Context, &srcclock);
  1495. values[1] = srcclock.count() / 1000000000.0;
  1496. return AL_TRUE;
  1497. case AL_POSITION:
  1498. values[0] = Source->Position[0];
  1499. values[1] = Source->Position[1];
  1500. values[2] = Source->Position[2];
  1501. return AL_TRUE;
  1502. case AL_VELOCITY:
  1503. values[0] = Source->Velocity[0];
  1504. values[1] = Source->Velocity[1];
  1505. values[2] = Source->Velocity[2];
  1506. return AL_TRUE;
  1507. case AL_DIRECTION:
  1508. values[0] = Source->Direction[0];
  1509. values[1] = Source->Direction[1];
  1510. values[2] = Source->Direction[2];
  1511. return AL_TRUE;
  1512. case AL_ORIENTATION:
  1513. values[0] = Source->OrientAt[0];
  1514. values[1] = Source->OrientAt[1];
  1515. values[2] = Source->OrientAt[2];
  1516. values[3] = Source->OrientUp[0];
  1517. values[4] = Source->OrientUp[1];
  1518. values[5] = Source->OrientUp[2];
  1519. return AL_TRUE;
  1520. /* 1x int */
  1521. case AL_SOURCE_RELATIVE:
  1522. case AL_LOOPING:
  1523. case AL_SOURCE_STATE:
  1524. case AL_BUFFERS_QUEUED:
  1525. case AL_BUFFERS_PROCESSED:
  1526. case AL_SOURCE_TYPE:
  1527. case AL_DIRECT_FILTER_GAINHF_AUTO:
  1528. case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
  1529. case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
  1530. case AL_DIRECT_CHANNELS_SOFT:
  1531. case AL_DISTANCE_MODEL:
  1532. case AL_SOURCE_RESAMPLER_SOFT:
  1533. case AL_SOURCE_SPATIALIZE_SOFT:
  1534. if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
  1535. *values = static_cast<ALdouble>(ivals[0]);
  1536. return err;
  1537. case AL_BUFFER:
  1538. case AL_DIRECT_FILTER:
  1539. case AL_AUXILIARY_SEND_FILTER:
  1540. case AL_SAMPLE_OFFSET_LATENCY_SOFT:
  1541. case AL_SAMPLE_OFFSET_CLOCK_SOFT:
  1542. break;
  1543. }
  1544. ERR("Unexpected property: 0x%04x\n", prop);
  1545. SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source double property 0x%04x",
  1546. prop);
  1547. }
  1548. ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
  1549. {
  1550. ALbufferlistitem *BufferList;
  1551. ALdouble dvals[6];
  1552. ALboolean err;
  1553. switch(prop)
  1554. {
  1555. case AL_SOURCE_RELATIVE:
  1556. *values = Source->HeadRelative;
  1557. return AL_TRUE;
  1558. case AL_LOOPING:
  1559. *values = Source->Looping;
  1560. return AL_TRUE;
  1561. case AL_BUFFER:
  1562. BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : nullptr;
  1563. *values = (BufferList && BufferList->num_buffers >= 1 && BufferList->buffers[0]) ?
  1564. BufferList->buffers[0]->id : 0;
  1565. return AL_TRUE;
  1566. case AL_SOURCE_STATE:
  1567. *values = GetSourceState(Source, GetSourceVoice(Source, Context));
  1568. return AL_TRUE;
  1569. case AL_BUFFERS_QUEUED:
  1570. if(!(BufferList=Source->queue))
  1571. *values = 0;
  1572. else
  1573. {
  1574. ALsizei count = 0;
  1575. do {
  1576. count += BufferList->num_buffers;
  1577. BufferList = BufferList->next.load(std::memory_order_relaxed);
  1578. } while(BufferList != nullptr);
  1579. *values = count;
  1580. }
  1581. return AL_TRUE;
  1582. case AL_BUFFERS_PROCESSED:
  1583. if(Source->Looping || Source->SourceType != AL_STREAMING)
  1584. {
  1585. /* Buffers on a looping source are in a perpetual state of
  1586. * PENDING, so don't report any as PROCESSED */
  1587. *values = 0;
  1588. }
  1589. else
  1590. {
  1591. const ALbufferlistitem *BufferList{Source->queue};
  1592. const ALbufferlistitem *Current{nullptr};
  1593. ALsizei played{0};
  1594. ALvoice *voice{GetSourceVoice(Source, Context)};
  1595. if(voice != nullptr)
  1596. Current = voice->mCurrentBuffer.load(std::memory_order_relaxed);
  1597. else if(Source->state == AL_INITIAL)
  1598. Current = BufferList;
  1599. while(BufferList && BufferList != Current)
  1600. {
  1601. played += BufferList->num_buffers;
  1602. BufferList = BufferList->next.load(std::memory_order_relaxed);
  1603. }
  1604. *values = played;
  1605. }
  1606. return AL_TRUE;
  1607. case AL_SOURCE_TYPE:
  1608. *values = Source->SourceType;
  1609. return AL_TRUE;
  1610. case AL_DIRECT_FILTER_GAINHF_AUTO:
  1611. *values = Source->DryGainHFAuto;
  1612. return AL_TRUE;
  1613. case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
  1614. *values = Source->WetGainAuto;
  1615. return AL_TRUE;
  1616. case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
  1617. *values = Source->WetGainHFAuto;
  1618. return AL_TRUE;
  1619. case AL_DIRECT_CHANNELS_SOFT:
  1620. *values = Source->DirectChannels;
  1621. return AL_TRUE;
  1622. case AL_DISTANCE_MODEL:
  1623. *values = static_cast<int>(Source->mDistanceModel);
  1624. return AL_TRUE;
  1625. case AL_SOURCE_RESAMPLER_SOFT:
  1626. *values = Source->mResampler;
  1627. return AL_TRUE;
  1628. case AL_SOURCE_SPATIALIZE_SOFT:
  1629. *values = Source->mSpatialize;
  1630. return AL_TRUE;
  1631. /* 1x float/double */
  1632. case AL_CONE_INNER_ANGLE:
  1633. case AL_CONE_OUTER_ANGLE:
  1634. case AL_PITCH:
  1635. case AL_GAIN:
  1636. case AL_MIN_GAIN:
  1637. case AL_MAX_GAIN:
  1638. case AL_REFERENCE_DISTANCE:
  1639. case AL_ROLLOFF_FACTOR:
  1640. case AL_CONE_OUTER_GAIN:
  1641. case AL_MAX_DISTANCE:
  1642. case AL_SEC_OFFSET:
  1643. case AL_SAMPLE_OFFSET:
  1644. case AL_BYTE_OFFSET:
  1645. case AL_DOPPLER_FACTOR:
  1646. case AL_AIR_ABSORPTION_FACTOR:
  1647. case AL_ROOM_ROLLOFF_FACTOR:
  1648. case AL_CONE_OUTER_GAINHF:
  1649. case AL_SOURCE_RADIUS:
  1650. if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
  1651. *values = static_cast<ALint>(dvals[0]);
  1652. return err;
  1653. /* 3x float/double */
  1654. case AL_POSITION:
  1655. case AL_VELOCITY:
  1656. case AL_DIRECTION:
  1657. if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
  1658. {
  1659. values[0] = static_cast<ALint>(dvals[0]);
  1660. values[1] = static_cast<ALint>(dvals[1]);
  1661. values[2] = static_cast<ALint>(dvals[2]);
  1662. }
  1663. return err;
  1664. /* 6x float/double */
  1665. case AL_ORIENTATION:
  1666. if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
  1667. {
  1668. values[0] = static_cast<ALint>(dvals[0]);
  1669. values[1] = static_cast<ALint>(dvals[1]);
  1670. values[2] = static_cast<ALint>(dvals[2]);
  1671. values[3] = static_cast<ALint>(dvals[3]);
  1672. values[4] = static_cast<ALint>(dvals[4]);
  1673. values[5] = static_cast<ALint>(dvals[5]);
  1674. }
  1675. return err;
  1676. case AL_SAMPLE_OFFSET_LATENCY_SOFT:
  1677. case AL_SAMPLE_OFFSET_CLOCK_SOFT:
  1678. break; /* i64 only */
  1679. case AL_SEC_OFFSET_LATENCY_SOFT:
  1680. case AL_SEC_OFFSET_CLOCK_SOFT:
  1681. break; /* Double only */
  1682. case AL_STEREO_ANGLES:
  1683. break; /* Float/double only */
  1684. case AL_DIRECT_FILTER:
  1685. case AL_AUXILIARY_SEND_FILTER:
  1686. break; /* ??? */
  1687. }
  1688. ERR("Unexpected property: 0x%04x\n", prop);
  1689. SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x",
  1690. prop);
  1691. }
  1692. ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64SOFT *values)
  1693. {
  1694. ALCdevice *device = Context->Device;
  1695. ClockLatency clocktime;
  1696. std::chrono::nanoseconds srcclock;
  1697. ALdouble dvals[6];
  1698. ALint ivals[3];
  1699. ALboolean err;
  1700. switch(prop)
  1701. {
  1702. case AL_SAMPLE_OFFSET_LATENCY_SOFT:
  1703. /* Get the source offset with the clock time first. Then get the
  1704. * clock time with the device latency. Order is important.
  1705. */
  1706. values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
  1707. { std::lock_guard<std::mutex> _{device->StateLock};
  1708. clocktime = GetClockLatency(device);
  1709. }
  1710. if(srcclock == clocktime.ClockTime)
  1711. values[1] = clocktime.Latency.count();
  1712. else
  1713. {
  1714. /* If the clock time incremented, reduce the latency by that
  1715. * much since it's that much closer to the source offset it got
  1716. * earlier.
  1717. */
  1718. auto diff = clocktime.ClockTime - srcclock;
  1719. values[1] = (clocktime.Latency - std::min(clocktime.Latency, diff)).count();
  1720. }
  1721. return AL_TRUE;
  1722. case AL_SAMPLE_OFFSET_CLOCK_SOFT:
  1723. values[0] = GetSourceSampleOffset(Source, Context, &srcclock);
  1724. values[1] = srcclock.count();
  1725. return AL_TRUE;
  1726. /* 1x float/double */
  1727. case AL_CONE_INNER_ANGLE:
  1728. case AL_CONE_OUTER_ANGLE:
  1729. case AL_PITCH:
  1730. case AL_GAIN:
  1731. case AL_MIN_GAIN:
  1732. case AL_MAX_GAIN:
  1733. case AL_REFERENCE_DISTANCE:
  1734. case AL_ROLLOFF_FACTOR:
  1735. case AL_CONE_OUTER_GAIN:
  1736. case AL_MAX_DISTANCE:
  1737. case AL_SEC_OFFSET:
  1738. case AL_SAMPLE_OFFSET:
  1739. case AL_BYTE_OFFSET:
  1740. case AL_DOPPLER_FACTOR:
  1741. case AL_AIR_ABSORPTION_FACTOR:
  1742. case AL_ROOM_ROLLOFF_FACTOR:
  1743. case AL_CONE_OUTER_GAINHF:
  1744. case AL_SOURCE_RADIUS:
  1745. if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
  1746. *values = static_cast<int64_t>(dvals[0]);
  1747. return err;
  1748. /* 3x float/double */
  1749. case AL_POSITION:
  1750. case AL_VELOCITY:
  1751. case AL_DIRECTION:
  1752. if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
  1753. {
  1754. values[0] = static_cast<int64_t>(dvals[0]);
  1755. values[1] = static_cast<int64_t>(dvals[1]);
  1756. values[2] = static_cast<int64_t>(dvals[2]);
  1757. }
  1758. return err;
  1759. /* 6x float/double */
  1760. case AL_ORIENTATION:
  1761. if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
  1762. {
  1763. values[0] = static_cast<int64_t>(dvals[0]);
  1764. values[1] = static_cast<int64_t>(dvals[1]);
  1765. values[2] = static_cast<int64_t>(dvals[2]);
  1766. values[3] = static_cast<int64_t>(dvals[3]);
  1767. values[4] = static_cast<int64_t>(dvals[4]);
  1768. values[5] = static_cast<int64_t>(dvals[5]);
  1769. }
  1770. return err;
  1771. /* 1x int */
  1772. case AL_SOURCE_RELATIVE:
  1773. case AL_LOOPING:
  1774. case AL_SOURCE_STATE:
  1775. case AL_BUFFERS_QUEUED:
  1776. case AL_BUFFERS_PROCESSED:
  1777. case AL_SOURCE_TYPE:
  1778. case AL_DIRECT_FILTER_GAINHF_AUTO:
  1779. case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
  1780. case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
  1781. case AL_DIRECT_CHANNELS_SOFT:
  1782. case AL_DISTANCE_MODEL:
  1783. case AL_SOURCE_RESAMPLER_SOFT:
  1784. case AL_SOURCE_SPATIALIZE_SOFT:
  1785. if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
  1786. *values = ivals[0];
  1787. return err;
  1788. /* 1x uint */
  1789. case AL_BUFFER:
  1790. case AL_DIRECT_FILTER:
  1791. if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
  1792. *values = static_cast<ALuint>(ivals[0]);
  1793. return err;
  1794. /* 3x uint */
  1795. case AL_AUXILIARY_SEND_FILTER:
  1796. if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
  1797. {
  1798. values[0] = static_cast<ALuint>(ivals[0]);
  1799. values[1] = static_cast<ALuint>(ivals[1]);
  1800. values[2] = static_cast<ALuint>(ivals[2]);
  1801. }
  1802. return err;
  1803. case AL_SEC_OFFSET_LATENCY_SOFT:
  1804. case AL_SEC_OFFSET_CLOCK_SOFT:
  1805. break; /* Double only */
  1806. case AL_STEREO_ANGLES:
  1807. break; /* Float/double only */
  1808. }
  1809. ERR("Unexpected property: 0x%04x\n", prop);
  1810. SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x",
  1811. prop);
  1812. }
  1813. } // namespace
  1814. AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
  1815. START_API_FUNC
  1816. {
  1817. ContextRef context{GetContextRef()};
  1818. if(UNLIKELY(!context)) return;
  1819. if(n < 0)
  1820. alSetError(context.get(), AL_INVALID_VALUE, "Generating %d sources", n);
  1821. else if(n == 1)
  1822. {
  1823. ALsource *source = AllocSource(context.get());
  1824. if(source) sources[0] = source->id;
  1825. }
  1826. else
  1827. {
  1828. al::vector<ALuint> tempids(n);
  1829. auto alloc_end = std::find_if_not(tempids.begin(), tempids.end(),
  1830. [&context](ALuint &id) -> bool
  1831. {
  1832. ALsource *source{AllocSource(context.get())};
  1833. if(!source) return false;
  1834. id = source->id;
  1835. return true;
  1836. }
  1837. );
  1838. if(alloc_end != tempids.end())
  1839. alDeleteSources(static_cast<ALsizei>(std::distance(tempids.begin(), alloc_end)),
  1840. tempids.data());
  1841. else
  1842. std::copy(tempids.cbegin(), tempids.cend(), sources);
  1843. }
  1844. }
  1845. END_API_FUNC
  1846. AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
  1847. START_API_FUNC
  1848. {
  1849. ContextRef context{GetContextRef()};
  1850. if(UNLIKELY(!context)) return;
  1851. if(n < 0)
  1852. SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d sources", n);
  1853. std::lock_guard<std::mutex> _{context->SourceLock};
  1854. /* Check that all Sources are valid */
  1855. const ALuint *sources_end = sources + n;
  1856. auto invsrc = std::find_if_not(sources, sources_end,
  1857. [&context](ALuint sid) -> bool
  1858. {
  1859. if(!LookupSource(context.get(), sid))
  1860. {
  1861. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", sid);
  1862. return false;
  1863. }
  1864. return true;
  1865. }
  1866. );
  1867. if(LIKELY(invsrc == sources_end))
  1868. {
  1869. /* All good. Delete source IDs. */
  1870. std::for_each(sources, sources_end,
  1871. [&context](ALuint sid) -> void
  1872. {
  1873. ALsource *src{LookupSource(context.get(), sid)};
  1874. if(src) FreeSource(context.get(), src);
  1875. }
  1876. );
  1877. }
  1878. }
  1879. END_API_FUNC
  1880. AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
  1881. START_API_FUNC
  1882. {
  1883. ContextRef context{GetContextRef()};
  1884. if(LIKELY(context))
  1885. {
  1886. std::lock_guard<std::mutex> _{context->SourceLock};
  1887. if(LookupSource(context.get(), source) != nullptr)
  1888. return AL_TRUE;
  1889. }
  1890. return AL_FALSE;
  1891. }
  1892. END_API_FUNC
  1893. AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value)
  1894. START_API_FUNC
  1895. {
  1896. ContextRef context{GetContextRef()};
  1897. if(UNLIKELY(!context)) return;
  1898. std::lock_guard<std::mutex> _{context->PropLock};
  1899. std::lock_guard<std::mutex> __{context->SourceLock};
  1900. ALsource *Source = LookupSource(context.get(), source);
  1901. if(UNLIKELY(!Source))
  1902. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  1903. else if(FloatValsByProp(param) != 1)
  1904. alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param);
  1905. else
  1906. SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), &value);
  1907. }
  1908. END_API_FUNC
  1909. AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
  1910. START_API_FUNC
  1911. {
  1912. ContextRef context{GetContextRef()};
  1913. if(UNLIKELY(!context)) return;
  1914. std::lock_guard<std::mutex> _{context->PropLock};
  1915. std::lock_guard<std::mutex> __{context->SourceLock};
  1916. ALsource *Source = LookupSource(context.get(), source);
  1917. if(UNLIKELY(!Source))
  1918. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  1919. else if(FloatValsByProp(param) != 3)
  1920. alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param);
  1921. else
  1922. {
  1923. ALfloat fvals[3] = { value1, value2, value3 };
  1924. SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), fvals);
  1925. }
  1926. }
  1927. END_API_FUNC
  1928. AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values)
  1929. START_API_FUNC
  1930. {
  1931. ContextRef context{GetContextRef()};
  1932. if(UNLIKELY(!context)) return;
  1933. std::lock_guard<std::mutex> _{context->PropLock};
  1934. std::lock_guard<std::mutex> __{context->SourceLock};
  1935. ALsource *Source = LookupSource(context.get(), source);
  1936. if(UNLIKELY(!Source))
  1937. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  1938. else if(!values)
  1939. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  1940. else if(FloatValsByProp(param) < 1)
  1941. alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param);
  1942. else
  1943. SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), values);
  1944. }
  1945. END_API_FUNC
  1946. AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value)
  1947. START_API_FUNC
  1948. {
  1949. ContextRef context{GetContextRef()};
  1950. if(UNLIKELY(!context)) return;
  1951. std::lock_guard<std::mutex> _{context->PropLock};
  1952. std::lock_guard<std::mutex> __{context->SourceLock};
  1953. ALsource *Source = LookupSource(context.get(), source);
  1954. if(UNLIKELY(!Source))
  1955. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  1956. else if(DoubleValsByProp(param) != 1)
  1957. alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param);
  1958. else
  1959. {
  1960. ALfloat fval = static_cast<ALfloat>(value);
  1961. SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), &fval);
  1962. }
  1963. }
  1964. END_API_FUNC
  1965. AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3)
  1966. START_API_FUNC
  1967. {
  1968. ContextRef context{GetContextRef()};
  1969. if(UNLIKELY(!context)) return;
  1970. std::lock_guard<std::mutex> _{context->PropLock};
  1971. std::lock_guard<std::mutex> __{context->SourceLock};
  1972. ALsource *Source = LookupSource(context.get(), source);
  1973. if(UNLIKELY(!Source))
  1974. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  1975. else if(DoubleValsByProp(param) != 3)
  1976. alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param);
  1977. else {
  1978. ALfloat fvals[3] = {static_cast<ALfloat>(value1),
  1979. static_cast<ALfloat>(value2),
  1980. static_cast<ALfloat>(value3)};
  1981. SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), fvals);
  1982. }
  1983. }
  1984. END_API_FUNC
  1985. AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values)
  1986. START_API_FUNC
  1987. {
  1988. ContextRef context{GetContextRef()};
  1989. if(UNLIKELY(!context)) return;
  1990. std::lock_guard<std::mutex> _{context->PropLock};
  1991. std::lock_guard<std::mutex> __{context->SourceLock};
  1992. ALsource *Source = LookupSource(context.get(), source);
  1993. if(UNLIKELY(!Source))
  1994. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  1995. else if(!values)
  1996. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  1997. else
  1998. {
  1999. ALint count{DoubleValsByProp(param)};
  2000. if(count < 1 || count > 6)
  2001. alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param);
  2002. else
  2003. {
  2004. ALfloat fvals[6];
  2005. ALint i;
  2006. for(i = 0;i < count;i++)
  2007. fvals[i] = static_cast<ALfloat>(values[i]);
  2008. SetSourcefv(Source, context.get(), static_cast<SourceProp>(param), fvals);
  2009. }
  2010. }
  2011. }
  2012. END_API_FUNC
  2013. AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
  2014. START_API_FUNC
  2015. {
  2016. ContextRef context{GetContextRef()};
  2017. if(UNLIKELY(!context)) return;
  2018. std::lock_guard<std::mutex> _{context->PropLock};
  2019. std::lock_guard<std::mutex> __{context->SourceLock};
  2020. ALsource *Source = LookupSource(context.get(), source);
  2021. if(UNLIKELY(!Source))
  2022. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2023. else if(IntValsByProp(param) != 1)
  2024. alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param);
  2025. else
  2026. SetSourceiv(Source, context.get(), static_cast<SourceProp>(param), &value);
  2027. }
  2028. END_API_FUNC
  2029. AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
  2030. START_API_FUNC
  2031. {
  2032. ContextRef context{GetContextRef()};
  2033. if(UNLIKELY(!context)) return;
  2034. std::lock_guard<std::mutex> _{context->PropLock};
  2035. std::lock_guard<std::mutex> __{context->SourceLock};
  2036. ALsource *Source = LookupSource(context.get(), source);
  2037. if(UNLIKELY(!Source))
  2038. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2039. else if(IntValsByProp(param) != 3)
  2040. alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param);
  2041. else
  2042. {
  2043. ALint ivals[3] = { value1, value2, value3 };
  2044. SetSourceiv(Source, context.get(), static_cast<SourceProp>(param), ivals);
  2045. }
  2046. }
  2047. END_API_FUNC
  2048. AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values)
  2049. START_API_FUNC
  2050. {
  2051. ContextRef context{GetContextRef()};
  2052. if(UNLIKELY(!context)) return;
  2053. std::lock_guard<std::mutex> _{context->PropLock};
  2054. std::lock_guard<std::mutex> __{context->SourceLock};
  2055. ALsource *Source = LookupSource(context.get(), source);
  2056. if(UNLIKELY(!Source))
  2057. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2058. else if(!values)
  2059. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  2060. else if(IntValsByProp(param) < 1)
  2061. alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param);
  2062. else
  2063. SetSourceiv(Source, context.get(), static_cast<SourceProp>(param), values);
  2064. }
  2065. END_API_FUNC
  2066. AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value)
  2067. START_API_FUNC
  2068. {
  2069. ContextRef context{GetContextRef()};
  2070. if(UNLIKELY(!context)) return;
  2071. std::lock_guard<std::mutex> _{context->PropLock};
  2072. std::lock_guard<std::mutex> __{context->SourceLock};
  2073. ALsource *Source{LookupSource(context.get(), source)};
  2074. if(UNLIKELY(!Source))
  2075. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2076. else if(Int64ValsByProp(param) != 1)
  2077. alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param);
  2078. else
  2079. SetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), &value);
  2080. }
  2081. END_API_FUNC
  2082. AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3)
  2083. START_API_FUNC
  2084. {
  2085. ContextRef context{GetContextRef()};
  2086. if(UNLIKELY(!context)) return;
  2087. std::lock_guard<std::mutex> _{context->PropLock};
  2088. std::lock_guard<std::mutex> __{context->SourceLock};
  2089. ALsource *Source{LookupSource(context.get(), source)};
  2090. if(UNLIKELY(!Source))
  2091. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2092. else if(Int64ValsByProp(param) != 3)
  2093. alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param);
  2094. else
  2095. {
  2096. ALint64SOFT i64vals[3] = { value1, value2, value3 };
  2097. SetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), i64vals);
  2098. }
  2099. }
  2100. END_API_FUNC
  2101. AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values)
  2102. START_API_FUNC
  2103. {
  2104. ContextRef context{GetContextRef()};
  2105. if(UNLIKELY(!context)) return;
  2106. std::lock_guard<std::mutex> _{context->PropLock};
  2107. std::lock_guard<std::mutex> __{context->SourceLock};
  2108. ALsource *Source{LookupSource(context.get(), source)};
  2109. if(UNLIKELY(!Source))
  2110. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2111. else if(!values)
  2112. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  2113. else if(Int64ValsByProp(param) < 1)
  2114. alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param);
  2115. else
  2116. SetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), values);
  2117. }
  2118. END_API_FUNC
  2119. AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value)
  2120. START_API_FUNC
  2121. {
  2122. ContextRef context{GetContextRef()};
  2123. if(UNLIKELY(!context)) return;
  2124. std::lock_guard<std::mutex> _{context->SourceLock};
  2125. ALsource *Source{LookupSource(context.get(), source)};
  2126. if(UNLIKELY(!Source))
  2127. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2128. else if(!value)
  2129. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  2130. else if(FloatValsByProp(param) != 1)
  2131. alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param);
  2132. else
  2133. {
  2134. ALdouble dval;
  2135. if(GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), &dval))
  2136. *value = static_cast<ALfloat>(dval);
  2137. }
  2138. }
  2139. END_API_FUNC
  2140. AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
  2141. START_API_FUNC
  2142. {
  2143. ContextRef context{GetContextRef()};
  2144. if(UNLIKELY(!context)) return;
  2145. std::lock_guard<std::mutex> _{context->SourceLock};
  2146. ALsource *Source{LookupSource(context.get(), source)};
  2147. if(UNLIKELY(!Source))
  2148. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2149. else if(!(value1 && value2 && value3))
  2150. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  2151. else if(FloatValsByProp(param) != 3)
  2152. alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param);
  2153. else
  2154. {
  2155. ALdouble dvals[3];
  2156. if(GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), dvals))
  2157. {
  2158. *value1 = static_cast<ALfloat>(dvals[0]);
  2159. *value2 = static_cast<ALfloat>(dvals[1]);
  2160. *value3 = static_cast<ALfloat>(dvals[2]);
  2161. }
  2162. }
  2163. }
  2164. END_API_FUNC
  2165. AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values)
  2166. START_API_FUNC
  2167. {
  2168. ContextRef context{GetContextRef()};
  2169. if(UNLIKELY(!context)) return;
  2170. std::lock_guard<std::mutex> _{context->SourceLock};
  2171. ALsource *Source{LookupSource(context.get(), source)};
  2172. if(UNLIKELY(!Source))
  2173. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2174. else if(!values)
  2175. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  2176. else
  2177. {
  2178. ALint count{FloatValsByProp(param)};
  2179. if(count < 1 && count > 6)
  2180. alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param);
  2181. else
  2182. {
  2183. ALdouble dvals[6];
  2184. if(GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), dvals))
  2185. {
  2186. for(ALint i{0};i < count;i++)
  2187. values[i] = static_cast<ALfloat>(dvals[i]);
  2188. }
  2189. }
  2190. }
  2191. }
  2192. END_API_FUNC
  2193. AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value)
  2194. START_API_FUNC
  2195. {
  2196. ContextRef context{GetContextRef()};
  2197. if(UNLIKELY(!context)) return;
  2198. std::lock_guard<std::mutex> _{context->SourceLock};
  2199. ALsource *Source{LookupSource(context.get(), source)};
  2200. if(UNLIKELY(!Source))
  2201. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2202. else if(!value)
  2203. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  2204. else if(DoubleValsByProp(param) != 1)
  2205. alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param);
  2206. else
  2207. GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), value);
  2208. }
  2209. END_API_FUNC
  2210. AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3)
  2211. START_API_FUNC
  2212. {
  2213. ContextRef context{GetContextRef()};
  2214. if(UNLIKELY(!context)) return;
  2215. std::lock_guard<std::mutex> _{context->SourceLock};
  2216. ALsource *Source{LookupSource(context.get(), source)};
  2217. if(UNLIKELY(!Source))
  2218. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2219. else if(!(value1 && value2 && value3))
  2220. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  2221. else if(DoubleValsByProp(param) != 3)
  2222. alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param);
  2223. else
  2224. {
  2225. ALdouble dvals[3];
  2226. if(GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), dvals))
  2227. {
  2228. *value1 = dvals[0];
  2229. *value2 = dvals[1];
  2230. *value3 = dvals[2];
  2231. }
  2232. }
  2233. }
  2234. END_API_FUNC
  2235. AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values)
  2236. START_API_FUNC
  2237. {
  2238. ContextRef context{GetContextRef()};
  2239. if(UNLIKELY(!context)) return;
  2240. std::lock_guard<std::mutex> _{context->SourceLock};
  2241. ALsource *Source{LookupSource(context.get(), source)};
  2242. if(UNLIKELY(!Source))
  2243. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2244. else if(!values)
  2245. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  2246. else if(DoubleValsByProp(param) < 1)
  2247. alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param);
  2248. else
  2249. GetSourcedv(Source, context.get(), static_cast<SourceProp>(param), values);
  2250. }
  2251. END_API_FUNC
  2252. AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
  2253. START_API_FUNC
  2254. {
  2255. ContextRef context{GetContextRef()};
  2256. if(UNLIKELY(!context)) return;
  2257. std::lock_guard<std::mutex> _{context->SourceLock};
  2258. ALsource *Source{LookupSource(context.get(), source)};
  2259. if(UNLIKELY(!Source))
  2260. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2261. else if(!value)
  2262. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  2263. else if(IntValsByProp(param) != 1)
  2264. alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param);
  2265. else
  2266. GetSourceiv(Source, context.get(), static_cast<SourceProp>(param), value);
  2267. }
  2268. END_API_FUNC
  2269. AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3)
  2270. START_API_FUNC
  2271. {
  2272. ContextRef context{GetContextRef()};
  2273. if(UNLIKELY(!context)) return;
  2274. std::lock_guard<std::mutex> _{context->SourceLock};
  2275. ALsource *Source{LookupSource(context.get(), source)};
  2276. if(UNLIKELY(!Source))
  2277. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2278. else if(!(value1 && value2 && value3))
  2279. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  2280. else if(IntValsByProp(param) != 3)
  2281. alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param);
  2282. else
  2283. {
  2284. ALint ivals[3];
  2285. if(GetSourceiv(Source, context.get(), static_cast<SourceProp>(param), ivals))
  2286. {
  2287. *value1 = ivals[0];
  2288. *value2 = ivals[1];
  2289. *value3 = ivals[2];
  2290. }
  2291. }
  2292. }
  2293. END_API_FUNC
  2294. AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values)
  2295. START_API_FUNC
  2296. {
  2297. ContextRef context{GetContextRef()};
  2298. if(UNLIKELY(!context)) return;
  2299. std::lock_guard<std::mutex> _{context->SourceLock};
  2300. ALsource *Source{LookupSource(context.get(), source)};
  2301. if(UNLIKELY(!Source))
  2302. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2303. else if(!values)
  2304. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  2305. else if(IntValsByProp(param) < 1)
  2306. alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param);
  2307. else
  2308. GetSourceiv(Source, context.get(), static_cast<SourceProp>(param), values);
  2309. }
  2310. END_API_FUNC
  2311. AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value)
  2312. START_API_FUNC
  2313. {
  2314. ContextRef context{GetContextRef()};
  2315. if(UNLIKELY(!context)) return;
  2316. std::lock_guard<std::mutex> _{context->SourceLock};
  2317. ALsource *Source{LookupSource(context.get(), source)};
  2318. if(UNLIKELY(!Source))
  2319. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2320. else if(!value)
  2321. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  2322. else if(Int64ValsByProp(param) != 1)
  2323. alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param);
  2324. else
  2325. GetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), value);
  2326. }
  2327. END_API_FUNC
  2328. AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3)
  2329. START_API_FUNC
  2330. {
  2331. ContextRef context{GetContextRef()};
  2332. if(UNLIKELY(!context)) return;
  2333. std::lock_guard<std::mutex> _{context->SourceLock};
  2334. ALsource *Source{LookupSource(context.get(), source)};
  2335. if(UNLIKELY(!Source))
  2336. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2337. else if(!(value1 && value2 && value3))
  2338. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  2339. else if(Int64ValsByProp(param) != 3)
  2340. alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param);
  2341. else
  2342. {
  2343. ALint64SOFT i64vals[3];
  2344. if(GetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), i64vals))
  2345. {
  2346. *value1 = i64vals[0];
  2347. *value2 = i64vals[1];
  2348. *value3 = i64vals[2];
  2349. }
  2350. }
  2351. }
  2352. END_API_FUNC
  2353. AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values)
  2354. START_API_FUNC
  2355. {
  2356. ContextRef context{GetContextRef()};
  2357. if(UNLIKELY(!context)) return;
  2358. std::lock_guard<std::mutex> _{context->SourceLock};
  2359. ALsource *Source{LookupSource(context.get(), source)};
  2360. if(UNLIKELY(!Source))
  2361. alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source);
  2362. else if(!values)
  2363. alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer");
  2364. else if(Int64ValsByProp(param) < 1)
  2365. alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param);
  2366. else
  2367. GetSourcei64v(Source, context.get(), static_cast<SourceProp>(param), values);
  2368. }
  2369. END_API_FUNC
  2370. AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
  2371. START_API_FUNC
  2372. { alSourcePlayv(1, &source); }
  2373. END_API_FUNC
  2374. AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
  2375. START_API_FUNC
  2376. {
  2377. ContextRef context{GetContextRef()};
  2378. if(UNLIKELY(!context)) return;
  2379. if(n < 0)
  2380. SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Playing %d sources", n);
  2381. if(n == 0) return;
  2382. std::lock_guard<std::mutex> _{context->SourceLock};
  2383. auto sources_end = sources+n;
  2384. auto bad_sid = std::find_if_not(sources, sources_end,
  2385. [&context](ALuint sid) -> bool
  2386. {
  2387. ALsource *source{LookupSource(context.get(), sid)};
  2388. return LIKELY(source != nullptr);
  2389. }
  2390. );
  2391. if(UNLIKELY(bad_sid != sources+n))
  2392. SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", *bad_sid);
  2393. ALCdevice *device{context->Device};
  2394. BackendLockGuard __{*device->Backend};
  2395. /* If the device is disconnected, go right to stopped. */
  2396. if(UNLIKELY(!device->Connected.load(std::memory_order_acquire)))
  2397. {
  2398. /* TODO: Send state change event? */
  2399. std::for_each(sources, sources_end,
  2400. [&context](ALuint sid) -> void
  2401. {
  2402. ALsource *source{LookupSource(context.get(), sid)};
  2403. source->OffsetType = AL_NONE;
  2404. source->Offset = 0.0;
  2405. source->state = AL_STOPPED;
  2406. }
  2407. );
  2408. return;
  2409. }
  2410. /* Count the number of reusable voices. */
  2411. auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed);
  2412. auto free_voices = std::accumulate(context->Voices, voices_end, ALsizei{0},
  2413. [](const ALsizei count, const ALvoice *voice) noexcept -> ALsizei
  2414. {
  2415. if(voice->mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped &&
  2416. voice->mSourceID.load(std::memory_order_relaxed) == 0u)
  2417. return count + 1;
  2418. return count;
  2419. }
  2420. );
  2421. if(UNLIKELY(n > free_voices))
  2422. {
  2423. /* Increment the number of voices to handle the request. */
  2424. const ALsizei need_voices{n - free_voices};
  2425. const ALsizei rem_voices{context->MaxVoices -
  2426. context->VoiceCount.load(std::memory_order_relaxed)};
  2427. if(UNLIKELY(need_voices > rem_voices))
  2428. {
  2429. /* Allocate more voices to get enough. */
  2430. const ALsizei alloc_count{need_voices - rem_voices};
  2431. if(UNLIKELY(context->MaxVoices > std::numeric_limits<ALsizei>::max()-alloc_count))
  2432. SETERR_RETURN(context.get(), AL_OUT_OF_MEMORY,,
  2433. "Overflow increasing voice count to %d + %d", context->MaxVoices, alloc_count);
  2434. const ALsizei newcount{context->MaxVoices + alloc_count};
  2435. AllocateVoices(context.get(), newcount, device->NumAuxSends);
  2436. }
  2437. context->VoiceCount.fetch_add(need_voices, std::memory_order_relaxed);
  2438. }
  2439. auto start_source = [&context,device](ALuint sid) -> void
  2440. {
  2441. ALsource *source{LookupSource(context.get(), sid)};
  2442. /* Check that there is a queue containing at least one valid, non zero
  2443. * length buffer.
  2444. */
  2445. ALbufferlistitem *BufferList{source->queue};
  2446. while(BufferList && BufferList->max_samples == 0)
  2447. BufferList = BufferList->next.load(std::memory_order_relaxed);
  2448. /* If there's nothing to play, go right to stopped. */
  2449. if(UNLIKELY(!BufferList))
  2450. {
  2451. /* NOTE: A source without any playable buffers should not have an
  2452. * ALvoice since it shouldn't be in a playing or paused state. So
  2453. * there's no need to look up its voice and clear the source.
  2454. */
  2455. ALenum oldstate{GetSourceState(source, nullptr)};
  2456. source->OffsetType = AL_NONE;
  2457. source->Offset = 0.0;
  2458. if(oldstate != AL_STOPPED)
  2459. {
  2460. source->state = AL_STOPPED;
  2461. SendStateChangeEvent(context.get(), source->id, AL_STOPPED);
  2462. }
  2463. return;
  2464. }
  2465. ALvoice *voice{GetSourceVoice(source, context.get())};
  2466. switch(GetSourceState(source, voice))
  2467. {
  2468. case AL_PLAYING:
  2469. assert(voice != nullptr);
  2470. /* A source that's already playing is restarted from the beginning. */
  2471. voice->mCurrentBuffer.store(BufferList, std::memory_order_relaxed);
  2472. voice->mPosition.store(0u, std::memory_order_relaxed);
  2473. voice->mPositionFrac.store(0, std::memory_order_release);
  2474. return;
  2475. case AL_PAUSED:
  2476. assert(voice != nullptr);
  2477. /* A source that's paused simply resumes. */
  2478. voice->mPlayState.store(ALvoice::Playing, std::memory_order_release);
  2479. source->state = AL_PLAYING;
  2480. SendStateChangeEvent(context.get(), source->id, AL_PLAYING);
  2481. return;
  2482. default:
  2483. assert(voice == nullptr);
  2484. break;
  2485. }
  2486. /* Look for an unused voice to play this source with. */
  2487. auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed);
  2488. auto voice_iter = std::find_if(context->Voices, voices_end,
  2489. [](const ALvoice *voice) noexcept -> bool
  2490. {
  2491. return voice->mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped &&
  2492. voice->mSourceID.load(std::memory_order_relaxed) == 0u;
  2493. }
  2494. );
  2495. assert(voice_iter != voices_end);
  2496. auto vidx = static_cast<ALint>(std::distance(context->Voices, voice_iter));
  2497. voice = *voice_iter;
  2498. voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release);
  2499. source->PropsClean.test_and_set(std::memory_order_acquire);
  2500. UpdateSourceProps(source, voice, context.get());
  2501. /* A source that's not playing or paused has any offset applied when it
  2502. * starts playing.
  2503. */
  2504. if(source->Looping)
  2505. voice->mLoopBuffer.store(source->queue, std::memory_order_relaxed);
  2506. else
  2507. voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed);
  2508. voice->mCurrentBuffer.store(BufferList, std::memory_order_relaxed);
  2509. voice->mPosition.store(0u, std::memory_order_relaxed);
  2510. voice->mPositionFrac.store(0, std::memory_order_relaxed);
  2511. bool start_fading{false};
  2512. if(ApplyOffset(source, voice) != AL_FALSE)
  2513. start_fading = voice->mPosition.load(std::memory_order_relaxed) != 0 ||
  2514. voice->mPositionFrac.load(std::memory_order_relaxed) != 0 ||
  2515. voice->mCurrentBuffer.load(std::memory_order_relaxed) != BufferList;
  2516. auto buffers_end = BufferList->buffers + BufferList->num_buffers;
  2517. auto buffer = std::find_if(BufferList->buffers, buffers_end,
  2518. std::bind(std::not_equal_to<const ALbuffer*>{}, _1, nullptr));
  2519. if(buffer != buffers_end)
  2520. {
  2521. voice->mFrequency = (*buffer)->Frequency;
  2522. voice->mFmtChannels = (*buffer)->mFmtChannels;
  2523. voice->mNumChannels = ChannelsFromFmt((*buffer)->mFmtChannels);
  2524. voice->mSampleSize = BytesFromFmt((*buffer)->mFmtType);
  2525. }
  2526. /* Clear the stepping value so the mixer knows not to mix this until
  2527. * the update gets applied.
  2528. */
  2529. voice->mStep = 0;
  2530. voice->mFlags = start_fading ? VOICE_IS_FADING : 0;
  2531. if(source->SourceType == AL_STATIC) voice->mFlags |= VOICE_IS_STATIC;
  2532. /* Don't need to set the VOICE_IS_AMBISONIC flag if the device is
  2533. * mixing in first order. No HF scaling is necessary to mix it.
  2534. */
  2535. if((voice->mFmtChannels == FmtBFormat2D || voice->mFmtChannels == FmtBFormat3D) &&
  2536. device->mAmbiOrder > 1)
  2537. {
  2538. const int *OrderFromChan;
  2539. if(voice->mFmtChannels == FmtBFormat2D)
  2540. {
  2541. static constexpr int Order2DFromChan[MAX_AMBI2D_CHANNELS]{
  2542. 0, 1,1, 2,2, 3,3
  2543. };
  2544. OrderFromChan = Order2DFromChan;
  2545. }
  2546. else
  2547. {
  2548. static constexpr int Order3DFromChan[MAX_AMBI_CHANNELS]{
  2549. 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3,
  2550. };
  2551. OrderFromChan = Order3DFromChan;
  2552. }
  2553. BandSplitter splitter{400.0f / static_cast<ALfloat>(device->Frequency)};
  2554. const auto scales = BFormatDec::GetHFOrderScales(1, device->mAmbiOrder);
  2555. auto init_ambi = [scales,&OrderFromChan,&splitter](ALvoice::ResampleData &resdata) -> void
  2556. {
  2557. resdata.mPrevSamples.fill(0.0f);
  2558. resdata.mAmbiScale = scales[*(OrderFromChan++)];
  2559. resdata.mAmbiSplitter = splitter;
  2560. };
  2561. std::for_each(voice->mResampleData.begin(),
  2562. voice->mResampleData.begin()+voice->mNumChannels, init_ambi);
  2563. voice->mFlags |= VOICE_IS_AMBISONIC;
  2564. }
  2565. else
  2566. {
  2567. /* Clear previous samples. */
  2568. auto clear_prevs = [](ALvoice::ResampleData &resdata) -> void
  2569. { resdata.mPrevSamples.fill(0.0f); };
  2570. std::for_each(voice->mResampleData.begin(),
  2571. voice->mResampleData.begin()+voice->mNumChannels, clear_prevs);
  2572. }
  2573. std::fill_n(std::begin(voice->mDirect.Params), voice->mNumChannels, DirectParams{});
  2574. std::for_each(voice->mSend.begin(), voice->mSend.end(),
  2575. [voice](ALvoice::SendData &send) -> void
  2576. { std::fill_n(std::begin(send.Params), voice->mNumChannels, SendParams{}); }
  2577. );
  2578. if(device->AvgSpeakerDist > 0.0f)
  2579. {
  2580. const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC /
  2581. (device->AvgSpeakerDist * device->Frequency)};
  2582. std::for_each(voice->mDirect.Params+0, voice->mDirect.Params+voice->mNumChannels,
  2583. [w1](DirectParams &parms) noexcept -> void
  2584. { parms.NFCtrlFilter.init(w1); }
  2585. );
  2586. }
  2587. voice->mSourceID.store(source->id, std::memory_order_relaxed);
  2588. voice->mPlayState.store(ALvoice::Playing, std::memory_order_release);
  2589. source->state = AL_PLAYING;
  2590. source->VoiceIdx = vidx;
  2591. SendStateChangeEvent(context.get(), source->id, AL_PLAYING);
  2592. };
  2593. std::for_each(sources, sources_end, start_source);
  2594. }
  2595. END_API_FUNC
  2596. AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
  2597. START_API_FUNC
  2598. { alSourcePausev(1, &source); }
  2599. END_API_FUNC
  2600. AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
  2601. START_API_FUNC
  2602. {
  2603. ContextRef context{GetContextRef()};
  2604. if(UNLIKELY(!context)) return;
  2605. if(n < 0)
  2606. SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Pausing %d sources", n);
  2607. if(n == 0) return;
  2608. std::lock_guard<std::mutex> _{context->SourceLock};
  2609. for(ALsizei i{0};i < n;i++)
  2610. {
  2611. if(!LookupSource(context.get(), sources[i]))
  2612. SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]);
  2613. }
  2614. ALCdevice *device{context->Device};
  2615. BackendLockGuard __{*device->Backend};
  2616. for(ALsizei i{0};i < n;i++)
  2617. {
  2618. ALsource *source{LookupSource(context.get(), sources[i])};
  2619. ALvoice *voice{GetSourceVoice(source, context.get())};
  2620. if(voice)
  2621. {
  2622. std::atomic_thread_fence(std::memory_order_release);
  2623. ALvoice::State oldvstate{ALvoice::Playing};
  2624. voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping,
  2625. std::memory_order_acq_rel, std::memory_order_acquire);
  2626. }
  2627. if(GetSourceState(source, voice) == AL_PLAYING)
  2628. {
  2629. source->state = AL_PAUSED;
  2630. SendStateChangeEvent(context.get(), source->id, AL_PAUSED);
  2631. }
  2632. }
  2633. }
  2634. END_API_FUNC
  2635. AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
  2636. START_API_FUNC
  2637. { alSourceStopv(1, &source); }
  2638. END_API_FUNC
  2639. AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
  2640. START_API_FUNC
  2641. {
  2642. ContextRef context{GetContextRef()};
  2643. if(UNLIKELY(!context)) return;
  2644. if(n < 0)
  2645. SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Stopping %d sources", n);
  2646. if(n == 0) return;
  2647. std::lock_guard<std::mutex> _{context->SourceLock};
  2648. for(ALsizei i{0};i < n;i++)
  2649. {
  2650. if(!LookupSource(context.get(), sources[i]))
  2651. SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]);
  2652. }
  2653. ALCdevice *device{context->Device};
  2654. BackendLockGuard __{*device->Backend};
  2655. for(ALsizei i{0};i < n;i++)
  2656. {
  2657. ALsource *source{LookupSource(context.get(), sources[i])};
  2658. ALvoice *voice{GetSourceVoice(source, context.get())};
  2659. if(voice != nullptr)
  2660. {
  2661. voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed);
  2662. voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed);
  2663. voice->mSourceID.store(0u, std::memory_order_relaxed);
  2664. std::atomic_thread_fence(std::memory_order_release);
  2665. ALvoice::State oldvstate{ALvoice::Playing};
  2666. voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping,
  2667. std::memory_order_acq_rel, std::memory_order_acquire);
  2668. voice = nullptr;
  2669. }
  2670. ALenum oldstate{GetSourceState(source, voice)};
  2671. if(oldstate != AL_INITIAL && oldstate != AL_STOPPED)
  2672. {
  2673. source->state = AL_STOPPED;
  2674. SendStateChangeEvent(context.get(), source->id, AL_STOPPED);
  2675. }
  2676. source->OffsetType = AL_NONE;
  2677. source->Offset = 0.0;
  2678. }
  2679. }
  2680. END_API_FUNC
  2681. AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
  2682. START_API_FUNC
  2683. { alSourceRewindv(1, &source); }
  2684. END_API_FUNC
  2685. AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
  2686. START_API_FUNC
  2687. {
  2688. ContextRef context{GetContextRef()};
  2689. if(UNLIKELY(!context)) return;
  2690. if(n < 0)
  2691. SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Rewinding %d sources", n);
  2692. if(n == 0) return;
  2693. std::lock_guard<std::mutex> _{context->SourceLock};
  2694. for(ALsizei i{0};i < n;i++)
  2695. {
  2696. if(!LookupSource(context.get(), sources[i]))
  2697. SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]);
  2698. }
  2699. ALCdevice *device{context->Device};
  2700. BackendLockGuard __{*device->Backend};
  2701. for(ALsizei i{0};i < n;i++)
  2702. {
  2703. ALsource *source{LookupSource(context.get(), sources[i])};
  2704. ALvoice *voice{GetSourceVoice(source, context.get())};
  2705. if(voice != nullptr)
  2706. {
  2707. voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed);
  2708. voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed);
  2709. voice->mSourceID.store(0u, std::memory_order_relaxed);
  2710. std::atomic_thread_fence(std::memory_order_release);
  2711. ALvoice::State oldvstate{ALvoice::Playing};
  2712. voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping,
  2713. std::memory_order_acq_rel, std::memory_order_acquire);
  2714. voice = nullptr;
  2715. }
  2716. if(GetSourceState(source, voice) != AL_INITIAL)
  2717. {
  2718. source->state = AL_INITIAL;
  2719. SendStateChangeEvent(context.get(), source->id, AL_INITIAL);
  2720. }
  2721. source->OffsetType = AL_NONE;
  2722. source->Offset = 0.0;
  2723. }
  2724. }
  2725. END_API_FUNC
  2726. AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers)
  2727. START_API_FUNC
  2728. {
  2729. ContextRef context{GetContextRef()};
  2730. if(UNLIKELY(!context)) return;
  2731. if(nb < 0)
  2732. SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffers", nb);
  2733. if(nb == 0) return;
  2734. std::lock_guard<std::mutex> _{context->SourceLock};
  2735. ALsource *source{LookupSource(context.get(),src)};
  2736. if(UNLIKELY(!source))
  2737. SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src);
  2738. /* Can't queue on a Static Source */
  2739. if(UNLIKELY(source->SourceType == AL_STATIC))
  2740. SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src);
  2741. /* Check for a valid Buffer, for its frequency and format */
  2742. ALCdevice *device{context->Device};
  2743. ALbuffer *BufferFmt{nullptr};
  2744. ALbufferlistitem *BufferList{source->queue};
  2745. while(BufferList)
  2746. {
  2747. for(ALsizei i{0};i < BufferList->num_buffers;i++)
  2748. {
  2749. if((BufferFmt=BufferList->buffers[i]) != nullptr)
  2750. break;
  2751. }
  2752. if(BufferFmt) break;
  2753. BufferList = BufferList->next.load(std::memory_order_relaxed);
  2754. }
  2755. std::unique_lock<std::mutex> buflock{device->BufferLock};
  2756. ALbufferlistitem *BufferListStart{nullptr};
  2757. BufferList = nullptr;
  2758. for(ALsizei i{0};i < nb;i++)
  2759. {
  2760. ALbuffer *buffer{nullptr};
  2761. if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr)
  2762. {
  2763. alSetError(context.get(), AL_INVALID_NAME, "Queueing invalid buffer ID %u",
  2764. buffers[i]);
  2765. goto buffer_error;
  2766. }
  2767. if(!BufferListStart)
  2768. {
  2769. BufferListStart = static_cast<ALbufferlistitem*>(al_calloc(DEF_ALIGN,
  2770. ALbufferlistitem::Sizeof(1u)));
  2771. BufferList = BufferListStart;
  2772. }
  2773. else
  2774. {
  2775. auto item = static_cast<ALbufferlistitem*>(al_calloc(DEF_ALIGN,
  2776. ALbufferlistitem::Sizeof(1u)));
  2777. BufferList->next.store(item, std::memory_order_relaxed);
  2778. BufferList = item;
  2779. }
  2780. BufferList->next.store(nullptr, std::memory_order_relaxed);
  2781. BufferList->max_samples = buffer ? buffer->SampleLen : 0;
  2782. BufferList->num_buffers = 1;
  2783. BufferList->buffers[0] = buffer;
  2784. if(!buffer) continue;
  2785. IncrementRef(&buffer->ref);
  2786. if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
  2787. {
  2788. alSetError(context.get(), AL_INVALID_OPERATION,
  2789. "Queueing non-persistently mapped buffer %u", buffer->id);
  2790. goto buffer_error;
  2791. }
  2792. if(BufferFmt == nullptr)
  2793. BufferFmt = buffer;
  2794. else if(BufferFmt->Frequency != buffer->Frequency ||
  2795. BufferFmt->mFmtChannels != buffer->mFmtChannels ||
  2796. BufferFmt->OriginalType != buffer->OriginalType)
  2797. {
  2798. alSetError(context.get(), AL_INVALID_OPERATION,
  2799. "Queueing buffer with mismatched format");
  2800. buffer_error:
  2801. /* A buffer failed (invalid ID or format), so unlock and release
  2802. * each buffer we had. */
  2803. while(BufferListStart)
  2804. {
  2805. ALbufferlistitem *next = BufferListStart->next.load(std::memory_order_relaxed);
  2806. for(i = 0;i < BufferListStart->num_buffers;i++)
  2807. {
  2808. if((buffer=BufferListStart->buffers[i]) != nullptr)
  2809. DecrementRef(&buffer->ref);
  2810. }
  2811. al_free(BufferListStart);
  2812. BufferListStart = next;
  2813. }
  2814. return;
  2815. }
  2816. }
  2817. /* All buffers good. */
  2818. buflock.unlock();
  2819. /* Source is now streaming */
  2820. source->SourceType = AL_STREAMING;
  2821. if(!(BufferList=source->queue))
  2822. source->queue = BufferListStart;
  2823. else
  2824. {
  2825. ALbufferlistitem *next;
  2826. while((next=BufferList->next.load(std::memory_order_relaxed)) != nullptr)
  2827. BufferList = next;
  2828. BufferList->next.store(BufferListStart, std::memory_order_release);
  2829. }
  2830. }
  2831. END_API_FUNC
  2832. AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers)
  2833. START_API_FUNC
  2834. {
  2835. ContextRef context{GetContextRef()};
  2836. if(UNLIKELY(!context)) return;
  2837. if(nb < 0)
  2838. SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffer layers", nb);
  2839. if(nb == 0) return;
  2840. std::lock_guard<std::mutex> _{context->SourceLock};
  2841. ALsource *source{LookupSource(context.get(),src)};
  2842. if(UNLIKELY(!source))
  2843. SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src);
  2844. /* Can't queue on a Static Source */
  2845. if(UNLIKELY(source->SourceType == AL_STATIC))
  2846. SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src);
  2847. /* Check for a valid Buffer, for its frequency and format */
  2848. ALCdevice *device{context->Device};
  2849. ALbuffer *BufferFmt{nullptr};
  2850. ALbufferlistitem *BufferList{source->queue};
  2851. while(BufferList)
  2852. {
  2853. for(ALsizei i{0};i < BufferList->num_buffers;i++)
  2854. {
  2855. if((BufferFmt=BufferList->buffers[i]) != nullptr)
  2856. break;
  2857. }
  2858. if(BufferFmt) break;
  2859. BufferList = BufferList->next.load(std::memory_order_relaxed);
  2860. }
  2861. std::unique_lock<std::mutex> buflock{device->BufferLock};
  2862. auto BufferListStart = static_cast<ALbufferlistitem*>(al_calloc(DEF_ALIGN,
  2863. ALbufferlistitem::Sizeof(nb)));
  2864. BufferList = BufferListStart;
  2865. BufferList->next.store(nullptr, std::memory_order_relaxed);
  2866. BufferList->max_samples = 0;
  2867. BufferList->num_buffers = 0;
  2868. for(ALsizei i{0};i < nb;i++)
  2869. {
  2870. ALbuffer *buffer{nullptr};
  2871. if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr)
  2872. {
  2873. alSetError(context.get(), AL_INVALID_NAME, "Queueing invalid buffer ID %u",
  2874. buffers[i]);
  2875. goto buffer_error;
  2876. }
  2877. BufferList->buffers[BufferList->num_buffers++] = buffer;
  2878. if(!buffer) continue;
  2879. IncrementRef(&buffer->ref);
  2880. BufferList->max_samples = maxi(BufferList->max_samples, buffer->SampleLen);
  2881. if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
  2882. {
  2883. alSetError(context.get(), AL_INVALID_OPERATION,
  2884. "Queueing non-persistently mapped buffer %u", buffer->id);
  2885. goto buffer_error;
  2886. }
  2887. if(BufferFmt == nullptr)
  2888. BufferFmt = buffer;
  2889. else if(BufferFmt->Frequency != buffer->Frequency ||
  2890. BufferFmt->mFmtChannels != buffer->mFmtChannels ||
  2891. BufferFmt->OriginalType != buffer->OriginalType)
  2892. {
  2893. alSetError(context.get(), AL_INVALID_OPERATION,
  2894. "Queueing buffer with mismatched format");
  2895. buffer_error:
  2896. /* A buffer failed (invalid ID or format), so unlock and release
  2897. * each buffer we had. */
  2898. while(BufferListStart)
  2899. {
  2900. ALbufferlistitem *next{BufferListStart->next.load(std::memory_order_relaxed)};
  2901. for(i = 0;i < BufferListStart->num_buffers;i++)
  2902. {
  2903. if((buffer=BufferListStart->buffers[i]) != nullptr)
  2904. DecrementRef(&buffer->ref);
  2905. }
  2906. al_free(BufferListStart);
  2907. BufferListStart = next;
  2908. }
  2909. return;
  2910. }
  2911. }
  2912. /* All buffers good. */
  2913. buflock.unlock();
  2914. /* Source is now streaming */
  2915. source->SourceType = AL_STREAMING;
  2916. if(!(BufferList=source->queue))
  2917. source->queue = BufferListStart;
  2918. else
  2919. {
  2920. ALbufferlistitem *next;
  2921. while((next=BufferList->next.load(std::memory_order_relaxed)) != nullptr)
  2922. BufferList = next;
  2923. BufferList->next.store(BufferListStart, std::memory_order_release);
  2924. }
  2925. }
  2926. END_API_FUNC
  2927. AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers)
  2928. START_API_FUNC
  2929. {
  2930. ContextRef context{GetContextRef()};
  2931. if(UNLIKELY(!context)) return;
  2932. if(nb < 0)
  2933. SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing %d buffers", nb);
  2934. if(nb == 0) return;
  2935. std::lock_guard<std::mutex> _{context->SourceLock};
  2936. ALsource *source{LookupSource(context.get(),src)};
  2937. if(UNLIKELY(!source))
  2938. SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src);
  2939. if(UNLIKELY(source->Looping))
  2940. SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing from looping source %u", src);
  2941. if(UNLIKELY(source->SourceType != AL_STREAMING))
  2942. SETERR_RETURN(context.get(), AL_INVALID_VALUE,,
  2943. "Unqueueing from a non-streaming source %u", src);
  2944. /* Make sure enough buffers have been processed to unqueue. */
  2945. ALbufferlistitem *BufferList{source->queue};
  2946. ALvoice *voice{GetSourceVoice(source, context.get())};
  2947. ALbufferlistitem *Current{nullptr};
  2948. if(voice)
  2949. Current = voice->mCurrentBuffer.load(std::memory_order_relaxed);
  2950. else if(source->state == AL_INITIAL)
  2951. Current = BufferList;
  2952. if(UNLIKELY(BufferList == Current))
  2953. SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers");
  2954. ALsizei i{BufferList->num_buffers};
  2955. while(i < nb)
  2956. {
  2957. /* If the next bufferlist to check is NULL or is the current one, it's
  2958. * trying to unqueue pending buffers.
  2959. */
  2960. ALbufferlistitem *next{BufferList->next.load(std::memory_order_relaxed)};
  2961. if(UNLIKELY(!next) || UNLIKELY(next == Current))
  2962. SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers");
  2963. BufferList = next;
  2964. i += BufferList->num_buffers;
  2965. }
  2966. while(nb > 0)
  2967. {
  2968. ALbufferlistitem *head{source->queue};
  2969. ALbufferlistitem *next{head->next.load(std::memory_order_relaxed)};
  2970. for(i = 0;i < head->num_buffers && nb > 0;i++,nb--)
  2971. {
  2972. ALbuffer *buffer{head->buffers[i]};
  2973. if(!buffer)
  2974. *(buffers++) = 0;
  2975. else
  2976. {
  2977. *(buffers++) = buffer->id;
  2978. DecrementRef(&buffer->ref);
  2979. }
  2980. }
  2981. if(i < head->num_buffers)
  2982. {
  2983. /* This head has some buffers left over, so move them to the front
  2984. * and update the sample and buffer count.
  2985. */
  2986. ALsizei max_length{0};
  2987. ALsizei j{0};
  2988. while(i < head->num_buffers)
  2989. {
  2990. ALbuffer *buffer{head->buffers[i++]};
  2991. if(buffer) max_length = maxi(max_length, buffer->SampleLen);
  2992. head->buffers[j++] = buffer;
  2993. }
  2994. head->max_samples = max_length;
  2995. head->num_buffers = j;
  2996. break;
  2997. }
  2998. /* Otherwise, free this item and set the source queue head to the next
  2999. * one.
  3000. */
  3001. al_free(head);
  3002. source->queue = next;
  3003. }
  3004. }
  3005. END_API_FUNC
  3006. ALsource::ALsource(ALsizei num_sends)
  3007. {
  3008. InnerAngle = 360.0f;
  3009. OuterAngle = 360.0f;
  3010. Pitch = 1.0f;
  3011. Position[0] = 0.0f;
  3012. Position[1] = 0.0f;
  3013. Position[2] = 0.0f;
  3014. Velocity[0] = 0.0f;
  3015. Velocity[1] = 0.0f;
  3016. Velocity[2] = 0.0f;
  3017. Direction[0] = 0.0f;
  3018. Direction[1] = 0.0f;
  3019. Direction[2] = 0.0f;
  3020. OrientAt[0] = 0.0f;
  3021. OrientAt[1] = 0.0f;
  3022. OrientAt[2] = -1.0f;
  3023. OrientUp[0] = 0.0f;
  3024. OrientUp[1] = 1.0f;
  3025. OrientUp[2] = 0.0f;
  3026. RefDistance = 1.0f;
  3027. MaxDistance = std::numeric_limits<float>::max();
  3028. RolloffFactor = 1.0f;
  3029. Gain = 1.0f;
  3030. MinGain = 0.0f;
  3031. MaxGain = 1.0f;
  3032. OuterGain = 0.0f;
  3033. OuterGainHF = 1.0f;
  3034. DryGainHFAuto = AL_TRUE;
  3035. WetGainAuto = AL_TRUE;
  3036. WetGainHFAuto = AL_TRUE;
  3037. AirAbsorptionFactor = 0.0f;
  3038. RoomRolloffFactor = 0.0f;
  3039. DopplerFactor = 1.0f;
  3040. HeadRelative = AL_FALSE;
  3041. Looping = AL_FALSE;
  3042. mDistanceModel = DistanceModel::Default;
  3043. mResampler = ResamplerDefault;
  3044. DirectChannels = AL_FALSE;
  3045. mSpatialize = SpatializeAuto;
  3046. StereoPan[0] = Deg2Rad( 30.0f);
  3047. StereoPan[1] = Deg2Rad(-30.0f);
  3048. Radius = 0.0f;
  3049. Direct.Gain = 1.0f;
  3050. Direct.GainHF = 1.0f;
  3051. Direct.HFReference = LOWPASSFREQREF;
  3052. Direct.GainLF = 1.0f;
  3053. Direct.LFReference = HIGHPASSFREQREF;
  3054. Send.resize(num_sends);
  3055. for(auto &send : Send)
  3056. {
  3057. send.Slot = nullptr;
  3058. send.Gain = 1.0f;
  3059. send.GainHF = 1.0f;
  3060. send.HFReference = LOWPASSFREQREF;
  3061. send.GainLF = 1.0f;
  3062. send.LFReference = HIGHPASSFREQREF;
  3063. }
  3064. Offset = 0.0;
  3065. OffsetType = AL_NONE;
  3066. SourceType = AL_UNDETERMINED;
  3067. state = AL_INITIAL;
  3068. queue = nullptr;
  3069. PropsClean.test_and_set(std::memory_order_relaxed);
  3070. VoiceIdx = -1;
  3071. }
  3072. ALsource::~ALsource()
  3073. {
  3074. ALbufferlistitem *BufferList{queue};
  3075. while(BufferList != nullptr)
  3076. {
  3077. ALbufferlistitem *next{BufferList->next.load(std::memory_order_relaxed)};
  3078. for(ALsizei i{0};i < BufferList->num_buffers;i++)
  3079. {
  3080. if(BufferList->buffers[i])
  3081. DecrementRef(&BufferList->buffers[i]->ref);
  3082. }
  3083. al_free(BufferList);
  3084. BufferList = next;
  3085. }
  3086. queue = nullptr;
  3087. std::for_each(Send.begin(), Send.end(),
  3088. [](ALsource::SendData &send) -> void
  3089. {
  3090. if(send.Slot)
  3091. DecrementRef(&send.Slot->ref);
  3092. send.Slot = nullptr;
  3093. }
  3094. );
  3095. }
  3096. void UpdateAllSourceProps(ALCcontext *context)
  3097. {
  3098. auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed);
  3099. std::for_each(context->Voices, voices_end,
  3100. [context](ALvoice *voice) -> void
  3101. {
  3102. ALuint sid{voice->mSourceID.load(std::memory_order_acquire)};
  3103. ALsource *source = sid ? LookupSource(context, sid) : nullptr;
  3104. if(source && !source->PropsClean.test_and_set(std::memory_order_acq_rel))
  3105. UpdateSourceProps(source, voice, context);
  3106. }
  3107. );
  3108. }
  3109. SourceSubList::~SourceSubList()
  3110. {
  3111. uint64_t usemask{~FreeMask};
  3112. while(usemask)
  3113. {
  3114. ALsizei idx{CTZ64(usemask)};
  3115. Sources[idx].~ALsource();
  3116. usemask &= ~(1_u64 << idx);
  3117. }
  3118. FreeMask = ~usemask;
  3119. al_free(Sources);
  3120. Sources = nullptr;
  3121. }