alu.cpp 88 KB

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