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

247 lines
8.1 KiB

  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 2018 by Raul Herraiz.
  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 <algorithm>
  22. #include <array>
  23. #include <cmath>
  24. #include <complex>
  25. #include <cstdlib>
  26. #include <iterator>
  27. #include "alc/effects/base.h"
  28. #include "alcomplex.h"
  29. #include "almalloc.h"
  30. #include "alnumbers.h"
  31. #include "alnumeric.h"
  32. #include "alspan.h"
  33. #include "core/bufferline.h"
  34. #include "core/context.h"
  35. #include "core/devformat.h"
  36. #include "core/device.h"
  37. #include "core/effectslot.h"
  38. #include "core/mixer.h"
  39. #include "core/mixer/defs.h"
  40. #include "intrusive_ptr.h"
  41. namespace {
  42. using uint = unsigned int;
  43. using complex_d = std::complex<double>;
  44. #define HIL_SIZE 1024
  45. #define OVERSAMP (1<<2)
  46. #define HIL_STEP (HIL_SIZE / OVERSAMP)
  47. #define FIFO_LATENCY (HIL_STEP * (OVERSAMP-1))
  48. /* Define a Hann window, used to filter the HIL input and output. */
  49. std::array<double,HIL_SIZE> InitHannWindow()
  50. {
  51. std::array<double,HIL_SIZE> ret;
  52. /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */
  53. for(size_t i{0};i < HIL_SIZE>>1;i++)
  54. {
  55. constexpr double scale{al::numbers::pi / double{HIL_SIZE}};
  56. const double val{std::sin(static_cast<double>(i+1) * scale)};
  57. ret[i] = ret[HIL_SIZE-1-i] = val * val;
  58. }
  59. return ret;
  60. }
  61. alignas(16) const std::array<double,HIL_SIZE> HannWindow = InitHannWindow();
  62. struct FshifterState final : public EffectState {
  63. /* Effect parameters */
  64. size_t mCount{};
  65. size_t mPos{};
  66. uint mPhaseStep[2]{};
  67. uint mPhase[2]{};
  68. double mSign[2]{};
  69. /* Effects buffers */
  70. double mInFIFO[HIL_SIZE]{};
  71. complex_d mOutFIFO[HIL_STEP]{};
  72. complex_d mOutputAccum[HIL_SIZE]{};
  73. complex_d mAnalytic[HIL_SIZE]{};
  74. complex_d mOutdata[BufferLineSize]{};
  75. alignas(16) float mBufferOut[BufferLineSize]{};
  76. /* Effect gains for each output channel */
  77. struct {
  78. float Current[MAX_OUTPUT_CHANNELS]{};
  79. float Target[MAX_OUTPUT_CHANNELS]{};
  80. } mGains[2];
  81. void deviceUpdate(const DeviceBase *device, const Buffer &buffer) override;
  82. void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props,
  83. const EffectTarget target) override;
  84. void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
  85. const al::span<FloatBufferLine> samplesOut) override;
  86. DEF_NEWDEL(FshifterState)
  87. };
  88. void FshifterState::deviceUpdate(const DeviceBase*, const Buffer&)
  89. {
  90. /* (Re-)initializing parameters and clear the buffers. */
  91. mCount = 0;
  92. mPos = FIFO_LATENCY;
  93. std::fill(std::begin(mPhaseStep), std::end(mPhaseStep), 0u);
  94. std::fill(std::begin(mPhase), std::end(mPhase), 0u);
  95. std::fill(std::begin(mSign), std::end(mSign), 1.0);
  96. std::fill(std::begin(mInFIFO), std::end(mInFIFO), 0.0);
  97. std::fill(std::begin(mOutFIFO), std::end(mOutFIFO), complex_d{});
  98. std::fill(std::begin(mOutputAccum), std::end(mOutputAccum), complex_d{});
  99. std::fill(std::begin(mAnalytic), std::end(mAnalytic), complex_d{});
  100. for(auto &gain : mGains)
  101. {
  102. std::fill(std::begin(gain.Current), std::end(gain.Current), 0.0f);
  103. std::fill(std::begin(gain.Target), std::end(gain.Target), 0.0f);
  104. }
  105. }
  106. void FshifterState::update(const ContextBase *context, const EffectSlot *slot,
  107. const EffectProps *props, const EffectTarget target)
  108. {
  109. const DeviceBase *device{context->mDevice};
  110. const float step{props->Fshifter.Frequency / static_cast<float>(device->Frequency)};
  111. mPhaseStep[0] = mPhaseStep[1] = fastf2u(minf(step, 1.0f) * MixerFracOne);
  112. switch(props->Fshifter.LeftDirection)
  113. {
  114. case FShifterDirection::Down:
  115. mSign[0] = -1.0;
  116. break;
  117. case FShifterDirection::Up:
  118. mSign[0] = 1.0;
  119. break;
  120. case FShifterDirection::Off:
  121. mPhase[0] = 0;
  122. mPhaseStep[0] = 0;
  123. break;
  124. }
  125. switch(props->Fshifter.RightDirection)
  126. {
  127. case FShifterDirection::Down:
  128. mSign[1] = -1.0;
  129. break;
  130. case FShifterDirection::Up:
  131. mSign[1] = 1.0;
  132. break;
  133. case FShifterDirection::Off:
  134. mPhase[1] = 0;
  135. mPhaseStep[1] = 0;
  136. break;
  137. }
  138. const auto lcoeffs = CalcDirectionCoeffs({-1.0f, 0.0f, 0.0f}, 0.0f);
  139. const auto rcoeffs = CalcDirectionCoeffs({ 1.0f, 0.0f, 0.0f}, 0.0f);
  140. mOutTarget = target.Main->Buffer;
  141. ComputePanGains(target.Main, lcoeffs.data(), slot->Gain, mGains[0].Target);
  142. ComputePanGains(target.Main, rcoeffs.data(), slot->Gain, mGains[1].Target);
  143. }
  144. void FshifterState::process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut)
  145. {
  146. for(size_t base{0u};base < samplesToDo;)
  147. {
  148. size_t todo{minz(HIL_STEP-mCount, samplesToDo-base)};
  149. /* Fill FIFO buffer with samples data */
  150. const size_t pos{mPos};
  151. size_t count{mCount};
  152. do {
  153. mInFIFO[pos+count] = samplesIn[0][base];
  154. mOutdata[base] = mOutFIFO[count];
  155. ++base; ++count;
  156. } while(--todo);
  157. mCount = count;
  158. /* Check whether FIFO buffer is filled */
  159. if(mCount < HIL_STEP) break;
  160. mCount = 0;
  161. mPos = (mPos+HIL_STEP) & (HIL_SIZE-1);
  162. /* Real signal windowing and store in Analytic buffer */
  163. for(size_t src{mPos}, k{0u};src < HIL_SIZE;++src,++k)
  164. mAnalytic[k] = mInFIFO[src]*HannWindow[k];
  165. for(size_t src{0u}, k{HIL_SIZE-mPos};src < mPos;++src,++k)
  166. mAnalytic[k] = mInFIFO[src]*HannWindow[k];
  167. /* Processing signal by Discrete Hilbert Transform (analytical signal). */
  168. complex_hilbert(mAnalytic);
  169. /* Windowing and add to output accumulator */
  170. for(size_t dst{mPos}, k{0u};dst < HIL_SIZE;++dst,++k)
  171. mOutputAccum[dst] += 2.0/OVERSAMP*HannWindow[k]*mAnalytic[k];
  172. for(size_t dst{0u}, k{HIL_SIZE-mPos};dst < mPos;++dst,++k)
  173. mOutputAccum[dst] += 2.0/OVERSAMP*HannWindow[k]*mAnalytic[k];
  174. /* Copy out the accumulated result, then clear for the next iteration. */
  175. std::copy_n(mOutputAccum + mPos, HIL_STEP, mOutFIFO);
  176. std::fill_n(mOutputAccum + mPos, HIL_STEP, complex_d{});
  177. }
  178. /* Process frequency shifter using the analytic signal obtained. */
  179. float *RESTRICT BufferOut{mBufferOut};
  180. for(int c{0};c < 2;++c)
  181. {
  182. const uint phase_step{mPhaseStep[c]};
  183. uint phase_idx{mPhase[c]};
  184. for(size_t k{0};k < samplesToDo;++k)
  185. {
  186. const double phase{phase_idx * (al::numbers::pi*2.0 / MixerFracOne)};
  187. BufferOut[k] = static_cast<float>(mOutdata[k].real()*std::cos(phase) +
  188. mOutdata[k].imag()*std::sin(phase)*mSign[c]);
  189. phase_idx += phase_step;
  190. phase_idx &= MixerFracMask;
  191. }
  192. mPhase[c] = phase_idx;
  193. /* Now, mix the processed sound data to the output. */
  194. MixSamples({BufferOut, samplesToDo}, samplesOut, mGains[c].Current, mGains[c].Target,
  195. maxz(samplesToDo, 512), 0);
  196. }
  197. }
  198. struct FshifterStateFactory final : public EffectStateFactory {
  199. al::intrusive_ptr<EffectState> create() override
  200. { return al::intrusive_ptr<EffectState>{new FshifterState{}}; }
  201. };
  202. } // namespace
  203. EffectStateFactory *FshifterStateFactory_getFactory()
  204. {
  205. static FshifterStateFactory FshifterFactory{};
  206. return &FshifterFactory;
  207. }