mixer_c.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. #include "config.h"
  2. #include <algorithm>
  3. #include <array>
  4. #include <cstddef>
  5. #include <limits>
  6. #include <variant>
  7. #include "alnumeric.h"
  8. #include "alspan.h"
  9. #include "core/bsinc_defs.h"
  10. #include "core/bufferline.h"
  11. #include "core/cubic_defs.h"
  12. #include "core/mixer/hrtfdefs.h"
  13. #include "core/resampler_limits.h"
  14. #include "defs.h"
  15. #include "hrtfbase.h"
  16. #include "opthelpers.h"
  17. struct CTag;
  18. struct PointTag;
  19. struct LerpTag;
  20. struct CubicTag;
  21. struct BSincTag;
  22. struct FastBSincTag;
  23. namespace {
  24. constexpr uint BsincPhaseDiffBits{MixerFracBits - BSincPhaseBits};
  25. constexpr uint BsincPhaseDiffOne{1 << BsincPhaseDiffBits};
  26. constexpr uint BsincPhaseDiffMask{BsincPhaseDiffOne - 1u};
  27. constexpr uint CubicPhaseDiffBits{MixerFracBits - CubicPhaseBits};
  28. constexpr uint CubicPhaseDiffOne{1 << CubicPhaseDiffBits};
  29. constexpr uint CubicPhaseDiffMask{CubicPhaseDiffOne - 1u};
  30. using SamplerNST = float(const al::span<const float>, const size_t, const uint) noexcept;
  31. template<typename T>
  32. using SamplerT = float(const T&,const al::span<const float>,const size_t,const uint) noexcept;
  33. [[nodiscard]] constexpr
  34. auto do_point(const al::span<const float> vals, const size_t pos, const uint) noexcept -> float
  35. { return vals[pos]; }
  36. [[nodiscard]] constexpr
  37. auto do_lerp(const al::span<const float> vals, const size_t pos, const uint frac) noexcept -> float
  38. { return lerpf(vals[pos+0], vals[pos+1], static_cast<float>(frac)*(1.0f/MixerFracOne)); }
  39. [[nodiscard]] constexpr
  40. auto do_cubic(const CubicState &istate, const al::span<const float> vals, const size_t pos,
  41. const uint frac) noexcept -> float
  42. {
  43. /* Calculate the phase index and factor. */
  44. const uint pi{frac >> CubicPhaseDiffBits}; ASSUME(pi < CubicPhaseCount);
  45. const float pf{static_cast<float>(frac&CubicPhaseDiffMask) * (1.0f/CubicPhaseDiffOne)};
  46. const auto fil = al::span{istate.filter[pi].mCoeffs};
  47. const auto phd = al::span{istate.filter[pi].mDeltas};
  48. /* Apply the phase interpolated filter. */
  49. return (fil[0] + pf*phd[0])*vals[pos+0] + (fil[1] + pf*phd[1])*vals[pos+1]
  50. + (fil[2] + pf*phd[2])*vals[pos+2] + (fil[3] + pf*phd[3])*vals[pos+3];
  51. }
  52. [[nodiscard]] constexpr
  53. auto do_fastbsinc(const BsincState &bsinc, const al::span<const float> vals, const size_t pos,
  54. const uint frac) noexcept -> float
  55. {
  56. const size_t m{bsinc.m};
  57. ASSUME(m > 0);
  58. ASSUME(m <= MaxResamplerPadding);
  59. /* Calculate the phase index and factor. */
  60. const uint pi{frac >> BsincPhaseDiffBits}; ASSUME(pi < BSincPhaseCount);
  61. const float pf{static_cast<float>(frac&BsincPhaseDiffMask) * (1.0f/BsincPhaseDiffOne)};
  62. const auto fil = bsinc.filter.subspan(2_uz*pi*m);
  63. const auto phd = fil.subspan(m);
  64. /* Apply the phase interpolated filter. */
  65. float r{0.0f};
  66. for(size_t j_f{0};j_f < m;++j_f)
  67. r += (fil[j_f] + pf*phd[j_f]) * vals[pos+j_f];
  68. return r;
  69. }
  70. [[nodiscard]] constexpr
  71. auto do_bsinc(const BsincState &bsinc, const al::span<const float> vals, const size_t pos,
  72. const uint frac) noexcept -> float
  73. {
  74. const size_t m{bsinc.m};
  75. ASSUME(m > 0);
  76. ASSUME(m <= MaxResamplerPadding);
  77. /* Calculate the phase index and factor. */
  78. const uint pi{frac >> BsincPhaseDiffBits}; ASSUME(pi < BSincPhaseCount);
  79. const float pf{static_cast<float>(frac&BsincPhaseDiffMask) * (1.0f/BsincPhaseDiffOne)};
  80. const auto fil = bsinc.filter.subspan(2_uz*pi*m);
  81. const auto phd = fil.subspan(m);
  82. const auto scd = fil.subspan(BSincPhaseCount*2_uz*m);
  83. const auto spd = scd.subspan(m);
  84. /* Apply the scale and phase interpolated filter. */
  85. float r{0.0f};
  86. for(size_t j_f{0};j_f < m;++j_f)
  87. r += (fil[j_f] + bsinc.sf*scd[j_f] + pf*(phd[j_f] + bsinc.sf*spd[j_f])) * vals[pos+j_f];
  88. return r;
  89. }
  90. template<SamplerNST Sampler>
  91. void DoResample(const al::span<const float> src, uint frac, const uint increment,
  92. const al::span<float> dst)
  93. {
  94. ASSUME(frac < MixerFracOne);
  95. size_t pos{0};
  96. std::generate(dst.begin(), dst.end(), [&pos,&frac,src,increment]() -> float
  97. {
  98. const float output{Sampler(src, pos, frac)};
  99. frac += increment;
  100. pos += frac>>MixerFracBits;
  101. frac &= MixerFracMask;
  102. return output;
  103. });
  104. }
  105. template<typename U, SamplerT<U> Sampler>
  106. void DoResample(const U istate, const al::span<const float> src, uint frac, const uint increment,
  107. const al::span<float> dst)
  108. {
  109. ASSUME(frac < MixerFracOne);
  110. size_t pos{0};
  111. std::generate(dst.begin(), dst.end(), [istate,src,&pos,&frac,increment]() -> float
  112. {
  113. const float output{Sampler(istate, src, pos, frac)};
  114. frac += increment;
  115. pos += frac>>MixerFracBits;
  116. frac &= MixerFracMask;
  117. return output;
  118. });
  119. }
  120. inline void ApplyCoeffs(const al::span<float2> Values, const size_t IrSize,
  121. const ConstHrirSpan Coeffs, const float left, const float right) noexcept
  122. {
  123. ASSUME(IrSize >= MinIrLength);
  124. ASSUME(IrSize <= HrirLength);
  125. auto mix_impulse = [left,right](const float2 &value, const float2 &coeff) noexcept -> float2
  126. { return float2{{value[0] + coeff[0]*left, value[1] + coeff[1]*right}}; };
  127. std::transform(Values.cbegin(), Values.cbegin()+ptrdiff_t(IrSize), Coeffs.cbegin(),
  128. Values.begin(), mix_impulse);
  129. }
  130. force_inline void MixLine(al::span<const float> InSamples, const al::span<float> dst,
  131. float &CurrentGain, const float TargetGain, const float delta, const size_t fade_len,
  132. size_t Counter)
  133. {
  134. const float step{(TargetGain-CurrentGain) * delta};
  135. auto output = dst.begin();
  136. if(std::abs(step) > std::numeric_limits<float>::epsilon())
  137. {
  138. auto input = InSamples.first(fade_len);
  139. InSamples = InSamples.subspan(fade_len);
  140. const float gain{CurrentGain};
  141. float step_count{0.0f};
  142. output = std::transform(input.begin(), input.end(), output, output,
  143. [gain,step,&step_count](const float in, float out) noexcept -> float
  144. {
  145. out += in * (gain + step*step_count);
  146. step_count += 1.0f;
  147. return out;
  148. });
  149. if(fade_len < Counter)
  150. {
  151. CurrentGain = gain + step*step_count;
  152. return;
  153. }
  154. }
  155. CurrentGain = TargetGain;
  156. if(!(std::abs(TargetGain) > GainSilenceThreshold))
  157. return;
  158. std::transform(InSamples.begin(), InSamples.end(), output, output,
  159. [TargetGain](const float in, const float out) noexcept -> float
  160. { return out + in*TargetGain; });
  161. }
  162. } // namespace
  163. template<>
  164. void Resample_<PointTag,CTag>(const InterpState*, const al::span<const float> src, uint frac,
  165. const uint increment, const al::span<float> dst)
  166. { DoResample<do_point>(src.subspan(MaxResamplerEdge), frac, increment, dst); }
  167. template<>
  168. void Resample_<LerpTag,CTag>(const InterpState*, const al::span<const float> src, uint frac,
  169. const uint increment, const al::span<float> dst)
  170. { DoResample<do_lerp>(src.subspan(MaxResamplerEdge), frac, increment, dst); }
  171. template<>
  172. void Resample_<CubicTag,CTag>(const InterpState *state, const al::span<const float> src, uint frac,
  173. const uint increment, const al::span<float> dst)
  174. {
  175. DoResample<CubicState,do_cubic>(std::get<CubicState>(*state), src.subspan(MaxResamplerEdge-1),
  176. frac, increment, dst);
  177. }
  178. template<>
  179. void Resample_<FastBSincTag,CTag>(const InterpState *state, const al::span<const float> src,
  180. uint frac, const uint increment, const al::span<float> dst)
  181. {
  182. const auto istate = std::get<BsincState>(*state);
  183. ASSUME(istate.l <= MaxResamplerEdge);
  184. DoResample<BsincState,do_fastbsinc>(istate, src.subspan(MaxResamplerEdge-istate.l), frac,
  185. increment, dst);
  186. }
  187. template<>
  188. void Resample_<BSincTag,CTag>(const InterpState *state, const al::span<const float> src, uint frac,
  189. const uint increment, const al::span<float> dst)
  190. {
  191. const auto istate = std::get<BsincState>(*state);
  192. ASSUME(istate.l <= MaxResamplerEdge);
  193. DoResample<BsincState,do_bsinc>(istate, src.subspan(MaxResamplerEdge-istate.l), frac,
  194. increment, dst);
  195. }
  196. template<>
  197. void MixHrtf_<CTag>(const al::span<const float> InSamples, const al::span<float2> AccumSamples,
  198. const uint IrSize, const MixHrtfFilter *hrtfparams, const size_t SamplesToDo)
  199. { MixHrtfBase<ApplyCoeffs>(InSamples, AccumSamples, IrSize, hrtfparams, SamplesToDo); }
  200. template<>
  201. void MixHrtfBlend_<CTag>(const al::span<const float> InSamples,const al::span<float2> AccumSamples,
  202. const uint IrSize, const HrtfFilter *oldparams, const MixHrtfFilter *newparams,
  203. const size_t SamplesToDo)
  204. {
  205. MixHrtfBlendBase<ApplyCoeffs>(InSamples, AccumSamples, IrSize, oldparams, newparams,
  206. SamplesToDo);
  207. }
  208. template<>
  209. void MixDirectHrtf_<CTag>(const FloatBufferSpan LeftOut, const FloatBufferSpan RightOut,
  210. const al::span<const FloatBufferLine> InSamples, const al::span<float2> AccumSamples,
  211. const al::span<float,BufferLineSize> TempBuf, const al::span<HrtfChannelState> ChanState,
  212. const size_t IrSize, const size_t SamplesToDo)
  213. {
  214. MixDirectHrtfBase<ApplyCoeffs>(LeftOut, RightOut, InSamples, AccumSamples, TempBuf, ChanState,
  215. IrSize, SamplesToDo);
  216. }
  217. template<>
  218. void Mix_<CTag>(const al::span<const float> InSamples, const al::span<FloatBufferLine> OutBuffer,
  219. const al::span<float> CurrentGains, const al::span<const float> TargetGains,
  220. const size_t Counter, const size_t OutPos)
  221. {
  222. const float delta{(Counter > 0) ? 1.0f / static_cast<float>(Counter) : 0.0f};
  223. const auto fade_len = std::min(Counter, InSamples.size());
  224. auto curgains = CurrentGains.begin();
  225. auto targetgains = TargetGains.cbegin();
  226. for(FloatBufferLine &output : OutBuffer)
  227. MixLine(InSamples, al::span{output}.subspan(OutPos), *curgains++, *targetgains++, delta,
  228. fade_len, Counter);
  229. }
  230. template<>
  231. void Mix_<CTag>(const al::span<const float> InSamples, const al::span<float> OutBuffer,
  232. float &CurrentGain, const float TargetGain, const size_t Counter)
  233. {
  234. const float delta{(Counter > 0) ? 1.0f / static_cast<float>(Counter) : 0.0f};
  235. const auto fade_len = std::min(Counter, InSamples.size());
  236. MixLine(InSamples, OutBuffer, CurrentGain, TargetGain, delta, fade_len, Counter);
  237. }