🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

129 lines
4.6 KiB

  1. #ifndef CORE_MIXER_HRTFBASE_H
  2. #define CORE_MIXER_HRTFBASE_H
  3. #include <algorithm>
  4. #include <cmath>
  5. #include "almalloc.h"
  6. #include "hrtfdefs.h"
  7. #include "opthelpers.h"
  8. using uint = unsigned int;
  9. using ApplyCoeffsT = void(&)(float2 *RESTRICT Values, const size_t irSize,
  10. const ConstHrirSpan Coeffs, const float left, const float right);
  11. template<ApplyCoeffsT ApplyCoeffs>
  12. inline void MixHrtfBase(const float *InSamples, float2 *RESTRICT AccumSamples, const size_t IrSize,
  13. const MixHrtfFilter *hrtfparams, const size_t BufferSize)
  14. {
  15. ASSUME(BufferSize > 0);
  16. const ConstHrirSpan Coeffs{hrtfparams->Coeffs};
  17. const float gainstep{hrtfparams->GainStep};
  18. const float gain{hrtfparams->Gain};
  19. size_t ldelay{HrtfHistoryLength - hrtfparams->Delay[0]};
  20. size_t rdelay{HrtfHistoryLength - hrtfparams->Delay[1]};
  21. float stepcount{0.0f};
  22. for(size_t i{0u};i < BufferSize;++i)
  23. {
  24. const float g{gain + gainstep*stepcount};
  25. const float left{InSamples[ldelay++] * g};
  26. const float right{InSamples[rdelay++] * g};
  27. ApplyCoeffs(AccumSamples+i, IrSize, Coeffs, left, right);
  28. stepcount += 1.0f;
  29. }
  30. }
  31. template<ApplyCoeffsT ApplyCoeffs>
  32. inline void MixHrtfBlendBase(const float *InSamples, float2 *RESTRICT AccumSamples,
  33. const size_t IrSize, const HrtfFilter *oldparams, const MixHrtfFilter *newparams,
  34. const size_t BufferSize)
  35. {
  36. ASSUME(BufferSize > 0);
  37. const ConstHrirSpan OldCoeffs{oldparams->Coeffs};
  38. const float oldGainStep{oldparams->Gain / static_cast<float>(BufferSize)};
  39. const ConstHrirSpan NewCoeffs{newparams->Coeffs};
  40. const float newGainStep{newparams->GainStep};
  41. if LIKELY(oldparams->Gain > GainSilenceThreshold)
  42. {
  43. size_t ldelay{HrtfHistoryLength - oldparams->Delay[0]};
  44. size_t rdelay{HrtfHistoryLength - oldparams->Delay[1]};
  45. auto stepcount = static_cast<float>(BufferSize);
  46. for(size_t i{0u};i < BufferSize;++i)
  47. {
  48. const float g{oldGainStep*stepcount};
  49. const float left{InSamples[ldelay++] * g};
  50. const float right{InSamples[rdelay++] * g};
  51. ApplyCoeffs(AccumSamples+i, IrSize, OldCoeffs, left, right);
  52. stepcount -= 1.0f;
  53. }
  54. }
  55. if LIKELY(newGainStep*static_cast<float>(BufferSize) > GainSilenceThreshold)
  56. {
  57. size_t ldelay{HrtfHistoryLength+1 - newparams->Delay[0]};
  58. size_t rdelay{HrtfHistoryLength+1 - newparams->Delay[1]};
  59. float stepcount{1.0f};
  60. for(size_t i{1u};i < BufferSize;++i)
  61. {
  62. const float g{newGainStep*stepcount};
  63. const float left{InSamples[ldelay++] * g};
  64. const float right{InSamples[rdelay++] * g};
  65. ApplyCoeffs(AccumSamples+i, IrSize, NewCoeffs, left, right);
  66. stepcount += 1.0f;
  67. }
  68. }
  69. }
  70. template<ApplyCoeffsT ApplyCoeffs>
  71. inline void MixDirectHrtfBase(const FloatBufferSpan LeftOut, const FloatBufferSpan RightOut,
  72. const al::span<const FloatBufferLine> InSamples, float2 *RESTRICT AccumSamples,
  73. float *TempBuf, HrtfChannelState *ChanState, const size_t IrSize, const size_t BufferSize)
  74. {
  75. ASSUME(BufferSize > 0);
  76. for(const FloatBufferLine &input : InSamples)
  77. {
  78. /* For dual-band processing, the signal needs extra scaling applied to
  79. * the high frequency response. The band-splitter applies this scaling
  80. * with a consistent phase shift regardless of the scale amount.
  81. */
  82. ChanState->mSplitter.processHfScale({input.data(), BufferSize}, TempBuf,
  83. ChanState->mHfScale);
  84. /* Now apply the HRIR coefficients to this channel. */
  85. const float *RESTRICT tempbuf{al::assume_aligned<16>(TempBuf)};
  86. const ConstHrirSpan Coeffs{ChanState->mCoeffs};
  87. for(size_t i{0u};i < BufferSize;++i)
  88. {
  89. const float insample{tempbuf[i]};
  90. ApplyCoeffs(AccumSamples+i, IrSize, Coeffs, insample, insample);
  91. }
  92. ++ChanState;
  93. }
  94. /* Add the HRTF signal to the existing "direct" signal. */
  95. float *RESTRICT left{al::assume_aligned<16>(LeftOut.data())};
  96. float *RESTRICT right{al::assume_aligned<16>(RightOut.data())};
  97. for(size_t i{0u};i < BufferSize;++i)
  98. left[i] += AccumSamples[i][0];
  99. for(size_t i{0u};i < BufferSize;++i)
  100. right[i] += AccumSamples[i][1];
  101. /* Copy the new in-progress accumulation values to the front and clear the
  102. * following samples for the next mix.
  103. */
  104. auto accum_iter = std::copy_n(AccumSamples+BufferSize, HrirLength, AccumSamples);
  105. std::fill_n(accum_iter, BufferSize, float2{});
  106. }
  107. #endif /* CORE_MIXER_HRTFBASE_H */