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

2055 lines
75 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 "alu.h"
  22. #include <algorithm>
  23. #include <array>
  24. #include <atomic>
  25. #include <cassert>
  26. #include <chrono>
  27. #include <climits>
  28. #include <cstdarg>
  29. #include <cstdio>
  30. #include <cstdlib>
  31. #include <functional>
  32. #include <iterator>
  33. #include <limits>
  34. #include <memory>
  35. #include <new>
  36. #include <stdint.h>
  37. #include <utility>
  38. #include "almalloc.h"
  39. #include "alnumbers.h"
  40. #include "alnumeric.h"
  41. #include "alspan.h"
  42. #include "alstring.h"
  43. #include "atomic.h"
  44. #include "core/ambidefs.h"
  45. #include "core/async_event.h"
  46. #include "core/bformatdec.h"
  47. #include "core/bs2b.h"
  48. #include "core/bsinc_defs.h"
  49. #include "core/bsinc_tables.h"
  50. #include "core/bufferline.h"
  51. #include "core/buffer_storage.h"
  52. #include "core/context.h"
  53. #include "core/cpu_caps.h"
  54. #include "core/devformat.h"
  55. #include "core/device.h"
  56. #include "core/effects/base.h"
  57. #include "core/effectslot.h"
  58. #include "core/filters/biquad.h"
  59. #include "core/filters/nfc.h"
  60. #include "core/fpu_ctrl.h"
  61. #include "core/hrtf.h"
  62. #include "core/mastering.h"
  63. #include "core/mixer.h"
  64. #include "core/mixer/defs.h"
  65. #include "core/mixer/hrtfdefs.h"
  66. #include "core/resampler_limits.h"
  67. #include "core/uhjfilter.h"
  68. #include "core/voice.h"
  69. #include "core/voice_change.h"
  70. #include "intrusive_ptr.h"
  71. #include "opthelpers.h"
  72. #include "ringbuffer.h"
  73. #include "strutils.h"
  74. #include "threads.h"
  75. #include "vecmat.h"
  76. #include "vector.h"
  77. struct CTag;
  78. #ifdef HAVE_SSE
  79. struct SSETag;
  80. #endif
  81. #ifdef HAVE_SSE2
  82. struct SSE2Tag;
  83. #endif
  84. #ifdef HAVE_SSE4_1
  85. struct SSE4Tag;
  86. #endif
  87. #ifdef HAVE_NEON
  88. struct NEONTag;
  89. #endif
  90. struct PointTag;
  91. struct LerpTag;
  92. struct CubicTag;
  93. struct BSincTag;
  94. struct FastBSincTag;
  95. static_assert(!(MaxResamplerPadding&1), "MaxResamplerPadding is not a multiple of two");
  96. namespace {
  97. using uint = unsigned int;
  98. constexpr uint MaxPitch{10};
  99. static_assert((BufferLineSize-1)/MaxPitch > 0, "MaxPitch is too large for BufferLineSize!");
  100. static_assert((INT_MAX>>MixerFracBits)/MaxPitch > BufferLineSize,
  101. "MaxPitch and/or BufferLineSize are too large for MixerFracBits!");
  102. using namespace std::placeholders;
  103. float InitConeScale()
  104. {
  105. float ret{1.0f};
  106. if(auto optval = al::getenv("__ALSOFT_HALF_ANGLE_CONES"))
  107. {
  108. if(al::strcasecmp(optval->c_str(), "true") == 0
  109. || strtol(optval->c_str(), nullptr, 0) == 1)
  110. ret *= 0.5f;
  111. }
  112. return ret;
  113. }
  114. /* Cone scalar */
  115. const float ConeScale{InitConeScale()};
  116. /* Localized scalars for mono sources (initialized in aluInit, after
  117. * configuration is loaded).
  118. */
  119. float XScale{1.0f};
  120. float YScale{1.0f};
  121. float ZScale{1.0f};
  122. } // namespace
  123. namespace {
  124. struct ChanMap {
  125. Channel channel;
  126. float angle;
  127. float elevation;
  128. };
  129. using HrtfDirectMixerFunc = void(*)(const FloatBufferSpan LeftOut, const FloatBufferSpan RightOut,
  130. const al::span<const FloatBufferLine> InSamples, float2 *AccumSamples, float *TempBuf,
  131. HrtfChannelState *ChanState, const size_t IrSize, const size_t BufferSize);
  132. HrtfDirectMixerFunc MixDirectHrtf{MixDirectHrtf_<CTag>};
  133. inline HrtfDirectMixerFunc SelectHrtfMixer(void)
  134. {
  135. #ifdef HAVE_NEON
  136. if((CPUCapFlags&CPU_CAP_NEON))
  137. return MixDirectHrtf_<NEONTag>;
  138. #endif
  139. #ifdef HAVE_SSE
  140. if((CPUCapFlags&CPU_CAP_SSE))
  141. return MixDirectHrtf_<SSETag>;
  142. #endif
  143. return MixDirectHrtf_<CTag>;
  144. }
  145. inline void BsincPrepare(const uint increment, BsincState *state, const BSincTable *table)
  146. {
  147. size_t si{BSincScaleCount - 1};
  148. float sf{0.0f};
  149. if(increment > MixerFracOne)
  150. {
  151. sf = MixerFracOne/static_cast<float>(increment) - table->scaleBase;
  152. sf = maxf(0.0f, BSincScaleCount*sf*table->scaleRange - 1.0f);
  153. si = float2uint(sf);
  154. /* The interpolation factor is fit to this diagonally-symmetric curve
  155. * to reduce the transition ripple caused by interpolating different
  156. * scales of the sinc function.
  157. */
  158. sf = 1.0f - std::cos(std::asin(sf - static_cast<float>(si)));
  159. }
  160. state->sf = sf;
  161. state->m = table->m[si];
  162. state->l = (state->m/2) - 1;
  163. state->filter = table->Tab + table->filterOffset[si];
  164. }
  165. inline ResamplerFunc SelectResampler(Resampler resampler, uint increment)
  166. {
  167. switch(resampler)
  168. {
  169. case Resampler::Point:
  170. return Resample_<PointTag,CTag>;
  171. case Resampler::Linear:
  172. #ifdef HAVE_NEON
  173. if((CPUCapFlags&CPU_CAP_NEON))
  174. return Resample_<LerpTag,NEONTag>;
  175. #endif
  176. #ifdef HAVE_SSE4_1
  177. if((CPUCapFlags&CPU_CAP_SSE4_1))
  178. return Resample_<LerpTag,SSE4Tag>;
  179. #endif
  180. #ifdef HAVE_SSE2
  181. if((CPUCapFlags&CPU_CAP_SSE2))
  182. return Resample_<LerpTag,SSE2Tag>;
  183. #endif
  184. return Resample_<LerpTag,CTag>;
  185. case Resampler::Cubic:
  186. return Resample_<CubicTag,CTag>;
  187. case Resampler::BSinc12:
  188. case Resampler::BSinc24:
  189. if(increment <= MixerFracOne)
  190. {
  191. /* fall-through */
  192. case Resampler::FastBSinc12:
  193. case Resampler::FastBSinc24:
  194. #ifdef HAVE_NEON
  195. if((CPUCapFlags&CPU_CAP_NEON))
  196. return Resample_<FastBSincTag,NEONTag>;
  197. #endif
  198. #ifdef HAVE_SSE
  199. if((CPUCapFlags&CPU_CAP_SSE))
  200. return Resample_<FastBSincTag,SSETag>;
  201. #endif
  202. return Resample_<FastBSincTag,CTag>;
  203. }
  204. #ifdef HAVE_NEON
  205. if((CPUCapFlags&CPU_CAP_NEON))
  206. return Resample_<BSincTag,NEONTag>;
  207. #endif
  208. #ifdef HAVE_SSE
  209. if((CPUCapFlags&CPU_CAP_SSE))
  210. return Resample_<BSincTag,SSETag>;
  211. #endif
  212. return Resample_<BSincTag,CTag>;
  213. }
  214. return Resample_<PointTag,CTag>;
  215. }
  216. } // namespace
  217. void aluInit(CompatFlagBitset flags)
  218. {
  219. MixDirectHrtf = SelectHrtfMixer();
  220. XScale = flags.test(CompatFlags::ReverseX) ? -1.0f : 1.0f;
  221. YScale = flags.test(CompatFlags::ReverseY) ? -1.0f : 1.0f;
  222. ZScale = flags.test(CompatFlags::ReverseZ) ? -1.0f : 1.0f;
  223. }
  224. ResamplerFunc PrepareResampler(Resampler resampler, uint increment, InterpState *state)
  225. {
  226. switch(resampler)
  227. {
  228. case Resampler::Point:
  229. case Resampler::Linear:
  230. case Resampler::Cubic:
  231. break;
  232. case Resampler::FastBSinc12:
  233. case Resampler::BSinc12:
  234. BsincPrepare(increment, &state->bsinc, &bsinc12);
  235. break;
  236. case Resampler::FastBSinc24:
  237. case Resampler::BSinc24:
  238. BsincPrepare(increment, &state->bsinc, &bsinc24);
  239. break;
  240. }
  241. return SelectResampler(resampler, increment);
  242. }
  243. void DeviceBase::ProcessHrtf(const size_t SamplesToDo)
  244. {
  245. /* HRTF is stereo output only. */
  246. const uint lidx{RealOut.ChannelIndex[FrontLeft]};
  247. const uint ridx{RealOut.ChannelIndex[FrontRight]};
  248. MixDirectHrtf(RealOut.Buffer[lidx], RealOut.Buffer[ridx], Dry.Buffer, HrtfAccumData,
  249. mHrtfState->mTemp.data(), mHrtfState->mChannels.data(), mHrtfState->mIrSize, SamplesToDo);
  250. }
  251. void DeviceBase::ProcessAmbiDec(const size_t SamplesToDo)
  252. {
  253. AmbiDecoder->process(RealOut.Buffer, Dry.Buffer.data(), SamplesToDo);
  254. }
  255. void DeviceBase::ProcessAmbiDecStablized(const size_t SamplesToDo)
  256. {
  257. /* Decode with front image stablization. */
  258. const uint lidx{RealOut.ChannelIndex[FrontLeft]};
  259. const uint ridx{RealOut.ChannelIndex[FrontRight]};
  260. const uint cidx{RealOut.ChannelIndex[FrontCenter]};
  261. AmbiDecoder->processStablize(RealOut.Buffer, Dry.Buffer.data(), lidx, ridx, cidx,
  262. SamplesToDo);
  263. }
  264. void DeviceBase::ProcessUhj(const size_t SamplesToDo)
  265. {
  266. /* UHJ is stereo output only. */
  267. const uint lidx{RealOut.ChannelIndex[FrontLeft]};
  268. const uint ridx{RealOut.ChannelIndex[FrontRight]};
  269. /* Encode to stereo-compatible 2-channel UHJ output. */
  270. mUhjEncoder->encode(RealOut.Buffer[lidx].data(), RealOut.Buffer[ridx].data(),
  271. Dry.Buffer.data(), SamplesToDo);
  272. }
  273. void DeviceBase::ProcessBs2b(const size_t SamplesToDo)
  274. {
  275. /* First, decode the ambisonic mix to the "real" output. */
  276. AmbiDecoder->process(RealOut.Buffer, Dry.Buffer.data(), SamplesToDo);
  277. /* BS2B is stereo output only. */
  278. const uint lidx{RealOut.ChannelIndex[FrontLeft]};
  279. const uint ridx{RealOut.ChannelIndex[FrontRight]};
  280. /* Now apply the BS2B binaural/crossfeed filter. */
  281. bs2b_cross_feed(Bs2b.get(), RealOut.Buffer[lidx].data(), RealOut.Buffer[ridx].data(),
  282. SamplesToDo);
  283. }
  284. namespace {
  285. /* This RNG method was created based on the math found in opusdec. It's quick,
  286. * and starting with a seed value of 22222, is suitable for generating
  287. * whitenoise.
  288. */
  289. inline uint dither_rng(uint *seed) noexcept
  290. {
  291. *seed = (*seed * 96314165) + 907633515;
  292. return *seed;
  293. }
  294. inline auto& GetAmbiScales(AmbiScaling scaletype) noexcept
  295. {
  296. switch(scaletype)
  297. {
  298. case AmbiScaling::FuMa: return AmbiScale::FromFuMa();
  299. case AmbiScaling::SN3D: return AmbiScale::FromSN3D();
  300. case AmbiScaling::UHJ: return AmbiScale::FromUHJ();
  301. case AmbiScaling::N3D: break;
  302. }
  303. return AmbiScale::FromN3D();
  304. }
  305. inline auto& GetAmbiLayout(AmbiLayout layouttype) noexcept
  306. {
  307. if(layouttype == AmbiLayout::FuMa) return AmbiIndex::FromFuMa();
  308. return AmbiIndex::FromACN();
  309. }
  310. inline auto& GetAmbi2DLayout(AmbiLayout layouttype) noexcept
  311. {
  312. if(layouttype == AmbiLayout::FuMa) return AmbiIndex::FromFuMa2D();
  313. return AmbiIndex::FromACN2D();
  314. }
  315. bool CalcContextParams(ContextBase *ctx)
  316. {
  317. ContextProps *props{ctx->mParams.ContextUpdate.exchange(nullptr, std::memory_order_acq_rel)};
  318. if(!props) return false;
  319. const alu::Vector pos{props->Position[0], props->Position[1], props->Position[2], 1.0f};
  320. ctx->mParams.Position = pos;
  321. /* AT then UP */
  322. alu::Vector N{props->OrientAt[0], props->OrientAt[1], props->OrientAt[2], 0.0f};
  323. N.normalize();
  324. alu::Vector V{props->OrientUp[0], props->OrientUp[1], props->OrientUp[2], 0.0f};
  325. V.normalize();
  326. /* Build and normalize right-vector */
  327. alu::Vector U{N.cross_product(V)};
  328. U.normalize();
  329. const alu::Matrix rot{
  330. U[0], V[0], -N[0], 0.0,
  331. U[1], V[1], -N[1], 0.0,
  332. U[2], V[2], -N[2], 0.0,
  333. 0.0, 0.0, 0.0, 1.0};
  334. const alu::Vector vel{props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0};
  335. ctx->mParams.Matrix = rot;
  336. ctx->mParams.Velocity = rot * vel;
  337. ctx->mParams.Gain = props->Gain * ctx->mGainBoost;
  338. ctx->mParams.MetersPerUnit = props->MetersPerUnit;
  339. ctx->mParams.AirAbsorptionGainHF = props->AirAbsorptionGainHF;
  340. ctx->mParams.DopplerFactor = props->DopplerFactor;
  341. ctx->mParams.SpeedOfSound = props->SpeedOfSound * props->DopplerVelocity;
  342. ctx->mParams.SourceDistanceModel = props->SourceDistanceModel;
  343. ctx->mParams.mDistanceModel = props->mDistanceModel;
  344. AtomicReplaceHead(ctx->mFreeContextProps, props);
  345. return true;
  346. }
  347. bool CalcEffectSlotParams(EffectSlot *slot, EffectSlot **sorted_slots, ContextBase *context)
  348. {
  349. EffectSlotProps *props{slot->Update.exchange(nullptr, std::memory_order_acq_rel)};
  350. if(!props) return false;
  351. /* If the effect slot target changed, clear the first sorted entry to force
  352. * a re-sort.
  353. */
  354. if(slot->Target != props->Target)
  355. *sorted_slots = nullptr;
  356. slot->Gain = props->Gain;
  357. slot->AuxSendAuto = props->AuxSendAuto;
  358. slot->Target = props->Target;
  359. slot->EffectType = props->Type;
  360. slot->mEffectProps = props->Props;
  361. if(props->Type == EffectSlotType::Reverb || props->Type == EffectSlotType::EAXReverb)
  362. {
  363. slot->RoomRolloff = props->Props.Reverb.RoomRolloffFactor;
  364. slot->DecayTime = props->Props.Reverb.DecayTime;
  365. slot->DecayLFRatio = props->Props.Reverb.DecayLFRatio;
  366. slot->DecayHFRatio = props->Props.Reverb.DecayHFRatio;
  367. slot->DecayHFLimit = props->Props.Reverb.DecayHFLimit;
  368. slot->AirAbsorptionGainHF = props->Props.Reverb.AirAbsorptionGainHF;
  369. }
  370. else
  371. {
  372. slot->RoomRolloff = 0.0f;
  373. slot->DecayTime = 0.0f;
  374. slot->DecayLFRatio = 0.0f;
  375. slot->DecayHFRatio = 0.0f;
  376. slot->DecayHFLimit = false;
  377. slot->AirAbsorptionGainHF = 1.0f;
  378. }
  379. EffectState *state{props->State.release()};
  380. EffectState *oldstate{slot->mEffectState};
  381. slot->mEffectState = state;
  382. /* Only release the old state if it won't get deleted, since we can't be
  383. * deleting/freeing anything in the mixer.
  384. */
  385. if(!oldstate->releaseIfNoDelete())
  386. {
  387. /* Otherwise, if it would be deleted send it off with a release event. */
  388. RingBuffer *ring{context->mAsyncEvents.get()};
  389. auto evt_vec = ring->getWriteVector();
  390. if LIKELY(evt_vec.first.len > 0)
  391. {
  392. AsyncEvent *evt{al::construct_at(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf),
  393. AsyncEvent::ReleaseEffectState)};
  394. evt->u.mEffectState = oldstate;
  395. ring->writeAdvance(1);
  396. }
  397. else
  398. {
  399. /* If writing the event failed, the queue was probably full. Store
  400. * the old state in the property object where it can eventually be
  401. * cleaned up sometime later (not ideal, but better than blocking
  402. * or leaking).
  403. */
  404. props->State.reset(oldstate);
  405. }
  406. }
  407. AtomicReplaceHead(context->mFreeEffectslotProps, props);
  408. EffectTarget output;
  409. if(EffectSlot *target{slot->Target})
  410. output = EffectTarget{&target->Wet, nullptr};
  411. else
  412. {
  413. DeviceBase *device{context->mDevice};
  414. output = EffectTarget{&device->Dry, &device->RealOut};
  415. }
  416. state->update(context, slot, &slot->mEffectProps, output);
  417. return true;
  418. }
  419. /* Scales the given azimuth toward the side (+/- pi/2 radians) for positions in
  420. * front.
  421. */
  422. inline float ScaleAzimuthFront(float azimuth, float scale)
  423. {
  424. const float abs_azi{std::fabs(azimuth)};
  425. if(!(abs_azi >= al::numbers::pi_v<float>*0.5f))
  426. return std::copysign(minf(abs_azi*scale, al::numbers::pi_v<float>*0.5f), azimuth);
  427. return azimuth;
  428. }
  429. /* Wraps the given value in radians to stay between [-pi,+pi] */
  430. inline float WrapRadians(float r)
  431. {
  432. static constexpr float Pi{al::numbers::pi_v<float>};
  433. static constexpr float Pi2{Pi*2.0f};
  434. if(r > Pi) return std::fmod(Pi+r, Pi2) - Pi;
  435. if(r < -Pi) return Pi - std::fmod(Pi-r, Pi2);
  436. return r;
  437. }
  438. /* Begin ambisonic rotation helpers.
  439. *
  440. * Rotating first-order B-Format just needs a straight-forward X/Y/Z rotation
  441. * matrix. Higher orders, however, are more complicated. The method implemented
  442. * here is a recursive algorithm (the rotation for first-order is used to help
  443. * generate the second-order rotation, which helps generate the third-order
  444. * rotation, etc).
  445. *
  446. * Adapted from
  447. * <https://github.com/polarch/Spherical-Harmonic-Transform/blob/master/getSHrotMtx.m>,
  448. * provided under the BSD 3-Clause license.
  449. *
  450. * Copyright (c) 2015, Archontis Politis
  451. * Copyright (c) 2019, Christopher Robinson
  452. *
  453. * The u, v, and w coefficients used for generating higher-order rotations are
  454. * precomputed since they're constant. The second-order coefficients are
  455. * followed by the third-order coefficients, etc.
  456. */
  457. struct RotatorCoeffs {
  458. float u, v, w;
  459. template<size_t N0, size_t N1>
  460. static std::array<RotatorCoeffs,N0+N1> ConcatArrays(const std::array<RotatorCoeffs,N0> &lhs,
  461. const std::array<RotatorCoeffs,N1> &rhs)
  462. {
  463. std::array<RotatorCoeffs,N0+N1> ret;
  464. auto iter = std::copy(lhs.cbegin(), lhs.cend(), ret.begin());
  465. std::copy(rhs.cbegin(), rhs.cend(), iter);
  466. return ret;
  467. }
  468. template<int l, int num_elems=l*2+1>
  469. static std::array<RotatorCoeffs,num_elems*num_elems> GenCoeffs()
  470. {
  471. std::array<RotatorCoeffs,num_elems*num_elems> ret{};
  472. auto coeffs = ret.begin();
  473. for(int m{-l};m <= l;++m)
  474. {
  475. for(int n{-l};n <= l;++n)
  476. {
  477. // compute u,v,w terms of Eq.8.1 (Table I)
  478. const bool d{m == 0}; // the delta function d_m0
  479. const float denom{static_cast<float>((std::abs(n) == l) ?
  480. (2*l) * (2*l - 1) : (l*l - n*n))};
  481. const int abs_m{std::abs(m)};
  482. coeffs->u = std::sqrt(static_cast<float>(l*l - m*m)/denom);
  483. coeffs->v = std::sqrt(static_cast<float>(l+abs_m-1) * static_cast<float>(l+abs_m) /
  484. denom) * (1.0f+d) * (1.0f - 2.0f*d) * 0.5f;
  485. coeffs->w = std::sqrt(static_cast<float>(l-abs_m-1) * static_cast<float>(l-abs_m) /
  486. denom) * (1.0f-d) * -0.5f;
  487. ++coeffs;
  488. }
  489. }
  490. return ret;
  491. }
  492. };
  493. const auto RotatorCoeffArray = RotatorCoeffs::ConcatArrays(RotatorCoeffs::GenCoeffs<2>(),
  494. RotatorCoeffs::GenCoeffs<3>());
  495. /**
  496. * Given the matrix, pre-filled with the (zeroth- and) first-order rotation
  497. * coefficients, this fills in the coefficients for the higher orders up to and
  498. * including the given order. The matrix is in ACN layout.
  499. */
  500. void AmbiRotator(std::array<std::array<float,MaxAmbiChannels>,MaxAmbiChannels> &matrix,
  501. const int order)
  502. {
  503. /* Don't do anything for < 2nd order. */
  504. if(order < 2) return;
  505. auto P = [](const int i, const int l, const int a, const int n, const size_t last_band,
  506. const std::array<std::array<float,MaxAmbiChannels>,MaxAmbiChannels> &R)
  507. {
  508. const float ri1{ R[static_cast<uint>(i+2)][ 1+2]};
  509. const float rim1{R[static_cast<uint>(i+2)][-1+2]};
  510. const float ri0{ R[static_cast<uint>(i+2)][ 0+2]};
  511. auto vec = R[static_cast<uint>(a+l-1) + last_band].cbegin() + last_band;
  512. if(n == -l)
  513. return ri1*vec[0] + rim1*vec[static_cast<uint>(l-1)*size_t{2}];
  514. if(n == l)
  515. return ri1*vec[static_cast<uint>(l-1)*size_t{2}] - rim1*vec[0];
  516. return ri0*vec[static_cast<uint>(n+l-1)];
  517. };
  518. auto U = [P](const int l, const int m, const int n, const size_t last_band,
  519. const std::array<std::array<float,MaxAmbiChannels>,MaxAmbiChannels> &R)
  520. {
  521. return P(0, l, m, n, last_band, R);
  522. };
  523. auto V = [P](const int l, const int m, const int n, const size_t last_band,
  524. const std::array<std::array<float,MaxAmbiChannels>,MaxAmbiChannels> &R)
  525. {
  526. using namespace al::numbers;
  527. if(m > 0)
  528. {
  529. const bool d{m == 1};
  530. const float p0{P( 1, l, m-1, n, last_band, R)};
  531. const float p1{P(-1, l, -m+1, n, last_band, R)};
  532. return d ? p0*sqrt2_v<float> : (p0 - p1);
  533. }
  534. const bool d{m == -1};
  535. const float p0{P( 1, l, m+1, n, last_band, R)};
  536. const float p1{P(-1, l, -m-1, n, last_band, R)};
  537. return d ? p1*sqrt2_v<float> : (p0 + p1);
  538. };
  539. auto W = [P](const int l, const int m, const int n, const size_t last_band,
  540. const std::array<std::array<float,MaxAmbiChannels>,MaxAmbiChannels> &R)
  541. {
  542. assert(m != 0);
  543. if(m > 0)
  544. {
  545. const float p0{P( 1, l, m+1, n, last_band, R)};
  546. const float p1{P(-1, l, -m-1, n, last_band, R)};
  547. return p0 + p1;
  548. }
  549. const float p0{P( 1, l, m-1, n, last_band, R)};
  550. const float p1{P(-1, l, -m+1, n, last_band, R)};
  551. return p0 - p1;
  552. };
  553. // compute rotation matrix of each subsequent band recursively
  554. auto coeffs = RotatorCoeffArray.cbegin();
  555. size_t band_idx{4}, last_band{1};
  556. for(int l{2};l <= order;++l)
  557. {
  558. size_t y{band_idx};
  559. for(int m{-l};m <= l;++m,++y)
  560. {
  561. size_t x{band_idx};
  562. for(int n{-l};n <= l;++n,++x)
  563. {
  564. float r{0.0f};
  565. // computes Eq.8.1
  566. const float u{coeffs->u};
  567. if(u != 0.0f) r += u * U(l, m, n, last_band, matrix);
  568. const float v{coeffs->v};
  569. if(v != 0.0f) r += v * V(l, m, n, last_band, matrix);
  570. const float w{coeffs->w};
  571. if(w != 0.0f) r += w * W(l, m, n, last_band, matrix);
  572. matrix[y][x] = r;
  573. ++coeffs;
  574. }
  575. }
  576. last_band = band_idx;
  577. band_idx += static_cast<uint>(l)*size_t{2} + 1;
  578. }
  579. }
  580. /* End ambisonic rotation helpers. */
  581. constexpr float Deg2Rad(float x) noexcept
  582. { return static_cast<float>(al::numbers::pi / 180.0 * x); }
  583. struct GainTriplet { float Base, HF, LF; };
  584. void CalcPanningAndFilters(Voice *voice, const float xpos, const float ypos, const float zpos,
  585. const float Distance, const float Spread, const GainTriplet &DryGain,
  586. const al::span<const GainTriplet,MAX_SENDS> WetGain, EffectSlot *(&SendSlots)[MAX_SENDS],
  587. const VoiceProps *props, const ContextParams &Context, const DeviceBase *Device)
  588. {
  589. static constexpr ChanMap MonoMap[1]{
  590. { FrontCenter, 0.0f, 0.0f }
  591. }, RearMap[2]{
  592. { BackLeft, Deg2Rad(-150.0f), Deg2Rad(0.0f) },
  593. { BackRight, Deg2Rad( 150.0f), Deg2Rad(0.0f) }
  594. }, QuadMap[4]{
  595. { FrontLeft, Deg2Rad( -45.0f), Deg2Rad(0.0f) },
  596. { FrontRight, Deg2Rad( 45.0f), Deg2Rad(0.0f) },
  597. { BackLeft, Deg2Rad(-135.0f), Deg2Rad(0.0f) },
  598. { BackRight, Deg2Rad( 135.0f), Deg2Rad(0.0f) }
  599. }, X51Map[6]{
  600. { FrontLeft, Deg2Rad( -30.0f), Deg2Rad(0.0f) },
  601. { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) },
  602. { FrontCenter, Deg2Rad( 0.0f), Deg2Rad(0.0f) },
  603. { LFE, 0.0f, 0.0f },
  604. { SideLeft, Deg2Rad(-110.0f), Deg2Rad(0.0f) },
  605. { SideRight, Deg2Rad( 110.0f), Deg2Rad(0.0f) }
  606. }, X61Map[7]{
  607. { FrontLeft, Deg2Rad(-30.0f), Deg2Rad(0.0f) },
  608. { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) },
  609. { FrontCenter, Deg2Rad( 0.0f), Deg2Rad(0.0f) },
  610. { LFE, 0.0f, 0.0f },
  611. { BackCenter, Deg2Rad(180.0f), Deg2Rad(0.0f) },
  612. { SideLeft, Deg2Rad(-90.0f), Deg2Rad(0.0f) },
  613. { SideRight, Deg2Rad( 90.0f), Deg2Rad(0.0f) }
  614. }, X71Map[8]{
  615. { FrontLeft, Deg2Rad( -30.0f), Deg2Rad(0.0f) },
  616. { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) },
  617. { FrontCenter, Deg2Rad( 0.0f), Deg2Rad(0.0f) },
  618. { LFE, 0.0f, 0.0f },
  619. { BackLeft, Deg2Rad(-150.0f), Deg2Rad(0.0f) },
  620. { BackRight, Deg2Rad( 150.0f), Deg2Rad(0.0f) },
  621. { SideLeft, Deg2Rad( -90.0f), Deg2Rad(0.0f) },
  622. { SideRight, Deg2Rad( 90.0f), Deg2Rad(0.0f) }
  623. };
  624. ChanMap StereoMap[2]{
  625. { FrontLeft, Deg2Rad(-30.0f), Deg2Rad(0.0f) },
  626. { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) }
  627. };
  628. const auto Frequency = static_cast<float>(Device->Frequency);
  629. const uint NumSends{Device->NumAuxSends};
  630. const size_t num_channels{voice->mChans.size()};
  631. ASSUME(num_channels > 0);
  632. for(auto &chandata : voice->mChans)
  633. {
  634. chandata.mDryParams.Hrtf.Target = HrtfFilter{};
  635. chandata.mDryParams.Gains.Target.fill(0.0f);
  636. std::for_each(chandata.mWetParams.begin(), chandata.mWetParams.begin()+NumSends,
  637. [](SendParams &params) -> void { params.Gains.Target.fill(0.0f); });
  638. }
  639. DirectMode DirectChannels{props->DirectChannels};
  640. const ChanMap *chans{nullptr};
  641. switch(voice->mFmtChannels)
  642. {
  643. case FmtMono:
  644. chans = MonoMap;
  645. /* Mono buffers are never played direct. */
  646. DirectChannels = DirectMode::Off;
  647. break;
  648. case FmtStereo:
  649. if(DirectChannels == DirectMode::Off)
  650. {
  651. /* Convert counter-clockwise to clock-wise, and wrap between
  652. * [-pi,+pi].
  653. */
  654. StereoMap[0].angle = WrapRadians(-props->StereoPan[0]);
  655. StereoMap[1].angle = WrapRadians(-props->StereoPan[1]);
  656. }
  657. chans = StereoMap;
  658. break;
  659. case FmtRear: chans = RearMap; break;
  660. case FmtQuad: chans = QuadMap; break;
  661. case FmtX51: chans = X51Map; break;
  662. case FmtX61: chans = X61Map; break;
  663. case FmtX71: chans = X71Map; break;
  664. case FmtBFormat2D:
  665. case FmtBFormat3D:
  666. case FmtUHJ2:
  667. case FmtUHJ3:
  668. case FmtUHJ4:
  669. case FmtSuperStereo:
  670. DirectChannels = DirectMode::Off;
  671. break;
  672. }
  673. voice->mFlags.reset(VoiceHasHrtf).reset(VoiceHasNfc);
  674. if(auto *decoder{voice->mDecoder.get()})
  675. decoder->mWidthControl = minf(props->EnhWidth, 0.7f);
  676. if(IsAmbisonic(voice->mFmtChannels))
  677. {
  678. /* Special handling for B-Format and UHJ sources. */
  679. if(Device->AvgSpeakerDist > 0.0f && voice->mFmtChannels != FmtUHJ2
  680. && voice->mFmtChannels != FmtSuperStereo)
  681. {
  682. if(!(Distance > std::numeric_limits<float>::epsilon()))
  683. {
  684. /* NOTE: The NFCtrlFilters were created with a w0 of 0, which
  685. * is what we want for FOA input. The first channel may have
  686. * been previously re-adjusted if panned, so reset it.
  687. */
  688. voice->mChans[0].mDryParams.NFCtrlFilter.adjust(0.0f);
  689. }
  690. else
  691. {
  692. /* Clamp the distance for really close sources, to prevent
  693. * excessive bass.
  694. */
  695. const float mdist{maxf(Distance, Device->AvgSpeakerDist/4.0f)};
  696. const float w0{SpeedOfSoundMetersPerSec / (mdist * Frequency)};
  697. /* Only need to adjust the first channel of a B-Format source. */
  698. voice->mChans[0].mDryParams.NFCtrlFilter.adjust(w0);
  699. }
  700. voice->mFlags.set(VoiceHasNfc);
  701. }
  702. /* Panning a B-Format sound toward some direction is easy. Just pan the
  703. * first (W) channel as a normal mono sound. The angular spread is used
  704. * as a directional scalar to blend between full coverage and full
  705. * panning.
  706. */
  707. const float coverage{!(Distance > std::numeric_limits<float>::epsilon()) ? 1.0f :
  708. (al::numbers::inv_pi_v<float>/2.0f * Spread)};
  709. auto calc_coeffs = [xpos,ypos,zpos](RenderMode mode)
  710. {
  711. if(mode != RenderMode::Pairwise)
  712. return CalcDirectionCoeffs({xpos, ypos, zpos}, 0.0f);
  713. /* Clamp Y, in case rounding errors caused it to end up outside
  714. * of -1...+1.
  715. */
  716. const float ev{std::asin(clampf(ypos, -1.0f, 1.0f))};
  717. /* Negate Z for right-handed coords with -Z in front. */
  718. const float az{std::atan2(xpos, -zpos)};
  719. /* A scalar of 1.5 for plain stereo results in +/-60 degrees
  720. * being moved to +/-90 degrees for direct right and left
  721. * speaker responses.
  722. */
  723. return CalcAngleCoeffs(ScaleAzimuthFront(az, 1.5f), ev, 0.0f);
  724. };
  725. auto coeffs = calc_coeffs(Device->mRenderMode);
  726. std::transform(coeffs.begin()+1, coeffs.end(), coeffs.begin()+1,
  727. std::bind(std::multiplies<float>{}, _1, 1.0f-coverage));
  728. /* NOTE: W needs to be scaled according to channel scaling. */
  729. auto&& scales = GetAmbiScales(voice->mAmbiScaling);
  730. ComputePanGains(&Device->Dry, coeffs.data(), DryGain.Base*scales[0],
  731. voice->mChans[0].mDryParams.Gains.Target);
  732. for(uint i{0};i < NumSends;i++)
  733. {
  734. if(const EffectSlot *Slot{SendSlots[i]})
  735. ComputePanGains(&Slot->Wet, coeffs.data(), WetGain[i].Base*scales[0],
  736. voice->mChans[0].mWetParams[i].Gains.Target);
  737. }
  738. if(coverage > 0.0f)
  739. {
  740. /* Local B-Format sources have their XYZ channels rotated according
  741. * to the orientation.
  742. */
  743. /* AT then UP */
  744. alu::Vector N{props->OrientAt[0], props->OrientAt[1], props->OrientAt[2], 0.0f};
  745. N.normalize();
  746. alu::Vector V{props->OrientUp[0], props->OrientUp[1], props->OrientUp[2], 0.0f};
  747. V.normalize();
  748. if(!props->HeadRelative)
  749. {
  750. N = Context.Matrix * N;
  751. V = Context.Matrix * V;
  752. }
  753. /* Build and normalize right-vector */
  754. alu::Vector U{N.cross_product(V)};
  755. U.normalize();
  756. /* Build a rotation matrix. Manually fill the zeroth- and first-
  757. * order elements, then construct the rotation for the higher
  758. * orders.
  759. */
  760. std::array<std::array<float,MaxAmbiChannels>,MaxAmbiChannels> shrot{};
  761. shrot[0][0] = 1.0f;
  762. shrot[1][1] = U[0]; shrot[1][2] = -V[0]; shrot[1][3] = -N[0];
  763. shrot[2][1] = -U[1]; shrot[2][2] = V[1]; shrot[2][3] = N[1];
  764. shrot[3][1] = U[2]; shrot[3][2] = -V[2]; shrot[3][3] = -N[2];
  765. AmbiRotator(shrot, static_cast<int>(minu(voice->mAmbiOrder, Device->mAmbiOrder)));
  766. /* Convert the rotation matrix for input ordering and scaling, and
  767. * whether input is 2D or 3D.
  768. */
  769. const uint8_t *index_map{Is2DAmbisonic(voice->mFmtChannels) ?
  770. GetAmbi2DLayout(voice->mAmbiLayout).data() :
  771. GetAmbiLayout(voice->mAmbiLayout).data()};
  772. static const uint8_t ChansPerOrder[MaxAmbiOrder+1]{1, 3, 5, 7,};
  773. static const uint8_t OrderOffset[MaxAmbiOrder+1]{0, 1, 4, 9,};
  774. for(size_t c{1};c < num_channels;c++)
  775. {
  776. const size_t acn{index_map[c]};
  777. const size_t order{AmbiIndex::OrderFromChannel()[acn]};
  778. const size_t tocopy{ChansPerOrder[order]};
  779. const size_t offset{OrderOffset[order]};
  780. const float scale{scales[acn] * coverage};
  781. auto in = shrot.cbegin() + offset;
  782. coeffs = std::array<float,MaxAmbiChannels>{};
  783. for(size_t x{0};x < tocopy;++x)
  784. coeffs[offset+x] = in[x][acn] * scale;
  785. ComputePanGains(&Device->Dry, coeffs.data(), DryGain.Base,
  786. voice->mChans[c].mDryParams.Gains.Target);
  787. for(uint i{0};i < NumSends;i++)
  788. {
  789. if(const EffectSlot *Slot{SendSlots[i]})
  790. ComputePanGains(&Slot->Wet, coeffs.data(), WetGain[i].Base,
  791. voice->mChans[c].mWetParams[i].Gains.Target);
  792. }
  793. }
  794. }
  795. }
  796. else if(DirectChannels != DirectMode::Off && !Device->RealOut.RemixMap.empty())
  797. {
  798. /* Direct source channels always play local. Skip the virtual channels
  799. * and write inputs to the matching real outputs.
  800. */
  801. voice->mDirect.Buffer = Device->RealOut.Buffer;
  802. for(size_t c{0};c < num_channels;c++)
  803. {
  804. uint idx{GetChannelIdxByName(Device->RealOut, chans[c].channel)};
  805. if(idx != INVALID_CHANNEL_INDEX)
  806. voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain.Base;
  807. else if(DirectChannels == DirectMode::RemixMismatch)
  808. {
  809. auto match_channel = [chans,c](const InputRemixMap &map) noexcept -> bool
  810. { return chans[c].channel == map.channel; };
  811. auto remap = std::find_if(Device->RealOut.RemixMap.cbegin(),
  812. Device->RealOut.RemixMap.cend(), match_channel);
  813. if(remap != Device->RealOut.RemixMap.cend())
  814. {
  815. for(const auto &target : remap->targets)
  816. {
  817. idx = GetChannelIdxByName(Device->RealOut, target.channel);
  818. if(idx != INVALID_CHANNEL_INDEX)
  819. voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain.Base *
  820. target.mix;
  821. }
  822. }
  823. }
  824. }
  825. /* Auxiliary sends still use normal channel panning since they mix to
  826. * B-Format, which can't channel-match.
  827. */
  828. for(size_t c{0};c < num_channels;c++)
  829. {
  830. const auto coeffs = CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f);
  831. for(uint i{0};i < NumSends;i++)
  832. {
  833. if(const EffectSlot *Slot{SendSlots[i]})
  834. ComputePanGains(&Slot->Wet, coeffs.data(), WetGain[i].Base,
  835. voice->mChans[c].mWetParams[i].Gains.Target);
  836. }
  837. }
  838. }
  839. else if(Device->mRenderMode == RenderMode::Hrtf)
  840. {
  841. /* Full HRTF rendering. Skip the virtual channels and render to the
  842. * real outputs.
  843. */
  844. voice->mDirect.Buffer = Device->RealOut.Buffer;
  845. if(Distance > std::numeric_limits<float>::epsilon())
  846. {
  847. const float ev{std::asin(clampf(ypos, -1.0f, 1.0f))};
  848. const float az{std::atan2(xpos, -zpos)};
  849. /* Get the HRIR coefficients and delays just once, for the given
  850. * source direction.
  851. */
  852. GetHrtfCoeffs(Device->mHrtf.get(), ev, az, Distance, Spread,
  853. voice->mChans[0].mDryParams.Hrtf.Target.Coeffs,
  854. voice->mChans[0].mDryParams.Hrtf.Target.Delay);
  855. voice->mChans[0].mDryParams.Hrtf.Target.Gain = DryGain.Base;
  856. /* Remaining channels use the same results as the first. */
  857. for(size_t c{1};c < num_channels;c++)
  858. {
  859. /* Skip LFE */
  860. if(chans[c].channel == LFE) continue;
  861. voice->mChans[c].mDryParams.Hrtf.Target = voice->mChans[0].mDryParams.Hrtf.Target;
  862. }
  863. /* Calculate the directional coefficients once, which apply to all
  864. * input channels of the source sends.
  865. */
  866. const auto coeffs = CalcDirectionCoeffs({xpos, ypos, zpos}, Spread);
  867. for(size_t c{0};c < num_channels;c++)
  868. {
  869. /* Skip LFE */
  870. if(chans[c].channel == LFE)
  871. continue;
  872. for(uint i{0};i < NumSends;i++)
  873. {
  874. if(const EffectSlot *Slot{SendSlots[i]})
  875. ComputePanGains(&Slot->Wet, coeffs.data(), WetGain[i].Base,
  876. voice->mChans[c].mWetParams[i].Gains.Target);
  877. }
  878. }
  879. }
  880. else
  881. {
  882. /* Local sources on HRTF play with each channel panned to its
  883. * relative location around the listener, providing "virtual
  884. * speaker" responses.
  885. */
  886. for(size_t c{0};c < num_channels;c++)
  887. {
  888. /* Skip LFE */
  889. if(chans[c].channel == LFE)
  890. continue;
  891. /* Get the HRIR coefficients and delays for this channel
  892. * position.
  893. */
  894. GetHrtfCoeffs(Device->mHrtf.get(), chans[c].elevation, chans[c].angle,
  895. std::numeric_limits<float>::infinity(), Spread,
  896. voice->mChans[c].mDryParams.Hrtf.Target.Coeffs,
  897. voice->mChans[c].mDryParams.Hrtf.Target.Delay);
  898. voice->mChans[c].mDryParams.Hrtf.Target.Gain = DryGain.Base;
  899. /* Normal panning for auxiliary sends. */
  900. const auto coeffs = CalcAngleCoeffs(chans[c].angle, chans[c].elevation, Spread);
  901. for(uint i{0};i < NumSends;i++)
  902. {
  903. if(const EffectSlot *Slot{SendSlots[i]})
  904. ComputePanGains(&Slot->Wet, coeffs.data(), WetGain[i].Base,
  905. voice->mChans[c].mWetParams[i].Gains.Target);
  906. }
  907. }
  908. }
  909. voice->mFlags.set(VoiceHasHrtf);
  910. }
  911. else
  912. {
  913. /* Non-HRTF rendering. Use normal panning to the output. */
  914. if(Distance > std::numeric_limits<float>::epsilon())
  915. {
  916. /* Calculate NFC filter coefficient if needed. */
  917. if(Device->AvgSpeakerDist > 0.0f)
  918. {
  919. /* Clamp the distance for really close sources, to prevent
  920. * excessive bass.
  921. */
  922. const float mdist{maxf(Distance, Device->AvgSpeakerDist/4.0f)};
  923. const float w0{SpeedOfSoundMetersPerSec / (mdist * Frequency)};
  924. /* Adjust NFC filters. */
  925. for(size_t c{0};c < num_channels;c++)
  926. voice->mChans[c].mDryParams.NFCtrlFilter.adjust(w0);
  927. voice->mFlags.set(VoiceHasNfc);
  928. }
  929. /* Calculate the directional coefficients once, which apply to all
  930. * input channels.
  931. */
  932. auto calc_coeffs = [xpos,ypos,zpos,Spread](RenderMode mode)
  933. {
  934. if(mode != RenderMode::Pairwise)
  935. return CalcDirectionCoeffs({xpos, ypos, zpos}, Spread);
  936. const float ev{std::asin(clampf(ypos, -1.0f, 1.0f))};
  937. const float az{std::atan2(xpos, -zpos)};
  938. return CalcAngleCoeffs(ScaleAzimuthFront(az, 1.5f), ev, Spread);
  939. };
  940. const auto coeffs = calc_coeffs(Device->mRenderMode);
  941. for(size_t c{0};c < num_channels;c++)
  942. {
  943. /* Special-case LFE */
  944. if(chans[c].channel == LFE)
  945. {
  946. if(Device->Dry.Buffer.data() == Device->RealOut.Buffer.data())
  947. {
  948. const uint idx{GetChannelIdxByName(Device->RealOut, chans[c].channel)};
  949. if(idx != INVALID_CHANNEL_INDEX)
  950. voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain.Base;
  951. }
  952. continue;
  953. }
  954. ComputePanGains(&Device->Dry, coeffs.data(), DryGain.Base,
  955. voice->mChans[c].mDryParams.Gains.Target);
  956. for(uint i{0};i < NumSends;i++)
  957. {
  958. if(const EffectSlot *Slot{SendSlots[i]})
  959. ComputePanGains(&Slot->Wet, coeffs.data(), WetGain[i].Base,
  960. voice->mChans[c].mWetParams[i].Gains.Target);
  961. }
  962. }
  963. }
  964. else
  965. {
  966. if(Device->AvgSpeakerDist > 0.0f)
  967. {
  968. /* If the source distance is 0, simulate a plane-wave by using
  969. * infinite distance, which results in a w0 of 0.
  970. */
  971. static constexpr float w0{0.0f};
  972. for(size_t c{0};c < num_channels;c++)
  973. voice->mChans[c].mDryParams.NFCtrlFilter.adjust(w0);
  974. voice->mFlags.set(VoiceHasNfc);
  975. }
  976. for(size_t c{0};c < num_channels;c++)
  977. {
  978. /* Special-case LFE */
  979. if(chans[c].channel == LFE)
  980. {
  981. if(Device->Dry.Buffer.data() == Device->RealOut.Buffer.data())
  982. {
  983. const uint idx{GetChannelIdxByName(Device->RealOut, chans[c].channel)};
  984. if(idx != INVALID_CHANNEL_INDEX)
  985. voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain.Base;
  986. }
  987. continue;
  988. }
  989. const auto coeffs = CalcAngleCoeffs((Device->mRenderMode == RenderMode::Pairwise)
  990. ? ScaleAzimuthFront(chans[c].angle, 3.0f) : chans[c].angle,
  991. chans[c].elevation, Spread);
  992. ComputePanGains(&Device->Dry, coeffs.data(), DryGain.Base,
  993. voice->mChans[c].mDryParams.Gains.Target);
  994. for(uint i{0};i < NumSends;i++)
  995. {
  996. if(const EffectSlot *Slot{SendSlots[i]})
  997. ComputePanGains(&Slot->Wet, coeffs.data(), WetGain[i].Base,
  998. voice->mChans[c].mWetParams[i].Gains.Target);
  999. }
  1000. }
  1001. }
  1002. }
  1003. {
  1004. const float hfNorm{props->Direct.HFReference / Frequency};
  1005. const float lfNorm{props->Direct.LFReference / Frequency};
  1006. voice->mDirect.FilterType = AF_None;
  1007. if(DryGain.HF != 1.0f) voice->mDirect.FilterType |= AF_LowPass;
  1008. if(DryGain.LF != 1.0f) voice->mDirect.FilterType |= AF_HighPass;
  1009. auto &lowpass = voice->mChans[0].mDryParams.LowPass;
  1010. auto &highpass = voice->mChans[0].mDryParams.HighPass;
  1011. lowpass.setParamsFromSlope(BiquadType::HighShelf, hfNorm, DryGain.HF, 1.0f);
  1012. highpass.setParamsFromSlope(BiquadType::LowShelf, lfNorm, DryGain.LF, 1.0f);
  1013. for(size_t c{1};c < num_channels;c++)
  1014. {
  1015. voice->mChans[c].mDryParams.LowPass.copyParamsFrom(lowpass);
  1016. voice->mChans[c].mDryParams.HighPass.copyParamsFrom(highpass);
  1017. }
  1018. }
  1019. for(uint i{0};i < NumSends;i++)
  1020. {
  1021. const float hfNorm{props->Send[i].HFReference / Frequency};
  1022. const float lfNorm{props->Send[i].LFReference / Frequency};
  1023. voice->mSend[i].FilterType = AF_None;
  1024. if(WetGain[i].HF != 1.0f) voice->mSend[i].FilterType |= AF_LowPass;
  1025. if(WetGain[i].LF != 1.0f) voice->mSend[i].FilterType |= AF_HighPass;
  1026. auto &lowpass = voice->mChans[0].mWetParams[i].LowPass;
  1027. auto &highpass = voice->mChans[0].mWetParams[i].HighPass;
  1028. lowpass.setParamsFromSlope(BiquadType::HighShelf, hfNorm, WetGain[i].HF, 1.0f);
  1029. highpass.setParamsFromSlope(BiquadType::LowShelf, lfNorm, WetGain[i].LF, 1.0f);
  1030. for(size_t c{1};c < num_channels;c++)
  1031. {
  1032. voice->mChans[c].mWetParams[i].LowPass.copyParamsFrom(lowpass);
  1033. voice->mChans[c].mWetParams[i].HighPass.copyParamsFrom(highpass);
  1034. }
  1035. }
  1036. }
  1037. void CalcNonAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBase *context)
  1038. {
  1039. const DeviceBase *Device{context->mDevice};
  1040. EffectSlot *SendSlots[MAX_SENDS];
  1041. voice->mDirect.Buffer = Device->Dry.Buffer;
  1042. for(uint i{0};i < Device->NumAuxSends;i++)
  1043. {
  1044. SendSlots[i] = props->Send[i].Slot;
  1045. if(!SendSlots[i] || SendSlots[i]->EffectType == EffectSlotType::None)
  1046. {
  1047. SendSlots[i] = nullptr;
  1048. voice->mSend[i].Buffer = {};
  1049. }
  1050. else
  1051. voice->mSend[i].Buffer = SendSlots[i]->Wet.Buffer;
  1052. }
  1053. /* Calculate the stepping value */
  1054. const auto Pitch = static_cast<float>(voice->mFrequency) /
  1055. static_cast<float>(Device->Frequency) * props->Pitch;
  1056. if(Pitch > float{MaxPitch})
  1057. voice->mStep = MaxPitch<<MixerFracBits;
  1058. else
  1059. voice->mStep = maxu(fastf2u(Pitch * MixerFracOne), 1);
  1060. voice->mResampler = PrepareResampler(props->mResampler, voice->mStep, &voice->mResampleState);
  1061. /* Calculate gains */
  1062. GainTriplet DryGain;
  1063. DryGain.Base = minf(clampf(props->Gain, props->MinGain, props->MaxGain) * props->Direct.Gain *
  1064. context->mParams.Gain, GainMixMax);
  1065. DryGain.HF = props->Direct.GainHF;
  1066. DryGain.LF = props->Direct.GainLF;
  1067. GainTriplet WetGain[MAX_SENDS];
  1068. for(uint i{0};i < Device->NumAuxSends;i++)
  1069. {
  1070. WetGain[i].Base = minf(clampf(props->Gain, props->MinGain, props->MaxGain) *
  1071. props->Send[i].Gain * context->mParams.Gain, GainMixMax);
  1072. WetGain[i].HF = props->Send[i].GainHF;
  1073. WetGain[i].LF = props->Send[i].GainLF;
  1074. }
  1075. CalcPanningAndFilters(voice, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, DryGain, WetGain, SendSlots, props,
  1076. context->mParams, Device);
  1077. }
  1078. void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBase *context)
  1079. {
  1080. const DeviceBase *Device{context->mDevice};
  1081. const uint NumSends{Device->NumAuxSends};
  1082. /* Set mixing buffers and get send parameters. */
  1083. voice->mDirect.Buffer = Device->Dry.Buffer;
  1084. EffectSlot *SendSlots[MAX_SENDS];
  1085. uint UseDryAttnForRoom{0};
  1086. for(uint i{0};i < NumSends;i++)
  1087. {
  1088. SendSlots[i] = props->Send[i].Slot;
  1089. if(!SendSlots[i] || SendSlots[i]->EffectType == EffectSlotType::None)
  1090. SendSlots[i] = nullptr;
  1091. else if(!SendSlots[i]->AuxSendAuto)
  1092. {
  1093. /* If the slot's auxiliary send auto is off, the data sent to the
  1094. * effect slot is the same as the dry path, sans filter effects.
  1095. */
  1096. UseDryAttnForRoom |= 1u<<i;
  1097. }
  1098. if(!SendSlots[i])
  1099. voice->mSend[i].Buffer = {};
  1100. else
  1101. voice->mSend[i].Buffer = SendSlots[i]->Wet.Buffer;
  1102. }
  1103. /* Transform source to listener space (convert to head relative) */
  1104. alu::Vector Position{props->Position[0], props->Position[1], props->Position[2], 1.0f};
  1105. alu::Vector Velocity{props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f};
  1106. alu::Vector Direction{props->Direction[0], props->Direction[1], props->Direction[2], 0.0f};
  1107. if(!props->HeadRelative)
  1108. {
  1109. /* Transform source vectors */
  1110. Position = context->mParams.Matrix * (Position - context->mParams.Position);
  1111. Velocity = context->mParams.Matrix * Velocity;
  1112. Direction = context->mParams.Matrix * Direction;
  1113. }
  1114. else
  1115. {
  1116. /* Offset the source velocity to be relative of the listener velocity */
  1117. Velocity += context->mParams.Velocity;
  1118. }
  1119. const bool directional{Direction.normalize() > 0.0f};
  1120. alu::Vector ToSource{Position[0], Position[1], Position[2], 0.0f};
  1121. const float Distance{ToSource.normalize()};
  1122. /* Calculate distance attenuation */
  1123. float ClampedDist{Distance};
  1124. float DryGainBase{props->Gain};
  1125. float WetGainBase{props->Gain};
  1126. switch(context->mParams.SourceDistanceModel ? props->mDistanceModel
  1127. : context->mParams.mDistanceModel)
  1128. {
  1129. case DistanceModel::InverseClamped:
  1130. if(props->MaxDistance < props->RefDistance) break;
  1131. ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance);
  1132. /*fall-through*/
  1133. case DistanceModel::Inverse:
  1134. if(props->RefDistance > 0.0f)
  1135. {
  1136. float dist{lerpf(props->RefDistance, ClampedDist, props->RolloffFactor)};
  1137. if(dist > 0.0f) DryGainBase *= props->RefDistance / dist;
  1138. dist = lerpf(props->RefDistance, ClampedDist, props->RoomRolloffFactor);
  1139. if(dist > 0.0f) WetGainBase *= props->RefDistance / dist;
  1140. }
  1141. break;
  1142. case DistanceModel::LinearClamped:
  1143. if(props->MaxDistance < props->RefDistance) break;
  1144. ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance);
  1145. /*fall-through*/
  1146. case DistanceModel::Linear:
  1147. if(props->MaxDistance != props->RefDistance)
  1148. {
  1149. float attn{(ClampedDist-props->RefDistance) /
  1150. (props->MaxDistance-props->RefDistance) * props->RolloffFactor};
  1151. DryGainBase *= maxf(1.0f - attn, 0.0f);
  1152. attn = (ClampedDist-props->RefDistance) /
  1153. (props->MaxDistance-props->RefDistance) * props->RoomRolloffFactor;
  1154. WetGainBase *= maxf(1.0f - attn, 0.0f);
  1155. }
  1156. break;
  1157. case DistanceModel::ExponentClamped:
  1158. if(props->MaxDistance < props->RefDistance) break;
  1159. ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance);
  1160. /*fall-through*/
  1161. case DistanceModel::Exponent:
  1162. if(ClampedDist > 0.0f && props->RefDistance > 0.0f)
  1163. {
  1164. const float dist_ratio{ClampedDist/props->RefDistance};
  1165. DryGainBase *= std::pow(dist_ratio, -props->RolloffFactor);
  1166. WetGainBase *= std::pow(dist_ratio, -props->RoomRolloffFactor);
  1167. }
  1168. break;
  1169. case DistanceModel::Disable:
  1170. break;
  1171. }
  1172. /* Calculate directional soundcones */
  1173. float ConeHF{1.0f}, WetConeHF{1.0f};
  1174. if(directional && props->InnerAngle < 360.0f)
  1175. {
  1176. static constexpr float Rad2Deg{static_cast<float>(180.0 / al::numbers::pi)};
  1177. const float Angle{Rad2Deg*2.0f * std::acos(-Direction.dot_product(ToSource)) * ConeScale};
  1178. float ConeGain{1.0f};
  1179. if(Angle >= props->OuterAngle)
  1180. {
  1181. ConeGain = props->OuterGain;
  1182. ConeHF = lerpf(1.0f, props->OuterGainHF, props->DryGainHFAuto);
  1183. }
  1184. else if(Angle >= props->InnerAngle)
  1185. {
  1186. const float scale{(Angle-props->InnerAngle) / (props->OuterAngle-props->InnerAngle)};
  1187. ConeGain = lerpf(1.0f, props->OuterGain, scale);
  1188. ConeHF = lerpf(1.0f, props->OuterGainHF, scale * props->DryGainHFAuto);
  1189. }
  1190. DryGainBase *= ConeGain;
  1191. WetGainBase *= lerpf(1.0f, ConeGain, props->WetGainAuto);
  1192. WetConeHF = lerpf(1.0f, ConeHF, props->WetGainHFAuto);
  1193. }
  1194. /* Apply gain and frequency filters */
  1195. DryGainBase = clampf(DryGainBase, props->MinGain, props->MaxGain) * context->mParams.Gain;
  1196. WetGainBase = clampf(WetGainBase, props->MinGain, props->MaxGain) * context->mParams.Gain;
  1197. GainTriplet DryGain{};
  1198. DryGain.Base = minf(DryGainBase * props->Direct.Gain, GainMixMax);
  1199. DryGain.HF = ConeHF * props->Direct.GainHF;
  1200. DryGain.LF = props->Direct.GainLF;
  1201. GainTriplet WetGain[MAX_SENDS]{};
  1202. for(uint i{0};i < NumSends;i++)
  1203. {
  1204. /* If this effect slot's Auxiliary Send Auto is off, then use the dry
  1205. * path distance and cone attenuation, otherwise use the wet (room)
  1206. * path distance and cone attenuation. The send filter is used instead
  1207. * of the direct filter, regardless.
  1208. */
  1209. const bool use_room{!(UseDryAttnForRoom&(1u<<i))};
  1210. const float gain{use_room ? WetGainBase : DryGainBase};
  1211. WetGain[i].Base = minf(gain * props->Send[i].Gain, GainMixMax);
  1212. WetGain[i].HF = (use_room ? WetConeHF : ConeHF) * props->Send[i].GainHF;
  1213. WetGain[i].LF = props->Send[i].GainLF;
  1214. }
  1215. /* Distance-based air absorption and initial send decay. */
  1216. if(likely(Distance > props->RefDistance))
  1217. {
  1218. const float distance_base{(Distance-props->RefDistance) * props->RolloffFactor};
  1219. const float absorption{distance_base * context->mParams.MetersPerUnit *
  1220. props->AirAbsorptionFactor};
  1221. if(absorption > std::numeric_limits<float>::epsilon())
  1222. {
  1223. const float hfattn{std::pow(context->mParams.AirAbsorptionGainHF, absorption)};
  1224. DryGain.HF *= hfattn;
  1225. for(uint i{0u};i < NumSends;++i)
  1226. WetGain[i].HF *= hfattn;
  1227. }
  1228. /* If the source's Auxiliary Send Filter Gain Auto is off, no extra
  1229. * adjustment is applied to the send gains.
  1230. */
  1231. for(uint i{props->WetGainAuto ? 0u : NumSends};i < NumSends;++i)
  1232. {
  1233. if(!SendSlots[i])
  1234. continue;
  1235. auto calc_attenuation = [](float distance, float refdist, float rolloff) noexcept
  1236. {
  1237. const float dist{lerpf(refdist, distance, rolloff)};
  1238. if(dist > refdist) return refdist / dist;
  1239. return 1.0f;
  1240. };
  1241. /* The reverb effect's room rolloff factor always applies to an
  1242. * inverse distance rolloff model.
  1243. */
  1244. WetGain[i].Base *= calc_attenuation(Distance, props->RefDistance,
  1245. SendSlots[i]->RoomRolloff);
  1246. /* If this effect slot's Auxiliary Send Auto is off, don't apply
  1247. * the automatic initial reverb decay (should the reverb's room
  1248. * rolloff still apply?).
  1249. */
  1250. if(!SendSlots[i]->AuxSendAuto)
  1251. continue;
  1252. GainTriplet DecayDistance;
  1253. /* Calculate the distances to where this effect's decay reaches
  1254. * -60dB.
  1255. */
  1256. DecayDistance.Base = SendSlots[i]->DecayTime * SpeedOfSoundMetersPerSec;
  1257. DecayDistance.LF = DecayDistance.Base * SendSlots[i]->DecayLFRatio;
  1258. DecayDistance.HF = DecayDistance.Base * SendSlots[i]->DecayHFRatio;
  1259. if(SendSlots[i]->DecayHFLimit)
  1260. {
  1261. const float airAbsorption{SendSlots[i]->AirAbsorptionGainHF};
  1262. if(airAbsorption < 1.0f)
  1263. {
  1264. /* Calculate the distance to where this effect's air
  1265. * absorption reaches -60dB, and limit the effect's HF
  1266. * decay distance (so it doesn't take any longer to decay
  1267. * than the air would allow).
  1268. */
  1269. static constexpr float log10_decaygain{-3.0f/*std::log10(ReverbDecayGain)*/};
  1270. const float absorb_dist{log10_decaygain / std::log10(airAbsorption)};
  1271. DecayDistance.HF = minf(absorb_dist, DecayDistance.HF);
  1272. }
  1273. }
  1274. const float baseAttn = calc_attenuation(Distance, props->RefDistance,
  1275. props->RolloffFactor);
  1276. /* Apply a decay-time transformation to the wet path, based on the
  1277. * source distance. The initial decay of the reverb effect is
  1278. * calculated and applied to the wet path.
  1279. */
  1280. const float fact{distance_base / DecayDistance.Base};
  1281. const float gain{std::pow(ReverbDecayGain, fact)*(1.0f-baseAttn) + baseAttn};
  1282. WetGain[i].Base *= gain;
  1283. if(gain > 0.0f)
  1284. {
  1285. const float hffact{distance_base / DecayDistance.HF};
  1286. const float gainhf{std::pow(ReverbDecayGain, hffact)*(1.0f-baseAttn) + baseAttn};
  1287. WetGain[i].HF *= minf(gainhf/gain, 1.0f);
  1288. const float lffact{distance_base / DecayDistance.LF};
  1289. const float gainlf{std::pow(ReverbDecayGain, lffact)*(1.0f-baseAttn) + baseAttn};
  1290. WetGain[i].LF *= minf(gainlf/gain, 1.0f);
  1291. }
  1292. }
  1293. }
  1294. /* Initial source pitch */
  1295. float Pitch{props->Pitch};
  1296. /* Calculate velocity-based doppler effect */
  1297. float DopplerFactor{props->DopplerFactor * context->mParams.DopplerFactor};
  1298. if(DopplerFactor > 0.0f)
  1299. {
  1300. const alu::Vector &lvelocity = context->mParams.Velocity;
  1301. float vss{Velocity.dot_product(ToSource) * -DopplerFactor};
  1302. float vls{lvelocity.dot_product(ToSource) * -DopplerFactor};
  1303. const float SpeedOfSound{context->mParams.SpeedOfSound};
  1304. if(!(vls < SpeedOfSound))
  1305. {
  1306. /* Listener moving away from the source at the speed of sound.
  1307. * Sound waves can't catch it.
  1308. */
  1309. Pitch = 0.0f;
  1310. }
  1311. else if(!(vss < SpeedOfSound))
  1312. {
  1313. /* Source moving toward the listener at the speed of sound. Sound
  1314. * waves bunch up to extreme frequencies.
  1315. */
  1316. Pitch = std::numeric_limits<float>::infinity();
  1317. }
  1318. else
  1319. {
  1320. /* Source and listener movement is nominal. Calculate the proper
  1321. * doppler shift.
  1322. */
  1323. Pitch *= (SpeedOfSound-vls) / (SpeedOfSound-vss);
  1324. }
  1325. }
  1326. /* Adjust pitch based on the buffer and output frequencies, and calculate
  1327. * fixed-point stepping value.
  1328. */
  1329. Pitch *= static_cast<float>(voice->mFrequency) / static_cast<float>(Device->Frequency);
  1330. if(Pitch > float{MaxPitch})
  1331. voice->mStep = MaxPitch<<MixerFracBits;
  1332. else
  1333. voice->mStep = maxu(fastf2u(Pitch * MixerFracOne), 1);
  1334. voice->mResampler = PrepareResampler(props->mResampler, voice->mStep, &voice->mResampleState);
  1335. float spread{0.0f};
  1336. if(props->Radius > Distance)
  1337. spread = al::numbers::pi_v<float>*2.0f - Distance/props->Radius*al::numbers::pi_v<float>;
  1338. else if(Distance > 0.0f)
  1339. spread = std::asin(props->Radius/Distance) * 2.0f;
  1340. CalcPanningAndFilters(voice, ToSource[0]*XScale, ToSource[1]*YScale, ToSource[2]*ZScale,
  1341. Distance*context->mParams.MetersPerUnit, spread, DryGain, WetGain, SendSlots, props,
  1342. context->mParams, Device);
  1343. }
  1344. void CalcSourceParams(Voice *voice, ContextBase *context, bool force)
  1345. {
  1346. VoicePropsItem *props{voice->mUpdate.exchange(nullptr, std::memory_order_acq_rel)};
  1347. if(!props && !force) return;
  1348. if(props)
  1349. {
  1350. voice->mProps = *props;
  1351. AtomicReplaceHead(context->mFreeVoiceProps, props);
  1352. }
  1353. if((voice->mProps.DirectChannels != DirectMode::Off && voice->mFmtChannels != FmtMono
  1354. && !IsAmbisonic(voice->mFmtChannels))
  1355. || voice->mProps.mSpatializeMode == SpatializeMode::Off
  1356. || (voice->mProps.mSpatializeMode==SpatializeMode::Auto && voice->mFmtChannels != FmtMono))
  1357. CalcNonAttnSourceParams(voice, &voice->mProps, context);
  1358. else
  1359. CalcAttnSourceParams(voice, &voice->mProps, context);
  1360. }
  1361. void SendSourceStateEvent(ContextBase *context, uint id, VChangeState state)
  1362. {
  1363. RingBuffer *ring{context->mAsyncEvents.get()};
  1364. auto evt_vec = ring->getWriteVector();
  1365. if(evt_vec.first.len < 1) return;
  1366. AsyncEvent *evt{al::construct_at(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf),
  1367. AsyncEvent::SourceStateChange)};
  1368. evt->u.srcstate.id = id;
  1369. switch(state)
  1370. {
  1371. case VChangeState::Reset:
  1372. evt->u.srcstate.state = AsyncEvent::SrcState::Reset;
  1373. break;
  1374. case VChangeState::Stop:
  1375. evt->u.srcstate.state = AsyncEvent::SrcState::Stop;
  1376. break;
  1377. case VChangeState::Play:
  1378. evt->u.srcstate.state = AsyncEvent::SrcState::Play;
  1379. break;
  1380. case VChangeState::Pause:
  1381. evt->u.srcstate.state = AsyncEvent::SrcState::Pause;
  1382. break;
  1383. /* Shouldn't happen. */
  1384. case VChangeState::Restart:
  1385. ASSUME(0);
  1386. }
  1387. ring->writeAdvance(1);
  1388. }
  1389. void ProcessVoiceChanges(ContextBase *ctx)
  1390. {
  1391. VoiceChange *cur{ctx->mCurrentVoiceChange.load(std::memory_order_acquire)};
  1392. VoiceChange *next{cur->mNext.load(std::memory_order_acquire)};
  1393. if(!next) return;
  1394. const uint enabledevt{ctx->mEnabledEvts.load(std::memory_order_acquire)};
  1395. do {
  1396. cur = next;
  1397. bool sendevt{false};
  1398. if(cur->mState == VChangeState::Reset || cur->mState == VChangeState::Stop)
  1399. {
  1400. if(Voice *voice{cur->mVoice})
  1401. {
  1402. voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed);
  1403. voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed);
  1404. /* A source ID indicates the voice was playing or paused, which
  1405. * gets a reset/stop event.
  1406. */
  1407. sendevt = voice->mSourceID.exchange(0u, std::memory_order_relaxed) != 0u;
  1408. Voice::State oldvstate{Voice::Playing};
  1409. voice->mPlayState.compare_exchange_strong(oldvstate, Voice::Stopping,
  1410. std::memory_order_relaxed, std::memory_order_acquire);
  1411. voice->mPendingChange.store(false, std::memory_order_release);
  1412. }
  1413. /* Reset state change events are always sent, even if the voice is
  1414. * already stopped or even if there is no voice.
  1415. */
  1416. sendevt |= (cur->mState == VChangeState::Reset);
  1417. }
  1418. else if(cur->mState == VChangeState::Pause)
  1419. {
  1420. Voice *voice{cur->mVoice};
  1421. Voice::State oldvstate{Voice::Playing};
  1422. sendevt = voice->mPlayState.compare_exchange_strong(oldvstate, Voice::Stopping,
  1423. std::memory_order_release, std::memory_order_acquire);
  1424. }
  1425. else if(cur->mState == VChangeState::Play)
  1426. {
  1427. /* NOTE: When playing a voice, sending a source state change event
  1428. * depends if there's an old voice to stop and if that stop is
  1429. * successful. If there is no old voice, a playing event is always
  1430. * sent. If there is an old voice, an event is sent only if the
  1431. * voice is already stopped.
  1432. */
  1433. if(Voice *oldvoice{cur->mOldVoice})
  1434. {
  1435. oldvoice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed);
  1436. oldvoice->mLoopBuffer.store(nullptr, std::memory_order_relaxed);
  1437. oldvoice->mSourceID.store(0u, std::memory_order_relaxed);
  1438. Voice::State oldvstate{Voice::Playing};
  1439. sendevt = !oldvoice->mPlayState.compare_exchange_strong(oldvstate, Voice::Stopping,
  1440. std::memory_order_relaxed, std::memory_order_acquire);
  1441. oldvoice->mPendingChange.store(false, std::memory_order_release);
  1442. }
  1443. else
  1444. sendevt = true;
  1445. Voice *voice{cur->mVoice};
  1446. voice->mPlayState.store(Voice::Playing, std::memory_order_release);
  1447. }
  1448. else if(cur->mState == VChangeState::Restart)
  1449. {
  1450. /* Restarting a voice never sends a source change event. */
  1451. Voice *oldvoice{cur->mOldVoice};
  1452. oldvoice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed);
  1453. oldvoice->mLoopBuffer.store(nullptr, std::memory_order_relaxed);
  1454. /* If there's no sourceID, the old voice finished so don't start
  1455. * the new one at its new offset.
  1456. */
  1457. if(oldvoice->mSourceID.exchange(0u, std::memory_order_relaxed) != 0u)
  1458. {
  1459. /* Otherwise, set the voice to stopping if it's not already (it
  1460. * might already be, if paused), and play the new voice as
  1461. * appropriate.
  1462. */
  1463. Voice::State oldvstate{Voice::Playing};
  1464. oldvoice->mPlayState.compare_exchange_strong(oldvstate, Voice::Stopping,
  1465. std::memory_order_relaxed, std::memory_order_acquire);
  1466. Voice *voice{cur->mVoice};
  1467. voice->mPlayState.store((oldvstate == Voice::Playing) ? Voice::Playing
  1468. : Voice::Stopped, std::memory_order_release);
  1469. }
  1470. oldvoice->mPendingChange.store(false, std::memory_order_release);
  1471. }
  1472. if(sendevt && (enabledevt&AsyncEvent::SourceStateChange))
  1473. SendSourceStateEvent(ctx, cur->mSourceID, cur->mState);
  1474. next = cur->mNext.load(std::memory_order_acquire);
  1475. } while(next);
  1476. ctx->mCurrentVoiceChange.store(cur, std::memory_order_release);
  1477. }
  1478. void ProcessParamUpdates(ContextBase *ctx, const EffectSlotArray &slots,
  1479. const al::span<Voice*> voices)
  1480. {
  1481. ProcessVoiceChanges(ctx);
  1482. IncrementRef(ctx->mUpdateCount);
  1483. if LIKELY(!ctx->mHoldUpdates.load(std::memory_order_acquire))
  1484. {
  1485. bool force{CalcContextParams(ctx)};
  1486. auto sorted_slots = const_cast<EffectSlot**>(slots.data() + slots.size());
  1487. for(EffectSlot *slot : slots)
  1488. force |= CalcEffectSlotParams(slot, sorted_slots, ctx);
  1489. for(Voice *voice : voices)
  1490. {
  1491. /* Only update voices that have a source. */
  1492. if(voice->mSourceID.load(std::memory_order_relaxed) != 0)
  1493. CalcSourceParams(voice, ctx, force);
  1494. }
  1495. }
  1496. IncrementRef(ctx->mUpdateCount);
  1497. }
  1498. void ProcessContexts(DeviceBase *device, const uint SamplesToDo)
  1499. {
  1500. ASSUME(SamplesToDo > 0);
  1501. for(ContextBase *ctx : *device->mContexts.load(std::memory_order_acquire))
  1502. {
  1503. const EffectSlotArray &auxslots = *ctx->mActiveAuxSlots.load(std::memory_order_acquire);
  1504. const al::span<Voice*> voices{ctx->getVoicesSpanAcquired()};
  1505. /* Process pending propery updates for objects on the context. */
  1506. ProcessParamUpdates(ctx, auxslots, voices);
  1507. /* Clear auxiliary effect slot mixing buffers. */
  1508. for(EffectSlot *slot : auxslots)
  1509. {
  1510. for(auto &buffer : slot->Wet.Buffer)
  1511. buffer.fill(0.0f);
  1512. }
  1513. /* Process voices that have a playing source. */
  1514. for(Voice *voice : voices)
  1515. {
  1516. const Voice::State vstate{voice->mPlayState.load(std::memory_order_acquire)};
  1517. if(vstate != Voice::Stopped && vstate != Voice::Pending)
  1518. voice->mix(vstate, ctx, SamplesToDo);
  1519. }
  1520. /* Process effects. */
  1521. if(const size_t num_slots{auxslots.size()})
  1522. {
  1523. auto slots = auxslots.data();
  1524. auto slots_end = slots + num_slots;
  1525. /* Sort the slots into extra storage, so that effect slots come
  1526. * before their effect slot target (or their targets' target).
  1527. */
  1528. const al::span<EffectSlot*> sorted_slots{const_cast<EffectSlot**>(slots_end),
  1529. num_slots};
  1530. /* Skip sorting if it has already been done. */
  1531. if(!sorted_slots[0])
  1532. {
  1533. /* First, copy the slots to the sorted list, then partition the
  1534. * sorted list so that all slots without a target slot go to
  1535. * the end.
  1536. */
  1537. std::copy(slots, slots_end, sorted_slots.begin());
  1538. auto split_point = std::partition(sorted_slots.begin(), sorted_slots.end(),
  1539. [](const EffectSlot *slot) noexcept -> bool
  1540. { return slot->Target != nullptr; });
  1541. /* There must be at least one slot without a slot target. */
  1542. assert(split_point != sorted_slots.end());
  1543. /* Simple case: no more than 1 slot has a target slot. Either
  1544. * all slots go right to the output, or the remaining one must
  1545. * target an already-partitioned slot.
  1546. */
  1547. if(split_point - sorted_slots.begin() > 1)
  1548. {
  1549. /* At least two slots target other slots. Starting from the
  1550. * back of the sorted list, continue partitioning the front
  1551. * of the list given each target until all targets are
  1552. * accounted for. This ensures all slots without a target
  1553. * go last, all slots directly targeting those last slots
  1554. * go second-to-last, all slots directly targeting those
  1555. * second-last slots go third-to-last, etc.
  1556. */
  1557. auto next_target = sorted_slots.end();
  1558. do {
  1559. /* This shouldn't happen, but if there's unsorted slots
  1560. * left that don't target any sorted slots, they can't
  1561. * contribute to the output, so leave them.
  1562. */
  1563. if UNLIKELY(next_target == split_point)
  1564. break;
  1565. --next_target;
  1566. split_point = std::partition(sorted_slots.begin(), split_point,
  1567. [next_target](const EffectSlot *slot) noexcept -> bool
  1568. { return slot->Target != *next_target; });
  1569. } while(split_point - sorted_slots.begin() > 1);
  1570. }
  1571. }
  1572. for(const EffectSlot *slot : sorted_slots)
  1573. {
  1574. EffectState *state{slot->mEffectState};
  1575. state->process(SamplesToDo, slot->Wet.Buffer, state->mOutTarget);
  1576. }
  1577. }
  1578. /* Signal the event handler if there are any events to read. */
  1579. RingBuffer *ring{ctx->mAsyncEvents.get()};
  1580. if(ring->readSpace() > 0)
  1581. ctx->mEventSem.post();
  1582. }
  1583. }
  1584. void ApplyDistanceComp(const al::span<FloatBufferLine> Samples, const size_t SamplesToDo,
  1585. const DistanceComp::ChanData *distcomp)
  1586. {
  1587. ASSUME(SamplesToDo > 0);
  1588. for(auto &chanbuffer : Samples)
  1589. {
  1590. const float gain{distcomp->Gain};
  1591. const size_t base{distcomp->Length};
  1592. float *distbuf{al::assume_aligned<16>(distcomp->Buffer)};
  1593. ++distcomp;
  1594. if(base < 1)
  1595. continue;
  1596. float *inout{al::assume_aligned<16>(chanbuffer.data())};
  1597. auto inout_end = inout + SamplesToDo;
  1598. if LIKELY(SamplesToDo >= base)
  1599. {
  1600. auto delay_end = std::rotate(inout, inout_end - base, inout_end);
  1601. std::swap_ranges(inout, delay_end, distbuf);
  1602. }
  1603. else
  1604. {
  1605. auto delay_start = std::swap_ranges(inout, inout_end, distbuf);
  1606. std::rotate(distbuf, delay_start, distbuf + base);
  1607. }
  1608. std::transform(inout, inout_end, inout, std::bind(std::multiplies<float>{}, _1, gain));
  1609. }
  1610. }
  1611. void ApplyDither(const al::span<FloatBufferLine> Samples, uint *dither_seed,
  1612. const float quant_scale, const size_t SamplesToDo)
  1613. {
  1614. ASSUME(SamplesToDo > 0);
  1615. /* Dithering. Generate whitenoise (uniform distribution of random values
  1616. * between -1 and +1) and add it to the sample values, after scaling up to
  1617. * the desired quantization depth amd before rounding.
  1618. */
  1619. const float invscale{1.0f / quant_scale};
  1620. uint seed{*dither_seed};
  1621. auto dither_sample = [&seed,invscale,quant_scale](const float sample) noexcept -> float
  1622. {
  1623. float val{sample * quant_scale};
  1624. uint rng0{dither_rng(&seed)};
  1625. uint rng1{dither_rng(&seed)};
  1626. val += static_cast<float>(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX));
  1627. return fast_roundf(val) * invscale;
  1628. };
  1629. for(FloatBufferLine &inout : Samples)
  1630. std::transform(inout.begin(), inout.begin()+SamplesToDo, inout.begin(), dither_sample);
  1631. *dither_seed = seed;
  1632. }
  1633. /* Base template left undefined. Should be marked =delete, but Clang 3.8.1
  1634. * chokes on that given the inline specializations.
  1635. */
  1636. template<typename T>
  1637. inline T SampleConv(float) noexcept;
  1638. template<> inline float SampleConv(float val) noexcept
  1639. { return val; }
  1640. template<> inline int32_t SampleConv(float val) noexcept
  1641. {
  1642. /* Floats have a 23-bit mantissa, plus an implied 1 bit and a sign bit.
  1643. * This means a normalized float has at most 25 bits of signed precision.
  1644. * When scaling and clamping for a signed 32-bit integer, these following
  1645. * values are the best a float can give.
  1646. */
  1647. return fastf2i(clampf(val*2147483648.0f, -2147483648.0f, 2147483520.0f));
  1648. }
  1649. template<> inline int16_t SampleConv(float val) noexcept
  1650. { return static_cast<int16_t>(fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f))); }
  1651. template<> inline int8_t SampleConv(float val) noexcept
  1652. { return static_cast<int8_t>(fastf2i(clampf(val*128.0f, -128.0f, 127.0f))); }
  1653. /* Define unsigned output variations. */
  1654. template<> inline uint32_t SampleConv(float val) noexcept
  1655. { return static_cast<uint32_t>(SampleConv<int32_t>(val)) + 2147483648u; }
  1656. template<> inline uint16_t SampleConv(float val) noexcept
  1657. { return static_cast<uint16_t>(SampleConv<int16_t>(val) + 32768); }
  1658. template<> inline uint8_t SampleConv(float val) noexcept
  1659. { return static_cast<uint8_t>(SampleConv<int8_t>(val) + 128); }
  1660. template<DevFmtType T>
  1661. void Write(const al::span<const FloatBufferLine> InBuffer, void *OutBuffer, const size_t Offset,
  1662. const size_t SamplesToDo, const size_t FrameStep)
  1663. {
  1664. ASSUME(FrameStep > 0);
  1665. ASSUME(SamplesToDo > 0);
  1666. DevFmtType_t<T> *outbase{static_cast<DevFmtType_t<T>*>(OutBuffer) + Offset*FrameStep};
  1667. size_t c{0};
  1668. for(const FloatBufferLine &inbuf : InBuffer)
  1669. {
  1670. DevFmtType_t<T> *out{outbase++};
  1671. auto conv_sample = [FrameStep,&out](const float s) noexcept -> void
  1672. {
  1673. *out = SampleConv<DevFmtType_t<T>>(s);
  1674. out += FrameStep;
  1675. };
  1676. std::for_each(inbuf.begin(), inbuf.begin()+SamplesToDo, conv_sample);
  1677. ++c;
  1678. }
  1679. if(const size_t extra{FrameStep - c})
  1680. {
  1681. const auto silence = SampleConv<DevFmtType_t<T>>(0.0f);
  1682. for(size_t i{0};i < SamplesToDo;++i)
  1683. {
  1684. std::fill_n(outbase, extra, silence);
  1685. outbase += FrameStep;
  1686. }
  1687. }
  1688. }
  1689. } // namespace
  1690. uint DeviceBase::renderSamples(const uint numSamples)
  1691. {
  1692. const uint samplesToDo{minu(numSamples, BufferLineSize)};
  1693. /* Clear main mixing buffers. */
  1694. for(FloatBufferLine &buffer : MixBuffer)
  1695. buffer.fill(0.0f);
  1696. /* Increment the mix count at the start (lsb should now be 1). */
  1697. IncrementRef(MixCount);
  1698. /* Process and mix each context's sources and effects. */
  1699. ProcessContexts(this, samplesToDo);
  1700. /* Increment the clock time. Every second's worth of samples is converted
  1701. * and added to clock base so that large sample counts don't overflow
  1702. * during conversion. This also guarantees a stable conversion.
  1703. */
  1704. SamplesDone += samplesToDo;
  1705. ClockBase += std::chrono::seconds{SamplesDone / Frequency};
  1706. SamplesDone %= Frequency;
  1707. /* Increment the mix count at the end (lsb should now be 0). */
  1708. IncrementRef(MixCount);
  1709. /* Apply any needed post-process for finalizing the Dry mix to the RealOut
  1710. * (Ambisonic decode, UHJ encode, etc).
  1711. */
  1712. postProcess(samplesToDo);
  1713. /* Apply compression, limiting sample amplitude if needed or desired. */
  1714. if(Limiter) Limiter->process(samplesToDo, RealOut.Buffer.data());
  1715. /* Apply delays and attenuation for mismatched speaker distances. */
  1716. if(ChannelDelays)
  1717. ApplyDistanceComp(RealOut.Buffer, samplesToDo, ChannelDelays->mChannels.data());
  1718. /* Apply dithering. The compressor should have left enough headroom for the
  1719. * dither noise to not saturate.
  1720. */
  1721. if(DitherDepth > 0.0f)
  1722. ApplyDither(RealOut.Buffer, &DitherSeed, DitherDepth, samplesToDo);
  1723. return samplesToDo;
  1724. }
  1725. void DeviceBase::renderSamples(const al::span<float*> outBuffers, const uint numSamples)
  1726. {
  1727. FPUCtl mixer_mode{};
  1728. uint total{0};
  1729. while(const uint todo{numSamples - total})
  1730. {
  1731. const uint samplesToDo{renderSamples(todo)};
  1732. auto *srcbuf = RealOut.Buffer.data();
  1733. for(auto *dstbuf : outBuffers)
  1734. {
  1735. std::copy_n(srcbuf->data(), samplesToDo, dstbuf + total);
  1736. ++srcbuf;
  1737. }
  1738. total += samplesToDo;
  1739. }
  1740. }
  1741. void DeviceBase::renderSamples(void *outBuffer, const uint numSamples, const size_t frameStep)
  1742. {
  1743. FPUCtl mixer_mode{};
  1744. uint total{0};
  1745. while(const uint todo{numSamples - total})
  1746. {
  1747. const uint samplesToDo{renderSamples(todo)};
  1748. if LIKELY(outBuffer)
  1749. {
  1750. /* Finally, interleave and convert samples, writing to the device's
  1751. * output buffer.
  1752. */
  1753. switch(FmtType)
  1754. {
  1755. #define HANDLE_WRITE(T) case T: \
  1756. Write<T>(RealOut.Buffer, outBuffer, total, samplesToDo, frameStep); break;
  1757. HANDLE_WRITE(DevFmtByte)
  1758. HANDLE_WRITE(DevFmtUByte)
  1759. HANDLE_WRITE(DevFmtShort)
  1760. HANDLE_WRITE(DevFmtUShort)
  1761. HANDLE_WRITE(DevFmtInt)
  1762. HANDLE_WRITE(DevFmtUInt)
  1763. HANDLE_WRITE(DevFmtFloat)
  1764. #undef HANDLE_WRITE
  1765. }
  1766. }
  1767. total += samplesToDo;
  1768. }
  1769. }
  1770. void DeviceBase::handleDisconnect(const char *msg, ...)
  1771. {
  1772. if(!Connected.exchange(false, std::memory_order_acq_rel))
  1773. return;
  1774. AsyncEvent evt{AsyncEvent::Disconnected};
  1775. va_list args;
  1776. va_start(args, msg);
  1777. int msglen{vsnprintf(evt.u.disconnect.msg, sizeof(evt.u.disconnect.msg), msg, args)};
  1778. va_end(args);
  1779. if(msglen < 0 || static_cast<size_t>(msglen) >= sizeof(evt.u.disconnect.msg))
  1780. evt.u.disconnect.msg[sizeof(evt.u.disconnect.msg)-1] = 0;
  1781. IncrementRef(MixCount);
  1782. for(ContextBase *ctx : *mContexts.load())
  1783. {
  1784. const uint enabledevt{ctx->mEnabledEvts.load(std::memory_order_acquire)};
  1785. if((enabledevt&AsyncEvent::Disconnected))
  1786. {
  1787. RingBuffer *ring{ctx->mAsyncEvents.get()};
  1788. auto evt_data = ring->getWriteVector().first;
  1789. if(evt_data.len > 0)
  1790. {
  1791. al::construct_at(reinterpret_cast<AsyncEvent*>(evt_data.buf), evt);
  1792. ring->writeAdvance(1);
  1793. ctx->mEventSem.post();
  1794. }
  1795. }
  1796. if(!ctx->mStopVoicesOnDisconnect)
  1797. {
  1798. ProcessVoiceChanges(ctx);
  1799. continue;
  1800. }
  1801. auto voicelist = ctx->getVoicesSpanAcquired();
  1802. auto stop_voice = [](Voice *voice) -> void
  1803. {
  1804. voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed);
  1805. voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed);
  1806. voice->mSourceID.store(0u, std::memory_order_relaxed);
  1807. voice->mPlayState.store(Voice::Stopped, std::memory_order_release);
  1808. };
  1809. std::for_each(voicelist.begin(), voicelist.end(), stop_voice);
  1810. }
  1811. IncrementRef(MixCount);
  1812. }