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

222 lines
7.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 <cstdlib>
  24. #include <iterator>
  25. #include <utility>
  26. #include "alc/effects/base.h"
  27. #include "almalloc.h"
  28. #include "alnumbers.h"
  29. #include "alnumeric.h"
  30. #include "alspan.h"
  31. #include "core/ambidefs.h"
  32. #include "core/bufferline.h"
  33. #include "core/context.h"
  34. #include "core/devformat.h"
  35. #include "core/device.h"
  36. #include "core/effectslot.h"
  37. #include "core/mixer.h"
  38. #include "intrusive_ptr.h"
  39. namespace {
  40. constexpr float GainScale{31621.0f};
  41. constexpr float MinFreq{20.0f};
  42. constexpr float MaxFreq{2500.0f};
  43. constexpr float QFactor{5.0f};
  44. struct AutowahState final : public EffectState {
  45. /* Effect parameters */
  46. float mAttackRate;
  47. float mReleaseRate;
  48. float mResonanceGain;
  49. float mPeakGain;
  50. float mFreqMinNorm;
  51. float mBandwidthNorm;
  52. float mEnvDelay;
  53. /* Filter components derived from the envelope. */
  54. struct {
  55. float cos_w0;
  56. float alpha;
  57. } mEnv[BufferLineSize];
  58. struct {
  59. /* Effect filters' history. */
  60. struct {
  61. float z1, z2;
  62. } Filter;
  63. /* Effect gains for each output channel */
  64. float CurrentGains[MAX_OUTPUT_CHANNELS];
  65. float TargetGains[MAX_OUTPUT_CHANNELS];
  66. } mChans[MaxAmbiChannels];
  67. /* Effects buffers */
  68. alignas(16) float mBufferOut[BufferLineSize];
  69. void deviceUpdate(const DeviceBase *device, const Buffer &buffer) override;
  70. void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props,
  71. const EffectTarget target) override;
  72. void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
  73. const al::span<FloatBufferLine> samplesOut) override;
  74. DEF_NEWDEL(AutowahState)
  75. };
  76. void AutowahState::deviceUpdate(const DeviceBase*, const Buffer&)
  77. {
  78. /* (Re-)initializing parameters and clear the buffers. */
  79. mAttackRate = 1.0f;
  80. mReleaseRate = 1.0f;
  81. mResonanceGain = 10.0f;
  82. mPeakGain = 4.5f;
  83. mFreqMinNorm = 4.5e-4f;
  84. mBandwidthNorm = 0.05f;
  85. mEnvDelay = 0.0f;
  86. for(auto &e : mEnv)
  87. {
  88. e.cos_w0 = 0.0f;
  89. e.alpha = 0.0f;
  90. }
  91. for(auto &chan : mChans)
  92. {
  93. std::fill(std::begin(chan.CurrentGains), std::end(chan.CurrentGains), 0.0f);
  94. chan.Filter.z1 = 0.0f;
  95. chan.Filter.z2 = 0.0f;
  96. }
  97. }
  98. void AutowahState::update(const ContextBase *context, const EffectSlot *slot,
  99. const EffectProps *props, const EffectTarget target)
  100. {
  101. const DeviceBase *device{context->mDevice};
  102. const auto frequency = static_cast<float>(device->Frequency);
  103. const float ReleaseTime{clampf(props->Autowah.ReleaseTime, 0.001f, 1.0f)};
  104. mAttackRate = std::exp(-1.0f / (props->Autowah.AttackTime*frequency));
  105. mReleaseRate = std::exp(-1.0f / (ReleaseTime*frequency));
  106. /* 0-20dB Resonance Peak gain */
  107. mResonanceGain = std::sqrt(std::log10(props->Autowah.Resonance)*10.0f / 3.0f);
  108. mPeakGain = 1.0f - std::log10(props->Autowah.PeakGain / GainScale);
  109. mFreqMinNorm = MinFreq / frequency;
  110. mBandwidthNorm = (MaxFreq-MinFreq) / frequency;
  111. mOutTarget = target.Main->Buffer;
  112. auto set_gains = [slot,target](auto &chan, al::span<const float,MaxAmbiChannels> coeffs)
  113. { ComputePanGains(target.Main, coeffs.data(), slot->Gain, chan.TargetGains); };
  114. SetAmbiPanIdentity(std::begin(mChans), slot->Wet.Buffer.size(), set_gains);
  115. }
  116. void AutowahState::process(const size_t samplesToDo,
  117. const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut)
  118. {
  119. const float attack_rate{mAttackRate};
  120. const float release_rate{mReleaseRate};
  121. const float res_gain{mResonanceGain};
  122. const float peak_gain{mPeakGain};
  123. const float freq_min{mFreqMinNorm};
  124. const float bandwidth{mBandwidthNorm};
  125. float env_delay{mEnvDelay};
  126. for(size_t i{0u};i < samplesToDo;i++)
  127. {
  128. float w0, sample, a;
  129. /* Envelope follower described on the book: Audio Effects, Theory,
  130. * Implementation and Application.
  131. */
  132. sample = peak_gain * std::fabs(samplesIn[0][i]);
  133. a = (sample > env_delay) ? attack_rate : release_rate;
  134. env_delay = lerpf(sample, env_delay, a);
  135. /* Calculate the cos and alpha components for this sample's filter. */
  136. w0 = minf((bandwidth*env_delay + freq_min), 0.46f) * (al::numbers::pi_v<float>*2.0f);
  137. mEnv[i].cos_w0 = std::cos(w0);
  138. mEnv[i].alpha = std::sin(w0)/(2.0f * QFactor);
  139. }
  140. mEnvDelay = env_delay;
  141. auto chandata = std::addressof(mChans[0]);
  142. for(const auto &insamples : samplesIn)
  143. {
  144. /* This effectively inlines BiquadFilter_setParams for a peaking
  145. * filter and BiquadFilter_processC. The alpha and cosine components
  146. * for the filter coefficients were previously calculated with the
  147. * envelope. Because the filter changes for each sample, the
  148. * coefficients are transient and don't need to be held.
  149. */
  150. float z1{chandata->Filter.z1};
  151. float z2{chandata->Filter.z2};
  152. for(size_t i{0u};i < samplesToDo;i++)
  153. {
  154. const float alpha{mEnv[i].alpha};
  155. const float cos_w0{mEnv[i].cos_w0};
  156. float input, output;
  157. float a[3], b[3];
  158. b[0] = 1.0f + alpha*res_gain;
  159. b[1] = -2.0f * cos_w0;
  160. b[2] = 1.0f - alpha*res_gain;
  161. a[0] = 1.0f + alpha/res_gain;
  162. a[1] = -2.0f * cos_w0;
  163. a[2] = 1.0f - alpha/res_gain;
  164. input = insamples[i];
  165. output = input*(b[0]/a[0]) + z1;
  166. z1 = input*(b[1]/a[0]) - output*(a[1]/a[0]) + z2;
  167. z2 = input*(b[2]/a[0]) - output*(a[2]/a[0]);
  168. mBufferOut[i] = output;
  169. }
  170. chandata->Filter.z1 = z1;
  171. chandata->Filter.z2 = z2;
  172. /* Now, mix the processed sound data to the output. */
  173. MixSamples({mBufferOut, samplesToDo}, samplesOut, chandata->CurrentGains,
  174. chandata->TargetGains, samplesToDo, 0);
  175. ++chandata;
  176. }
  177. }
  178. struct AutowahStateFactory final : public EffectStateFactory {
  179. al::intrusive_ptr<EffectState> create() override
  180. { return al::intrusive_ptr<EffectState>{new AutowahState{}}; }
  181. };
  182. } // namespace
  183. EffectStateFactory *AutowahStateFactory_getFactory()
  184. {
  185. static AutowahStateFactory AutowahFactory{};
  186. return &AutowahFactory;
  187. }