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

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